Merge branch 'collectd-4.4'
authorFlorian Forster <octo@huhu.verplant.org>
Wed, 30 Apr 2008 09:04:23 +0000 (11:04 +0200)
committerFlorian Forster <octo@huhu.verplant.org>
Wed, 30 Apr 2008 09:04:23 +0000 (11:04 +0200)
Conflicts:

src/collectd-perl.pod
src/email.c

1  2 
src/collectd-perl.pod
src/collectd.c
src/email.c
src/interface.c
src/load.c
src/memory.c
src/perl.c
src/swap.c

diff --combined src/collectd-perl.pod
@@@ -67,7 -67,7 +67,7 @@@ registered by the plugins. Any plugin b
  of these callback functions and initializing code which registers the
  functions with collectd. See the section "EXAMPLES" below for a really basic
  example. The following types of B<callback functions> are known to collectd
- (all of these are optional):
+ (all of them are optional):
  
  =over 4
  
@@@ -92,6 -92,12 +92,12 @@@ amount of time until it returns B<true
  This type of function is used to write the dispatched values. It is called
  once for each call to B<plugin_dispatch_values>.
  
+ =item flush functions
+ This type of function is used to flush internal caches of plugins. It is
+ usually triggered by the user only. Any plugin which caches data before
+ writing it to disk should provide this kind of callback function.
  =item log functions
  
  This type of function is used to pass messages of plugins or the daemon itself
@@@ -160,7 -166,6 +166,7 @@@ layout looks like this
      time   => time (),
      host   => $hostname_g,
      plugin => 'myplugin',
 +    type   => 'myplugin',
      plugin_instance => '',
      type_instance   => ''
    }
@@@ -204,6 -209,8 +210,8 @@@ I<type> can be one of
  
  =item TYPE_WRITE
  
+ =item TYPE_FLUSH
  =item TYPE_LOG
  
  =item TYPE_NOTIF
@@@ -246,13 -253,18 +254,18 @@@ arguments
  
  =item TYPE_SHUTDOWN
  
- No arguments are passed
+ No arguments are passed.
  
  =item TYPE_WRITE
  
  The arguments passed are I<type>, I<data-set>, and I<value-list>. I<type> is a
  string. For the layout of I<data-set> and I<value-list> see above.
  
+ =item TYPE_FLUSH
+ The only argument passed is I<timeout> which indicates that only data older
+ than I<timeout> seconds is to be flushed.
  =item TYPE_LOG
  
  The arguments are I<log-level> and I<message>. The log level is small for
@@@ -273,19 -285,29 +286,35 @@@ data type
  Removes a callback or data-set from collectd's internal list of
  functionsE<nbsp>/ datasets.
  
 -=item B<plugin_dispatch_values> (I<type>, I<value-list>)
 +=item B<plugin_dispatch_values> (I<value-list>)
  
 -Submits a I<value-list> of type I<type> to the daemon. If the data-set I<type>
 +Submits a I<value-list> to the daemon. If the data-set identified by
 +I<value-list>->{I<type>}
  is found (and the number of values matches the number of data-sources) then the
  type, data-set and value-list is passed to all write-callbacks that are
  registered with the daemon.
  
 +B<Note>: Prior to version 4.4 of collectd, the data-set type used to be passed
 +as the first argument to B<plugin_register>. This syntax is still supported
 +for backwards compatibility but has been deprecated and will be removed in
 +some future version of collectd.
 +
+ =item B<plugin_flush> ([B<timeout> => I<timeout>,] [B<plugins> => I<...>])
+ Flush one or more plugins. I<timeout> is passed on to the registered
+ flush-callbacks. If omitted, C<-1> is used. If the I<plugins> argument has
+ been specified, only named plugins will be flushed. The argument's value may
+ either be a string or a reference to an array of strings.
+ =item B<plugin_flush_one> (I<timeout>, I<plugin>)
+ This is identical to using "plugin_flush (timeout =E<gt> I<timeout>, plugins
+ =E<gt> I<plugin>".
+ =item B<plugin_flush_all> (I<timeout>)
+ This is identical to using "plugin_flush (timeout =E<gt> I<timeout>)".
  =item B<plugin_dispatch_notification> (I<notification>)
  
  Submits a I<notification> to the daemon which will then pass it to all
@@@ -339,6 -361,12 +368,12 @@@ available (B<:all> will export all of t
  
  =item B<plugin_dispatch_values> ()
  
+ =item B<plugin_flush> ()
+ =item B<plugin_flush_one> ()
+ =item B<plugin_flush_all> ()
  =item B<plugin_dispatch_notification> ()
  
  =item B<plugin_log> ()
  
  =item B<TYPE_WRITE>
  
+ =item B<TYPE_FLUSH>
  =item B<TYPE_SHUTDOWN>
  
  =item B<TYPE_LOG>
@@@ -511,6 -541,18 +548,18 @@@ instead
  
  =back
  
+ =head1 KNOWN BUGS
+ =over 4
+ =item
+ Currently, it is not possible to flush a single Perl plugin only. You can
+ either flush all Perl plugins or none at all and you have to use C<perl> as
+ plugin name when doing so.
+ =back
  =head1 SEE ALSO
  
  L<collectd(1)>,
diff --combined src/collectd.c
  #include "plugin.h"
  #include "configfile.h"
  
+ #if HAVE_STATGRAB_H
+ # include <statgrab.h>
+ #endif
  /*
   * Global variables
   */
@@@ -86,7 -90,8 +90,7 @@@ static int init_hostname (void
        str = global_option_get ("Hostname");
        if (str != NULL)
        {
 -              strncpy (hostname_g, str, sizeof (hostname_g));
 -              hostname_g[sizeof (hostname_g) - 1] = '\0';
 +              sstrncpy (hostname_g, str, sizeof (hostname_g));
                return (0);
        }
  
                if (ai_ptr->ai_canonname == NULL)
                        continue;
  
 -              strncpy (hostname_g, ai_ptr->ai_canonname, sizeof (hostname_g));
 -              hostname_g[sizeof (hostname_g) - 1] = '\0';
 +              sstrncpy (hostname_g, ai_ptr->ai_canonname, sizeof (hostname_g));
                break;
        }
  
diff --combined src/email.c
@@@ -1,6 -1,6 +1,6 @@@
  /**
   * collectd - src/email.c
-  * Copyright (C) 2006,2007  Sebastian Harl
+  * Copyright (C) 2006-2008  Sebastian Harl
   *
   * 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
  #     include <grp.h>
  #endif /* HAVE_GRP_H */
  
- #define MODULE_NAME "email"
- /* 256 bytes ought to be enough for anybody ;-) */
- #define BUFSIZE 256
  #define SOCK_PATH LOCALSTATEDIR"/run/"PACKAGE_NAME"-email"
  #define MAX_CONNS 5
  #define MAX_CONNS_LIMIT 16384
  
- #define log_err(...) ERROR (MODULE_NAME": "__VA_ARGS__)
- #define log_warn(...) WARNING (MODULE_NAME": "__VA_ARGS__)
+ #define log_debug(...) DEBUG ("email: "__VA_ARGS__)
+ #define log_err(...) ERROR ("email: "__VA_ARGS__)
+ #define log_warn(...) WARNING ("email: "__VA_ARGS__)
  
  /*
   * Private data structures
@@@ -90,19 -86,15 +86,15 @@@ typedef struct collector 
        pthread_t thread;
  
        /* socket descriptor of the current/last connection */
-       int socket;
+       FILE *socket;
  } collector_t;
  
  /* linked list of pending connections */
  typedef struct conn {
        /* socket to read data from */
-       int socket;
-       /* buffer to read data to */
-       char *buffer;
-       int  idx; /* current write position in buffer */
-       int  length; /* length of the current line, i.e. index of '\0' */
+       FILE *socket;
  
+       /* linked list of connections */
        struct conn *next;
  } conn_t;
  
