pluto: Check for processes with the PID stored in pluto.pid.

This commit is contained in:
Tobias Brunner
2011-09-28 13:57:59 +02:00
parent 0b706426a5
commit 192f714076
+74 -43
View File
@@ -29,6 +29,7 @@
#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */ #include <arpa/nameser.h> /* missing from <resolv.h> on old systems */
#include <sys/queue.h> #include <sys/queue.h>
#include <sys/prctl.h> #include <sys/prctl.h>
#include <signal.h>
#include <pwd.h> #include <pwd.h>
#include <grp.h> #include <grp.h>
@@ -84,6 +85,23 @@
*/ */
#define DEFAULT_THREADS 4 #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) static void usage(const char *mess)
{ {
if (mess != NULL && *mess != '\0') if (mess != NULL && *mess != '\0')
@@ -148,59 +166,66 @@ static void usage(const char *mess)
exit_pluto(mess == NULL? 0 : 1); exit_pluto(mess == NULL? 0 : 1);
} }
static bool check_lock()
/* 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)
{ {
int fd = open(pluto_lock, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC struct stat stb;
, S_IRUSR | S_IRGRP | S_IROTH); 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" char buf[64];
, pluto_lock); pid_t pid = 0;
exit_pluto(10);
} memset(buf, 0, sizeof(buf));
else if (fread(buf, 1, sizeof(buf), fpid))
{ {
fprintf(stderr buf[sizeof(buf) - 1] = '\0';
, "pluto: unable to create lock file \"%s\" (%d %s)\n" pid = atoi(buf);
, pluto_lock, errno, strerror(errno)); }
exit_pluto(1); 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; pluto_lock_checked = TRUE;
return fd; return FALSE;
} }
static bool fill_lock(int lockfd, pid_t pid) static void fill_lock(void)
{ {
char buf[30]; /* holds "<pid>\n" */ pidfile = fopen(pluto_lock, "w");
int len = snprintf(buf, sizeof(buf), "%u\n", (unsigned int) pid); if (pidfile)
bool ok = len > 0 && write(lockfd, buf, len) == len; {
fprintf(pidfile, "%u\n", (u_int)getpid());
close(lockfd); fflush(pidfile);
return ok; }
/* keep pidfile open so we can truncate it, if we cannot delete it */
} }
static void delete_lock(void) 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(); 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; unsigned int keep_alive = 0;
bool force_keepalive = FALSE; bool force_keepalive = FALSE;
char *virtual_private = NULL; char *virtual_private = NULL;
int lockfd;
#ifdef CAPABILITIES #ifdef CAPABILITIES
int keep[] = { CAP_NET_ADMIN, CAP_NET_BIND_SERVICE }; int keep[] = { CAP_NET_ADMIN, CAP_NET_BIND_SERVICE };
#endif /* CAPABILITIES */ #endif /* CAPABILITIES */
@@ -545,7 +569,12 @@ int main(int argc, char **argv)
if (optind != argc) if (optind != argc)
usage("unexpected argument"); usage("unexpected argument");
reset_debugging(); 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 */ /* select between logging methods */
@@ -598,11 +627,13 @@ int main(int argc, char **argv)
if (pid != 0) if (pid != 0)
{ {
/* parent: die, after filling PID into lock file. /* parent: die
* must not use exit_pluto: lock would be removed! * 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) if (setsid() < 0)
@@ -617,7 +648,7 @@ int main(int argc, char **argv)
else else
{ {
/* no daemon fork: we have to fill in lock file */ /* no daemon fork: we have to fill in lock file */
(void) fill_lock(lockfd, getpid()); fill_lock();
fprintf(stdout, "Pluto initialized\n"); fprintf(stdout, "Pluto initialized\n");
fflush(stdout); fflush(stdout);
} }