X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Frrd_daemon.c;h=40785b00778cc19ffc40b3e97bc687f553f5b4a9;hb=59525f3de81d5f6a9c5e5fc3a6662fa7e074163f;hp=8b23e5202a236676978b09ae1baaa6d9e4c35074;hpb=3426dc792f7e35312ed11ccb07b483f8ed3c8b12;p=rrdtool.git diff --git a/src/rrd_daemon.c b/src/rrd_daemon.c index 8b23e52..40785b0 100644 --- a/src/rrd_daemon.c +++ b/src/rrd_daemon.c @@ -286,7 +286,7 @@ static void install_signal_handlers(void) /* {{{ */ } /* }}} void install_signal_handlers */ -static int open_pidfile(void) /* {{{ */ +static int open_pidfile(char *action, int oflag) /* {{{ */ { int fd; char *file; @@ -295,14 +295,52 @@ static int open_pidfile(void) /* {{{ */ ? config_pid_file : LOCALSTATEDIR "/run/rrdcached.pid"; - fd = open(file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IRGRP|S_IROTH); + fd = open(file, oflag, S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH); if (fd < 0) - fprintf(stderr, "FATAL: cannot create '%s' (%s)\n", - file, rrd_strerror(errno)); + fprintf(stderr, "rrdcached: can't %s pid file '%s' (%s)\n", + action, file, rrd_strerror(errno)); return(fd); } /* }}} static int open_pidfile */ +/* check existing pid file to see whether a daemon is running */ +static int check_pidfile(void) +{ + int pid_fd; + pid_t pid; + char pid_str[16]; + + pid_fd = open_pidfile("open", O_RDWR); + if (pid_fd < 0) + return pid_fd; + + if (read(pid_fd, pid_str, sizeof(pid_str)) <= 0) + return -1; + + pid = atoi(pid_str); + if (pid <= 0) + return -1; + + /* another running process that we can signal COULD be + * a competing rrdcached */ + if (pid != getpid() && kill(pid, 0) == 0) + { + fprintf(stderr, + "FATAL: Another rrdcached daemon is running?? (pid %d)\n", pid); + close(pid_fd); + return -1; + } + + lseek(pid_fd, 0, SEEK_SET); + ftruncate(pid_fd, 0); + + fprintf(stderr, + "rrdcached: removed stale PID file (no rrdcached on pid %d)\n" + "rrdcached: starting normally.\n", pid); + + return pid_fd; +} /* }}} static int check_pidfile */ + static int write_pidfile (int fd) /* {{{ */ { pid_t pid; @@ -1487,6 +1525,9 @@ static int handle_request_update (listen_socket_t *sock, /* {{{ */ if (values_num < 1) { + /* journal replay mode */ + if (sock == NULL) return RESP_ERR; + /* if we had only one update attempt, then return the full error message... try to get the most information out of the limited error space allowed by the protocol @@ -2318,13 +2359,16 @@ static void *listen_thread_main (void *args __attribute__((unused))) /* {{{ */ static int daemonize (void) /* {{{ */ { int status; - int fd; + int pid_fd; char *base_dir; daemon_uid = geteuid(); - fd = open_pidfile(); - if (fd < 0) return fd; + pid_fd = open_pidfile("create", O_CREAT|O_EXCL|O_WRONLY); + if (pid_fd < 0) + pid_fd = check_pidfile(); + if (pid_fd < 0) + return pid_fd; if (!stay_foreground) { @@ -2377,7 +2421,7 @@ static int daemonize (void) /* {{{ */ return (-1); } - status = write_pidfile (fd); + status = write_pidfile (pid_fd); return status; } /* }}} int daemonize */ @@ -2493,6 +2537,7 @@ static int read_options (int argc, char **argv) /* {{{ */ case 'b': { size_t len; + char base_realpath[PATH_MAX]; if (config_base_dir != NULL) free (config_base_dir); @@ -2503,6 +2548,27 @@ static int read_options (int argc, char **argv) /* {{{ */ return (3); } + /* make sure that the base directory is not resolved via + * symbolic links. this makes some performance-enhancing + * assumptions possible (we don't have to resolve paths + * that start with a "/") + */ + if (realpath(config_base_dir, base_realpath) == NULL) + { + fprintf (stderr, "Invalid base directory '%s'.\n", config_base_dir); + return 5; + } + else if (strncmp(config_base_dir, + base_realpath, sizeof(base_realpath)) != 0) + { + fprintf(stderr, + "Base directory (-b) resolved via file system links!\n" + "Please consult rrdcached '-b' documentation!\n" + "Consider specifying the real directory (%s)\n", + base_realpath); + return 5; + } + len = strlen (config_base_dir); while ((len > 0) && (config_base_dir[len - 1] == '/')) {