Merge branch 'ls/sensors'
authorFlorian Forster <octo@leeloo.lan.home.verplant.org>
Fri, 22 Dec 2006 09:38:07 +0000 (10:38 +0100)
committerFlorian Forster <octo@leeloo.lan.home.verplant.org>
Fri, 22 Dec 2006 09:38:07 +0000 (10:38 +0100)
ChangeLog
configure.in
debian/changelog
src/collectd.c
src/collectd.conf.pod
src/collectd.pod
src/email.c
src/network.c
src/processes.c

index 27836d7..2615eaf 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -22,6 +22,11 @@ pending, Version 3.11.0
          plugin, including `extended naming', collection of voltage values
          and the possibility to ignore certain values.
 
+2006-12-21, Version 3.10.4
+       * Max Kellermann has identified a bug in the server routine: When
+         opening a socket fails the daemon will (re)try opening the socket in
+         an endless loop, ultimately leading to a `EMFILE' error.
+
 2006-11-04, Version 3.10.3
        * Lubos Stanek has identified a bug in the ntpd-plugin: When the
          ntpd's reply was sent in more than one packet, the buffer size was
index 69ac2cf..27c2978 100644 (file)
@@ -1,5 +1,5 @@
 dnl Process this file with autoconf to produce a configure script.
-AC_INIT(collectd, 3.10.3)
+AC_INIT(collectd, 3.10.4)
 AC_CONFIG_SRCDIR(src/collectd.c)
 AC_CONFIG_HEADERS(src/config.h)
 AM_INIT_AUTOMAKE(dist-bzip2)
index 3bd5e05..c187e48 100644 (file)
@@ -1,3 +1,9 @@
+collectd (3.10.4-0octo1) unstable; urgency=low
+
+  * New upstream release.
+
+ -- Florian Forster <octo@leeloo.home.verplant.org>  Thu, 21 Dec 2006 20:36:37 +0100
+
 collectd (3.10.3-0octo1) unstable; urgency=low
 
   * New upstream release.
