]> git.itanic.dy.fi Git - rrdd/commitdiff
Add support for daemonizing rrdd
authorTimo Kokkonen <timo.t.kokkonen@iki.fi>
Thu, 9 Nov 2017 19:39:30 +0000 (21:39 +0200)
committerTimo Kokkonen <timo.t.kokkonen@iki.fi>
Thu, 9 Nov 2017 19:49:48 +0000 (21:49 +0200)
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 <timo.t.kokkonen@iki.fi>
main.c

diff --git a/main.c b/main.c
index ef879e648826866653564ac9fc01171e2c88fb02..f756bdea4e63d0e7934a8a295f9dcfc0d0cb3af1 100644 (file)
--- a/main.c
+++ b/main.c
@@ -1,4 +1,6 @@
 #include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
 #include <unistd.h>
 #include <getopt.h>
 #include <time.h>
@@ -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();