Merge branch 'collectd-4.4'
[collectd.git] / src / qmail.c
1 /**
2  * collectd - src/qmail.c
3  * Copyright (C) 2008  Alessandro Iurlano
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; only version 2 of the License is applicable.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
17  *
18  * Author:
19  *   Alessandro Iurlano <alessandro.iurlano at gmail.com>
20  **/
21
22 #include "collectd.h"
23 #include "common.h"
24 #include "plugin.h"       
25
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29 #include <dirent.h>
30
31 #define DEFAULT_BASE_DIR "/var/qmail"
32
33 static char *qmail_base_dir;
34
35 static const char *config_keys[] =
36 {
37   "QmailDir"
38 };
39 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
40
41 static void qmail_submit (const char *plugin_instance, gauge_t value)
42 {
43   value_t values[1];
44   value_list_t vl = VALUE_LIST_INIT;
45
46   values[0].gauge = value;
47
48   vl.values = values;
49   vl.values_len = STATIC_ARRAY_SIZE (values);
50   vl.time = time (NULL);
51   sstrncpy (vl.host, hostname_g, sizeof (vl.host));
52   sstrncpy (vl.type, "gauge", sizeof (vl.type));
53   sstrncpy (vl.plugin, "qmail", sizeof (vl.plugin));
54   sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
55
56   plugin_dispatch_values (&vl);
57 } /* void qmail_submit */
58
59 static int count_files_in_subtree (const char *path, int depth)
60 {
61 #if NAME_MAX < 1024
62 # define DIRENT_BUFFER_SIZE (sizeof (struct dirent) + 1024 + 1)
63 #else
64 # define DIRENT_BUFFER_SIZE (sizeof (struct dirent) + NAME_MAX + 1)
65 #endif
66
67   DIR *dh;
68   struct dirent *de;
69   char dirent_buffer[DIRENT_BUFFER_SIZE];
70   int status;
71
72   char **subdirs;
73   size_t subdirs_num;
74
75   int count;
76   int i;
77
78   dh = opendir (path);
79   if (dh == NULL)
80   {
81     ERROR ("qmail plugin: opendir (%s) failed.", path);
82     return (-1);
83   }
84
85   subdirs = NULL;
86   subdirs_num = 0;
87
88   count = 0;
89   while (42)
90   {
91     char abs_path[PATH_MAX];
92     struct stat statbuf;
93
94     de = NULL;
95     status = readdir_r (dh, (struct dirent *) dirent_buffer, &de);
96     if (status != 0)
97     {
98       char errbuf[4096];
99       ERROR ("qmail plugin: readdir_r failed: %s",
100           sstrerror (errno, errbuf, sizeof (errbuf)));
101       closedir (dh);
102       return (-1);
103     }
104     else if (de == NULL)
105     {
106       /* end of directory */
107       break;
108     }
109
110     if (de->d_name[0] == '.')
111       continue;
112
113     ssnprintf (abs_path, sizeof (abs_path), "%s/%s", path, de->d_name);
114
115     status = lstat (abs_path, &statbuf);
116     if (status != 0)
117     {
118       ERROR ("qmail plugin: stat (%s) failed.", abs_path);
119       continue;
120     }
121
122     if (S_ISREG (statbuf.st_mode))
123     {
124       count++;
125     }
126     else if (S_ISDIR (statbuf.st_mode))
127     {
128       char **temp;
129
130       temp = (char **) realloc (subdirs, sizeof (char *) * (subdirs_num + 1));
131       if (temp == NULL)
132       {
133         ERROR ("qmail plugin: realloc failed.");
134         continue;
135       }
136       subdirs = temp;
137
138       subdirs[subdirs_num] = strdup (abs_path);
139       if (subdirs[subdirs_num] == NULL)
140       {
141         ERROR ("qmail plugin: strdup failed.");
142         continue;
143       }
144       subdirs_num++;
145     }
146   }
147
148   closedir (dh);
149   dh = NULL;
150
151   if (depth > 0)
152   {
153     for (i = 0; i < subdirs_num; i++)
154     {
155       status = count_files_in_subtree (subdirs[i], depth - 1);
156       if (status > 0)
157         count += status;
158     }
159   }
160
161   for (i = 0; i < subdirs_num; i++)
162   {
163     sfree (subdirs[i]);
164   }
165   sfree (subdirs);
166
167   return (count);
168 } /* int count_files_in_subtree */
169
170 static int read_queue_length (const char *queue_name, const char *path)
171 {
172   int64_t num_files;
173
174   num_files = count_files_in_subtree (path, /* depth = */ 1);
175   if (num_files < 0)
176   {
177     ERROR ("qmail plugin: Counting files in `%s' failed.", path);
178     return (-1);
179   }
180
181   qmail_submit (queue_name, (gauge_t) num_files);
182   return (0);
183 } /* int read_queue_length */
184
185 static int queue_len_read (void)
186 {
187   char path[4096];
188   int success;
189   int status;
190
191   success = 0;
192   
193   ssnprintf (path, sizeof (path), "%s/queue/mess",
194       (qmail_base_dir != NULL)
195       ? qmail_base_dir
196       : DEFAULT_BASE_DIR);
197
198   status = read_queue_length ("messages", path);
199   if (status == 0)
200     success++;
201
202   ssnprintf (path, sizeof (path), "%s/queue/todo",
203       (qmail_base_dir != NULL)
204       ? qmail_base_dir
205       : DEFAULT_BASE_DIR);
206
207   status = read_queue_length ("todo", path);
208   if (status == 0)
209     success++;
210
211   if (success > 0)
212     return 0;
213   return (-1);
214 } /* int queue_len_read */
215
216 static int qmail_config (const char *key, const char *val)
217 {
218   if (strcasecmp ("QmailDir", key) == 0)
219   {
220     size_t qmail_base_dir_len;
221
222     sfree (qmail_base_dir);
223     qmail_base_dir = strdup(val);
224     if (qmail_base_dir == NULL)
225     {
226       ERROR ("qmail plugin: strdup failed.");
227       return (1);
228     }
229
230     qmail_base_dir_len = strlen (qmail_base_dir);
231     while ((qmail_base_dir_len > 0)
232         && (qmail_base_dir[qmail_base_dir_len - 1] == '/'))
233     {
234       qmail_base_dir[qmail_base_dir_len - 1] = 0;
235       qmail_base_dir_len--;
236     }
237
238     if (qmail_base_dir_len == 0)
239     {
240       ERROR ("qmail plugin: QmailDir is invalid.");
241       sfree (qmail_base_dir);
242       qmail_base_dir = NULL;
243       return (1);
244     }
245   }
246   else
247   {
248     return (-1);
249   }
250
251   return (0);
252 } /* int qmail_config */
253
254 void module_register (void)
255 {
256   plugin_register_config ("qmail", qmail_config,
257       config_keys, config_keys_num);
258   plugin_register_read ("qmail", queue_len_read);
259 } /* void module_register */
260
261 /*
262  * vim: set sw=2 sts=2 et :
263  */