#include "common.h"
#include "plugin.h"
#include "utils_complain.h"
+#include "utils_ignorelist.h"
#include <errno.h>
#include <pthread.h>
-#include <regex.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#define PROCEVENT_FIELDS 4 // pid, status, extra, timestamp
#define BUFSIZE 512
#define PROCDIR "/proc"
-#define PROCEVENT_REGEX_MATCHES 1
#define PROCEVENT_DOMAIN_FIELD "domain"
#define PROCEVENT_DOMAIN_VALUE "fault"
struct processlist_s {
char *process;
- char *process_regex;
- regex_t process_regex_obj;
-
- uint32_t is_regex;
uint32_t pid;
struct processlist_s *next;
/*
* Private variables
*/
+static ignorelist_t *ignorelist = NULL;
static int procevent_thread_loop = 0;
static int procevent_thread_error = 0;
long long unsigned int timestamp, char **buf) {
const unsigned char *buf2;
yajl_gen g;
+ char json_str[DATA_MAX_NAME_LEN];
#if !defined(HAVE_YAJL_V2)
yajl_gen_config conf = {};
event_id = event_id + 1;
int event_id_len = sizeof(char) * sizeof(int) * 4 + 1;
- char *event_id_str = malloc(event_id_len);
- snprintf(event_id_str, event_id_len, "%d", event_id);
+ memset(json_str, '\0', DATA_MAX_NAME_LEN);
+ snprintf(json_str, event_id_len, "%d", event_id);
- if (yajl_gen_number(g, event_id_str, strlen(event_id_str)) !=
- yajl_gen_status_ok) {
- sfree(event_id_str);
+ if (yajl_gen_number(g, json_str, strlen(json_str)) != yajl_gen_status_ok) {
goto err;
}
- sfree(event_id_str);
-
// eventName
if (yajl_gen_string(g, (u_char *)PROCEVENT_EVENT_NAME_FIELD,
strlen(PROCEVENT_EVENT_NAME_FIELD)) != yajl_gen_status_ok)
event_name_len = event_name_len + (state == 0 ? 4 : 2); // "down" or "up"
event_name_len = event_name_len +
13; // "process", 3 spaces, 2 parentheses and null-terminator
- char *event_name_str = malloc(event_name_len);
- memset(event_name_str, '\0', event_name_len);
- snprintf(event_name_str, event_name_len, "process %s (%d) %s", process, pid,
+ memset(json_str, '\0', DATA_MAX_NAME_LEN);
+ snprintf(json_str, event_name_len, "process %s (%d) %s", process, pid,
(state == 0 ? PROCEVENT_EVENT_NAME_DOWN_VALUE
: PROCEVENT_EVENT_NAME_UP_VALUE));
- if (yajl_gen_string(g, (u_char *)event_name_str, strlen(event_name_str)) !=
+ if (yajl_gen_string(g, (u_char *)json_str, strlen(json_str)) !=
yajl_gen_status_ok) {
- sfree(event_name_str);
goto err;
}
- sfree(event_name_str);
-
// lastEpochMicrosec
if (yajl_gen_string(g, (u_char *)PROCEVENT_LAST_EPOCH_MICROSEC_FIELD,
strlen(PROCEVENT_LAST_EPOCH_MICROSEC_FIELD)) !=
int last_epoch_microsec_len =
sizeof(char) * sizeof(long long unsigned int) * 4 + 1;
- char *last_epoch_microsec_str = malloc(last_epoch_microsec_len);
- snprintf(last_epoch_microsec_str, last_epoch_microsec_len, "%llu",
+ memset(json_str, '\0', DATA_MAX_NAME_LEN);
+ snprintf(json_str, last_epoch_microsec_len, "%llu",
(long long unsigned int)CDTIME_T_TO_US(cdtime()));
- if (yajl_gen_number(g, last_epoch_microsec_str,
- strlen(last_epoch_microsec_str)) != yajl_gen_status_ok) {
- sfree(last_epoch_microsec_str);
+ if (yajl_gen_number(g, json_str, strlen(json_str)) != yajl_gen_status_ok) {
goto err;
}
- sfree(last_epoch_microsec_str);
-
// priority
if (yajl_gen_string(g, (u_char *)PROCEVENT_PRIORITY_FIELD,
strlen(PROCEVENT_PRIORITY_FIELD)) != yajl_gen_status_ok)
int start_epoch_microsec_len =
sizeof(char) * sizeof(long long unsigned int) * 4 + 1;
- char *start_epoch_microsec_str = malloc(start_epoch_microsec_len);
- snprintf(start_epoch_microsec_str, start_epoch_microsec_len, "%llu",
+ memset(json_str, '\0', DATA_MAX_NAME_LEN);
+ snprintf(json_str, start_epoch_microsec_len, "%llu",
(long long unsigned int)timestamp);
- if (yajl_gen_number(g, start_epoch_microsec_str,
- strlen(start_epoch_microsec_str)) != yajl_gen_status_ok) {
- sfree(start_epoch_microsec_str);
+ if (yajl_gen_number(g, json_str, strlen(json_str)) != yajl_gen_status_ok) {
goto err;
}
- sfree(start_epoch_microsec_str);
-
// version
if (yajl_gen_string(g, (u_char *)PROCEVENT_VERSION_FIELD,
strlen(PROCEVENT_VERSION_FIELD)) != yajl_gen_status_ok)
alarm_condition_len =
alarm_condition_len + 25; // "process", "state", "change", 4 spaces, 2
// parentheses and null-terminator
- char *alarm_condition_str = malloc(alarm_condition_len);
- memset(alarm_condition_str, '\0', alarm_condition_len);
- snprintf(alarm_condition_str, alarm_condition_len,
- "process %s (%d) state change", process, pid);
-
- if (yajl_gen_string(g, (u_char *)alarm_condition_str,
- strlen(alarm_condition_str)) != yajl_gen_status_ok) {
- sfree(alarm_condition_str);
+ memset(json_str, '\0', DATA_MAX_NAME_LEN);
+ snprintf(json_str, alarm_condition_len, "process %s (%d) state change",
+ process, pid);
+
+ if (yajl_gen_string(g, (u_char *)json_str, strlen(json_str)) !=
+ yajl_gen_status_ok) {
goto err;
}
- sfree(alarm_condition_str);
-
// alarmInterfaceA
if (yajl_gen_string(g, (u_char *)PROCEVENT_ALARM_INTERFACE_A_FIELD,
strlen(PROCEVENT_ALARM_INTERFACE_A_FIELD)) !=
specific_problem_len =
specific_problem_len +
13; // "process", 3 spaces, 2 parentheses and null-terminator
- char *specific_problem_str = malloc(specific_problem_len);
- memset(specific_problem_str, '\0', specific_problem_len);
- snprintf(specific_problem_str, specific_problem_len, "process %s (%d) %s",
- process, pid, (state == 0 ? PROCEVENT_SPECIFIC_PROBLEM_DOWN_VALUE
- : PROCEVENT_SPECIFIC_PROBLEM_UP_VALUE));
-
- if (yajl_gen_string(g, (u_char *)specific_problem_str,
- strlen(specific_problem_str)) != yajl_gen_status_ok) {
- sfree(specific_problem_str);
+ memset(json_str, '\0', DATA_MAX_NAME_LEN);
+ snprintf(json_str, specific_problem_len, "process %s (%d) %s", process, pid,
+ (state == 0 ? PROCEVENT_SPECIFIC_PROBLEM_DOWN_VALUE
+ : PROCEVENT_SPECIFIC_PROBLEM_UP_VALUE));
+
+ if (yajl_gen_string(g, (u_char *)json_str, strlen(json_str)) !=
+ yajl_gen_status_ok) {
goto err;
}
- sfree(specific_problem_str);
-
// vfStatus
if (yajl_gen_string(g, (u_char *)PROCEVENT_VF_STATUS_FIELD,
strlen(PROCEVENT_VF_STATUS_FIELD)) != yajl_gen_status_ok)
*buf = malloc(strlen((char *)buf2) + 1);
+ if (*buf == NULL) {
+ char errbuf[1024];
+ ERROR("procevent plugin: malloc failed during gen_message_payload: %s",
+ sstrerror(errno, errbuf, sizeof(errbuf)));
+ goto err;
+ }
+
sstrncpy(*buf, (char *)buf2, strlen((char *)buf2) + 1);
yajl_gen_free(g);
// Does /proc/<pid>/comm contain a process name we are interested in?
static processlist_t *process_check(int pid) {
- int len, is_match, status, retval;
+ int len, is_match, retval;
char file[BUFSIZE];
FILE *fh;
char buffer[BUFSIZE];
- regmatch_t matches[PROCEVENT_REGEX_MATCHES];
len = snprintf(file, sizeof(file), PROCDIR "/%d/comm", pid);
if (retval < 0) {
WARNING("procevent process_check: unable to read comm file for pid %d",
pid);
+ fclose(fh);
+ return NULL;
+ }
+
+ // Now that we have the process name in the buffer, check if we are
+ // even interested in it
+ if (ignorelist_match(ignorelist, buffer) != 0) {
+ DEBUG("procevent process_check: ignoring process %s (%d)", buffer, pid);
+ fclose(fh);
return NULL;
}
+ if (fh != NULL) {
+ fclose(fh);
+ fh = NULL;
+ }
+
//
// Go through the processlist linked list and look for the process name
// in /proc/<pid>/comm. If found:
- // 1. If pl->pid is -1, then set pl->pid to <pid>
+ // 1. If pl->pid is -1, then set pl->pid to <pid> (and return that object)
// 2. If pl->pid is not -1, then another <process name> process was already
// found. If <pid> == pl->pid, this is an old match, so do nothing.
- // If the <pid> is different, however, make a new processlist_t and
+ // If the <pid> is different, however, make a new processlist_t and
// associate <pid> with it (with the same process name as the existing).
//
processlist_t *match = NULL;
for (pl = processlist_head; pl != NULL; pl = pl->next) {
- if (pl->is_regex != 0) {
- is_match = (regexec(&pl->process_regex_obj, buffer,
- PROCEVENT_REGEX_MATCHES, matches, 0) == 0
- ? 1
- : 0);
- } else {
- is_match = (strcmp(buffer, pl->process) == 0 ? 1 : 0);
- }
+
+ is_match = (strcmp(buffer, pl->process) == 0 ? 1 : 0);
if (is_match == 1) {
- DEBUG("procevent plugin: process %d name match (pattern: %s) for %s", pid,
- (pl->is_regex == 0 ? pl->process : pl->process_regex), buffer);
-
- if (pl->is_regex == 1) {
- // If this is a regex name, copy the actual process name into the object
- // for cleaner log reporting
-
- if (pl->process != NULL)
- sfree(pl->process);
- pl->process = strdup(buffer);
- if (pl->process == NULL) {
- char errbuf[1024];
- ERROR("procevent plugin: strdup failed during process_check: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
- pthread_mutex_unlock(&procevent_list_lock);
- return NULL;
- }
- }
+ DEBUG("procevent plugin: process %d name match for %s", pid, buffer);
if (pl->pid == pid) {
// this is a match, and we've already stored the exact pid/name combo
}
}
- if (match != NULL && match->pid != -1 && match->pid != pid) {
+ if (match == NULL ||
+ (match != NULL && match->pid != -1 && match->pid != pid)) {
+ // if there wasn't an existing match, OR
// if there was a match but the associated processlist_t object already
// contained a pid/name combo,
// then make a new one and add it to the linked list
DEBUG(
"procevent plugin: allocating new processlist_t object for PID %d (%s)",
- pid, match->process);
+ pid, buffer);
processlist_t *pl2;
char *process;
- char *process_regex;
pl2 = malloc(sizeof(*pl2));
if (pl2 == NULL) {
return NULL;
}
- process = strdup(match->process);
+ process = strdup(buffer);
if (process == NULL) {
char errbuf[1024];
sfree(pl2);
return NULL;
}
- if (match->is_regex == 1) {
- pl2->is_regex = 1;
- status =
- regcomp(&pl2->process_regex_obj, match->process_regex, REG_EXTENDED);
-
- if (status != 0) {
- ERROR("procevent plugin: invalid regular expression: %s",
- match->process_regex);
- return NULL;
- }
-
- process_regex = strdup(match->process_regex);
- if (process_regex == NULL) {
- char errbuf[1024];
- sfree(pl);
- ERROR("procevent plugin: strdup failed during process_check: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
- return NULL;
- }
-
- pl2->process_regex = process_regex;
- }
-
pl2->process = process;
pl2->pid = pid;
pl2->next = processlist_head;
pthread_mutex_unlock(&procevent_list_lock);
- if (fh != NULL) {
- fclose(fh);
- fh = NULL;
- }
-
return match;
}
// in the ring buffer for consumption by the main polling thread.
if (proc_status != -1) {
- pthread_mutex_unlock(&procevent_lock);
+ pthread_mutex_lock(&procevent_lock);
int next = ring.head + 1;
if (next >= ring.maxLen)
{
int status;
- if (processlist_head == NULL) {
- NOTICE("procevent plugin: No processes have been configured.");
- return (-1);
- }
-
ring.head = 0;
ring.tail = 0;
ring.maxLen = buffer_length;
return (-1);
}
+ if (processlist_head == NULL) {
+ NOTICE("procevent plugin: No processes have been configured.");
+ return (-1);
+ }
+
return (start_thread());
} /* }}} int procevent_init */
{
int status;
+ if (ignorelist == NULL)
+ ignorelist = ignorelist_create(/* invert = */ 1);
+
if (strcasecmp(key, "BufferLength") == 0) {
buffer_length = atoi(value);
- } else if (strcasecmp(key, "Process") == 0 ||
- strcasecmp(key, "RegexProcess") == 0) {
-
- processlist_t *pl;
- char *process;
- char *process_regex;
+ } else if (strcasecmp(key, "Process") == 0) {
+ ignorelist_add(ignorelist, value);
+ } else if (strcasecmp(key, "RegexProcess") == 0) {
+#if HAVE_REGEX_H
+ status = ignorelist_add(ignorelist, value);
- pl = malloc(sizeof(*pl));
- if (pl == NULL) {
- char errbuf[1024];
- ERROR("procevent plugin: malloc failed during procevent_config: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
- return (1);
- }
-
- process = strdup(value);
- if (process == NULL) {
- char errbuf[1024];
- sfree(pl);
- ERROR("procevent plugin: strdup failed during procevent_config: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ if (status != 0) {
+ ERROR("procevent plugin: invalid regular expression: %s", value);
return (1);
}
-
- if (strcasecmp(key, "RegexProcess") == 0) {
- pl->is_regex = 1;
- status = regcomp(&pl->process_regex_obj, value, REG_EXTENDED);
-
- if (status != 0) {
- ERROR("procevent plugin: invalid regular expression: %s", value);
- return (1);
- }
-
- process_regex = strdup(value);
- if (process_regex == NULL) {
- char errbuf[1024];
- sfree(pl);
- ERROR("procevent plugin: strdup failed during procevent_config: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
- return (1);
- }
-
- pl->process_regex = process_regex;
- } else {
- pl->is_regex = 0;
- }
-
- pl->process = process;
- pl->pid = -1;
- pl->next = processlist_head;
- processlist_head = pl;
+#else
+ WARNING("procevent plugin: The plugin has been compiled without support "
+ "for the \"RegexProcess\" option.");
+#endif
} else {
return (-1);
}
if (value == 1)
n.severity = NOTIF_OKAY;
- char hostname[1024];
- gethostname(hostname, sizeof(hostname));
-
- sstrncpy(n.host, hostname, sizeof(n.host));
+ sstrncpy(n.host, hostname_g, sizeof(n.host));
sstrncpy(n.plugin_instance, process, sizeof(n.plugin_instance));
sstrncpy(n.type, "gauge", sizeof(n.type));
sstrncpy(n.type_instance, "process_status", sizeof(n.type_instance));
pl_next = pl->next;
- if (pl->is_regex == 1) {
- sfree(pl->process_regex);
- regfree(&pl->process_regex_obj);
- }
-
sfree(pl->process);
sfree(pl);
plugin_register_init("procevent", procevent_init);
plugin_register_read("procevent", procevent_read);
plugin_register_shutdown("procevent", procevent_shutdown);
-} /* void module_register */
\ No newline at end of file
+} /* void module_register */