2 * collectd - src/collectdmon.c
3 * Copyright (C) 2007 Sebastian Harl
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.
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.
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
19 * Sebastian Harl <sh at tokkee.org>
39 #include <sys/resource.h>
41 #include <sys/types.h>
49 #ifndef COLLECTDMON_PIDFILE
50 # define COLLECTDMON_PIDFILE LOCALSTATEDIR"/run/collectdmon.pid"
51 #endif /* ! COLLECTDMON_PIDFILE */
54 # define WCOREDUMP(s) 0
55 #endif /* ! WCOREDUMP */
59 static char *pidfile = NULL;
60 static pid_t collectd_pid = 0;
62 static void exit_usage (char *name)
64 printf ("Usage: %s <options> [-- <collectd options>]\n"
66 "\nAvailable options:\n"
67 " -h Display this help and exit.\n"
68 " -c <path> Path to the collectd binary.\n"
69 " -P <file> PID-file.\n"
71 "\nFor <collectd options> see collectd.conf(5).\n"
73 "\n"PACKAGE" "VERSION", http://collectd.org/\n"
74 "by Florian octo Forster <octo@verplant.org>\n"
75 "for contributions see `AUTHORS'\n", name);
79 static int pidfile_create (void)
84 pidfile = COLLECTDMON_PIDFILE;
86 if (NULL == (file = fopen (pidfile, "w"))) {
87 syslog (LOG_ERR, "Error: couldn't open PID-file (%s) for writing: %s",
88 pidfile, strerror (errno));
92 fprintf (file, "%i\n", (int)getpid ());
95 } /* pidfile_create */
97 static int pidfile_delete (void)
99 assert (NULL != pidfile);
101 if (0 != unlink (pidfile)) {
102 syslog (LOG_ERR, "Error: couldn't delete PID-file (%s): %s",
103 pidfile, strerror (errno));
107 } /* pidfile_remove */
109 static int daemonize (void)
116 if (0 != chdir ("/")) {
117 fprintf (stderr, "Error: chdir() failed: %s\n", strerror (errno));
121 if (0 != getrlimit (RLIMIT_NOFILE, &rl)) {
122 fprintf (stderr, "Error: getrlimit() failed: %s\n", strerror (errno));
126 if (0 > (pid = fork ())) {
127 fprintf (stderr, "Error: fork() failed: %s\n", strerror (errno));
134 if (0 != pidfile_create ())
139 if (RLIM_INFINITY == rl.rlim_max)
142 for (i = 0; i < rl.rlim_max; ++i)
146 if (open ("/dev/null", O_RDWR) != 0) {
147 syslog (LOG_ERR, "Error: couldn't connect STDIN to /dev/null: %s",
154 syslog (LOG_ERR, "Error: couldn't connect STDOUT to /dev/null: %s",
161 syslog (LOG_ERR, "Error: couldn't connect STDERR to /dev/null: %s",
168 static int collectd_start (int argc, char **argv)
172 if (0 > (pid = fork ())) {
173 syslog (LOG_ERR, "Error: fork() failed: %s", strerror (errno));
181 execvp (argv[0], argv);
182 syslog (LOG_ERR, "Error: execvp(%s) failed: %s",
183 argv[0], strerror (errno));
185 } /* collectd_start */
187 static int collectd_stop (void)
189 if (0 == collectd_pid)
192 if (0 != kill (collectd_pid, SIGTERM)) {
193 syslog (LOG_ERR, "Error: kill() failed: %s", strerror (errno));
197 } /* collectd_stop */
199 static void sig_int_term_handler (int signo)
203 } /* sig_int_term_handler */
205 static void log_status (int status)
207 if (WIFEXITED (status)) {
208 syslog (LOG_INFO, "Info: collectd terminated with exit status %i",
209 WEXITSTATUS (status));
211 else if (WIFSIGNALED (status)) {
212 syslog (LOG_WARNING, "Warning: collectd was terminated by signal %i%s",
213 WTERMSIG (status), WCOREDUMP (status) ? " (core dumped)" : "");
218 static void check_respawn (void)
220 time_t t = time (NULL);
222 static time_t timestamp = 0;
223 static int counter = 0;
225 if ((t - 120) < timestamp)
233 unsigned int time_left = 300;
235 syslog (LOG_ERR, "Error: collectd is respawning too fast - "
236 "disabled for %i seconds", time_left);
238 while ((0 < (time_left = sleep (time_left))) && (0 == loop));
241 } /* check_respawn */
243 int main (int argc, char **argv)
245 int collectd_argc = 0;
246 char *collectd = NULL;
247 char **collectd_argv = NULL;
253 /* parse command line options */
255 int c = getopt (argc, argv, "hc:P:");
269 exit_usage (argv[0]);
273 for (i = optind; i < argc; ++i)
274 if (0 == strcmp (argv[i], "-f"))
277 /* i < argc => -f already present */
278 collectd_argc = 1 + argc - optind + ((i < argc) ? 0 : 1);
279 collectd_argv = (char **)calloc (collectd_argc + 1, sizeof (char *));
281 if (NULL == collectd_argv) {
282 fprintf (stderr, "Out of memory.");
286 collectd_argv[0] = (NULL == collectd) ? "collectd" : collectd;
289 collectd_argv[collectd_argc - 1] = "-f";
291 for (i = optind; i < argc; ++i)
292 collectd_argv[i - optind + 1] = argv[i];
294 collectd_argv[collectd_argc] = NULL;
296 openlog ("collectdmon", LOG_CONS | LOG_PID, LOG_DAEMON);
298 if (-1 == daemonize ())
301 sa.sa_handler = sig_int_term_handler;
303 sigemptyset (&sa.sa_mask);
305 if (0 != sigaction (SIGINT, &sa, NULL)) {
306 syslog (LOG_ERR, "Error: sigaction() failed: %s", strerror (errno));
310 if (0 != sigaction (SIGTERM, &sa, NULL)) {
311 syslog (LOG_ERR, "Error: sigaction() failed: %s", strerror (errno));
315 sigaddset (&sa.sa_mask, SIGCHLD);
316 if (0 != sigprocmask (SIG_BLOCK, &sa.sa_mask, NULL)) {
317 syslog (LOG_ERR, "Error: sigprocmask() failed: %s", strerror (errno));
324 if (0 != collectd_start (collectd_argc, collectd_argv)) {
325 syslog (LOG_ERR, "Error: failed to start collectd.");
329 assert (0 < collectd_pid);
330 while ((collectd_pid != waitpid (collectd_pid, &status, 0))
341 syslog (LOG_WARNING, "Warning: restarting collectd");
344 syslog (LOG_INFO, "Info: shutting down collectdmon");
349 free (collectd_argv);
353 /* vim: set sw=4 ts=4 tw=78 noexpandtab : */