From: Timo Kokkonen Date: Thu, 9 Nov 2017 19:39:30 +0000 (+0200) Subject: Add support for daemonizing rrdd X-Git-Url: http://git.itanic.dy.fi/?p=rrdd;a=commitdiff_plain;h=d78c739152d9b656908423a41c6c9f119e47fc44 Add support for daemonizing rrdd Daemonizing rrdd is useful if we wish to leave it running on background. We might need to prevent it from starting multiple times, so add support for creating and verifying a pid file as well. Signed-off-by: Timo Kokkonen --- diff --git a/main.c b/main.c index ef879e6..f756bde 100644 --- a/main.c +++ b/main.c @@ -1,4 +1,6 @@ #include +#include +#include #include #include #include @@ -16,7 +18,9 @@ struct user_options { int max_jobs; + int daemonize; char *config_file; + char *pid_file; }; int read_args(int argc, char *argv[], struct user_options *opts) @@ -26,11 +30,13 @@ int read_args(int argc, char *argv[], struct user_options *opts) { .val = 'j', .has_arg = 1, .name = "jobs", }, { .val = 'c', .has_arg = 1, .name = "config", }, { .val = 'l', .has_arg = 1, .name = "log-file", }, + { .val = 'p', .has_arg = 1, .name = "pid-file", }, + { .val = 'd', .name = "daemon", }, { .val = 'v', .name = "verbose", }, { .val = 'q', .name = "quiet", }, { }, }; - char short_options[] = "j:c:l:vq"; + char short_options[] = "j:c:l:p:dvq"; while (1) { c = getopt_long(argc, argv, short_options, long_options, @@ -60,6 +66,14 @@ int read_args(int argc, char *argv[], struct user_options *opts) trace_level--; break; + case 'd': + opts->daemonize = 1; + break; + + case 'p': + opts->pid_file = optarg; + break; + case '?': return -1; } @@ -73,6 +87,73 @@ int read_args(int argc, char *argv[], struct user_options *opts) return 0; } +static int is_already_running(const char *pidfile) +{ + struct stat s; + char pidstr[16], procpath[256] = { 0 }; + int fd, ret, pid; + + fd = open(pidfile, O_RDONLY); + if (fd < 0) { + /* No pid, no running instance */ + return 0; + } + + ret = read(fd, pidstr, sizeof(pidstr) - 1); + if (ret < 0) { + pr_err("Failed to read pid file: %m\n"); + close(fd); + + return ret; + } + close(fd); + + pidstr[ret] = 0; + + ret = sscanf(pidstr, "%d", &pid); + + /* Corrupted pid data? Maybe leftover from prev boot or something */ + if (ret != 1) + return 0; + + snprintf(procpath, sizeof(procpath) - 1, "/proc/%d/", pid); + + ret = stat(procpath, &s); + + if (ret < 0) { + pr_info("Ignoring stale pid %d from pid file %s\n", + pid, pidfile); + + return 0; + } + + pr_err("Process %d is already running as stated in pid file %s\n", + pid, pidfile); + + return 1; +} + +static int write_pidfile(const char *pidfile) +{ + char pidstr[16]; + int fd, ret; + + fd = open(pidfile, O_WRONLY | O_CREAT, 0644); + if (fd < 0) { + pr_err("Failed to open pidfile %s for writing: %m\n", pidfile); + return -1; + } + + ret = snprintf(pidstr, sizeof(pidstr), "%d", getpid()); + ret = write(fd, pidstr, ret); + if (ret < 0) + pr_err("Failed to write to pidfile %s: %m\n", pidfile); + + close(fd); + + return ret; +} + int main(int argc, char *argv[]) { struct user_options opts; @@ -87,6 +168,23 @@ int main(int argc, char *argv[]) if (read_args(argc, argv, &opts) < 0) return -1; + if (opts.daemonize) { + pr_info("Setting itself as a daemon\n"); + ret = daemon(1, 0); + if (ret < 0) { + pr_err("Failed to daemonize: %m\n"); + return -1; + } + } + + if (opts.pid_file) { + if (is_already_running(opts.pid_file)) + return -1; + + if (write_pidfile(opts.pid_file) < 0) + return -1; + } + init_plugin_manager(argv[0]); register_built_in_parsers();