@@@ -125,8 -117,8 +117,8 @@@ static const char *config_keys[] 
  static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
  
  /* socket configuration */
- static char *sock_file  = SOCK_PATH;
- static char *sock_group = COLLECTD_GRP_NAME;
+ static char *sock_file  = NULL;
+ static char *sock_group = NULL;
  static int  sock_perms  = S_IRWXU | S_IRWXG;
  static int  max_conns   = MAX_CONNS;
  
@@@ -154,17 -146,20 +146,20 @@@ static pthread_mutex_t available_mutex 
  static int available_collectors;
  
  static pthread_mutex_t count_mutex = PTHREAD_MUTEX_INITIALIZER;
- static type_list_t count;
+ static type_list_t list_count;
+ static type_list_t list_count_copy;
  
  static pthread_mutex_t size_mutex = PTHREAD_MUTEX_INITIALIZER;
- static type_list_t size;
+ static type_list_t list_size;
+ static type_list_t list_size_copy;
  
  static pthread_mutex_t score_mutex = PTHREAD_MUTEX_INITIALIZER;
  static double score;
  static int score_count;
  
  static pthread_mutex_t check_mutex = PTHREAD_MUTEX_INITIALIZER;
- static type_list_t check;
+ static type_list_t list_check;
+ static type_list_t list_check_copy;
  
  /*
   * Private functions
  static int email_config (const char *key, const char *value)
  {
        if (0 == strcasecmp (key, "SocketFile")) {
+               if (NULL != sock_file)
+                       free (sock_file);
                sock_file = sstrdup (value);
        }
        else if (0 == strcasecmp (key, "SocketGroup")) {
+               if (NULL != sock_group)
+                       free (sock_group);
                sock_group = sstrdup (value);
        }
        else if (0 == strcasecmp (key, "SocketPerms")) {
@@@ -241,139 -240,10 +240,10 @@@ static void type_list_incr (type_list_
        return;
  } /* static void type_list_incr (type_list_t *, char *) */
  
