{GPL, other}: Relicense to MIT license.
[collectd.git] / src / processes.c
index 2084251..210e6f1 100644 (file)
@@ -25,7 +25,7 @@
  *
  * Authors:
  *   Lyonel Vincent <lyonel at ezix.org>
- *   Florian octo Forster <octo at verplant.org>
+ *   Florian octo Forster <octo at collectd.org>
  *   Oleg King <king2 at kaluga.ru>
  *   Sebastian Harl <sh at tokkee.org>
  *   Andrés J. Díaz <ajdiaz at connectical.com>
@@ -227,8 +227,8 @@ int getargs (struct procentry64 *processBuffer, int bufferLen, char *argsBuffer,
 #endif /* HAVE_PROCINFO_H */
 
 /* put name of process from config to list_head_g tree
  list_head_g is a list of 'procstat_t' structs with
  processes names we want to watch */
* list_head_g is a list of 'procstat_t' structs with
* processes names we want to watch */
 static void ps_list_register (const char *name, const char *regexp)
 {
        procstat_t *new;
@@ -723,7 +723,7 @@ 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_size = %lu; vmem_rss = %lu; vmem_data = %lu; "
                        "vmem_code = %lu; "
                        "vmem_minflt_counter = %"PRIi64"; vmem_majflt_counter = %"PRIi64"; "
                        "cpu_user_counter = %"PRIi64"; cpu_system_counter = %"PRIi64"; "
@@ -737,6 +737,26 @@ static void ps_submit_proc_list (procstat_t *ps)
                        ps->io_rchar, ps->io_wchar, ps->io_syscr, ps->io_syscw);
 } /* void ps_submit_proc_list */
 
+#if KERNEL_LINUX || KERNEL_SOLARIS
+static void ps_submit_fork_rate (derive_t value)
+{
+       value_t values[1];
+       value_list_t vl = VALUE_LIST_INIT;
+
+       values[0].derive = value;
+
+       vl.values = values;
+       vl.values_len = 1;
+       sstrncpy(vl.host, hostname_g, sizeof (vl.host));
+       sstrncpy(vl.plugin, "processes", sizeof (vl.plugin));
+       sstrncpy(vl.plugin_instance, "", sizeof (vl.plugin_instance));
+       sstrncpy(vl.type, "fork_rate", sizeof (vl.type));
+       sstrncpy(vl.type_instance, "", sizeof (vl.type_instance));
+
+       plugin_dispatch_values(&vl);
+}
+#endif /* KERNEL_LINUX || KERNEL_SOLARIS*/
+
 /* ------- additional functions for KERNEL_LINUX/HAVE_THREAD_INFO ------- */
 #if KERNEL_LINUX
 static int ps_read_tasks (int pid)
@@ -791,7 +811,7 @@ static procstat_t *ps_read_vmem (int pid, procstat_t *ps)
                        continue;
 
                numfields = strsplit (buffer, fields,
-                                      STATIC_ARRAY_SIZE (fields));
+                               STATIC_ARRAY_SIZE (fields));
 
                if (numfields < 2)
                        continue;
@@ -1128,92 +1148,77 @@ static char *ps_get_cmdline (pid_t pid, char *name, char *buf, size_t buf_len)
        return buf;
 } /* char *ps_get_cmdline (...) */
 
