processes: use long for pids on linux and solaris
[collectd.git] / src / processes.c
index a09eb50..faeb7c9 100644 (file)
 /* #endif HAVE_PROCINFO_H */
 
 #elif KERNEL_SOLARIS
+/* Hack: Avoid #error when building a 32-bit binary with
+ * _FILE_OFFSET_BITS=64. There is a reason for this #error, as one
+ * of the structures in <sys/procfs.h> uses an off_t, but that
+ * isn't relevant to our usage of procfs. */
+#if !defined(_LP64) && _FILE_OFFSET_BITS == 64
+#  define SAVE_FOB_64
+#  undef _FILE_OFFSET_BITS
+#endif
+
 # include <procfs.h>
+
+#ifdef SAVE_FOB_64
+#  define _FILE_OFFSET_BITS 64
+#  undef SAVE_FOB_64
+#endif
+
 # include <dirent.h>
 /* #endif KERNEL_SOLARIS */
 
@@ -223,12 +238,12 @@ static int pagesize;
 int     getprocs64 (void *procsinfo, int sizproc, void *fdsinfo, int sizfd, pid_t *index, int count);
 int     getthrds64( pid_t, void *, int, tid64_t *, int );
 #endif
-int getargs (struct procentry64 *processBuffer, int bufferLen, char *argsBuffer, int argsLen);
+int getargs (void *processBuffer, int bufferLen, char *argsBuffer, int argsLen);
 #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;
@@ -261,6 +276,7 @@ static void ps_list_register (const char *name, const char *regexp)
                {
                        DEBUG ("ProcessMatch: compiling the regular expression \"%s\" failed.", regexp);
                        sfree(new->re);
+                       sfree(new);
                        return;
                }
        }
@@ -286,7 +302,9 @@ static void ps_list_register (const char *name, const char *regexp)
                                        "`ProcessMatch' with the same name. "
                                        "All but the first setting will be "
                                        "ignored.");
+#if HAVE_REGEX_H
                        sfree (new->re);
+#endif
                        sfree (new);
                        return;
                }
@@ -723,7 +741,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"; "
@@ -759,14 +777,14 @@ static void ps_submit_fork_rate (derive_t value)
 
 /* ------- additional functions for KERNEL_LINUX/HAVE_THREAD_INFO ------- */
 #if KERNEL_LINUX
