Merge branch 'collectd-4.5' into collectd-4.6
authorFlorian Forster <octo@leeloo.lan.home.verplant.org>
Fri, 17 Apr 2009 23:04:48 +0000 (01:04 +0200)
committerFlorian Forster <octo@leeloo.lan.home.verplant.org>
Fri, 17 Apr 2009 23:04:48 +0000 (01:04 +0200)
Conflicts:
src/cpu.c

1  2 
src/battery.c
src/cpu.c
src/interface.c
src/memory.c
src/ping.c
src/processes.c

diff --combined src/battery.c
@@@ -23,6 -23,8 +23,8 @@@
  #include "common.h"
  #include "plugin.h"
  
+ #include "utils_complain.h"
  #if HAVE_MACH_MACH_TYPES_H
  #  include <mach/mach_types.h>
  #endif
@@@ -98,6 -100,7 +100,6 @@@ static void battery_submit (const char 
  
        vl.values = values;
        vl.values_len = 1;
 -      vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "battery", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
@@@ -314,8 -317,8 +316,8 @@@ static void get_via_generic_iokit (doub
  #endif /* HAVE_IOKIT_IOKITLIB_H */
  
  #if KERNEL_LINUX
 -static int battery_read_acpi (const char *dir, const char *name,
 -              void *user_data)
 +static int battery_read_acpi (const char __attribute__((unused)) *dir,
 +              const char *name, void __attribute__((unused)) *user_data)
  {
        double  current = INVALID_VALUE;
        double  voltage = INVALID_VALUE;
@@@ -436,6 -439,8 +438,8 @@@ static int battery_read (void
  /* #endif HAVE_IOKIT_IOKITLIB_H || HAVE_IOKIT_PS_IOPOWERSOURCES_H */
  
  #elif KERNEL_LINUX
+       static c_complain_t acpi_dir_complaint = C_COMPLAIN_INIT_STATIC;
        FILE *fh;
        char buffer[1024];
        char filename[256];
                        battery_submit ("0", "voltage", voltage);
        }
  
-       walk_directory (battery_acpi_dir, battery_read_acpi,
-                       /* user_data = */ NULL);
+       if (0 == access (battery_acpi_dir, R_OK))
+               walk_directory (battery_acpi_dir, battery_read_acpi,
+                               /* user_data = */ NULL);
+       else
+       {
+               char errbuf[1024];
+               c_complain_once (LOG_WARNING, &acpi_dir_complaint,
+                               "battery plugin: Failed to access `%s': %s",
+                               battery_acpi_dir,
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+       }
  
  #endif /* KERNEL_LINUX */
  
diff --combined src/cpu.c
+++ b/src/cpu.c
@@@ -1,7 -1,7 +1,8 @@@
  /**
   * collectd - src/cpu.c
   * Copyright (C) 2005-2009  Florian octo Forster
-  * Copyright (C) 2009 Simon Kuhnle
+  * Copyright (C) 2008       Oleg King
++ * Copyright (C) 2009       Simon Kuhnle
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License as published by the
@@@ -18,7 -18,7 +19,8 @@@
   *
   * Authors:
   *   Florian octo Forster <octo at verplant.org>
+  *   Oleg King <king2 at kaluga.ru>
 + *   Simon Kuhnle <simon at blarzwurst.de>
   **/
  
  #include "collectd.h"
@@@ -51,8 -51,7 +53,8 @@@
  # include <sys/sysinfo.h>
  #endif /* HAVE_LIBKSTAT */
  
 -#ifdef HAVE_SYSCTLBYNAME
 +#if (defined(HAVE_SYSCTL) && HAVE_SYSCTL) \
 +      || (defined(HAVE_SYSCTLBYNAME) && HAVE_SYSCTLBYNAME)
  # ifdef HAVE_SYS_SYSCTL_H
  #  include <sys/sysctl.h>
  # endif
  #  define CP_IDLE   4
  #  define CPUSTATES 5
  # endif
 -#endif /* HAVE_SYSCTLBYNAME */
 +#endif /* HAVE_SYSCTL || HAVE_SYSCTLBYNAME */
 +
 +#if HAVE_SYSCTL
 +# if defined(CTL_HW) && defined(HW_NCPU) \
 +      && defined(CTL_KERN) && defined(KERN_CPTIME) && defined(CPUSTATES)
 +#  define CAN_USE_SYSCTL 1
 +# else
 +#  define CAN_USE_SYSCTL 0
 +# endif
 +#else
 +# define CAN_USE_SYSCTL 0
 +#endif
  
  #if HAVE_STATGRAB_H
  # include <statgrab.h>
  #endif
  
  #if !PROCESSOR_CPU_LOAD_INFO && !KERNEL_LINUX && !HAVE_LIBKSTAT \
 -      && !HAVE_SYSCTLBYNAME && !HAVE_LIBSTATGRAB
 +      && !CAN_USE_SYSCTL && !HAVE_SYSCTLBYNAME && !HAVE_LIBSTATGRAB
  # error "No applicable input method."
  #endif
  
@@@ -115,10 -103,6 +117,10 @@@ static kstat_t *ksp[MAX_NUMCPU]
  static int numcpu;
  /* #endif HAVE_LIBKSTAT */
  
 +#elif CAN_USE_SYSCTL
 +static int numcpu;
 +/* #endif CAN_USE_SYSCTL */
 +
  #elif defined(HAVE_SYSCTLBYNAME)
  static int numcpu;
  /* #endif HAVE_SYSCTLBYNAME */
@@@ -164,25 -148,6 +166,25 @@@ static int init (void
                        ksp[numcpu++] = ksp_chain;
  /* #endif HAVE_LIBKSTAT */
  
 +#elif CAN_USE_SYSCTL
 +      size_t numcpu_size;
 +      int mib[2] = {CTL_HW, HW_NCPU};
 +      int status;
 +
 +      numcpu = 0;
 +      numcpu_size = sizeof (numcpu);
 +
 +      status = sysctl (mib, STATIC_ARRAY_SIZE (mib),
 +                      &numcpu, &numcpu_size, NULL, 0);
 +      if (status == -1)
 +      {
 +              char errbuf[1024];
 +              WARNING ("cpu plugin: sysctl: %s",
 +                              sstrerror (errno, errbuf, sizeof (errbuf)));
 +              return (-1);
 +      }
 +/* #endif CAN_USE_SYSCTL */
 +
  #elif defined (HAVE_SYSCTLBYNAME)
        size_t numcpu_size;
  
@@@ -216,6 -181,7 +218,6 @@@ static void submit (int cpu_num, const 
  
        vl.values = values;
        vl.values_len = 1;
 -      vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "cpu", sizeof (vl.plugin));
        ssnprintf (vl.plugin_instance, sizeof (vl.type_instance),
@@@ -399,70 -365,6 +401,70 @@@ static int cpu_read (void
        }
  /* #endif defined(HAVE_LIBKSTAT) */
  
 +#elif CAN_USE_SYSCTL
 +      uint64_t cpuinfo[numcpu][CPUSTATES];
 +      size_t cpuinfo_size;
 +      int status;
 +      int i;
 +
 +      if (numcpu < 1)
 +      {
 +              ERROR ("cpu plugin: Could not determine number of "
 +                              "installed CPUs using sysctl(3).");
 +              return (-1);
 +      }
 +
 +      memset (cpuinfo, 0, sizeof (cpuinfo));
 +
 +#if defined(KERN_CPTIME2)
 +      if (numcpu > 1) {
 +              for (i = 0; i < numcpu; i++) {
 +                      int mib[] = {CTL_KERN, KERN_CPTIME2, i};
 +
 +                      cpuinfo_size = sizeof (cpuinfo[0]);
 +
 +                      status = sysctl (mib, STATIC_ARRAY_SIZE (mib),
 +                                      cpuinfo[i], &cpuinfo_size, NULL, 0);
 +                      if (status == -1) {
 +                              char errbuf[1024];
 +                              ERROR ("cpu plugin: sysctl failed: %s.",
 +                                              sstrerror (errno, errbuf, sizeof (errbuf)));
 +                              return (-1);
 +                      }
 +              }
 +      }
 +      else
 +#endif /* defined(KERN_CPTIME2) */
 +      {
 +              int mib[] = {CTL_KERN, KERN_CPTIME};
 +              long cpuinfo_tmp[CPUSTATES];
 +
 +              cpuinfo_size = sizeof(cpuinfo_tmp);
 +
 +              status = sysctl (mib, STATIC_ARRAY_SIZE (mib),
 +                                      &cpuinfo_tmp, &cpuinfo_size, NULL, 0);
 +              if (status == -1)
 +              {
 +                      char errbuf[1024];
 +                      ERROR ("cpu plugin: sysctl failed: %s.",
 +                                      sstrerror (errno, errbuf, sizeof (errbuf)));
 +                      return (-1);
 +              }
 +
 +              for(i = 0; i < CPUSTATES; i++) {
 +                      cpuinfo[0][i] = cpuinfo_tmp[i];
 +              }
 +      }
 +
 +      for (i = 0; i < numcpu; i++) {
 +              submit (i, "user",      cpuinfo[i][CP_USER]);
 +              submit (i, "nice",      cpuinfo[i][CP_NICE]);
 +              submit (i, "system",    cpuinfo[i][CP_SYS]);
 +              submit (i, "idle",      cpuinfo[i][CP_IDLE]);
 +              submit (i, "interrupt", cpuinfo[i][CP_INTR]);
 +      }
 +/* #endif CAN_USE_SYSCTL */
 +
  #elif defined(HAVE_SYSCTLBYNAME)
        long cpuinfo[CPUSTATES];
        size_t cpuinfo_size;
                return (-1);
        }
  
 -      cpuinfo[CP_SYS] += cpuinfo[CP_INTR];
 -
        submit (0, "user", cpuinfo[CP_USER]);
        submit (0, "nice", cpuinfo[CP_NICE]);
        submit (0, "system", cpuinfo[CP_SYS]);
        submit (0, "idle", cpuinfo[CP_IDLE]);
 +      submit (0, "interrupt", cpuinfo[CP_INTR]);
  /* #endif HAVE_SYSCTLBYNAME */
  
  #elif defined(HAVE_LIBSTATGRAB)
 -       sg_cpu_stats *cs;
 -       cs = sg_get_cpu_stats ();
 -
 -       if (cs == NULL)
 -       {
 -             ERROR ("cpu plugin: sg_get_cpu_stats failed.");
 -               return (-1);
 -       }
 -
 -       submit (0, "idle",   (counter_t) cs->idle);
 -       submit (0, "nice",   (counter_t) cs->nice);
 -       submit (0, "swap",   (counter_t) cs->swap);
 -       submit (0, "system", (counter_t) cs->kernel);
 -       submit (0, "user",   (counter_t) cs->user);
 -       submit (0, "wait",   (counter_t) cs->iowait);
 +      sg_cpu_stats *cs;
 +      cs = sg_get_cpu_stats ();
 +
 +      if (cs == NULL)
 +      {
 +              ERROR ("cpu plugin: sg_get_cpu_stats failed.");
 +              return (-1);
 +      }
 +
 +      submit (0, "idle",   (counter_t) cs->idle);
 +      submit (0, "nice",   (counter_t) cs->nice);
 +      submit (0, "swap",   (counter_t) cs->swap);
 +      submit (0, "system", (counter_t) cs->kernel);
 +      submit (0, "user",   (counter_t) cs->user);
 +      submit (0, "wait",   (counter_t) cs->iowait);
  #endif /* HAVE_LIBSTATGRAB */
  
        return (0);
diff --combined src/interface.c
@@@ -1,6 -1,6 +1,6 @@@
  /**
   * collectd - src/interface.c
-  * Copyright (C) 2005-2007  Florian octo Forster
+  * Copyright (C) 2005-2008  Florian octo Forster
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License as published by the
@@@ -24,7 -24,6 +24,7 @@@
  #include "common.h"
  #include "plugin.h"
  #include "configfile.h"
 +#include "utils_ignorelist.h"
  
  #if HAVE_SYS_TYPES_H
  #  include <sys/types.h>
@@@ -78,7 -77,14 +78,7 @@@ static const char *config_keys[] 
  };
  static int config_keys_num = 2;
  
 -static char **if_list = NULL;
 -static int    if_list_num = 0;
 -/* 
 - * if_list_action:
 - * 0 => default is to collect selected interface
 - * 1 => ignore selcted interfaces
 - */
 -static int    if_list_action = 0;
 +static ignorelist_t *ignorelist = NULL;
  
  #ifdef HAVE_LIBKSTAT
  #define MAX_NUMIF 256
@@@ -89,21 -95,33 +89,21 @@@ static int numif = 0
  
  static int interface_config (const char *key, const char *value)
  {
 -      char **temp;
 +      if (ignorelist == NULL)
 +              ignorelist = ignorelist_create (/* invert = */ 1);
  
        if (strcasecmp (key, "Interface") == 0)
        {
 -              temp = (char **) realloc (if_list, (if_list_num + 1) * sizeof (char *));
 -              if (temp == NULL)
 -              {
 -                      ERROR ("Cannot allocate more memory.");
 -                      return (1);
 -              }
 -              if_list = temp;
 -
 -              if ((if_list[if_list_num] = strdup (value)) == NULL)
 -              {
 -                      ERROR ("Cannot allocate memory.");
 -                      return (1);
 -              }
 -              if_list_num++;
 +              ignorelist_add (ignorelist, value);
        }
        else if (strcasecmp (key, "IgnoreSelected") == 0)
        {
 +              int invert = 1;
                if ((strcasecmp (value, "True") == 0)
                                || (strcasecmp (value, "Yes") == 0)
                                || (strcasecmp (value, "On") == 0))
 -                      if_list_action = 1;
 -              else
 -                      if_list_action = 0;
 +                      invert = 0;
 +              ignorelist_set_invert (ignorelist, invert);
        }
        else
        {
@@@ -143,6 -161,26 +143,6 @@@ static int interface_init (void
  } /* int interface_init */
  #endif /* HAVE_LIBKSTAT */
  
 -/*
 - * Check if this interface/instance should be ignored. This is called from
 - * both, `submit' and `write' to give client and server the ability to
 - * ignore certain stuff..
 - */
 -static int check_ignore_if (const char *interface)
 -{
 -      int i;
 -
 -      /* If no interfaces are given collect all interfaces. Mostly to be
 -       * backwards compatible, but also because this is much easier. */
 -      if (if_list_num < 1)
 -              return (0);
 -
 -      for (i = 0; i < if_list_num; i++)
 -              if (strcasecmp (interface, if_list[i]) == 0)
 -                      return (if_list_action);
 -      return (1 - if_list_action);
 -} /* int check_ignore_if */
 -
  static void if_submit (const char *dev, const char *type,
                unsigned long long rx,
                unsigned long long tx)
        value_t values[2];
        value_list_t vl = VALUE_LIST_INIT;
  
 -      if (check_ignore_if (dev))
 +      if (ignorelist_match (ignorelist, dev) != 0)
                return;
  
        values[0].counter = rx;
  
        vl.values = values;
        vl.values_len = 2;
 -      vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "interface", sizeof (vl.plugin));
        sstrncpy (vl.type, type, sizeof (vl.type));
diff --combined src/memory.c
@@@ -1,6 -1,6 +1,6 @@@
  /**
   * collectd - src/memory.c
-  * Copyright (C) 2005-2007  Florian octo Forster
+  * Copyright (C) 2005-2008  Florian octo Forster
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License as published by the
@@@ -111,6 -111,7 +111,6 @@@ static void memory_submit (const char *
  
        vl.values = values;
        vl.values_len = 1;
 -      vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "memory", sizeof (vl.plugin));
        sstrncpy (vl.type, "memory", sizeof (vl.type));
diff --combined src/ping.c
@@@ -1,6 -1,6 +1,6 @@@
  /**
   * collectd - src/ping.c
-  * Copyright (C) 2005,2006  Florian octo Forster
+  * Copyright (C) 2005-2007  Florian octo Forster
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License as published by the
@@@ -185,6 -185,7 +185,6 @@@ static void ping_submit (char *host, do
  
        vl.values = values;
        vl.values_len = 1;
 -      vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "ping", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_instance));
diff --combined src/processes.c
@@@ -22,7 -22,6 +22,7 @@@
   *   Lyonel Vincent <lyonel at ezix.org>
   *   Florian octo Forster <octo at verplant.org>
   *   Oleg King <king2 at kaluga.ru>
 + *   Sebastian Harl <sh at tokkee.org>
   **/
  
  #include "collectd.h"
  # include <regex.h>
  #endif
  
 +#ifndef ARG_MAX
 +#  define ARG_MAX 4096
 +#endif
 +
  #define BUFSIZE 256
  
  static const char *config_keys[] =
@@@ -122,9 -117,7 +122,9 @@@ typedef struct procstat_entry_
  
        unsigned long num_proc;
        unsigned long num_lwp;
 +      unsigned long vmem_size;
        unsigned long vmem_rss;
 +      unsigned long stack_size;
  
        unsigned long vmem_minflt;
        unsigned long vmem_majflt;
@@@ -149,9 -142,7 +149,9 @@@ typedef struct procsta
  
        unsigned long num_proc;
        unsigned long num_lwp;
 +      unsigned long vmem_size;
        unsigned long vmem_rss;
 +      unsigned long stack_size;
  
        unsigned long vmem_minflt_counter;
        unsigned long vmem_majflt_counter;
@@@ -323,17 -314,13 +323,17 @@@ static void ps_list_add (const char *na
                }
  
                pse->age = 0;
 -              pse->num_proc = entry->num_proc;
 -              pse->num_lwp  = entry->num_lwp;
 -              pse->vmem_rss = entry->vmem_rss;
 -
 -              ps->num_proc += pse->num_proc;
 -              ps->num_lwp  += pse->num_lwp;
 -              ps->vmem_rss += pse->vmem_rss;
 +              pse->num_proc   = entry->num_proc;
 +              pse->num_lwp    = entry->num_lwp;
 +              pse->vmem_size  = entry->vmem_size;
 +              pse->vmem_rss   = entry->vmem_rss;
 +              pse->stack_size = entry->stack_size;
 +
 +              ps->num_proc   += pse->num_proc;
 +              ps->num_lwp    += pse->num_lwp;
 +              ps->vmem_size  += pse->vmem_size;
 +              ps->vmem_rss   += pse->vmem_rss;
 +              ps->stack_size += pse->stack_size;
  
                if ((entry->vmem_minflt_counter == 0)
                                && (entry->vmem_majflt_counter == 0))
@@@ -422,9 -409,7 +422,9 @@@ static void ps_list_reset (void
        {
                ps->num_proc    = 0;
                ps->num_lwp     = 0;
 +              ps->vmem_size   = 0;
                ps->vmem_rss    = 0;
 +              ps->stack_size  = 0;
  
                pse_prev = NULL;
                pse = ps->instances;
@@@ -473,18 -458,12 +473,18 @@@ static int ps_config (const char *key, 
                int fields_num;
  
                new_val = strdup (value);
 -              if (new_val == NULL)
 +              if (new_val == NULL) {
 +                      ERROR ("processes plugin: strdup failed when processing "
 +                                      "`ProcessMatch %s'.", value);
                        return (1);
 +              }
 +
                fields_num = strsplit (new_val, fields,
                                STATIC_ARRAY_SIZE (fields));
                if (fields_num != 2)
                {
 +                      ERROR ("processes plugin: `ProcessMatch' needs exactly "
 +                                      "two string arguments.");
                        sfree (new_val);
                        return (1);
                }
        }
        else
        {
 +              ERROR ("processes plugin: The `%s' configuration option is not "
 +                              "understood and will be ignored.", key);
                return (-1);
        }
  
@@@ -553,6 -530,7 +553,6 @@@ static void ps_submit_state (const cha
  
        vl.values = values;
        vl.values_len = 1;
 -      vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "processes", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_instance));
@@@ -570,25 -548,16 +570,25 @@@ static void ps_submit_proc_list (procst
  
        vl.values = values;
        vl.values_len = 2;
 -      vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "processes", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, ps->name, sizeof (vl.plugin_instance));
  
 +      sstrncpy (vl.type, "ps_vm", sizeof (vl.type));
 +      vl.values[0].gauge = ps->vmem_size;
 +      vl.values_len = 1;
 +      plugin_dispatch_values (&vl);
 +
        sstrncpy (vl.type, "ps_rss", sizeof (vl.type));
        vl.values[0].gauge = ps->vmem_rss;
        vl.values_len = 1;
        plugin_dispatch_values (&vl);
  
 +      sstrncpy (vl.type, "ps_stacksize", sizeof (vl.type));
 +      vl.values[0].gauge = ps->stack_size;
 +      vl.values_len = 1;
 +      plugin_dispatch_values (&vl);
 +
        sstrncpy (vl.type, "ps_cputime", sizeof (vl.type));
        vl.values[0].counter = ps->cpu_user_counter;
        vl.values[1].counter = ps->cpu_system_counter;
@@@ -694,9 -663,7 +694,9 @@@ int ps_read_process (int pid, procstat_
  
        long long unsigned cpu_user_counter;
        long long unsigned cpu_system_counter;
 +      long long unsigned vmem_size;
        long long unsigned vmem_rss;
 +      long long unsigned stack_size;
  
        memset (ps, 0, sizeof (procstat_t));
  
  
        cpu_user_counter   = atoll (fields[13]);
        cpu_system_counter = atoll (fields[14]);
 -      vmem_rss = atoll (fields[23]);
 +      vmem_size          = atoll (fields[22]);
 +      vmem_rss           = atoll (fields[23]);
        ps->vmem_minflt_counter = atol (fields[9]);
        ps->vmem_majflt_counter = atol (fields[11]);
 -      
 +
 +      {
 +              unsigned long long stack_start = atoll (fields[27]);
 +              unsigned long long stack_ptr   = atoll (fields[28]);
 +
 +              stack_size = (stack_start > stack_ptr)
 +                      ? stack_start - stack_ptr
 +                      : stack_ptr - stack_start;
 +      }
 +
        /* Convert jiffies to useconds */
        cpu_user_counter   = cpu_user_counter   * 1000000 / CONFIG_HZ;
        cpu_system_counter = cpu_system_counter * 1000000 / CONFIG_HZ;
  
        ps->cpu_user_counter = (unsigned long) cpu_user_counter;
        ps->cpu_system_counter = (unsigned long) cpu_system_counter;
 +      ps->vmem_size = (unsigned long) vmem_size;
        ps->vmem_rss = (unsigned long) vmem_rss;
 +      ps->stack_size = (unsigned long) stack_size;
  
        /* success */
        return (0);
  } /* int ps_read_process (...) */
 +
 +static char *ps_get_cmdline (pid_t pid, char *name, char *buf, size_t buf_len)
 +{
 +      char  *buf_ptr;
 +      size_t len;
 +
 +      char file[PATH_MAX];
 +      int  fd;
 +
 +      size_t n;
 +
 +      if ((pid < 1) || (NULL == buf) || (buf_len < 2))
 +              return NULL;
 +
 +      ssnprintf (file, sizeof (file), "/proc/%u/cmdline", pid);
 +
 +      fd = open (file, O_RDONLY);
 +      if (fd < 0) {
 +              char errbuf[4096];
 +              WARNING ("processes plugin: Failed to open `%s': %s.", file,
 +                              sstrerror (errno, errbuf, sizeof (errbuf)));
 +              return NULL;
 +      }
 +
 +      buf_ptr = buf;
 +      len     = buf_len;
 +
 +      n = 0;
 +
 +      while (42) {
 +              ssize_t status;
 +
 +              status = read (fd, (void *)buf_ptr, len);
 +
 +              if (status < 0) {
 +                      char errbuf[4096];
 +
 +                      if ((EAGAIN == errno) || (EINTR == errno))
 +                              continue;
 +
 +                      WARNING ("processes plugin: Failed to read from `%s': %s.", file,
 +                                      sstrerror (errno, errbuf, sizeof (errbuf)));
 +                      close (fd);
 +                      return NULL;
 +              }
 +
 +              n += status;
 +
 +              if (status == 0)
 +                      break;
 +
 +              buf_ptr += status;
 +              len     -= status;
 +
 +              if (len <= 0)
 +                      break;
 +      }
 +
 +      close (fd);
 +
 +      if (0 == n) {
 +              /* cmdline not available; e.g. kernel thread, zombie */
 +              if (NULL == name)
 +                      return NULL;
 +
 +              ssnprintf (buf, buf_len, "[%s]", name);
 +              return buf;
 +      }
 +
 +      assert (n <= buf_len);
 +
 +      if (n == buf_len)
 +              --n;
 +      buf[n] = '\0';
 +
 +      --n;
 +      /* remove trailing whitespace */
 +      while ((n > 0) && (isspace (buf[n]) || ('\0' == buf[n]))) {
 +              buf[n] = '\0';
 +              --n;
 +      }
 +
 +      /* arguments are separated by '\0' in /proc/<pid>/cmdline */
 +      while (n > 0) {
 +              if ('\0' == buf[n])
 +                      buf[n] = ' ';
 +              --n;
 +      }
 +      return buf;
 +} /* char *ps_get_cmdline (...) */
  #endif /* KERNEL_LINUX */
  
  #if HAVE_THREAD_INFO
@@@ -1196,8 -1061,6 +1196,8 @@@ static int ps_read (void
        DIR           *proc;
        int            pid;
  
 +      char cmdline[ARG_MAX];
 +
        int        status;
        procstat_t ps;
        procstat_entry_t pse;
                pse.id       = pid;
                pse.age      = 0;
  
 -              pse.num_proc = ps.num_proc;
 -              pse.num_lwp  = ps.num_lwp;
 -              pse.vmem_rss = ps.vmem_rss;
 +              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.stack_size = ps.stack_size;
  
                pse.vmem_minflt = 0;
                pse.vmem_minflt_counter = ps.vmem_minflt_counter;
                        case 'W': paging++;   break;
                }
  
 -              /* FIXME: cmdline should be here instead of NULL */
 -              ps_list_add (ps.name, NULL, &pse);
 +              ps_list_add (ps.name,
 +                              ps_get_cmdline (pid, ps.name, cmdline, sizeof (cmdline)),
 +                              &pse);
        }
  
        closedir (proc);
                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.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;