-static unsigned long read_fork_rate ()
+static int read_fork_rate ()
 {
        FILE *proc_stat;
-       char buf[1024];
-       unsigned long result = 0;
-       int numfields;
-       char *fields[3];
+       char buffer[1024];
+       value_t value;
+       _Bool value_valid = 0;
 
-       proc_stat = fopen("/proc/stat", "r");
-       if (proc_stat == NULL) {
+       proc_stat = fopen ("/proc/stat", "r");
+       if (proc_stat == NULL)
+       {
                char errbuf[1024];
                ERROR ("processes plugin: fopen (/proc/stat) failed: %s",
                                sstrerror (errno, errbuf, sizeof (errbuf)));
-               return ULONG_MAX;
+               return (-1);
        }
 
-       while (fgets (buf, sizeof(buf), proc_stat) != NULL)
+       while (fgets (buffer, sizeof (buffer), proc_stat) != NULL)
        {
-               char *endptr;
+               int status;
+               char *fields[3];
+               int fields_num;
 
-               numfields = strsplit(buf, fields, STATIC_ARRAY_SIZE (fields));
-               if (numfields != 2)
+               fields_num = strsplit (buffer, fields,
+                               STATIC_ARRAY_SIZE (fields));
+               if (fields_num != 2)
                        continue;
 
                if (strcmp ("processes", fields[0]) != 0)
                        continue;
 
-               errno = 0;
-               endptr = NULL;
-               result = strtoul(fields[1], &endptr, /* base = */ 10);
-               if ((endptr == fields[1]) || (errno != 0)) {
-                       ERROR ("processes plugin: Cannot parse fork rate: %s",
-                                       fields[1]);
-                       result = ULONG_MAX;
-                       break;
-               }
+               status = parse_value (fields[1], &value, DS_TYPE_DERIVE);
+               if (status == 0)
+                       value_valid = 1;
 
                break;
        }
-
        fclose(proc_stat);
 
-       return result;
-}
-#endif /*KERNEL_LINUX */
-
-#if KERNEL_LINUX || KERNEL_SOLARIS
-static void ps_submit_fork_rate (unsigned long value)
-{
-       value_t values[1];
-       value_list_t vl = VALUE_LIST_INIT;
-
-       values[0].derive = (derive_t) value;
-
-       vl.values = values;
-       vl.values_len = 1;
-       sstrncpy(vl.host, hostname_g, sizeof (vl.host));
-       sstrncpy(vl.plugin, "processes", sizeof (vl.plugin));
-       sstrncpy(vl.plugin_instance, "", sizeof (vl.plugin_instance));
-       sstrncpy(vl.type, "fork_rate", sizeof (vl.type));
-       sstrncpy(vl.type_instance, "", sizeof (vl.type_instance));
+       if (!value_valid)
+               return (-1);
 
-       plugin_dispatch_values(&vl);
+       ps_submit_fork_rate (value.derive);
+       return (0);
 }
-#endif /* KERNEL_LINUX || KERNEL_SOLARIS*/
+#endif /*KERNEL_LINUX */
 
 #if KERNEL_SOLARIS
-static char *ps_get_cmdline(pid_t pid)
+static const char *ps_get_cmdline (pid_t pid, /* {{{ */
+               char *buffer, size_t buffer_size)
 {
-       char f_psinfo[64];
-       char cmdline[80];
-       char *buffer = NULL;
-       psinfo_t *myInfo;
+       char path[PATH_MAX];
+       psinfo_t info;
+       int status;
 
-       snprintf(f_psinfo, sizeof (f_psinfo), "/proc/%i/psinfo", pid);
+       snprintf(path, sizeof (path), "/proc/%i/psinfo", pid);
 
-       buffer = (char *)malloc(sizeof (psinfo_t));
-       memset(buffer, 0, sizeof(psinfo_t));
-       read_file_contents(f_psinfo, buffer, sizeof (psinfo_t));
-       myInfo = (psinfo_t *) buffer;
+       status = read_file_contents (path, (void *) &info, sizeof (info));
+       if (status != ((int) buffer_size))
+       {
+               ERROR ("processes plugin: Unexpected return value "
+                               "while reading \"%s\": "
+                               "Returned %i but expected %zu.",
+                               path, status, buffer_size);
+               return (NULL);
+       }
 
-       sstrncpy(cmdline, myInfo->pr_psargs, sizeof (myInfo->pr_psargs));
+       info.pr_psargs[sizeof (info.pr_psargs) - 1] = 0;
+       sstrncpy (buffer, info.pr_psargs, buffer_size);
 
-       sfree(myInfo);
-       return strtok(cmdline, " ");
-}
+       return (buffer);
+} /* }}} int ps_get_cmdline */
 
 /*
  * Reads process information on the Solaris OS. The information comes mainly from
@@ -1223,13 +1228,10 @@ static char *ps_get_cmdline(pid_t pid)
  */
 static int ps_read_process(int pid, procstat_t *ps, char *state)
 {
-
        char filename[64];
        char f_psinfo[64], f_usage[64];
-       int i;
        char *buffer;
 
-
        pstatus_t *myStatus;
        psinfo_t *myInfo;
        prusage_t *myUsage;
@@ -1335,25 +1337,35 @@ static int ps_read_process(int pid, procstat_t *ps, char *state)
  * are retrieved from kstat (module cpu, name sys, class misc, stat nthreads).
  * The result is the sum for all the threads created on each cpu
  */
-static unsigned long read_fork_rate()
+static int read_fork_rate()
 {
        extern kstat_ctl_t *kc;
        kstat_t *ksp_chain = NULL;
-       unsigned long result = 0;
+       derive_t result = 0;
 
        if (kc == NULL)
-               return ULONG_MAX;
-
-       for (ksp_chain = kc->kc_chain; ksp_chain != NULL;
-            ksp_chain = ksp_chain->ks_next) {
-               if ((strncmp(ksp_chain->ks_module, "cpu", 3) == 0) &&
-                   (strncmp(ksp_chain->ks_name, "sys", 3) == 0) &&
-                   (strncmp(ksp_chain->ks_class, "misc", 4) == 0)) {
-                       kstat_read(kc, ksp_chain, NULL);
-                       result += get_kstat_value(ksp_chain, "nthreads");
+               return (-1);
+
+       for (ksp_chain = kc->kc_chain;
+                       ksp_chain != NULL;
+                       ksp_chain = ksp_chain->ks_next)
+       {
+               if ((strcmp (ksp_chain->ks_module, "cpu") == 0)
+                               && (strcmp (ksp_chain->ks_name, "sys") == 0)
+                               && (strcmp (ksp_chain->ks_class, "misc") == 0))
+               {
+                       long long tmp;
+
+                       kstat_read (kc, ksp_chain, NULL);
+
+                       tmp = get_kstat_value(ksp_chain, "nthreads");
+                       if (tmp != -1LL)
+                               result += tmp;
                }
        }
-       return result;
+
+       ps_submit_fork_rate (result);
+       return (0);
 }
 #endif /* KERNEL_SOLARIS */
 
@@ -1681,8 +1693,6 @@ static int ps_read (void)
        procstat_entry_t pse;
        char       state;
 
-       unsigned long fork_rate;
-
        procstat_t *ps_ptr;
 
        running = sleeping = zombies = stopped = paging = blocked = 0;
@@ -1764,9 +1774,7 @@ static int ps_read (void)
        for (ps_ptr = list_head_g; ps_ptr != NULL; ps_ptr = ps_ptr->next)
                ps_submit_proc_list (ps_ptr);
 
-       fork_rate = read_fork_rate();
-       if (fork_rate != ULONG_MAX)
-               ps_submit_fork_rate(fork_rate);
+       read_fork_rate();
 /* #endif KERNEL_LINUX */
 
 #elif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_FREEBSD
@@ -1780,9 +1788,9 @@ static int ps_read (void)
 
        kvm_t *kd;
        char errbuf[1024];
-       struct kinfo_proc *procs;          /* array of processes */
+       struct kinfo_proc *procs;          /* array of processes */
        struct kinfo_proc *proc_ptr = NULL;
-       int count;                         /* returns number of processes */
+       int count;                         /* returns number of processes */
        int i;
 
        procstat_t *ps_ptr;
@@ -1953,7 +1961,7 @@ static int ps_read (void)
                                if (procentry[i].pi_pid == 0)
                                        cmdline = "swapper";
                                cargs = cmdline;
-                       }
+                       }
                        else
                        {
                                if (getargs(&procentry[i], sizeof(struct procentry64), arglist, MAXARGLN) >= 0)
@@ -2049,10 +2057,10 @@ static int ps_read (void)
 
 #elif KERNEL_SOLARIS
        /*
-         * The Solaris section adds a few more process states and removes some
-         * process states compared to linux. Most notably there is no "PAGING"
-         * and "BLOCKED" state for a process.  The rest is similar to the linux
-         * code.
+        * The Solaris section adds a few more process states and removes some
+        * process states compared to linux. Most notably there is no "PAGING"
+        * and "BLOCKED" state for a process.  The rest is similar to the linux
+        * code.
         */
        int running = 0;
        int sleeping = 0;
@@ -2062,46 +2070,50 @@ static int ps_read (void)
        int daemon = 0;
        int system = 0;
        int orphan = 0;
-       unsigned long fork_rate;
+
        struct dirent *ent;
        DIR *proc;
-       int pid;
 
        int status;
-       struct procstat ps;
-       procstat_entry_t pse;
        procstat_t *ps_ptr;
        char state;
 
-       ps_list_reset();
+       char cmdline[PRARGSZ];
 
+       ps_list_reset ();
 
-       proc = opendir("/proc");
-       if (proc == NULL) {
+       proc = opendir ("/proc");
+       if (proc == NULL)
                return (-1);
-       }
 
-       while ((ent = readdir(proc)) != NULL) {
-               if (!isdigit(ent->d_name[0]))
+       while ((ent = readdir(proc)) != NULL)
+       {
+               int pid;
+               struct procstat ps;
+               procstat_entry_t pse;
+
+               if (!isdigit ((int) ent->d_name[0]))
                        continue;
 
-               if ((pid = atoi(ent->d_name)) < 1)
+               if ((pid = atoi (ent->d_name)) < 1)
                        continue;
 
-               status = ps_read_process(pid, &ps, &state);
-               if (status != 0) {
+               status = ps_read_process (pid, &ps, &state);
+               if (status != 0)
+               {
                        DEBUG("ps_read_process failed: %i", status);
                        continue;
                }
+
                pse.id = pid;
                pse.age = 0;
 
-               pse.num_proc = ps.num_proc;
-               pse.num_lwp = ps.num_lwp;
-               pse.vmem_size = ps.vmem_size;
-               pse.vmem_rss = ps.vmem_rss;
-               pse.vmem_data = ps.vmem_data;
-               pse.vmem_code = ps.vmem_code;
+               pse.num_proc   = ps.num_proc;
+               pse.num_lwp    = ps.num_lwp;
+               pse.vmem_size  = ps.vmem_size;
+               pse.vmem_rss   = ps.vmem_rss;
+               pse.vmem_data  = ps.vmem_data;
+               pse.vmem_code  = ps.vmem_code;
                pse.stack_size = ps.stack_size;
 
                pse.vmem_minflt = 0;
@@ -2119,48 +2131,39 @@ static int ps_read (void)
                pse.io_syscr = ps.io_syscr;
                pse.io_syscw = ps.io_syscw;
 
-               switch (state) {
-               case 'R': running++;
-                       break;
-               case 'S': sleeping++;
-                       break;
-               case 'E': detached++;
-                       break;
-               case 'Z': zombies++;
-                       break;
-               case 'T': stopped++;
-                       break;
-               case 'A': daemon++;
-                       break;
-               case 'Y': system++;
-                       break;
-               case 'O': orphan++;
-                       break;
+               switch (state)
+               {
+                       case 'R': running++;  break;
+                       case 'S': sleeping++; break;
+                       case 'E': detached++; break;
+                       case 'Z': zombies++;  break;
+                       case 'T': stopped++;  break;
+                       case 'A': daemon++;   break;
+                       case 'Y': system++;   break;
+                       case 'O': orphan++;   break;
                }
 
-               ps_list_add(ps.name, ps_get_cmdline(pid), &pse);
 
-       } // while()
-       closedir(proc);
+               ps_list_add (ps.name,
+                               ps_get_cmdline ((pid_t) pid,
+                                       cmdline, sizeof (cmdline)),
+                               &pse);
+       } /* while(readdir) */
+       closedir (proc);
 
-       ps_submit_state("running", running);
-       ps_submit_state("sleeping", sleeping);
-       ps_submit_state("zombies", zombies);
-       ps_submit_state("stopped", stopped);
-       ps_submit_state("detached", detached);
-       ps_submit_state("daemon", daemon);
-       ps_submit_state("system", system);
-       ps_submit_state("orphan", orphan);
+       ps_submit_state ("running",  running);
+       ps_submit_state ("sleeping", sleeping);
+       ps_submit_state ("zombies",  zombies);
+       ps_submit_state ("stopped",  stopped);
+       ps_submit_state ("detached", detached);
+       ps_submit_state ("daemon",   daemon);
+       ps_submit_state ("system",   system);
+       ps_submit_state ("orphan",   orphan);
 
        for (ps_ptr = list_head_g; ps_ptr != NULL; ps_ptr = ps_ptr->next)
-               ps_submit_proc_list(ps_ptr);
-
-
-       fork_rate = read_fork_rate();
-       if (fork_rate != ULONG_MAX) {
-               ps_submit_fork_rate(fork_rate);
-       }
+               ps_submit_proc_list (ps_ptr);
 
+       read_fork_rate();
 #endif /* KERNEL_SOLARIS */
 
        return (0);