ddfb9f207a391734e60d32831fe9bab85a1b4262
[collectd.git] / src / collectd.c
1 #include "collectd.h"
2
3 #include "multicast.h"
4 #include "plugin.h"
5
6 #include "ping.h"
7
8 static int loop = 0;
9
10 #ifdef HAVE_LIBKSTAT
11 kstat_ctl_t *kc;
12 #endif /* HAVE_LIBKSTAT */
13
14 #if COLLECT_PING
15 char *pinghosts[MAX_PINGHOSTS];
16 int   num_pinghosts = 0;
17 #endif
18
19 /*
20  * exported variables
21  */
22 time_t curtime;
23
24 #ifdef HAVE_LIBRRD
25 int operating_mode;
26 #endif
27
28 void sigIntHandler (int signal)
29 {
30         loop++;
31 }
32
33 int change_basedir (char *dir)
34 {
35         int dirlen = strlen (dir);
36         
37         while ((dirlen > 0) && (dir[dirlen - 1] == '/'))
38                 dir[--dirlen] = '\0';
39
40         if (dirlen <= 0)
41                 return (-1);
42
43         if (chdir (dir) == -1)
44         {
45                 if (errno == ENOENT)
46                 {
47                         if (mkdir (dir, 0755) == -1)
48                         {
49                                 syslog (LOG_ERR, "mkdir: %s", strerror (errno));
50                                 return (-1);
51                         }
52                         else if (chdir (dir) == -1)
53                         {
54                                 syslog (LOG_ERR, "chdir: %s", strerror (errno));
55                                 return (-1);
56                         }
57                 }
58                 else
59                 {
60                         syslog (LOG_ERR, "chdir: %s", strerror (errno));
61                         return (-1);
62                 }
63         }
64
65         return (0);
66 }
67
68 #ifdef HAVE_LIBKSTAT
69 void update_kstat (void)
70 {
71         if (kc == NULL)
72         {
73                 if ((kc = kstat_open ()) == NULL)
74                         syslog (LOG_ERR, "Unable to open kstat control structure");
75         }
76         else
77         {
78                 kid_t kid;
79                 kid = kstat_chain_update (kc);
80                 if (kid > 0)
81                 {
82                         syslog (LOG_INFO, "kstat chain has been updated");
83                         plugin_init_all ();
84                 }
85                 else if (kid < 0)
86                         syslog (LOG_ERR, "kstat chain update failed");
87                 /* else: everything works as expected */
88         }
89
90         return;
91 }
92 #endif /* HAVE_LIBKSTAT */
93
94 void exit_usage (char *name)
95 {
96         printf ("Usage: %s [OPTIONS]\n\n"
97                         
98                         "Available options:\n"
99                         "  General:\n"
100                         "    -d <dir>        Base directory to use.\n"
101                         "                    Default: %s\n"
102                         "    -P <dir>        Set the plugin-directory\n"
103                         "                    Default: %s\n"
104                         "    -f              Don't fork to the background\n"
105 #ifdef HAVE_LIBRRD
106                         "    -l              Start in local mode (no network)\n"
107                         "    -c              Start in client (sender) mode\n"
108                         "    -s              Start in server (listener) mode\n"
109 #endif /* HAVE_LIBRRD */
110 #if COLLECT_PING
111                         "  Ping:\n"
112                         "    -p <host>       Host to ping periodically, may be repeated to ping\n"
113                         "                    more than one host.\n"
114 #endif /* COLLECT_PING */
115                         "\n%s %s, http://verplant.org/collectd/\n"
116                         "by Florian octo Forster <octo@verplant.org>\n"
117                         "for contributions see `AUTHORS'\n",
118                         PACKAGE, DATADIR, PLUGINDIR, PACKAGE, VERSION);
119         exit (0);
120 }
121
122 int start_client (void)
123 {
124         int sleepingtime;
125
126 #ifdef HAVE_LIBKSTAT
127         kc = NULL;
128         update_kstat ();
129 #endif
130
131 #ifdef HAVE_LIBSTATGRAB
132         if (sg_init ())
133         {
134                 syslog (LOG_ERR, "sg_init: %s", sg_str_error (sg_get_error ()));
135                 return (-1);
136         }
137
138         if (sg_drop_privileges ())
139         {
140                 syslog (LOG_ERR, "sg_drop_privileges: %s", sg_str_error (sg_get_error ()));
141                 return (-1);
142         }
143 #endif
144
145         plugin_init_all ();
146
147         while (loop == 0)
148         {
149                 curtime = time (NULL);
150 #ifdef HAVE_LIBKSTAT
151                 update_kstat ();
152 #endif
153                 plugin_read_all ();
154
155                 sleepingtime = 10;
156                 while (sleepingtime != 0)
157                 {
158                         if (loop != 0)
159                                 break;
160                         sleepingtime = sleep (sleepingtime);
161                 }
162         }
163
164         return (0);
165 }
166
167 #ifdef HAVE_LIBRRD
168 int start_server (void)
169 {
170         char *host;
171         char *type;
172         char *instance;
173         char *values;
174
175         while (loop == 0)
176         {
177                 if (multicast_receive (&host, &type, &instance, &values) == 0)
178                         plugin_write (host, type, instance, values);
179
180                 if (host     != NULL) free (host);     host     = NULL;
181                 if (type     != NULL) free (type);     type     = NULL;
182                 if (instance != NULL) free (instance); instance = NULL;
183                 if (values   != NULL) free (values);   values   = NULL;
184         }
185         
186         return (0);
187 }
188 #endif /* HAVE_LIBRRD */
189
190 int pidfile_create (void)
191 {
192         FILE *fh;
193
194         if ((fh = fopen (PIDFILE, "w")) == NULL)
195         {
196                 syslog (LOG_ERR, "fopen (pidfile): %s", strerror (errno));
197                 return (1);
198         }
199
200         fprintf (fh, "%d\n", getpid());
201         fclose(fh);
202
203         return (0);
204 }
205
206 int pidfile_remove (void)
207 {
208       return (unlink (PIDFILE));
209 }
210
211 int main (int argc, char **argv)
212 {
213         struct sigaction sigIntAction, sigChldAction;
214 #if COLLECT_DAEMON
215         pid_t pid;
216 #endif
217
218         char *plugindir = NULL;
219         char *basedir = DATADIR;
220
221         int daemonize = 1;
222
223 #ifdef HAVE_LIBRRD
224         operating_mode = MODE_LOCAL;
225 #endif
226         
227         /*
228          * open syslog
229          */
230         openlog (PACKAGE, LOG_CONS | LOG_PID, LOG_DAEMON);
231
232         /*
233          * read options
234          */
235         while (1)
236         {
237                 int c;
238
239                 c = getopt (argc, argv, "d:fP:h"
240 #if HAVE_LIBRRD
241                                 "csl"
242 #endif /* HAVE_LIBRRD */
243 #if COLLECT_PING
244                                 "p:"
245 #endif /* COLLECT_PING */
246                 );
247
248                 if (c == -1)
249                         break;
250
251                 switch (c)
252                 {
253 #ifdef HAVE_LIBRRD
254                         case 'c':
255                                 operating_mode = MODE_CLIENT;
256                                 break;
257
258                         case 's':
259                                 operating_mode = MODE_SERVER;
260                                 break;
261
262                         case 'l':
263                                 operating_mode = MODE_LOCAL;
264                                 break;
265 #endif /* HAVE_LIBRRD */
266                         case 'd':
267                                 basedir = optarg;
268                                 break;
269                         case 'f':
270                                 daemonize = 0;
271                                 break;
272 #if COLLECT_PING
273                         case 'p':
274                                 if (num_pinghosts < MAX_PINGHOSTS)
275                                         pinghosts[num_pinghosts++] = optarg;
276                                 else
277                                         fprintf (stderr, "Maximum of %i ping hosts reached.\n", MAX_PINGHOSTS);
278                                 break;
279 #endif /* COLLECT_PING */
280                         case 'P':
281                                 plugindir = optarg;
282                                 break;
283
284                         case 'h':
285                         default:
286                                 exit_usage (argv[0]);
287                 }
288                                 
289         }
290
291         /*
292          * Load plugins and change to output directory
293          * Loading plugins is done first so relative paths work as expected..
294          */
295         if (plugin_load_all (plugindir) < 1)
296         {
297                 fprintf (stderr, "Error: No plugins found.\n");
298                 return (1);
299         }
300
301         if (change_basedir (basedir))
302         {
303                 fprintf (stderr, "Error: Unable to change to directory `%s'.\n", basedir);
304                 return (1);
305         }
306
307         /*
308          * install signal handlers
309          */
310         sigIntAction.sa_handler = sigIntHandler;
311         sigaction (SIGINT, &sigIntAction, NULL);
312
313         sigChldAction.sa_handler = SIG_IGN;
314         sigaction (SIGCHLD, &sigChldAction, NULL);
315
316         /*
317          * fork off child
318          */
319 #if COLLECT_DAEMON
320         if (daemonize)
321         {
322                 if ((pid = fork ()) == -1)
323                 {
324                         /* error */
325                         fprintf (stderr, "fork: %s", strerror (errno));
326                         return (1);
327                 }
328                 else if (pid != 0)
329                 {
330                         /* parent */
331                         /* printf ("Running (PID %i)\n", pid); */
332                         return (0);
333                 }
334
335                 /* Detach from session */
336                 setsid ();
337
338                 /* Write pidfile */
339                 if (pidfile_create ())
340                         exit (2);
341
342                 /* close standard descriptors */
343                 close (2);
344                 close (1);
345                 close (0);
346
347                 if (open ("/dev/null", O_RDWR) != 0)
348                 {
349                         syslog (LOG_ERR, "Error: Could not connect `STDIN' to `/dev/null'");
350                         return (1);
351                 }
352                 if (dup (0) != 1)
353                 {
354                         syslog (LOG_ERR, "Error: Could not connect `STDOUT' to `/dev/null'");
355                         return (1);
356                 }
357                 if (dup (0) != 2)
358                 {
359                         syslog (LOG_ERR, "Error: Could not connect `STDERR' to `/dev/null'");
360                         return (1);
361                 }
362         } /* if (daemonize) */
363 #endif /* COLLECT_DAEMON */
364
365         /*
366          * run the actual loops
367          */
368 #ifdef HAVE_LIBRRD
369         if (operating_mode == MODE_SERVER)
370                 start_server ();
371         else /* if (operating_mode == MODE_CLIENT || operating_mode == MODE_LOCAL) */
372 #endif
373                 start_client ();
374
375         /*
376          * close syslog
377          */
378         syslog (LOG_INFO, "Exiting normally");
379         closelog ();
380
381         if (daemonize)
382                 pidfile_remove();
383
384         return (0);
385 }