index a1e15bf..a93cc28 100644 (file)
@@ -223,16 +223,27 @@ static int start_client (void)
 #if HAVE_LIBRRD
 static int start_server (void)
 {
-       /* FIXME use stack here! */
        char *host;
        char *type;
        char *instance;
        char *values;
 
-       while (loop == 0)
+       int  error_counter = 0;
+       int  status;
+
+       while ((loop == 0) && (error_counter < 3))
        {
-               if (network_receive (&host, &type, &instance, &values) == 0)
-                       plugin_write (host, type, instance, values);
+               status = network_receive (&host, &type, &instance, &values);
+
+               if (status != 0)
+               {
+                       if (status < 0)
+                               error_counter++;
+                       continue;
+               }
+               error_counter = 0;
+
+               plugin_write (host, type, instance, values);
 
                if (host     != NULL) free (host);     host     = NULL;
                if (type     != NULL) free (type);     type     = NULL;
index e7ebaf9..aa4799a 100644 (file)
@@ -208,7 +208,8 @@ Ignore packets that originate from this address.
 
 =item B<SocketGroup> I<Group>
 
-Change the group of the UNIX-socket after it has been created.
+If running as root change the group of the UNIX-socket after it has been 
+created. Defaults to B<collectd>.
 
 =item B<SocketPerms> I<Permissions>
 
@@ -218,7 +219,7 @@ L<chmod(1)>. Defaults to B<0770>.
 
 =item B<MaxConns> I<Number>
 
-Sets the maximum number of connections that can be handeled in parallel. Since
+Sets the maximum number of connections that can be handled in parallel. Since
 this many threads will be started immediately setting this to a very high
 value will waste valuable resources. Defaults to B<5> and will be forced to be
 at most B<16384> to prevent typos and dumb mistakes.
index 4919f55..f5ed782 100644 (file)
@@ -188,6 +188,27 @@ not exist make sure B<cpufreqd> (L<http://cpufreqd.sourceforge.net/>) or a
 similar tool is installed and an "cpu governor" (that's kernel module) is
 loaded.
 
+=head2 email
+
+This plugin collects data indirectly by providing a UNIX socket that external
+programs can connect to. A simple line based protocol is used to communicate
+with the plugin:
+
+E-Mail type (e.g. "ham", "spam", "virus", ...) and size (bytes):
+
+  e:<type>:<size>
+
+Spam score:
+
+  s:<value>
+
+Successful spam checks (e.g. "BAYES_99", "SUBJECT_DRUG_GAP_C", ...):
+
+  c:<type1>[,<type2>,...]
+
+Each line is limited to 256 characters (including the newline character). 
+Longer lines will be ignored.
+
 =head2 mysql
 
 Requires B<mysqlclient> to be installed. It connects to the database when
@@ -334,6 +355,14 @@ The DS'es depend on the module creating the RRD files:
   DS:wcount:COUNTER:HEARTBEAT:0:U
   DS:wbytes:COUNTER:HEARTBEAT:0:U
 
+=item E-Mail count (F<email/email-I<E<lt>typeE<gt>>.rrd>)
+
+  DS:count:GAUGE:HEARTBEAT:0:U
+
+=item E-Mail size (F<email/email_size-I<E<lt>typeE<gt>>.rrd>)
+
+  DS:size:GAUGE:HEARTBEAT:0:U
+
 =item HDD Temperature (F<hddtemp-I<E<lt>majorE<gt>>-I<E<lt>minorE<gt>>.rrd>)
 
   DS:value:GAUGE:HEARTBEAT:U:U
@@ -446,6 +475,14 @@ The DS'es depend on the module creating the RRD files:
   DS:incoming:COUNTER:HEARTBEAT:0:U
   DS:outgoing:COUNTER:HEARTBEAT:0:U
 
+=item Spam score (F<email/spam_score.rrd>)
+
+  DS:score:GAUGE:HEARTBEAT:0:U
+
+=item Spam checks (F<email/spam_check-I<E<lt>typeE<gt>>.rrd>)
+
+  DS:hits:GAUGE:HEARTBEAT:0:U
+
 =item Swap usage (F<swap.rrd>)
 
   DS:used:GAUGE:HEARTBEAT:0:1099511627776
index 377a6b1..64b82e4 100644 (file)
@@ -84,6 +84,9 @@
 #define MAX_CONNS 5
 #define MAX_CONNS_LIMIT 16384
 
+#define log_err(...) syslog (LOG_ERR, MODULE_NAME": "__VA_ARGS__)
+#define log_warn(...) syslog (LOG_WARNING, MODULE_NAME": "__VA_ARGS__)
+
 /*
  * Private data structures
  */
@@ -287,7 +290,7 @@ static void type_list_incr (type_list_t *list, char *name, int incr)
 
 /* Read a single character from the socket. If an error occurs or end-of-file
  * is reached return '\0'. */
-char read_char (conn_t *src)
+static char read_char (conn_t *src)
 {
        char ret = '\0';
 
@@ -297,7 +300,7 @@ char read_char (conn_t *src)
        FD_SET (src->socket, &fdset);
 
        if (-1 == select (src->socket + 1, &fdset, NULL, NULL, NULL)) {
-               syslog (LOG_ERR, "select() failed: %s", strerror (errno));
+               log_err ("select() failed: %s", strerror (errno));
                return '\0';
        }
 
@@ -309,7 +312,7 @@ char read_char (conn_t *src)
                errno = 0;
                if (0 > (len = read (src->socket, (void *)&ret, 1))) {
                        if (EINTR != errno) {
-                               syslog (LOG_ERR, "read() failed: %s", strerror (errno));
+                               log_err ("read() failed: %s", strerror (errno));
                                return '\0';
                        }
                }
@@ -318,7 +321,7 @@ char read_char (conn_t *src)
                        return '\0';
        } while (EINTR == errno);
        return ret;
-} /* char read_char (conn_t *) */
+} /* static char read_char (conn_t *) */
 
 /* Read a single line (terminated by '\n') from the the socket.
  *
@@ -331,7 +334,7 @@ char read_char (conn_t *src)
  * 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 ;-) */
-char *read_line (conn_t *src)
+static char *read_line (conn_t *src)
 {
        int i = 0;
 
@@ -358,7 +361,7 @@ char *read_line (conn_t *src)
                FD_SET (src->socket, &fdset);
 
                if (-1 == select (src->socket + 1, &fdset, NULL, NULL, NULL)) {
-                       syslog (LOG_ERR, "select() failed: %s", strerror (errno));
+                       log_err ("select() failed: %s", strerror (errno));
                        return NULL;
                }
 
@@ -370,7 +373,7 @@ char *read_line (conn_t *src)
                                                        (void *)(src->buffer + src->idx),
                                                        BUFSIZE - src->idx))) {
                                if (EINTR != errno) {
-                                       syslog (LOG_ERR, "read() failed: %s", strerror (errno));
+                                       log_err ("read() failed: %s", strerror (errno));
                                        return NULL;
                                }
                        }