- /* Read a single character from the socket. If an error occurs or end-of-file
-  * is reached return '\0'. */
- static char read_char (conn_t *src)
- {
-       char ret = '\0';
-       fd_set fdset;
-       FD_ZERO (&fdset);
-       FD_SET (src->socket, &fdset);
-       if (-1 == select (src->socket + 1, &fdset, NULL, NULL, NULL)) {
-               char errbuf[1024];
-               log_err ("select() failed: %s",
-                               sstrerror (errno, errbuf, sizeof (errbuf)));
-               return '\0';
-       }
-       assert (FD_ISSET (src->socket, &fdset));
-       do {
-               ssize_t len = 0;
-               errno = 0;
-               if (0 > (len = read (src->socket, (void *)&ret, 1))) {
-                       if (EINTR != errno) {
-                               char errbuf[1024];
-                               log_err ("read() failed: %s",
-                                               sstrerror (errno, errbuf, sizeof (errbuf)));
-                               return '\0';
-                       }
-               }
-               if (0 == len)
-                       return '\0';
-       } while (EINTR == errno);
-       return ret;
- } /* static char read_char (conn_t *) */
- /* Read a single line (terminated by '\n') from the the socket.
-  *
-  * The return value is zero terminated and does not contain any newline
-  * characters.
-  *
-  * If an error occurs or end-of-file is reached return NULL.
-  *
-  * IMPORTANT NOTE: If there is no newline character found in BUFSIZE
-  * characters of the input stream, the line will will be ignored! By
-  * definition we should not get any longer input lines, thus this is
-  * acceptable in this case ;-) */
- static char *read_line (conn_t *src)
- {
-       int i = 0;
-       assert ((BUFSIZE >= src->idx) && (src->idx >= 0));
-       assert ((src->idx > src->length) || (src->length == 0));
-       if (src->length > 0) { /* remove old line */
-               src->idx -= (src->length + 1);
-               memmove (src->buffer, src->buffer + src->length + 1, src->idx);
-               src->length = 0;
-       }
-       for (i = 0; i < src->idx; ++i) {
-               if ('\n' == src->buffer[i])
-                       break;
-       }
-       if (i == src->idx) {
-               fd_set fdset;
-               ssize_t len = 0;
-               FD_ZERO (&fdset);
-               FD_SET (src->socket, &fdset);
-               if (-1 == select (src->socket + 1, &fdset, NULL, NULL, NULL)) {
-                       char errbuf[1024];
-                       log_err ("select() failed: %s",
-                                       sstrerror (errno, errbuf, sizeof (errbuf)));
-                       return NULL;
-               }
-               assert (FD_ISSET (src->socket, &fdset));
-               do {
-                       errno = 0;
-                       if (0 > (len = read (src->socket,
-                                                       (void *)(src->buffer + src->idx),
-                                                       BUFSIZE - src->idx))) {
-                               if (EINTR != errno) {
-                                       char errbuf[1024];
-                                       log_err ("read() failed: %s",
-                                                       sstrerror (errno, errbuf, sizeof (errbuf)));
-                                       return NULL;
-                               }
-                       }
-                       if (0 == len)
-                               return NULL;
-               } while (EINTR == errno);
-               src->idx += len;
-               for (i = src->idx - len; i < src->idx; ++i) {
-                       if ('\n' == src->buffer[i])
-                               break;
-               }
-               if (i == src->idx) {
-                       src->length = 0;
-                       if (BUFSIZE == src->idx) { /* no space left in buffer */
-                               while ('\n' != read_char (src))
-                                       /* ignore complete line */;
-                               src->idx = 0;
-                       }
-                       return read_line (src);
-               }
-       }
-       src->buffer[i] = '\0';
-       src->length    = i;
-       return src->buffer;
- } /* static char *read_line (conn_t *) */
  static void *collect (void *arg)
  {
        collector_t *this = (collector_t *)arg;
-       char *buffer = (char *)smalloc (BUFSIZE);
+       pthread_t    self = pthread_self ();
  
        while (1) {
                int loop = 1;
                        conns.tail = NULL;
                }
  
-               this->socket = connection->socket;
                pthread_mutex_unlock (&conns_mutex);
  
-               connection->buffer = buffer;
-               connection->idx    = 0;
-               connection->length = 0;
+               /* make the socket available to the global
+                * thread and connection management */
+               this->socket = connection->socket;
  
-               { /* put the socket in non-blocking mode */
-                       int flags = 0;
+               log_debug ("[thread #%5lu] handling connection on fd #%i",
+                               self, fileno (this->socket));
  
-                       errno = 0;
-                       if (-1 == fcntl (connection->socket, F_GETFL, &flags)) {
-                               char errbuf[1024];
-                               log_err ("fcntl() failed: %s",
-                                               sstrerror (errno, errbuf, sizeof (errbuf)));
-                               loop = 0;
-                       }
+               while (loop) {
+                       /* 256 bytes ought to be enough for anybody ;-) */
+                       char line[256 + 1]; /* line + '\0' */
+                       int  len = 0;
  
                        errno = 0;
-                       if (-1 == fcntl (connection->socket, F_SETFL, flags | O_NONBLOCK)) {
-                               char errbuf[1024];
-                               log_err ("fcntl() failed: %s",
-                                               sstrerror (errno, errbuf, sizeof (errbuf)));
+                       if (NULL == fgets (line, sizeof (line), this->socket)) {
                                loop = 0;
+                               if (0 != errno) {
+                                       char errbuf[1024];
+                                       log_err ("[thread #%5lu] reading from socket (fd #%i) "
+                                                       "failed: %s", self, fileno (this->socket),
+                                                       sstrerror (errno, errbuf, sizeof (errbuf)));
+                               }
+                               break;
                        }
-               }
  
-               while (loop) {
-                       char *line = read_line (connection);
+                       len = strlen (line);
+                       if (('\n' != line[len - 1]) && ('\r' != line[len - 1])) {
+                               log_warn ("[thread #%5lu] line too long (> %i characters): "
+                                               "'%s' (truncated)", self, sizeof (line) - 1, line);
  
-                       if (NULL == line) {
-                               loop = 0;
-                               break;
+                               while (NULL != fgets (line, sizeof (line), this->socket))
+                                       if (('\n' == line[len - 1]) || ('\r' == line[len - 1]))
+                                               break;
+                               continue;
                        }
  
+                       line[len - 1] = '\0';
+                       log_debug ("[thread #%5lu] line = '%s'", self, line);
                        if (':' != line[1]) {
-                               log_err ("syntax error in line '%s'", line);
+                               log_err ("[thread #%5lu] syntax error in line '%s'",
+                                               self, line);
                                continue;
                        }
  
                                int  bytes = 0;
  
                                if (NULL == tmp) {
-                                       log_err ("syntax error in line '%s'", line);
+                                       log_err ("[thread #%5lu] syntax error in line '%s'",
+                                                       self, line);
                                        continue;
                                }
  
                                bytes = atoi (tmp);
  
                                pthread_mutex_lock (&count_mutex);
-                               type_list_incr (&count, type, 1);
+                               type_list_incr (&list_count, type, 1);
                                pthread_mutex_unlock (&count_mutex);
  
                                if (bytes > 0) {
                                        pthread_mutex_lock (&size_mutex);
-                                       type_list_incr (&size, type, bytes);
+                                       type_list_incr (&list_size, type, bytes);
                                        pthread_mutex_unlock (&size_mutex);
                                }
                        }
  
                                do {
                                        pthread_mutex_lock (&check_mutex);
-                                       type_list_incr (&check, type, 1);
+                                       type_list_incr (&list_check, type, 1);
                                        pthread_mutex_unlock (&check_mutex);
                                } while (NULL != (type = strtok_r (NULL, ",", &ptr)));
                        }
                        else {
-                               log_err ("unknown type '%c'", line[0]);
+                               log_err ("[thread #%5lu] unknown type '%c'", self, line[0]);
                        }
                } /* while (loop) */
  
-               close (connection->socket);
+               log_debug ("[thread #%5lu] shutting down connection on fd #%i",
+                               pthread_self (), fileno (this->socket));
+               fclose (connection->socket);
                free (connection);
  
-               this->socket = -1;
+               this->socket = NULL;
  
                pthread_mutex_lock (&available_mutex);
                ++available_collectors;
                pthread_cond_signal (&collector_available);
        } /* while (1) */
  
-       free (buffer);
        pthread_exit ((void *)0);
  } /* static void *collect (void *) */
  
