X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fprocesses.c;h=8a1436e1855fd0f8b1f4c5f76e8c73b43832621a;hb=483e801902bca3c779793224eddf3bb2749d7288;hp=655cddb7d085a15a7e9e13e6dacabd20cb22d9a1;hpb=0eff156c7816507fa1865b76e948574dd320fae0;p=collectd.git diff --git a/src/processes.c b/src/processes.c index 655cddb7..8a1436e1 100644 --- a/src/processes.c +++ b/src/processes.c @@ -121,13 +121,6 @@ # define ARG_MAX 4096 #endif -static const char *config_keys[] = -{ - "Process", - "ProcessMatch" -}; -static int config_keys_num = STATIC_ARRAY_SIZE (config_keys); - typedef struct procstat_entry_s { unsigned long id; @@ -520,42 +513,61 @@ static void ps_list_reset (void) } /* put all pre-defined 'Process' names from config to list_head_g tree */ -static int ps_config (const char *key, const char *value) +static int ps_config (oconfig_item_t *ci) { - if (strcasecmp (key, "Process") == 0) - { - ps_list_register (value, NULL); - } - else if (strcasecmp (key, "ProcessMatch") == 0) - { - char *new_val; - char *fields[3]; - int fields_num; - - new_val = strdup (value); - if (new_val == NULL) { - ERROR ("processes plugin: strdup failed when processing " - "`ProcessMatch %s'.", value); - return (1); + int i; + + for (i = 0; i < ci->children_num; ++i) { + oconfig_item_t *c = ci->children + i; + + if (strcasecmp (c->key, "Process") == 0) + { + if ((c->values_num != 1) + || (OCONFIG_TYPE_STRING != c->values[0].type)) { + ERROR ("processes plugin: `Process' expects exactly " + "one string argument (got %i).", + c->values_num); + continue; + } + + if (c->children_num != 0) { + WARNING ("processes plugin: the `Process' config option " + "does not expect any child elements -- ignoring " + "content (%i elements) of the block.", + c->children_num, c->values[0].value.string); + } + + ps_list_register (c->values[0].value.string, NULL); } + else if (strcasecmp (c->key, "ProcessMatch") == 0) + { + if ((c->values_num != 2) + || (OCONFIG_TYPE_STRING != c->values[0].type) + || (OCONFIG_TYPE_STRING != c->values[1].type)) + { + ERROR ("processes plugin: `ProcessMatch' needs exactly " + "two string arguments (got %i).", + c->values_num); + continue; + } - fields_num = strsplit (new_val, fields, - STATIC_ARRAY_SIZE (fields)); - if (fields_num != 2) + if (c->children_num != 0) { + WARNING ("processes plugin: the `ProcessMatch' config option " + "does not expect any child elements -- ignoring " + "content (%i elements) of the " + "block.", c->children_num, c->values[0].value.string, + c->values[1].value.string); + } + + ps_list_register (c->values[0].value.string, + c->values[1].value.string); + } + else { - ERROR ("processes plugin: `ProcessMatch' needs exactly " - "two string arguments."); - sfree (new_val); - return (1); + ERROR ("processes plugin: The `%s' configuration option is not " + "understood and will be ignored.", c->key); + continue; } - ps_list_register (fields[0], fields[1]); - sfree (new_val); - } - else - { - ERROR ("processes plugin: The `%s' configuration option is not " - "understood and will be ignored.", key); - return (-1); } return (0); @@ -869,10 +881,12 @@ int ps_read_process (int pid, procstat_t *ps, char *state) char *fields[64]; char fields_len; - int i; + int buffer_len; - int ppid; - int name_len; + char *buffer_ptr; + size_t name_start_pos; + size_t name_end_pos; + size_t name_len; derive_t cpu_user_counter; derive_t cpu_system_counter; @@ -884,34 +898,56 @@ int ps_read_process (int pid, procstat_t *ps, char *state) ssnprintf (filename, sizeof (filename), "/proc/%i/stat", pid); - i = read_file_contents (filename, buffer, sizeof(buffer) - 1); - if (i <= 0) + buffer_len = read_file_contents (filename, + buffer, sizeof(buffer) - 1); + if (buffer_len <= 0) return (-1); - buffer[i] = 0; - - fields_len = strsplit (buffer, fields, STATIC_ARRAY_SIZE (fields)); - if (fields_len < 24) + buffer[buffer_len] = 0; + + /* The name of the process is enclosed in parens. Since the name can + * contain parens itself, spaces, numbers and pretty much everything + * else, use these to determine the process name. We don't use + * strchr(3) and strrchr(3) to avoid pointer arithmetic which would + * otherwise be required to determine name_len. */ + name_start_pos = 0; + while ((buffer[name_start_pos] != '(') + && (name_start_pos < buffer_len)) + name_start_pos++; + + name_end_pos = buffer_len; + while ((buffer[name_end_pos] != ')') + && (name_end_pos > 0)) + name_end_pos--; + + /* Either '(' or ')' is not found or they are in the wrong order. + * Anyway, something weird that shouldn't happen ever. */ + if (name_start_pos >= name_end_pos) { - DEBUG ("processes plugin: ps_read_process (pid = %i):" - " `%s' has only %i fields..", - (int) pid, filename, fields_len); + ERROR ("processes plugin: name_start_pos = %zu >= name_end_pos = %zu", + name_start_pos, name_end_pos); return (-1); } - /* copy the name, strip brackets in the process */ - name_len = strlen (fields[1]) - 2; - if ((fields[1][0] != '(') || (fields[1][name_len + 1] != ')')) + name_len = (name_end_pos - name_start_pos) - 1; + if (name_len >= sizeof (ps->name)) + name_len = sizeof (ps->name) - 1; + + sstrncpy (ps->name, &buffer[name_start_pos + 1], name_len + 1); + + if ((buffer_len - name_end_pos) < 2) + return (-1); + buffer_ptr = &buffer[name_end_pos + 2]; + + fields_len = strsplit (buffer_ptr, fields, STATIC_ARRAY_SIZE (fields)); + if (fields_len < 22) { - DEBUG ("No brackets found in process name: `%s'", fields[1]); + DEBUG ("processes plugin: ps_read_process (pid = %i):" + " `%s' has only %i fields..", + (int) pid, filename, fields_len); return (-1); } - fields[1] = fields[1] + 1; - fields[1][name_len] = '\0'; - strncpy (ps->name, fields[1], PROCSTAT_NAME_LEN); - - ppid = atoi (fields[3]); - *state = fields[2][0]; + *state = fields[0][0]; if (*state == 'Z') { @@ -936,16 +972,16 @@ int ps_read_process (int pid, procstat_t *ps, char *state) return (0); } - cpu_user_counter = atoll (fields[13]); - cpu_system_counter = atoll (fields[14]); - vmem_size = atoll (fields[22]); - vmem_rss = atoll (fields[23]); - ps->vmem_minflt_counter = atoll (fields[9]); - ps->vmem_majflt_counter = atoll (fields[11]); + cpu_user_counter = atoll (fields[11]); + cpu_system_counter = atoll (fields[12]); + vmem_size = atoll (fields[20]); + vmem_rss = atoll (fields[21]); + ps->vmem_minflt_counter = atol (fields[7]); + ps->vmem_majflt_counter = atol (fields[9]); { - unsigned long long stack_start = atoll (fields[27]); - unsigned long long stack_ptr = atoll (fields[28]); + unsigned long long stack_start = atoll (fields[25]); + unsigned long long stack_ptr = atoll (fields[26]); stack_size = (stack_start > stack_ptr) ? stack_start - stack_ptr @@ -1594,9 +1630,9 @@ static int ps_read (void) procs = kvm_getprocs(kd, KERN_PROC_ALL, 0, &count); if (procs == NULL) { - kvm_close (kd); ERROR ("processes plugin: Cannot get kvm processes list: %s", kvm_geterr(kd)); + kvm_close (kd); return (0); } @@ -1829,8 +1865,7 @@ static int ps_read (void) void module_register (void) { - plugin_register_config ("processes", ps_config, - config_keys, config_keys_num); + plugin_register_complex_config ("processes", ps_config); plugin_register_init ("processes", ps_init); plugin_register_read ("processes", ps_read); } /* void module_register */