src/plugin.c: Initialize "next_read" field of read callbacks.
[collectd.git] / src / processes.c
index e58076a..66237dc 100644 (file)
@@ -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
@@ -1580,12 +1606,10 @@ static int ps_read (void)
        kvm_t *kd;
        char errbuf[1024];
        struct kinfo_proc *procs;          /* array of processes */
-       char **argv;
+       struct kinfo_proc *proc_ptr = NULL;
        int count;                         /* returns number of processes */
        int i;
 
-       struct kinfo_proc *proc_ptr = NULL;
-
        procstat_t *ps_ptr;
        procstat_entry_t pse;
 
@@ -1599,6 +1623,7 @@ static int ps_read (void)
                                errbuf);
                return (0);
        }
+
        /* Get the list of processes. */
        procs = kvm_getprocs(kd, KERN_PROC_ALL, 0, &count);
        if (procs == NULL)
@@ -1616,37 +1641,33 @@ static int ps_read (void)
                 * filter out threads (duplicate PID entries). */
                if ((proc_ptr == NULL) || (proc_ptr->ki_pid != procs[i].ki_pid))
                {
-                       char cmdline[ARG_MAX];
+                       char cmdline[ARG_MAX] = "";
                        _Bool have_cmdline = 0;
 
-                       memset (cmdline, 0, sizeof (cmdline));
-
                        proc_ptr = &(procs[i]);
-                       /* not probe system processes and processes without arguments*/
+                       /* Don't probe system processes and processes without arguments */
                        if (((procs[i].ki_flag & P_SYSTEM) == 0)
-                                       && (procs[i].ki_args != NULL ))
+                                       && (procs[i].ki_args != NULL))
                        {
+                               char **argv;
+                               int argc;
+                               int status;
+
                                /* retrieve the arguments */
                                argv = kvm_getargv (kd, proc_ptr, /* nchr = */ 0);
-                               if ( argv != NULL && *argv)
+                               argc = 0;
+                               if ((argv != NULL) && (argv[0] != NULL))
                                {
-                                       int status;
-                                       int argc;
-
-                                       argc = 0;
                                        while (argv[argc] != NULL)
                                                argc++;
 
-                                       status = strjoin (cmdline, sizeof (cmdline),
-                                                       argv, 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;
@@ -1701,10 +1722,10 @@ static int ps_read (void)
                        case SLOCK:     blocked++;      break;
                        case SZOMB:     zombies++;      break;
                }
-
        }
 
        kvm_close(kd);
+
        ps_submit_state ("running",  running);
        ps_submit_state ("sleeping", sleeping);
        ps_submit_state ("zombies",  zombies);
@@ -1712,6 +1733,7 @@ static int ps_read (void)
        ps_submit_state ("blocked",  blocked);
        ps_submit_state ("idle",     idle);
        ps_submit_state ("wait",     wait);
+
        for (ps_ptr = list_head_g; ps_ptr != NULL; ps_ptr = ps_ptr->next)
                ps_submit_proc_list (ps_ptr);
 /* #endif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_FREEBSD */