diff --git a/src/processes.c b/src/processes.c
index 8f4eb88fc168f3c1b36835c5ed294c95dd31ed08..66237dc376be56414b29d62000d8a39c6fd70e1b 100644 (file)
--- a/src/processes.c
+++ b/src/processes.c
/* #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
/* #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
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;
}
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;
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')
{
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
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;
/* 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)
{
case SLOCK: blocked++; break;
case SZOMB: zombies++; break;
}
-
- ps_list_add (procs[i].ki_comm, cmdline_ptr, &pse);
}
kvm_close(kd);