ddfb9f207a391734e60d32831fe9bab85a1b4262
1 #include "collectd.h"
3 #include "multicast.h"
4 #include "plugin.h"
6 #include "ping.h"
8 static int loop = 0;
10 #ifdef HAVE_LIBKSTAT
11 kstat_ctl_t *kc;
12 #endif /* HAVE_LIBKSTAT */
14 #if COLLECT_PING
15 char *pinghosts[MAX_PINGHOSTS];
16 int num_pinghosts = 0;
17 #endif
19 /*
20 * exported variables
21 */
22 time_t curtime;
24 #ifdef HAVE_LIBRRD
25 int operating_mode;
26 #endif
28 void sigIntHandler (int signal)
29 {
30 loop++;
31 }
33 int change_basedir (char *dir)
34 {
35 int dirlen = strlen (dir);
37 while ((dirlen > 0) && (dir[dirlen - 1] == '/'))
38 dir[--dirlen] = '\0';
40 if (dirlen <= 0)
41 return (-1);
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 }
65 return (0);
66 }
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 }
90 return;
91 }
92 #endif /* HAVE_LIBKSTAT */
94 void exit_usage (char *name)
95 {
96 printf ("Usage: %s [OPTIONS]\n\n"
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 }
122 int start_client (void)
123 {
124 int sleepingtime;
126 #ifdef HAVE_LIBKSTAT
127 kc = NULL;
128 update_kstat ();
129 #endif
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 }
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
145 plugin_init_all ();
147 while (loop == 0)
148 {
149 curtime = time (NULL);
150 #ifdef HAVE_LIBKSTAT
151 update_kstat ();
152 #endif
153 plugin_read_all ();
155 sleepingtime = 10;
156 while (sleepingtime != 0)
157 {
158 if (loop != 0)
159 break;
160 sleepingtime = sleep (sleepingtime);
161 }
162 }
164 return (0);
165 }
167 #ifdef HAVE_LIBRRD
168 int start_server (void)
169 {
170 char *host;
171 char *type;
172 char *instance;
173 char *values;
175 while (loop == 0)
176 {
177 if (multicast_receive (&host, &type, &instance, &values) == 0)
178 plugin_write (host, type, instance, values);
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 }
186 return (0);
187 }
188 #endif /* HAVE_LIBRRD */
190 int pidfile_create (void)
191 {
192 FILE *fh;
194 if ((fh = fopen (PIDFILE, "w")) == NULL)
195 {
196 syslog (LOG_ERR, "fopen (pidfile): %s", strerror (errno));
197 return (1);
198 }
200 fprintf (fh, "%d\n", getpid());
201 fclose(fh);
203 return (0);
204 }
206 int pidfile_remove (void)
207 {
208 return (unlink (PIDFILE));
209 }
211 int main (int argc, char **argv)
212 {
213 struct sigaction sigIntAction, sigChldAction;
214 #if COLLECT_DAEMON
215 pid_t pid;
216 #endif
218 char *plugindir = NULL;
219 char *basedir = DATADIR;
221 int daemonize = 1;
223 #ifdef HAVE_LIBRRD
224 operating_mode = MODE_LOCAL;
225 #endif
227 /*
228 * open syslog
229 */
230 openlog (PACKAGE, LOG_CONS | LOG_PID, LOG_DAEMON);
232 /*
233 * read options
234 */
235 while (1)
236 {
237 int c;
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 );
248 if (c == -1)
249 break;
251 switch (c)
252 {
253 #ifdef HAVE_LIBRRD
254 case 'c':
255 operating_mode = MODE_CLIENT;
256 break;
258 case 's':
259 operating_mode = MODE_SERVER;
260 break;
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;
284 case 'h':
285 default:
286 exit_usage (argv[0]);
287 }
289 }
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 }
301 if (change_basedir (basedir))
302 {
303 fprintf (stderr, "Error: Unable to change to directory `%s'.\n", basedir);
304 return (1);
305 }
307 /*
308 * install signal handlers
309 */
310 sigIntAction.sa_handler = sigIntHandler;
311 sigaction (SIGINT, &sigIntAction, NULL);
313 sigChldAction.sa_handler = SIG_IGN;
314 sigaction (SIGCHLD, &sigChldAction, NULL);
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 }
335 /* Detach from session */
336 setsid ();
338 /* Write pidfile */
339 if (pidfile_create ())
340 exit (2);
342 /* close standard descriptors */
343 close (2);
344 close (1);
345 close (0);
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 */
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 ();
375 /*
376 * close syslog
377 */
378 syslog (LOG_INFO, "Exiting normally");
379 closelog ();
381 if (daemonize)
382 pidfile_remove();
384 return (0);
385 }