23 #include <core/exception.h>
24 #include <libdaemon/dfork.h>
25 #include <libdaemon/dlog.h>
26 #include <libdaemon/dpid.h>
38 bool g_force_quit =
false;
39 int g_signum = SIGINT;
42 handle_signal(
int signum)
44 printf(
"Received %s signal\n", strsignal(signum));
47 case SIGINT: g_quit += 1;
break;
48 case SIGTERM: g_quit = 3;
break;
49 case SIGKILL: g_quit = 4;
break;
58 usage(
const char *progname)
60 printf(
"Usage: %s [options] <progfile> [args...]\n"
61 "progfile full absolute path to executable\n"
62 "args any number of arguments, passed to program as-is\n\n"
63 "where [options] passed in before <progfile> are one or more of:\n"
64 " -D[pid file] Run daemonized in the background, pid file is optional,\n"
65 " defaults to /var/run/ffwatchdog_basename.pid, must be absolute path.\n"
66 " -D[pid file] -k Kill a daemonized process running in the background,\n"
67 " pid file is optional as above.\n"
68 " -D[pid file] -s Check status of daemon.\n"
69 " -h Show help instructions.\n\n",
74 fork_and_exec(
int argc,
char **argv,
int prog_start)
79 printf(
"Forking for new process failed: %s\n", strerror(errno));
81 }
else if (pid == 0) {
84 signal(SIGINT, SIG_IGN);
85 if (execve(argv[prog_start], &argv[prog_start], environ) == -1) {
86 printf(
"Failed to execute %s, exited with %i: %s\n",
100 daemon_retval_send(-1);
101 daemon_retval_done();
102 daemon_pid_file_remove();
106 daemonize(
int argc,
char **argv)
109 mode_t old_umask = umask(0);
112 daemon_retval_init();
115 if ((pid = daemon_fork()) < 0) {
122 if ((ret = daemon_retval_wait(20)) < 0) {
123 daemon_log(LOG_ERR,
"Could not recieve return value from daemon process.");
128 daemon_log(LOG_ERR,
"*** Daemon startup failed, see syslog for details. ***");
130 case 1: daemon_log(LOG_ERR,
"Daemon failed to close file descriptors");
break;
131 case 2: daemon_log(LOG_ERR,
"Daemon failed to create PID file");
break;
139 #ifdef DAEMON_CLOSE_ALL_AVAILABLE
140 if (daemon_close_all(-1) < 0) {
141 daemon_log(LOG_ERR,
"Failed to close all file descriptors: %s", strerror(errno));
143 daemon_retval_send(1);
149 if (daemon_pid_file_create() < 0) {
150 printf(
"Could not create PID file (%s).", strerror(errno));
151 daemon_log(LOG_ERR,
"Could not create PID file (%s).", strerror(errno));
154 daemon_retval_send(2);
159 daemon_retval_send(0);
161 daemon_log(LOG_INFO,
"Sucessfully started");
170 const char *ffwatchdog_pid_file;
176 ffwatchdog_daemon_pid_file_proc()
178 return ffwatchdog_pid_file;
186 main(
int argc,
char **argv)
193 bool arg_verbose =
false;
194 bool arg_daemonize =
false;
195 bool arg_daemon_kill =
false;
196 bool arg_daemon_status =
false;
197 const char *daemon_pid_file = NULL;
200 for (prog_start = 1; prog_start < argc; ++prog_start) {
201 if (argv[prog_start][0] ==
'-') {
203 char param = argv[prog_start][1];
209 arg_daemonize =
true;
210 daemon_pid_file = NULL;
211 if (strlen(&argv[prog_start][1]) > 1) {
212 daemon_pid_file = &argv[prog_start][2];
214 }
else if (param ==
'k') {
215 arg_daemon_kill =
true;
216 }
else if (param ==
's') {
217 arg_daemon_status =
true;
218 }
else if (param ==
'v') {
220 }
else if (param ==
'h') {
224 printf(
"Unknown argument '%c'\n", param);
234 if (prog_start >= argc) {
239 if (access(argv[prog_start], X_OK) != 0) {
240 printf(
"Cannot execute '%s': %s\n\n", argv[1], strerror(errno));
247 char *daemon_ident = NULL;
252 char *argv_copy = strdup(argv[prog_start]);
253 if (asprintf(&daemon_ident,
"ffwatchdog_%s", basename(argv_copy)) == -1) {
255 printf(
"Failed to create daemon ident, not enough memory\n");
259 daemon_pid_file_ident = daemon_log_ident = daemon_ident;
260 if (daemon_pid_file != NULL) {
261 ffwatchdog_pid_file = daemon_pid_file;
262 daemon_pid_file_proc = ffwatchdog_daemon_pid_file_proc;
266 if (arg_daemon_kill) {
268 if ((dpid = daemon_pid_file_is_running()) < 0) {
269 daemon_log(LOG_ERR,
"Watchdog daemon for %s not running.", argv[prog_start]);
275 if ((ret = daemon_pid_file_kill_wait(SIGINT, 5)) < 0) {
276 daemon_log(LOG_WARNING,
"Failed to kill watchdog daemon for %s", argv[prog_start]);
278 return (ret < 0) ? 1 : 0;
281 if (arg_daemon_status) {
283 if (daemon_pid_file_is_running() < 0) {
285 printf(
"Watchdog daemon for %s is not running\n", argv[prog_start]);
290 printf(
"Watchdog daemon for %s is running\n", argv[prog_start]);
297 if ((dpid = daemon_pid_file_is_running()) >= 0) {
299 "Watchdog daemon for %s already running on (PID %u)",
305 dpid = daemonize(argc, argv);
316 sa.sa_handler = handle_signal;
317 sigemptyset(&sa.sa_mask);
319 sigaction(SIGINT, &sa, NULL);
320 sigaction(SIGKILL, &sa, NULL);
321 sigaction(SIGTERM, &sa, NULL);
322 sigaction(SIGUSR1, &sa, NULL);
323 sigaction(SIGUSR2, &sa, NULL);
327 pid = fork_and_exec(argc, argv, prog_start);
329 while (pid != -1 && !g_quit) {
331 pid_t cpid = waitpid(pid, &status, WUNTRACED | WCONTINUED);
332 printf(
"Wait returned\n");
335 printf(
"Failed to wait for child: %s\n", strerror(errno));
336 }
else if (WIFEXITED(status)) {
337 printf(
"%i|%s exited, status=%d\n", cpid, argv[prog_start], WEXITSTATUS(status));
339 }
else if (WIFSIGNALED(status)) {
340 printf(
"%i|%s killed by signal %s\n", cpid, argv[prog_start], strsignal(WTERMSIG(status)));
342 }
else if (WIFSTOPPED(status)) {
343 printf(
"%i|%s stopped by signal %s\n", cpid, argv[prog_start], strsignal(WSTOPSIG(status)));
345 }
else if (WIFCONTINUED(status)) {
346 printf(
"%i|%s continued\n", cpid, argv[prog_start]);
353 printf(
"Stopping child. Press Ctrl-C again to escalate.\n");
355 for (
unsigned int i = 0; i < 600; ++i) {
356 if (last_quit != g_quit) {
360 }
else if (g_quit == 3) {
366 printf(
"Killing %s with signal %s\n", argv[prog_start], strsignal(signum));
367 if (kill(pid, signum) == -1) {
368 printf(
"Failed to kill %s: %s\n", argv[prog_start], strerror(errno));
375 int rv = waitpid(pid, &status, WNOHANG);
379 if (errno == ECHILD) {