X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fprocesses.c;h=8a1436e1855fd0f8b1f4c5f76e8c73b43832621a;hb=483e801902bca3c779793224eddf3bb2749d7288;hp=c642e58a88b1b8def6a13b8d0dbea887060e5a55;hpb=96382507c3296a35399f6b3c258ae2a47761bf06;p=collectd.git diff --git a/src/processes.c b/src/processes.c index c642e58a..8a1436e1 100644 --- a/src/processes.c +++ b/src/processes.c @@ -1,7 +1,7 @@ /** * collectd - src/processes.c * Copyright (C) 2005 Lyonel Vincent - * Copyright (C) 2006-2008 Florian octo Forster + * Copyright (C) 2006-2010 Florian octo Forster * Copyright (C) 2008 Oleg King * Copyright (C) 2009 Sebastian Harl * Copyright (C) 2009 Andrés J. Díaz @@ -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; @@ -143,13 +136,13 @@ typedef struct procstat_entry_s unsigned long vmem_minflt; unsigned long vmem_majflt; - unsigned long vmem_minflt_counter; - unsigned long vmem_majflt_counter; + derive_t vmem_minflt_counter; + derive_t vmem_majflt_counter; unsigned long cpu_user; unsigned long cpu_system; - unsigned long cpu_user_counter; - unsigned long cpu_system_counter; + derive_t cpu_user_counter; + derive_t cpu_system_counter; /* io data */ derive_t io_rchar; @@ -176,11 +169,11 @@ typedef struct procstat unsigned long vmem_code; unsigned long stack_size; - unsigned long vmem_minflt_counter; - unsigned long vmem_majflt_counter; + derive_t vmem_minflt_counter; + derive_t vmem_majflt_counter; - unsigned long cpu_user_counter; - unsigned long cpu_system_counter; + derive_t cpu_user_counter; + derive_t cpu_system_counter; /* io data */ derive_t io_rchar; @@ -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); @@ -664,8 +676,8 @@ static void ps_submit_proc_list (procstat_t *ps) plugin_dispatch_values (&vl); sstrncpy (vl.type, "ps_cputime", sizeof (vl.type)); - vl.values[0].counter = ps->cpu_user_counter; - vl.values[1].counter = ps->cpu_system_counter; + vl.values[0].derive = ps->cpu_user_counter; + vl.values[1].derive = ps->cpu_system_counter; vl.values_len = 2; plugin_dispatch_values (&vl); @@ -676,8 +688,8 @@ static void ps_submit_proc_list (procstat_t *ps) plugin_dispatch_values (&vl); sstrncpy (vl.type, "ps_pagefaults", sizeof (vl.type)); - vl.values[0].counter = ps->vmem_minflt_counter; - vl.values[1].counter = ps->vmem_majflt_counter; + vl.values[0].derive = ps->vmem_minflt_counter; + vl.values[1].derive = ps->vmem_majflt_counter; vl.values_len = 2; plugin_dispatch_values (&vl); @@ -702,8 +714,8 @@ static void ps_submit_proc_list (procstat_t *ps) DEBUG ("name = %s; num_proc = %lu; num_lwp = %lu; " "vmem_size = %lu; vmem_rss = %lu; vmem_data = %lu; " "vmem_code = %lu; " - "vmem_minflt_counter = %lu; vmem_majflt_counter = %lu; " - "cpu_user_counter = %lu; cpu_system_counter = %lu; " + "vmem_minflt_counter = %"PRIi64"; vmem_majflt_counter = %"PRIi64"; " + "cpu_user_counter = %"PRIi64"; cpu_system_counter = %"PRIi64"; " "io_rchar = %"PRIi64"; io_wchar = %"PRIi64"; " "io_syscr = %"PRIi64"; io_syscw = %"PRIi64";", ps->name, ps->num_proc, ps->num_lwp, @@ -869,13 +881,15 @@ 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; - long long unsigned cpu_user_counter; - long long unsigned cpu_system_counter; + derive_t cpu_user_counter; + derive_t cpu_system_counter; long long unsigned vmem_size; long long unsigned vmem_rss; long long unsigned stack_size; @@ -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 = atol (fields[9]); - ps->vmem_majflt_counter = atol (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 @@ -965,8 +1001,8 @@ int ps_read_process (int pid, procstat_t *ps, char *state) DEBUG("ps_read_process: did not get vmem data for pid %i",pid); } - ps->cpu_user_counter = (unsigned long) cpu_user_counter; - ps->cpu_system_counter = (unsigned long) cpu_system_counter; + ps->cpu_user_counter = cpu_user_counter; + ps->cpu_system_counter = cpu_system_counter; ps->vmem_size = (unsigned long) vmem_size; ps->vmem_rss = (unsigned long) vmem_rss; ps->stack_size = (unsigned long) stack_size; @@ -999,13 +1035,18 @@ static char *ps_get_cmdline (pid_t pid, char *name, char *buf, size_t buf_len) if ((pid < 1) || (NULL == buf) || (buf_len < 2)) return NULL; - ssnprintf (file, sizeof (file), "/proc/%u/cmdline", pid); + ssnprintf (file, sizeof (file), "/proc/%u/cmdline", + (unsigned int) pid); + errno = 0; fd = open (file, O_RDONLY); if (fd < 0) { char errbuf[4096]; - WARNING ("processes plugin: Failed to open `%s': %s.", file, - sstrerror (errno, errbuf, sizeof (errbuf))); + /* ENOENT means the process exited while we were handling it. + * Don't complain about this, it only fills the logs. */ + if (errno != ENOENT) + WARNING ("processes plugin: Failed to open `%s': %s.", file, + sstrerror (errno, errbuf, sizeof (errbuf))); return NULL; } @@ -1020,7 +1061,7 @@ static char *ps_get_cmdline (pid_t pid, char *name, char *buf, size_t buf_len) status = read (fd, (void *)buf_ptr, len); if (status < 0) { - char errbuf[4096]; + char errbuf[1024]; if ((EAGAIN == errno) || (EINTR == errno)) continue; @@ -1589,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); } @@ -1797,6 +1838,11 @@ static int ps_read (void) pse.vmem_code = 0; pse.stack_size = 0; + pse.io_rchar = -1; + pse.io_wchar = -1; + pse.io_syscr = -1; + pse.io_syscw = -1; + ps_list_add (cmdline, cargs, &pse); } /* for (i = 0 .. nprocs) */ @@ -1819,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 */