@@ -403,7 +406,7 @@ char *read_line (conn_t *src)
        src->length    = i;
 
        return src->buffer;
-} /* char *read_line (conn_t *) */
+} /* static char *read_line (conn_t *) */
 
 static void *collect (void *arg)
 {
@@ -442,13 +445,13 @@ static void *collect (void *arg)
 
                        errno = 0;
                        if (-1 == fcntl (connection->socket, F_GETFL, &flags)) {
-                               syslog (LOG_ERR, "fcntl() failed: %s", strerror (errno));
+                               log_err ("fcntl() failed: %s", strerror (errno));
                                loop = 0;
                        }
 
                        errno = 0;
                        if (-1 == fcntl (connection->socket, F_SETFL, flags | O_NONBLOCK)) {
-                               syslog (LOG_ERR, "fcntl() failed: %s", strerror (errno));
+                               log_err ("fcntl() failed: %s", strerror (errno));
                                loop = 0;
                        }
                }
@@ -462,7 +465,7 @@ static void *collect (void *arg)
                        }
 
                        if (':' != line[1]) {
-                               syslog (LOG_ERR, "email: syntax error in line '%s'", line);
+                               log_err ("syntax error in line '%s'", line);
                                continue;
                        }
 
@@ -473,7 +476,7 @@ static void *collect (void *arg)
                                int  bytes = 0;
 
                                if (NULL == tmp) {
-                                       syslog (LOG_ERR, "email: syntax error in line '%s'", line);
+                                       log_err ("syntax error in line '%s'", line);
                                        continue;
                                }
 
@@ -505,7 +508,7 @@ static void *collect (void *arg)
                                } while (NULL != (type = strtok_r (NULL, ",", &ptr)));
                        }
                        else {
-                               syslog (LOG_ERR, "email: unknown type '%c'", line[0]);
+                               log_err ("unknown type '%c'", line[0]);
                        }
                } /* while (loop) */
 
@@ -522,7 +525,7 @@ static void *collect (void *arg)
 
        free (buffer);
        pthread_exit ((void *)0);
-} /* void *collect (void *) */
+} /* static void *collect (void *) */
 
 static void *open_connection (void *arg)
 {
@@ -532,7 +535,7 @@ static void *open_connection (void *arg)
        errno = 0;
        if (-1 == (connector_socket = socket (PF_UNIX, SOCK_STREAM, 0))) {
                disabled = 1;
-               syslog (LOG_ERR, "socket() failed: %s", strerror (errno));
+               log_err ("socket() failed: %s", strerror (errno));
                pthread_exit ((void *)1);
        }
 
@@ -547,14 +550,14 @@ static void *open_connection (void *arg)
                                offsetof (struct sockaddr_un, sun_path)
                                        + strlen(addr.sun_path))) {
                disabled = 1;
-               syslog (LOG_ERR, "bind() failed: %s", strerror (errno));
+               log_err ("bind() failed: %s", strerror (errno));
                pthread_exit ((void *)1);
        }
 
        errno = 0;
        if (-1 == listen (connector_socket, 5)) {
                disabled = 1;
-               syslog (LOG_ERR, "listen() failed: %s", strerror (errno));
+               log_err ("listen() failed: %s", strerror (errno));
                pthread_exit ((void *)1);
        }
 
