X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fprocesses.c;h=66237dc376be56414b29d62000d8a39c6fd70e1b;hb=ab55c79a0fee35932995d9f492730dc131034d52;hp=8f4eb88fc168f3c1b36835c5ed294c95dd31ed08;hpb=61fba41289decabc1a18c855fcd462fece9ab983;p=collectd.git diff --git a/src/processes.c b/src/processes.c index 8f4eb88f..66237dc3 100644 --- a/src/processes.c +++ b/src/processes.c @@ -200,7 +200,7 @@ static long pagesize_g; /* #endif KERNEL_LINUX */ #elif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_FREEBSD -/* no global variables */ +static int pagesize; /* #endif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_FREEBSD */ #elif HAVE_PROCINFO_H @@ -609,7 +609,7 @@ static int ps_init (void) /* #endif KERNEL_LINUX */ #elif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_FREEBSD -/* no initialization */ + pagesize = getpagesize(); /* #endif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_FREEBSD */ #elif HAVE_PROCINFO_H @@ -790,7 +790,7 @@ static procstat_t *ps_read_vmem (int pid, procstat_t *ps) tmp = strtoll (fields[1], &endptr, /* base = */ 10); if ((errno == 0) && (endptr != fields[1])) { - if (strncmp (buffer, "VmData", 6) == 0) + if (strncmp (buffer, "VmData", 6) == 0) { data = tmp; } @@ -881,9 +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 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; @@ -895,33 +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); - - *state = fields[2][0]; + *state = fields[0][0]; if (*state == 'Z') { @@ -946,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 @@ -1579,10 +1605,8 @@ static int ps_read (void) kvm_t *kd; char errbuf[1024]; - char cmdline[ARG_MAX]; - char *cmdline_ptr; struct kinfo_proc *procs; /* array of processes */ - char **argv; + struct kinfo_proc *proc_ptr = NULL; int count; /* returns number of processes */ int i; @@ -1613,64 +1637,80 @@ static int ps_read (void) /* Iterate through the processes in kinfo_proc */ for (i = 0; i < count; i++) { - /* retrieve the arguments */ - cmdline[0] = 0; - cmdline_ptr = NULL; - - argv = kvm_getargv (kd, (const struct kinfo_proc *) &(procs[i]), 0); - if (argv != NULL) + /* Create only one process list entry per _process_, i.e. + * filter out threads (duplicate PID entries). */ + if ((proc_ptr == NULL) || (proc_ptr->ki_pid != procs[i].ki_pid)) { - int status; - int argc; - - argc = 0; - while (argv[argc] != NULL) - argc++; - - status = strjoin (cmdline, sizeof (cmdline), - argv, argc, " "); + char cmdline[ARG_MAX] = ""; + _Bool have_cmdline = 0; - if (status < 0) + proc_ptr = &(procs[i]); + /* Don't probe system processes and processes without arguments */ + if (((procs[i].ki_flag & P_SYSTEM) == 0) + && (procs[i].ki_args != NULL)) { - WARNING ("processes plugin: Command line did " - "not fit into buffer."); - } - else - { - cmdline_ptr = &cmdline[0]; - } - } + char **argv; + int argc; + int status; + + /* retrieve the arguments */ + argv = kvm_getargv (kd, proc_ptr, /* nchr = */ 0); + argc = 0; + if ((argv != NULL) && (argv[0] != NULL)) + { + while (argv[argc] != NULL) + argc++; + + status = strjoin (cmdline, sizeof (cmdline), argv, argc, " "); + if (status < 0) + WARNING ("processes plugin: Command line did not fit into buffer."); + else + have_cmdline = 1; + } + } /* if (process has argument list) */ - pse.id = procs[i].ki_pid; - pse.age = 0; + pse.id = procs[i].ki_pid; + pse.age = 0; - pse.num_proc = 1; - pse.num_lwp = procs[i].ki_numthreads; + pse.num_proc = 1; + pse.num_lwp = procs[i].ki_numthreads; - pse.vmem_size = procs[i].ki_size; - pse.vmem_rss = procs[i].ki_rssize * getpagesize(); - pse.vmem_data = procs[i].ki_dsize * getpagesize(); - pse.vmem_code = procs[i].ki_tsize * getpagesize(); - pse.stack_size = procs[i].ki_ssize * getpagesize(); - pse.vmem_minflt = 0; - pse.vmem_minflt_counter = procs[i].ki_rusage.ru_minflt; - pse.vmem_majflt = 0; - pse.vmem_majflt_counter = procs[i].ki_rusage.ru_majflt; + pse.vmem_size = procs[i].ki_size; + pse.vmem_rss = procs[i].ki_rssize * pagesize; + pse.vmem_data = procs[i].ki_dsize * pagesize; + pse.vmem_code = procs[i].ki_tsize * pagesize; + pse.stack_size = procs[i].ki_ssize * pagesize; + pse.vmem_minflt = 0; + pse.vmem_minflt_counter = procs[i].ki_rusage.ru_minflt; + pse.vmem_majflt = 0; + pse.vmem_majflt_counter = procs[i].ki_rusage.ru_majflt; - pse.cpu_user = 0; - pse.cpu_user_counter = procs[i].ki_rusage.ru_utime.tv_sec - * 1000 - + procs[i].ki_rusage.ru_utime.tv_usec; - pse.cpu_system = 0; - pse.cpu_system_counter = procs[i].ki_rusage.ru_stime.tv_sec - * 1000 - + procs[i].ki_rusage.ru_stime.tv_usec; + pse.cpu_user = 0; + pse.cpu_system = 0; + pse.cpu_user_counter = 0; + pse.cpu_system_counter = 0; + /* + * The u-area might be swapped out, and we can't get + * at it because we have a crashdump and no swap. + * If it's here fill in these fields, otherwise, just + * leave them 0. + */ + if (procs[i].ki_flag & P_INMEM) + { + pse.cpu_user_counter = procs[i].ki_rusage.ru_utime.tv_usec + + (1000000lu * procs[i].ki_rusage.ru_utime.tv_sec); + pse.cpu_system_counter = procs[i].ki_rusage.ru_stime.tv_usec + + (1000000lu * procs[i].ki_rusage.ru_stime.tv_sec); + } - /* no io data */ - pse.io_rchar = -1; - pse.io_wchar = -1; - pse.io_syscr = -1; - pse.io_syscw = -1; + /* no I/O data */ + pse.io_rchar = -1; + pse.io_wchar = -1; + pse.io_syscr = -1; + pse.io_syscw = -1; + + ps_list_add (procs[i].ki_comm, have_cmdline ? cmdline : NULL, &pse); + } /* if ((proc_ptr == NULL) || (proc_ptr->ki_pid != procs[i].ki_pid)) */ switch (procs[i].ki_stat) { @@ -1682,8 +1722,6 @@ static int ps_read (void) case SLOCK: blocked++; break; case SZOMB: zombies++; break; } - - ps_list_add (procs[i].ki_comm, cmdline_ptr, &pse); } kvm_close(kd);