-static int ps_read_tasks (int pid)
+static int ps_read_tasks (long pid)
 {
        char           dirname[64];
        DIR           *dh;
        struct dirent *ent;
        int count = 0;
 
-       ssnprintf (dirname, sizeof (dirname), "/proc/%i/task", pid);
+       ssnprintf (dirname, sizeof (dirname), "/proc/%li/task", pid);
 
        if ((dh = opendir (dirname)) == NULL)
        {
@@ -787,7 +805,7 @@ static int ps_read_tasks (int pid)
 } /* int *ps_read_tasks */
 
 /* Read advanced virtual memory data from /proc/pid/status */
-static procstat_t *ps_read_vmem (int pid, procstat_t *ps)
+static procstat_t *ps_read_vmem (long pid, procstat_t *ps)
 {
        FILE *fh;
        char buffer[1024];
@@ -798,7 +816,7 @@ static procstat_t *ps_read_vmem (int pid, procstat_t *ps)
        char *fields[8];
        int numfields;
 
-       ssnprintf (filename, sizeof (filename), "/proc/%i/status", pid);
+       ssnprintf (filename, sizeof (filename), "/proc/%li/status", pid);
        if ((fh = fopen (filename, "r")) == NULL)
                return (NULL);
 
@@ -811,7 +829,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;
@@ -849,7 +867,7 @@ static procstat_t *ps_read_vmem (int pid, procstat_t *ps)
        return (ps);
 } /* procstat_t *ps_read_vmem */
 
-static procstat_t *ps_read_io (int pid, procstat_t *ps)
+static procstat_t *ps_read_io (long pid, procstat_t *ps)
 {
        FILE *fh;
        char buffer[1024];
@@ -858,7 +876,7 @@ static procstat_t *ps_read_io (int pid, procstat_t *ps)
        char *fields[8];
        int numfields;
 
-       ssnprintf (filename, sizeof (filename), "/proc/%i/io", pid);
+       ssnprintf (filename, sizeof (filename), "/proc/%li/io", pid);
        if ((fh = fopen (filename, "r")) == NULL)
                return (NULL);
 
@@ -904,7 +922,7 @@ static procstat_t *ps_read_io (int pid, procstat_t *ps)
        return (ps);
 } /* procstat_t *ps_read_io */
 
-int ps_read_process (int pid, procstat_t *ps, char *state)
+int ps_read_process (long pid, procstat_t *ps, char *state)
 {
        char  filename[64];
        char  buffer[1024];
@@ -927,7 +945,7 @@ int ps_read_process (int pid, procstat_t *ps, char *state)
 
        memset (ps, 0, sizeof (procstat_t));
 
-       ssnprintf (filename, sizeof (filename), "/proc/%i/stat", pid);
+       ssnprintf (filename, sizeof (filename), "/proc/%li/stat", pid);
 
        buffer_len = read_file_contents (filename,
                        buffer, sizeof(buffer) - 1);
@@ -972,9 +990,9 @@ int ps_read_process (int pid, procstat_t *ps, char *state)
        fields_len = strsplit (buffer_ptr, fields, STATIC_ARRAY_SIZE (fields));
        if (fields_len < 22)
        {
-               DEBUG ("processes plugin: ps_read_process (pid = %i):"
+               DEBUG ("processes plugin: ps_read_process (pid = %li):"
                                " `%s' has only %i fields..",
-                               (int) pid, filename, fields_len);
+                               pid, filename, fields_len);
                return (-1);
        }
 
@@ -998,7 +1016,7 @@ int ps_read_process (int pid, procstat_t *ps, char *state)
        /* Leave the rest at zero if this is only a zombi */
        if (ps->num_proc == 0)
        {
-               DEBUG ("processes plugin: This is only a zombi: pid = %i; "
+               DEBUG ("processes plugin: This is only a zombie: pid = %li; "
                                "name = %s;", pid, ps->name);
                return (0);
        }
@@ -1046,14 +1064,14 @@ int ps_read_process (int pid, procstat_t *ps, char *state)
                ps->io_syscr = -1;
                ps->io_syscw = -1;
 
-               DEBUG("ps_read_process: not get io data for pid %i",pid);
+               DEBUG("ps_read_process: not get io data for pid %li", pid);
        }
 
        /* success */
        return (0);
 } /* int ps_read_process (...) */
 
-static char *ps_get_cmdline (pid_t pid, char *name, char *buf, size_t buf_len)
+static char *ps_get_cmdline (long pid, char *name, char *buf, size_t buf_len)
 {
        char  *buf_ptr;
        size_t len;
@@ -1066,8 +1084,7 @@ 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",
-                       (unsigned int) pid);
+       ssnprintf (file, sizeof (file), "/proc/%li/cmdline", pid);
 
        errno = 0;
        fd = open (file, O_RDONLY);
@@ -1195,17 +1212,17 @@ static int read_fork_rate ()
 #endif /*KERNEL_LINUX */
 
 #if KERNEL_SOLARIS
-static const char *ps_get_cmdline (pid_t pid, /* {{{ */
-               char *buffer, size_t buffer_size)
+static char *ps_get_cmdline (long pid, char *name __attribute__((unused)), /* {{{ */
+    char *buffer, size_t buffer_size)
 {
        char path[PATH_MAX];
        psinfo_t info;
        int status;
 
-       snprintf(path, sizeof (path), "/proc/%i/psinfo", pid);
+       snprintf(path, sizeof (path), "/proc/%li/psinfo", pid);
 
        status = read_file_contents (path, (void *) &info, sizeof (info));
-       if (status != ((int) buffer_size))
+       if (status != sizeof (info))
        {
                ERROR ("processes plugin: Unexpected return value "
                                "while reading \"%s\": "
@@ -1226,21 +1243,19 @@ static const char *ps_get_cmdline (pid_t pid, /* {{{ */
  * The values for input and ouput chars are calculated "by hand"
  * Added a few "solaris" specific process states as well
  */
-static int ps_read_process(int pid, procstat_t *ps, char *state)
+static int ps_read_process(long 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;
 
-       snprintf(filename, sizeof (filename), "/proc/%i/status", pid);
-       snprintf(f_psinfo, sizeof (f_psinfo), "/proc/%i/psinfo", pid);
-       snprintf(f_usage, sizeof (f_usage), "/proc/%i/usage", pid);
+       snprintf(filename, sizeof (filename), "/proc/%li/status", pid);
+       snprintf(f_psinfo, sizeof (f_psinfo), "/proc/%li/psinfo", pid);
+       snprintf(f_usage, sizeof (f_usage), "/proc/%li/usage", pid);
 
 
        buffer = malloc(sizeof (pstatus_t));
@@ -1686,7 +1701,7 @@ static int ps_read (void)
 
        struct dirent *ent;
        DIR           *proc;
-       int            pid;
+       long           pid;
 
        char cmdline[ARG_MAX];
 
@@ -1713,7 +1728,7 @@ static int ps_read (void)
                if (!isdigit (ent->d_name[0]))
                        continue;
 
-               if ((pid = atoi (ent->d_name)) < 1)
+               if ((pid = atol (ent->d_name)) < 1)
                        continue;
 
                status = ps_read_process (pid, &ps, &state);
@@ -1789,10 +1804,10 @@ static int ps_read (void)
        int wait     = 0;
 
        kvm_t *kd;
-       char errbuf[1024];
-       struct kinfo_proc *procs;          /* array of processes */
+       char errbuf[_POSIX2_LINE_MAX];
+       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;
@@ -1801,7 +1816,7 @@ static int ps_read (void)
        ps_list_reset ();
 
        /* Open the kvm interface, get a descriptor */
-       kd = kvm_open (NULL, NULL, NULL, 0, errbuf);
+       kd = kvm_openfiles (NULL, "/dev/null", NULL, 0, errbuf);
        if (kd == NULL)
        {
                ERROR ("processes plugin: Cannot open kvm interface: %s",
@@ -1895,18 +1910,18 @@ static int ps_read (void)
                        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 SSTOP:     stopped++;      break;
-                       case SSLEEP:    sleeping++;     break;
-                       case SRUN:      running++;      break;
-                       case SIDL:      idle++;         break;
-                       case SWAIT:     wait++;         break;
-                       case SLOCK:     blocked++;      break;
-                       case SZOMB:     zombies++;      break;
-               }
+                       switch (procs[i].ki_stat)
+                       {
+                               case SSTOP:     stopped++;      break;
+                               case SSLEEP:    sleeping++;     break;
+                               case SRUN:      running++;      break;
+                               case SIDL:      idle++;         break;
+                               case SWAIT:     wait++;         break;
+                               case SLOCK:     blocked++;      break;
+                               case SZOMB:     zombies++;      break;
+                       }
+               } /* if ((proc_ptr == NULL) || (proc_ptr->ki_pid != procs[i].ki_pid)) */
        }
 
        kvm_close(kd);
@@ -1963,7 +1978,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)
@@ -2059,10 +2074,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;
@@ -2072,46 +2087,52 @@ static int ps_read (void)
        int daemon = 0;
        int system = 0;
        int orphan = 0;
+
        struct dirent *ent;
        DIR *proc;
-       int pid;
 
        int status;
-       struct procstat ps;
-       procstat_entry_t pse;
        procstat_t *ps_ptr;
        char state;
 
-       char cmdline[ARG_MAX];
+       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)
+       {
+               long pid;
+               struct procstat ps;
+               procstat_entry_t pse;
+               char *endptr;
+
+               if (!isdigit ((int) ent->d_name[0]))
                        continue;
 
-               if ((pid = atoi(ent->d_name)) < 1)
+               pid = strtol (ent->d_name, &endptr, 10);
+               if (*endptr != 0) /* value didn't completely parse as a number */
                        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;
@@ -2129,29 +2150,21 @@ 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_t) pid,
-                                       cmdline, sizeof (cmdline)),
+                               ps_get_cmdline (pid, ps.name, cmdline, sizeof (cmdline)),
                                &pse);
        } /* while(readdir) */
        closedir (proc);