@@ -565,20 +568,20 @@ static void *open_connection (void *arg)
                if (NULL != (grp = getgrnam (sock_group))) {
                        errno = 0;
                        if (0 != chown (SOCK_PATH, (uid_t)-1, grp->gr_gid)) {
-                               syslog (LOG_WARNING, "chown() failed: %s", strerror (errno));
+                               log_warn ("chown() failed: %s", strerror (errno));
                        }
                }
                else {
-                       syslog (LOG_WARNING, "getgrnam() failed: %s", strerror (errno));
+                       log_warn ("getgrnam() failed: %s", strerror (errno));
                }
        }
        else {
-               syslog (LOG_WARNING, "not running as root");
+               log_warn ("not running as root");
        }
 
        errno = 0;
        if (0 != chmod (SOCK_PATH, sock_perms)) {
-               syslog (LOG_WARNING, "chmod() failed: %s", strerror (errno));
+               log_warn ("chmod() failed: %s", strerror (errno));
        }
 
        { /* initialize collector threads */
@@ -604,8 +607,7 @@ static void *open_connection (void *arg)
 
                        if (0 != (err = pthread_create (&collectors[i]->thread, &ptattr,
                                                        collect, collectors[i]))) {
-                               syslog (LOG_ERR, "pthread_create() failed: %s",
-                                               strerror (err));
+                               log_err ("pthread_create() failed: %s", strerror (err));
                        }
                }
 
@@ -632,7 +634,7 @@ static void *open_connection (void *arg)
                        if (-1 == (remote = accept (connector_socket, NULL, NULL))) {
                                if (EINTR != errno) {
                                        disabled = 1;
-                                       syslog (LOG_ERR, "accept() failed: %s", strerror (errno));
+                                       log_err ("accept() failed: %s", strerror (errno));
                                        pthread_exit ((void *)1);
                                }
                        }
@@ -659,7 +661,7 @@ static void *open_connection (void *arg)
                pthread_cond_signal (&conn_available);
        }
        pthread_exit ((void *)0);
-} /* void *open_connection (void *) */
+} /* static void *open_connection (void *) */
 #endif /* EMAIL_HAVE_READ */
 
 static void email_init (void)
@@ -670,7 +672,7 @@ static void email_init (void)
        if (0 != (err = pthread_create (&connector, NULL,
                                open_connection, NULL))) {
                disabled = 1;
-               syslog (LOG_ERR, "pthread_create() failed: %s", strerror (err));
+               log_err ("pthread_create() failed: %s", strerror (err));
                return;
        }
 #endif /* EMAIL_HAVE_READ */
@@ -685,15 +687,15 @@ static void email_shutdown (void)
        if (disabled)
                return;
 
-       close (connector_socket);
        pthread_kill (connector, SIGTERM);
+       close (connector_socket);
 
        /* don't allow any more connections to be processed */
        pthread_mutex_lock (&conns_mutex);
 
        for (i = 0; i < max_conns; ++i) {
-               close (collectors[i]->socket);
                pthread_kill (collectors[i]->thread, SIGTERM);
+               close (collectors[i]->socket);
        }
 
        pthread_mutex_unlock (&conns_mutex);
@@ -754,9 +756,6 @@ static void type_submit (char *plugin, char *inst, int value)
        char buf[BUFSIZE] = "";
        int  len          = 0;
 
-       if (0 == value)
-               return;
-
        len = snprintf (buf, BUFSIZE, "%u:%i", (unsigned int)curtime, value);
        if ((len < 0) || (len >= BUFSIZE))
                return;
@@ -770,58 +769,123 @@ static void score_submit (double value)
        char buf[BUFSIZE] = "";
        int  len          = 0;
 
-       if (0.0 == value)
-               return;
-
        len = snprintf (buf, BUFSIZE, "%u:%.2f", (unsigned int)curtime, value);
        if ((len < 0) || (len >= BUFSIZE))
                return;
 
        plugin_submit ("email_spam_score", NULL, buf);
        return;
