diff options
-rw-r--r-- | src/pluto/plutomain.c | 117 |
1 files changed, 74 insertions, 43 deletions
diff --git a/src/pluto/plutomain.c b/src/pluto/plutomain.c index 309bde649..b1ec7cb56 100644 --- a/src/pluto/plutomain.c +++ b/src/pluto/plutomain.c @@ -29,6 +29,7 @@ #include <arpa/nameser.h> /* missing from <resolv.h> on old systems */ #include <sys/queue.h> #include <sys/prctl.h> +#include <signal.h> #include <pwd.h> #include <grp.h> @@ -84,6 +85,23 @@ */ #define DEFAULT_THREADS 4 +/** + * PID file, in which pluto stores its process id + */ +static char pluto_lock[sizeof(ctl_addr.sun_path)] = DEFAULT_CTLBASE LOCK_SUFFIX; + +/** + * TRUE if the lock has been checked. This helps to avoid any unintended + * deletion of the lock or control socket. + */ +static bool pluto_lock_checked = FALSE; + +/** + * Global reference to PID file (required to truncate, if undeletable) + */ +static FILE *pidfile = NULL; + + static void usage(const char *mess) { if (mess != NULL && *mess != '\0') @@ -148,59 +166,66 @@ static void usage(const char *mess) exit_pluto(mess == NULL? 0 : 1); } - -/* lock file support - * - provides convenient way for scripts to find Pluto's pid - * - prevents multiple Plutos competing for the same port - * - same basename as unix domain control socket - * NOTE: will not take account of sharing LOCK_DIR with other systems. - */ - -static char pluto_lock[sizeof(ctl_addr.sun_path)] = DEFAULT_CTLBASE LOCK_SUFFIX; -static bool pluto_lock_created = FALSE; - -/* create lockfile, or die in the attempt */ -static int create_lock(void) +static bool check_lock() { - int fd = open(pluto_lock, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC - , S_IRUSR | S_IRGRP | S_IROTH); + struct stat stb; + FILE *fpid; - if (fd < 0) + if (stat(pluto_lock, &stb) == 0) { - if (errno == EEXIST) + fpid = fopen(pluto_lock, "r"); + if (fpid) { - fprintf(stderr, "pluto: lock file \"%s\" already exists\n" - , pluto_lock); - exit_pluto(10); - } - else - { - fprintf(stderr - , "pluto: unable to create lock file \"%s\" (%d %s)\n" - , pluto_lock, errno, strerror(errno)); - exit_pluto(1); + char buf[64]; + pid_t pid = 0; + + memset(buf, 0, sizeof(buf)); + if (fread(buf, 1, sizeof(buf), fpid)) + { + buf[sizeof(buf) - 1] = '\0'; + pid = atoi(buf); + } + fclose(fpid); + if (pid && kill(pid, 0) == 0) + { /* such a process is running */ + return TRUE; + } } + fprintf(stderr, "pluto: removing lock file \"%s\", process not " + "running\n", pluto_lock); + unlink(pluto_lock); } - pluto_lock_created = TRUE; - return fd; + pluto_lock_checked = TRUE; + return FALSE; } -static bool fill_lock(int lockfd, pid_t pid) +static void fill_lock(void) { - char buf[30]; /* holds "<pid>\n" */ - int len = snprintf(buf, sizeof(buf), "%u\n", (unsigned int) pid); - bool ok = len > 0 && write(lockfd, buf, len) == len; - - close(lockfd); - return ok; + pidfile = fopen(pluto_lock, "w"); + if (pidfile) + { + fprintf(pidfile, "%u\n", (u_int)getpid()); + fflush(pidfile); + } + /* keep pidfile open so we can truncate it, if we cannot delete it */ } static void delete_lock(void) { - if (pluto_lock_created) + /* because unlinking the PID file may fail, we truncate it to ensure the + * daemon can be properly restarted. one probable cause for this is the + * combination of not running as root and the effective user lacking + * permissions on the parent dir(s) of the PID file */ + if (pluto_lock_checked) { + if (pidfile) + { + ignore_result(ftruncate(fileno(pidfile), 0)); + fclose(pidfile); + } + unlink(pluto_lock); + /* delete this here to avoid that exit_pluto calls delete the socket */ delete_ctl_socket(); - unlink(pluto_lock); /* is noting failure useful? */ } } @@ -263,7 +288,6 @@ int main(int argc, char **argv) unsigned int keep_alive = 0; bool force_keepalive = FALSE; char *virtual_private = NULL; - int lockfd; #ifdef CAPABILITIES int keep[] = { CAP_NET_ADMIN, CAP_NET_BIND_SERVICE }; #endif /* CAPABILITIES */ @@ -545,7 +569,12 @@ int main(int argc, char **argv) if (optind != argc) usage("unexpected argument"); reset_debugging(); - lockfd = create_lock(); + + if (check_lock()) + { + fprintf(stderr, "pluto: lock file \"%s\" already exists\n", pluto_lock); + exit_pluto(10); + } /* select between logging methods */ @@ -598,11 +627,13 @@ int main(int argc, char **argv) if (pid != 0) { - /* parent: die, after filling PID into lock file. + /* parent: die * must not use exit_pluto: lock would be removed! */ - exit(fill_lock(lockfd, pid)? 0 : 1); + exit(0); } + /* child: fill PID into lock file */ + fill_lock(); } if (setsid() < 0) @@ -617,7 +648,7 @@ int main(int argc, char **argv) else { /* no daemon fork: we have to fill in lock file */ - (void) fill_lock(lockfd, getpid()); + fill_lock(); fprintf(stdout, "Pluto initialized\n"); fflush(stdout); } |