@@@ -499,6 -379,9 +379,9 @@@ static void *open_connection (void *arg
  {
        struct sockaddr_un addr;
  
+       char *path  = (NULL == sock_file) ? SOCK_PATH : sock_file;
+       char *group = (NULL == sock_group) ? COLLECTD_GRP_NAME : sock_group;
        /* create UNIX socket */
        errno = 0;
        if (-1 == (connector_socket = socket (PF_UNIX, SOCK_STREAM, 0))) {
  
        addr.sun_family = AF_UNIX;
  
-       sstrncpy (addr.sun_path, sock_file, sizeof (addr.sun_path));
 -      strncpy (addr.sun_path, path, (size_t)(UNIX_PATH_MAX - 1));
 -      addr.sun_path[UNIX_PATH_MAX - 1] = '\0';
++      sstrncpy (addr.sun_path, path, (size_t)(UNIX_PATH_MAX - 1));
        unlink (addr.sun_path);
  
        errno = 0;
                                        + strlen(addr.sun_path))) {
                char errbuf[1024];
                disabled = 1;
-               connector_socket = -1; /* TODO: close? */
+               close (connector_socket);
+               connector_socket = -1;
                log_err ("bind() failed: %s",
                                sstrerror (errno, errbuf, sizeof (errbuf)));
                pthread_exit ((void *)1);
        if (-1 == listen (connector_socket, 5)) {
                char errbuf[1024];
                disabled = 1;
-               connector_socket = -1; /* TODO: close? */
+               close (connector_socket);
+               connector_socket = -1;
                log_err ("listen() failed: %s",
                                sstrerror (errno, errbuf, sizeof (errbuf)));
                pthread_exit ((void *)1);
        }
  
-       if ((uid_t) 0 == geteuid ())
        {
                struct group sg;
                struct group *grp;
                int status;
  
                grp = NULL;
-               status = getgrnam_r (sock_group, &sg, grbuf, sizeof (grbuf), &grp);
+               status = getgrnam_r (group, &sg, grbuf, sizeof (grbuf), &grp);
                if (status != 0)
                {
                        char errbuf[1024];
-                       log_warn ("getgrnam_r (%s) failed: %s", sock_group,
+                       log_warn ("getgrnam_r (%s) failed: %s", group,
                                        sstrerror (errno, errbuf, sizeof (errbuf)));
                }
                else if (grp == NULL)
                {
-                       log_warn ("No such group: `%s'", sock_group);
+                       log_warn ("No such group: `%s'", group);
                }
                else
                {
-                       status = chown (sock_file, (uid_t) -1, grp->gr_gid);
+                       status = chown (path, (uid_t) -1, grp->gr_gid);
                        if (status != 0)
                        {
                                char errbuf[1024];
                                log_warn ("chown (%s, -1, %i) failed: %s",
-                                               sock_file, (int) grp->gr_gid,
+                                               path, (int) grp->gr_gid,
                                                sstrerror (errno, errbuf, sizeof (errbuf)));
                        }
                }
        }
-       else /* geteuid != 0 */
-       {
-               log_warn ("not running as root");
-       }
  
        errno = 0;
-       if (0 != chmod (sock_file, sock_perms)) {
+       if (0 != chmod (path, sock_perms)) {
                char errbuf[1024];
                log_warn ("chmod() failed: %s",
                                sstrerror (errno, errbuf, sizeof (errbuf)));
  
                for (i = 0; i < max_conns; ++i) {
                        collectors[i] = (collector_t *)smalloc (sizeof (collector_t));
-                       collectors[i]->socket = -1;
+                       collectors[i]->socket = NULL;
  
                        if (0 != (err = pthread_create (&collectors[i]->thread, &ptattr,
                                                        collect, collectors[i]))) {
                                if (EINTR != errno) {
                                        char errbuf[1024];
                                        disabled = 1;
-                                       connector_socket = -1; /* TODO: close? */
+                                       close (connector_socket);
+                                       connector_socket = -1;
                                        log_err ("accept() failed: %s",
                                                        sstrerror (errno, errbuf, sizeof (errbuf)));
                                        pthread_exit ((void *)1);
  
                connection = (conn_t *)smalloc (sizeof (conn_t));
  
-               connection->socket = remote;
+               connection->socket = fdopen (remote, "r");
                connection->next   = NULL;
  
+               if (NULL == connection->socket) {
+                       close (remote);
+                       continue;
+               }
                pthread_mutex_lock (&conns_mutex);
  
                if (NULL == conns.head) {
@@@ -682,6 -569,8 +568,8 @@@ static int email_init (void
  
  static int email_shutdown (void)
  {
+       type_t *ptr = NULL;
        int i = 0;
  
        if (connector != ((pthread_t) 0)) {
        /* don't allow any more connections to be processed */
        pthread_mutex_lock (&conns_mutex);
  
+       available_collectors = 0;
        if (collectors != NULL) {
                for (i = 0; i < max_conns; ++i) {
                        if (collectors[i] == NULL)
                                collectors[i]->thread = (pthread_t) 0;
                        }
  
-                       if (collectors[i]->socket >= 0) {
-                               close (collectors[i]->socket);
-                               collectors[i]->socket = -1;
+                       if (collectors[i]->socket != NULL) {
+                               fclose (collectors[i]->socket);
+                               collectors[i]->socket = NULL;
                        }
+                       sfree (collectors[i]);
                }
+               sfree (collectors);
        } /* if (collectors != NULL) */
  
        pthread_mutex_unlock (&conns_mutex);
  
-       unlink (sock_file);
-       errno = 0;
+       for (ptr = list_count.head; NULL != ptr; ptr = ptr->next) {
+               free (ptr->name);
+               free (ptr);
+       }
+       for (ptr = list_count_copy.head; NULL != ptr; ptr = ptr->next) {
+               free (ptr->name);
+               free (ptr);
+       }
+       for (ptr = list_size.head; NULL != ptr; ptr = ptr->next) {
+               free (ptr->name);
+               free (ptr);
+       }
  
+       for (ptr = list_size_copy.head; NULL != ptr; ptr = ptr->next) {
+               free (ptr->name);
+               free (ptr);
+       }
+       for (ptr = list_check.head; NULL != ptr; ptr = ptr->next) {
+               free (ptr->name);
+               free (ptr);
+       }
+       for (ptr = list_check_copy.head; NULL != ptr; ptr = ptr->next) {
+               free (ptr->name);
+               free (ptr);
+       }
+       unlink ((NULL == sock_file) ? SOCK_PATH : sock_file);
+       sfree (sock_file);
+       sfree (sock_group);
        return (0);
  } /* static void email_shutdown (void) */
  
@@@ -734,10 -659,9 +658,10 @@@ static void email_submit (const char *t
        vl.time = time (NULL);
        strcpy (vl.host, hostname_g);
        strcpy (vl.plugin, "email");
 -      strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 +      sstrncpy (vl.type, type, sizeof (vl.type));
 +      sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
  
 -      plugin_dispatch_values (type, &vl);
 +      plugin_dispatch_values (&vl);
  } /* void email_submit */
  
  /* Copy list l1 to list l2. l2 may partly exist already, but it is assumed
@@@ -785,47 -709,28 +709,28 @@@ static int email_read (void
        double score_old;
        int score_count_old;
  
-       static type_list_t *cnt;
-       static type_list_t *sz;
-       static type_list_t *chk;
        if (disabled)
                return (-1);
  
-       if (NULL == cnt) {
-               cnt = (type_list_t *)smalloc (sizeof (type_list_t));
-               cnt->head = NULL;
-       }
-       if (NULL == sz) {
-               sz = (type_list_t *)smalloc (sizeof (type_list_t));
-               sz->head = NULL;
-       }
-       if (NULL == chk) {
-               chk = (type_list_t *)smalloc (sizeof (type_list_t));
-               chk->head = NULL;
-       }
        /* email count */
        pthread_mutex_lock (&count_mutex);
  
-       copy_type_list (&count, cnt);
+       copy_type_list (&list_count, &list_count_copy);
  
        pthread_mutex_unlock (&count_mutex);
  
-       for (ptr = cnt->head; NULL != ptr; ptr = ptr->next) {
+       for (ptr = list_count_copy.head; NULL != ptr; ptr = ptr->next) {
                email_submit ("email_count", ptr->name, ptr->value);
        }
  
        /* email size */
        pthread_mutex_lock (&size_mutex);
  
-       copy_type_list (&size, sz);
+       copy_type_list (&list_size, &list_size_copy);
  
        pthread_mutex_unlock (&size_mutex);
  
-       for (ptr = sz->head; NULL != ptr; ptr = ptr->next) {
+       for (ptr = list_size_copy.head; NULL != ptr; ptr = ptr->next) {
                email_submit ("email_size", ptr->name, ptr->value);
        }
  
        /* spam checks */
        pthread_mutex_lock (&check_mutex);
  
-       copy_type_list (&check, chk);
+       copy_type_list (&list_check, &list_check_copy);
  
        pthread_mutex_unlock (&check_mutex);
  
-       for (ptr = chk->head; NULL != ptr; ptr = ptr->next)
+       for (ptr = list_check_copy.head; NULL != ptr; ptr = ptr->next)
                email_submit ("spam_check", ptr->name, ptr->value);
  
        return (0);
diff --combined src/interface.c
  #  include <ifaddrs.h>
  #endif
  
+ #if HAVE_STATGRAB_H
+ # include <statgrab.h>
+ #endif
  /*
   * Various people have reported problems with `getifaddrs' and varying versions
   * of `glibc'. That's why it's disabled by default. Since more statistics are
@@@ -195,10 -199,9 +199,10 @@@ static void if_submit (const char *dev
        vl.time = time (NULL);
        strcpy (vl.host, hostname_g);
        strcpy (vl.plugin, "interface");
 -      strncpy (vl.type_instance, dev, sizeof (vl.type_instance));
 +      sstrncpy (vl.type, type, sizeof (vl.type));
 +      sstrncpy (vl.type_instance, dev, sizeof (vl.type_instance));
  
 -      plugin_dispatch_values (type, &vl);
 +      plugin_dispatch_values (&vl);
  } /* void if_submit */
  
  static int interface_read (void)
diff --combined src/load.c
  #include <sys/loadavg.h>
  #endif
  
+ #if HAVE_STATGRAB_H
+ # include <statgrab.h>
+ #endif
  #ifdef HAVE_GETLOADAVG
  #if !defined(LOADAVG_1MIN) || !defined(LOADAVG_5MIN) || !defined(LOADAVG_15MIN)
  #define LOADAVG_1MIN  0
@@@ -49,9 -53,8 +53,9 @@@ static void load_submit (gauge_t snum, 
        vl.time = time (NULL);
        strcpy (vl.host, hostname_g);
        strcpy (vl.plugin, "load");
 +      strcpy (vl.type, "load");
  
 -      plugin_dispatch_values ("load", &vl);
 +      plugin_dispatch_values (&vl);
  }
  
  static int load_read (void)
        load_submit (snum, mnum, lnum);
  /* #endif KERNEL_LINUX */
  
- #elif defined(HAVE_LIBSTATGRAB)
+ #elif HAVE_LIBSTATGRAB
        gauge_t snum, mnum, lnum;
        sg_load_stats *ls;
  
diff --combined src/memory.c
  # include <mach/vm_statistics.h>
  #endif
  
+ #if HAVE_STATGRAB_H
+ # include <statgrab.h>
+ #endif
  /* vm_statistics_data_t */
  #if HAVE_HOST_STATISTICS
  static mach_port_t port_host;
@@@ -62,6 -66,10 +66,10 @@@ static int pagesize
  static kstat_t *ksp;
  /* #endif HAVE_LIBKSTAT */
  
+ #elif HAVE_LIBSTATGRAB
+ /* no global variables */
+ /* endif HAVE_LIBSTATGRAB */
  #else
  # error "No applicable input method."
  #endif
@@@ -103,10 -111,10 +111,10 @@@ static void memory_submit (const char *
        vl.time = time (NULL);
        strcpy (vl.host, hostname_g);
        strcpy (vl.plugin, "memory");
 -      strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 -      vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
 +      strcpy (vl.type, "memory");
 +      sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
  
 -      plugin_dispatch_values ("memory", &vl);
 +      plugin_dispatch_values (&vl);
  }
  
  static int memory_read (void)
        memory_submit ("cache",    sysctl_vals[6]);
  /* #endif HAVE_SYSCTLBYNAME */
  
- #elif defined(KERNEL_LINUX)
+ #elif KERNEL_LINUX
        FILE *fh;
        char buffer[1024];
        
                memory_submit ("cached",   mem_cached);
                memory_submit ("free",     mem_free);
        }
- /* #endif defined(KERNEL_LINUX) */
+ /* #endif KERNEL_LINUX */
  
- #elif defined(HAVE_LIBKSTAT)
+ #elif HAVE_LIBKSTAT
        long long mem_used;
        long long mem_free;
        long long mem_lock;
        memory_submit ("used",   mem_used);
        memory_submit ("free",   mem_free);
        memory_submit ("locked", mem_lock);
- /* #endif defined(HAVE_LIBKSTAT) */
+ /* #endif HAVE_LIBKSTAT */
  
- #elif defined(HAVE_LIBSTATGRAB)
+ #elif HAVE_LIBSTATGRAB
        sg_mem_stats *ios;
  
        if ((ios = sg_get_mem_stats ()) != NULL)
diff --combined src/perl.c
@@@ -61,8 -61,9 +61,9 @@@
  #define PLUGIN_SHUTDOWN 3
  #define PLUGIN_LOG      4
  #define PLUGIN_NOTIF    5
+ #define PLUGIN_FLUSH    6
  
- #define PLUGIN_TYPES    6
+ #define PLUGIN_TYPES    7
  
  #define PLUGIN_DATASET  255
  
@@@ -77,6 -78,8 +78,8 @@@ void boot_DynaLoader (PerlInterpreter *
  static XS (Collectd_plugin_register_ds);
  static XS (Collectd_plugin_unregister_ds);
  static XS (Collectd_plugin_dispatch_values);
+ static XS (Collectd_plugin_flush_one);
+ static XS (Collectd_plugin_flush_all);
  static XS (Collectd_plugin_dispatch_notification);
  static XS (Collectd_plugin_log);
  static XS (Collectd_call_by_name);
@@@ -130,6 -133,8 +133,8 @@@ static struct 
        { "Collectd::plugin_register_data_set",   Collectd_plugin_register_ds },
        { "Collectd::plugin_unregister_data_set", Collectd_plugin_unregister_ds },
        { "Collectd::plugin_dispatch_values",     Collectd_plugin_dispatch_values },
+       { "Collectd::plugin_flush_one",           Collectd_plugin_flush_one },
+       { "Collectd::plugin_flush_all",           Collectd_plugin_flush_all },
        { "Collectd::plugin_dispatch_notification",
                Collectd_plugin_dispatch_notification },
        { "Collectd::plugin_log",                 Collectd_plugin_log },
@@@ -148,6 -153,7 +153,7 @@@ struct 
        { "Collectd::TYPE_SHUTDOWN",   PLUGIN_SHUTDOWN },
        { "Collectd::TYPE_LOG",        PLUGIN_LOG },
        { "Collectd::TYPE_NOTIF",      PLUGIN_NOTIF },
+       { "Collectd::TYPE_FLUSH",      PLUGIN_FLUSH },
        { "Collectd::TYPE_DATASET",    PLUGIN_DATASET },
        { "Collectd::DS_TYPE_COUNTER", DS_TYPE_COUNTER },
        { "Collectd::DS_TYPE_GAUGE",   DS_TYPE_GAUGE },
@@@ -204,7 -210,8 +210,7 @@@ static int hv2data_source (pTHX_ HV *ha
                return -1;
  
        if (NULL != (tmp = hv_fetch (hash, "name", 4, 0))) {
 -              strncpy (ds->name, SvPV_nolen (*tmp), DATA_MAX_NAME_LEN);
 -              ds->name[DATA_MAX_NAME_LEN - 1] = '\0';
 +              sstrncpy (ds->name, SvPV_nolen (*tmp), sizeof (ds->name));
        }
        else {
                log_err ("hv2data_source: No DS name given.");
@@@ -366,10 -373,6 +372,10 @@@ static int value_list2hv (pTHX_ value_l
                                newSVpv (vl->plugin_instance, 0), 0))
                        return -1;
  
 +      if ('\0' != vl->type[0])
 +              if (NULL == hv_store (hash, "type", 4, newSVpv (vl->type, 0), 0))
 +                      return -1;
 +
        if ('\0' != vl->type_instance[0])
                if (NULL == hv_store (hash, "type_instance", 13,
                                newSVpv (vl->type_instance, 0), 0))
@@@ -421,11 -424,12 +427,11 @@@ static int notification2hv (pTHX_ notif
  static char *get_module_name (char *buf, size_t buf_len, const char *module) {
        int status = 0;
        if (base_name[0] == '\0')
 -              status = snprintf (buf, buf_len, "%s", module);
 +              status = ssnprintf (buf, buf_len, "%s", module);
        else
 -              status = snprintf (buf, buf_len, "%s::%s", base_name, module);
 +              status = ssnprintf (buf, buf_len, "%s::%s", base_name, module);
        if ((status < 0) || ((unsigned int)status >= buf_len))
                return (NULL);
 -      buf[buf_len - 1] = '\0';
        return (buf);
  } /* char *get_module_name */
  
@@@ -471,7 -475,8 +477,7 @@@ static int pplugin_register_data_set (p
                                ds[i].name, ds[i].type, ds[i].min, ds[i].max);
        }
  
 -      strncpy (set->type, name, DATA_MAX_NAME_LEN);
 -      set->type[DATA_MAX_NAME_LEN - 1] = '\0';
 +      sstrncpy (set->type, name, sizeof (set->type));
  
        set->ds_num = len + 1;
        set->ds = ds;
@@@ -506,7 -511,7 +512,7 @@@ static int pplugin_unregister_data_set 
   *   type_instance   => $tinstance,
   * }
   */
 -static int pplugin_dispatch_values (pTHX_ char *name, HV *values)
 +static int pplugin_dispatch_values (pTHX_ HV *values)
  {
        value_list_t list = VALUE_LIST_INIT;
        value_t      *val = NULL;
  
        int ret = 0;
  
 -      if ((NULL == name) || (NULL == values))
 +      if (NULL == values)
 +              return -1;
 +
 +      if (NULL == (tmp = hv_fetch (values, "type", 4, 0))) {
 +              log_err ("pplugin_dispatch_values: No type given.");
                return -1;
 +      }
 +
 +      sstrncpy (list.type, SvPV_nolen (*tmp), sizeof (list.type));
  
        if ((NULL == (tmp = hv_fetch (values, "values", 6, 0)))
                        || (! (SvROK (*tmp) && (SVt_PVAV == SvTYPE (SvRV (*tmp)))))) {
  
                val = (value_t *)smalloc (len * sizeof (value_t));
  
 -              list.values_len = av2value (aTHX_ name, (AV *)SvRV (*tmp), val, len);
 +              list.values_len = av2value (aTHX_ list.type, (AV *)SvRV (*tmp),
 +                              val, len);
                list.values = val;
  
                if (-1 == list.values_len) {
        }
  
        if (NULL != (tmp = hv_fetch (values, "host", 4, 0))) {
 -              strncpy (list.host, SvPV_nolen (*tmp), DATA_MAX_NAME_LEN);
 -              list.host[DATA_MAX_NAME_LEN - 1] = '\0';
 +              sstrncpy (list.host, SvPV_nolen (*tmp), sizeof (list.host));
        }
        else {
                strcpy (list.host, hostname_g);
        }
  
 -      if (NULL != (tmp = hv_fetch (values, "plugin", 6, 0))) {
 -              strncpy (list.plugin, SvPV_nolen (*tmp), DATA_MAX_NAME_LEN);
 -              list.plugin[DATA_MAX_NAME_LEN - 1] = '\0';
 -      }
 +      if (NULL != (tmp = hv_fetch (values, "plugin", 6, 0)))
 +              sstrncpy (list.plugin, SvPV_nolen (*tmp), sizeof (list.plugin));
  
 -      if (NULL != (tmp = hv_fetch (values, "plugin_instance", 15, 0))) {
 -              strncpy (list.plugin_instance, SvPV_nolen (*tmp), DATA_MAX_NAME_LEN);
 -              list.plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
 -      }
 +      if (NULL != (tmp = hv_fetch (values, "plugin_instance", 15, 0)))
 +              sstrncpy (list.plugin_instance, SvPV_nolen (*tmp),
 +                              sizeof (list.plugin_instance));
  
 -      if (NULL != (tmp = hv_fetch (values, "type_instance", 13, 0))) {
 -              strncpy (list.type_instance, SvPV_nolen (*tmp), DATA_MAX_NAME_LEN);
 -              list.type_instance[DATA_MAX_NAME_LEN - 1] = '\0';
 -      }
 +      if (NULL != (tmp = hv_fetch (values, "type_instance", 13, 0)))
 +              sstrncpy (list.type_instance, SvPV_nolen (*tmp),
 +                              sizeof (list.type_instance));
  
 -      ret = plugin_dispatch_values (name, &list);
 +      ret = plugin_dispatch_values (&list);
  
        sfree (val);
        return ret;
@@@ -618,25 -620,31 +624,25 @@@ static int pplugin_dispatch_notificatio
                n.time = time (NULL);
  
        if (NULL != (tmp = hv_fetch (notif, "message", 7, 0)))
 -              strncpy (n.message, SvPV_nolen (*tmp), sizeof (n.message));
 -      n.message[sizeof (n.message) - 1] = '\0';
 +              sstrncpy (n.message, SvPV_nolen (*tmp), sizeof (n.message));
  
        if (NULL != (tmp = hv_fetch (notif, "host", 4, 0)))
 -              strncpy (n.host, SvPV_nolen (*tmp), sizeof (n.host));
 +              sstrncpy (n.host, SvPV_nolen (*tmp), sizeof (n.host));
        else
 -              strncpy (n.host, hostname_g, sizeof (n.host));
 -      n.host[sizeof (n.host) - 1] = '\0';
 +              sstrncpy (n.host, hostname_g, sizeof (n.host));
  
        if (NULL != (tmp = hv_fetch (notif, "plugin", 6, 0)))
 -              strncpy (n.plugin, SvPV_nolen (*tmp), sizeof (n.plugin));
 -      n.plugin[sizeof (n.plugin) - 1] = '\0';
 +              sstrncpy (n.plugin, SvPV_nolen (*tmp), sizeof (n.plugin));
  
        if (NULL != (tmp = hv_fetch (notif, "plugin_instance", 15, 0)))
 -              strncpy (n.plugin_instance, SvPV_nolen (*tmp),
 +              sstrncpy (n.plugin_instance, SvPV_nolen (*tmp),
                                sizeof (n.plugin_instance));
 -      n.plugin_instance[sizeof (n.plugin_instance) - 1] = '\0';
  
        if (NULL != (tmp = hv_fetch (notif, "type", 4, 0)))
 -              strncpy (n.type, SvPV_nolen (*tmp), sizeof (n.type));
 -      n.type[sizeof (n.type) - 1] = '\0';
 +              sstrncpy (n.type, SvPV_nolen (*tmp), sizeof (n.type));
  
        if (NULL != (tmp = hv_fetch (notif, "type_instance", 13, 0)))
 -              strncpy (n.type_instance, SvPV_nolen (*tmp), sizeof (n.type_instance));
 -      n.type_instance[sizeof (n.type_instance) - 1] = '\0';
 +              sstrncpy (n.type_instance, SvPV_nolen (*tmp), sizeof (n.type_instance));
        return plugin_dispatch_notification (&n);
  } /* static int pplugin_dispatch_notification (HV *) */
  
@@@ -685,7 -693,6 +691,7 @@@ static int pplugin_call_all (pTHX_ int 
                 *   time   => $time,
                 *   host   => $hostname,
                 *   plugin => $plugin,
 +               *   type   => $type,
                 *   plugin_instance => $instance,
                 *   type_instance   => $type_instance
                 * };
  
                XPUSHs (sv_2mortal (newRV_noinc ((SV *)notif)));
        }
+       else if (PLUGIN_FLUSH == type) {
+               /*
+                * $_[0] = $timeout;
+                */
+               XPUSHs (sv_2mortal (newSViv (va_arg (ap, int))));
+       }
  
        PUTBACK;
  
@@@ -855,43 -868,33 +867,43 @@@ static XS (Collectd_plugin_unregister_d
   */
  static XS (Collectd_plugin_dispatch_values)
  {
 -      SV *values = NULL;
 +      SV *values     = NULL;
 +      int values_idx = 0;
  
        int ret = 0;
  
        dXSARGS;
  
 -      if (2 != items) {
 -              log_err ("Usage: Collectd::plugin_dispatch_values(name, values)");
 +      if (2 == items) {
 +              log_warn ("Collectd::plugin_dispatch_values with two arguments "
 +                              "is deprecated - pass the type through values->{type}.");
 +              values_idx = 1;
 +      }
 +      else if (1 != items) {
 +              log_err ("Usage: Collectd::plugin_dispatch_values(values)");
                XSRETURN_EMPTY;
        }
  
 -      log_debug ("Collectd::plugin_dispatch_values: "
 -                      "name = \"%s\", values=\"%s\"",
 -                      SvPV_nolen (ST (0)), SvPV_nolen (ST (1)));
 +      log_debug ("Collectd::plugin_dispatch_values: values=\"%s\"",
 +                      SvPV_nolen (ST (values_idx)));
  
 -      values = ST (1);
 +      values = ST (values_idx);
  
        if (! (SvROK (values) && (SVt_PVHV == SvTYPE (SvRV (values))))) {
                log_err ("Collectd::plugin_dispatch_values: Invalid values.");
                XSRETURN_EMPTY;
        }
  
 -      if ((NULL == ST (0)) || (NULL == values))
 +      if (((2 == items) && (NULL == ST (0))) || (NULL == values))
                XSRETURN_EMPTY;
  
 -      ret = pplugin_dispatch_values (aTHX_ SvPV_nolen (ST (0)),
 -                      (HV *)SvRV (values));
 +      if ((2 == items) && (NULL == hv_store ((HV *)SvRV (values), "type", 4,
 +                      newSVsv (ST (0)), 0))) {
 +              log_err ("Collectd::plugin_dispatch_values: Could not store type.");
 +              XSRETURN_EMPTY;
 +      }
 +
 +      ret = pplugin_dispatch_values (aTHX_ (HV *)SvRV (values));
  
        if (0 == ret)
                XSRETURN_YES;
  } /* static XS (Collectd_plugin_dispatch_values) */
  
  /*
+  * Collectd::plugin_flush_one (timeout, name).
+  *
+  * timeout:
+  *   timeout to use when flushing the data
+  *
+  * name:
+  *   name of the plugin to flush
+  */
+ static XS (Collectd_plugin_flush_one)
+ {
+       dXSARGS;
+       if (2 != items) {
+               log_err ("Usage: Collectd::plugin_flush_one(timeout, name)");
+               XSRETURN_EMPTY;
+       }
+       log_debug ("Collectd::plugin_flush_one: timeout = %i, name = \"%s\"",
+                       (int)SvIV (ST (0)), SvPV_nolen (ST (1)));
+       if (0 == plugin_flush_one ((int)SvIV (ST (0)), SvPV_nolen (ST (1))))
+               XSRETURN_YES;
+       else
+               XSRETURN_EMPTY;
+ } /* static XS (Collectd_plugin_flush_one) */
+ /*
+  * Collectd::plugin_flush_all (timeout).
+  *
+  * timeout:
+  *   timeout to use when flushing the data
+  */
+ static XS (Collectd_plugin_flush_all)
+ {
+       dXSARGS;
+       if (1 != items) {
+               log_err ("Usage: Collectd::plugin_flush_all(timeout)");
+               XSRETURN_EMPTY;
+       }
+       log_debug ("Collectd::plugin_flush_all: timeout = %i", (int)SvIV (ST (0)));
+       plugin_flush_all ((int)SvIV (ST (0)));
+       XSRETURN_YES;
+ } /* static XS (Collectd_plugin_flush_all) */
+ /*
   * Collectd::plugin_dispatch_notification (notif).
   *
   * notif:
@@@ -1204,6 -1255,25 +1264,25 @@@ static int perl_notify (const notificat
        return pplugin_call_all (aTHX_ PLUGIN_NOTIF, notif);
  } /* static int perl_notify (const notification_t *) */
  
+ static int perl_flush (const int timeout)
+ {
+       dTHX;
+       if (NULL == perl_threads)
+               return 0;
+       if (NULL == aTHX) {
+               c_ithread_t *t = NULL;
+               pthread_mutex_lock (&perl_threads->mutex);
+               t = c_ithread_create (perl_threads->head->interp);
+               pthread_mutex_unlock (&perl_threads->mutex);
+               aTHX = t->interp;
+       }
+       return pplugin_call_all (aTHX_ PLUGIN_FLUSH, timeout);
+ } /* static int perl_flush (const int) */
  static int perl_shutdown (void)
  {
        c_ithread_t *t = NULL;
        plugin_unregister_init ("perl");
        plugin_unregister_read ("perl");
        plugin_unregister_write ("perl");
+       plugin_unregister_flush ("perl");
  
        ret = pplugin_call_all (aTHX_ PLUGIN_SHUTDOWN);
  
@@@ -1281,7 -1352,8 +1361,7 @@@ static int g_pv_get (pTHX_ SV *var, MAG
  static int g_pv_set (pTHX_ SV *var, MAGIC *mg)
  {
        char *pv = mg->mg_ptr;
 -      strncpy (pv, SvPV_nolen (var), DATA_MAX_NAME_LEN);
 -      pv[DATA_MAX_NAME_LEN - 1] = '\0';
 +      sstrncpy (pv, SvPV_nolen (var), DATA_MAX_NAME_LEN);
        return 0;
  } /* static int g_pv_set (pTHX_ SV *, MAGIC *) */
  
@@@ -1372,6 -1444,11 +1452,11 @@@ static int init_pi (int argc, char **ar
                exit (1);
        }
  
+ #ifdef __FreeBSD__
+       /* On FreeBSD, PERL_SYS_INIT3 expands to some expression which
+        * triggers a "value computed is not used" warning by gcc. */
+       (void)
+ #endif
        PERL_SYS_INIT3 (&argc, &argv, &environ);
  
        perl_threads = (c_ithread_list_t *)smalloc (sizeof (c_ithread_list_t));
        plugin_register_read ("perl", perl_read);
  
        plugin_register_write ("perl", perl_write);
+       plugin_register_flush ("perl", perl_flush);
        plugin_register_shutdown ("perl", perl_shutdown);
        return 0;
  } /* static int init_pi (const char **, const int) */
@@@ -1468,7 -1546,8 +1554,7 @@@ static int perl_config_basename (pTHX_ 
        value = ci->values[0].value.string;
  
        log_debug ("perl_config: Setting plugin basename to \"%s\"", value);
 -      strncpy (base_name, value, sizeof (base_name));
 -      base_name[sizeof (base_name) - 1] = '\0';
 +      sstrncpy (base_name, value, sizeof (base_name));
        return 0;
  } /* static int perl_config_basename (oconfig_item_it *) */
  
diff --combined src/swap.c
  #  include <kvm.h>
  #endif
  
+ #if HAVE_STATGRAB_H
+ # include <statgrab.h>
+ #endif
  #undef  MAX
  #define MAX(x,y) ((x) > (y) ? (x) : (y))
  
@@@ -122,10 -126,9 +126,10 @@@ static void swap_submit (const char *ty
        vl.time = time (NULL);
        strcpy (vl.host, hostname_g);
        strcpy (vl.plugin, "swap");
 -      strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 +      strcpy (vl.type, "swap");
 +      sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
  
 -      plugin_dispatch_values ("swap", &vl);
 +      plugin_dispatch_values (&vl);
  } /* void swap_submit */
  
  static int swap_read (void)