+} /* static void score_submit (double) */
+
+/* Copy list l1 to list l2. l2 may partly exist already, but it is assumed
+ * that neither the order nor the name of any element of either list is
+ * changed and no elements are deleted. The values of l1 are reset to zero
+ * after they have been copied to l2. */
+static void copy_type_list (type_list_t *l1, type_list_t *l2)
+{
+       type_t *ptr1;
+       type_t *ptr2;
+
+       type_t *last = NULL;
+
+       for (ptr1 = l1->head, ptr2 = l2->head; NULL != ptr1;
+                       ptr1 = ptr1->next, last = ptr2, ptr2 = ptr2->next) {
+               if (NULL == ptr2) {
+                       ptr2 = (type_t *)smalloc (sizeof (type_t));
+                       ptr2->name = NULL;
+                       ptr2->next = NULL;
+
+                       if (NULL == last) {
+                               l2->head = ptr2;
+                       }
+                       else {
+                               last->next = ptr2;
+                       }
+
+                       l2->tail = ptr2;
+               }
+
+               if (NULL == ptr2->name) {
+                       ptr2->name = sstrdup (ptr1->name);
+               }
+
+               ptr2->value = ptr1->value;
+               ptr1->value = 0;
+       }
+       return;
 }
 
 static void email_read (void)
 {
        type_t *ptr;
 
+       double sc;
+
+       static type_list_t *cnt;
+       static type_list_t *sz;
+       static type_list_t *chk;
+
        if (disabled)
                return;
 
-       pthread_mutex_lock (&count_mutex);
+       if (NULL == cnt) {
+               cnt = (type_list_t *)smalloc (sizeof (type_list_t));
+               cnt->head = NULL;
+       }
 
-       for (ptr = count.head; NULL != ptr; ptr = ptr->next) {
-               type_submit ("email_count", ptr->name, ptr->value);
-               ptr->value = 0;
+       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);
+
        pthread_mutex_unlock (&count_mutex);
 
+       for (ptr = cnt->head; NULL != ptr; ptr = ptr->next) {
+               type_submit ("email_count", ptr->name, ptr->value);
+       }
+
+       /* email size */
        pthread_mutex_lock (&size_mutex);
 
-       for (ptr = size.head; NULL != ptr; ptr = ptr->next) {
-               type_submit ("email_size", ptr->name, ptr->value);
-               ptr->value = 0;
-       }
+       copy_type_list (&size, sz);
 
        pthread_mutex_unlock (&size_mutex);
 
+       for (ptr = sz->head; NULL != ptr; ptr = ptr->next) {
+               type_submit ("email_size", ptr->name, ptr->value);
+       }
+
+       /* spam score */
        pthread_mutex_lock (&score_mutex);
 
-       score_submit (score);
+       sc = score;
        score = 0.0;
        score_count = 0;
 
        pthread_mutex_unlock (&score_mutex);
 
+       score_submit (sc);
+
+       /* spam checks */
        pthread_mutex_lock (&check_mutex);
 
-       for (ptr = check.head; NULL != ptr; ptr = ptr->next) {
-               type_submit ("email_spam_check", ptr->name, ptr->value);
-               ptr->value = 0;
-       }
+       copy_type_list (&check, chk);
 
        pthread_mutex_unlock (&check_mutex);
+
+       for (ptr = chk->head; NULL != ptr; ptr = ptr->next) {
+               type_submit ("email_spam_check", ptr->name, ptr->value);
+       }
        return;
 } /* static void read (void) */
 #else /* if !EMAIL_HAVE_READ */
index 22e911a..e9ba84b 100644 (file)
@@ -284,6 +284,7 @@ int network_create_socket (const char *node, const char *service)
                {
                        if (network_bind_socket (se, ai_ptr) != 0)
                        {
+                               close (se->fd);
                                free (se->addr);
                                free (se);
                                continue;
@@ -451,7 +452,7 @@ int network_receive (char **host, char **type, char **inst, char **value)
        {
                syslog (LOG_WARNING, "Invalid message from `%s'", *host);
                free (*host); *host = NULL;
-               return (-1);
+               return (1);
        }
 
        if ((*type = strdup (fields[0])) == NULL)
index ebf1381..c8f3016 100644 (file)
@@ -600,8 +600,7 @@ static int *ps_read_tasks (int pid)
 
        if ((dh = opendir (dirname)) == NULL)
        {
-               syslog (LOG_NOTICE, "processes plugin: Failed to open directory `%s'",
-                               dirname);
+               DBG ("Failed to open directory `%s'", dirname);
                return (NULL);
        }