summaryrefslogtreecommitdiff
path: root/misc/uuidd.c
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2007-12-25 14:19:15 -0500
committerTheodore Ts'o <tytso@mit.edu>2007-12-25 14:19:15 -0500
commit113d636a2bfe984fc1f6cae42fac2974d2a3f432 (patch)
tree9a2de203a49526fddc720f6a6054c16d93c57786 /misc/uuidd.c
parentf79fb4976cd1e4775a4959be3ddda557204939e0 (diff)
downloade2fsprogs-113d636a2bfe984fc1f6cae42fac2974d2a3f432.tar.gz
uuidd: Avoid race conditions to that only one uuidd is started
Use an improved locking protocol based on the pid file to assure that only one uuidd is started. Apparently the kernel does not prevent multiple processes from racing to bind to a Unix domain socket. Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'misc/uuidd.c')
-rw-r--r--misc/uuidd.c106
1 files changed, 64 insertions, 42 deletions
diff --git a/misc/uuidd.c b/misc/uuidd.c
index 19c86246..6c64f47c 100644
--- a/misc/uuidd.c
+++ b/misc/uuidd.c
@@ -49,11 +49,10 @@ static void usage(const char *progname)
exit(1);
}
-static void create_daemon(const char *pidfile_path)
+static void create_daemon(void)
{
pid_t pid;
uid_t euid;
- FILE *f;
pid = fork();
if (pid == -1) {
@@ -74,12 +73,6 @@ static void create_daemon(const char *pidfile_path)
(void) setsid();
euid = geteuid();
(void) setreuid(euid, euid);
-
- f = fopen(pidfile_path, "w");
- if (f) {
- fprintf(f, "%d\n", getpid());
- fclose(f);
- }
}
static int read_all(int fd, char *buf, size_t count)
@@ -107,13 +100,13 @@ static const char *cleanup_pidfile, *cleanup_socket;
static void terminate_intr(int signo CODE_ATTR((unused)))
{
(void) unlink(cleanup_pidfile);
- (void) unlink(cleanup_socket);
+ if (cleanup_socket)
+ (void) unlink(cleanup_socket);
exit(0);
}
static void server_loop(const char *socket_path, int debug,
- const char *pidfile_path,
- int timeout, int quiet)
+ int fd_pidfile, int timeout, int quiet)
{
struct sockaddr_un my_addr, from_addr;
unsigned char reply_buf[1024], *cp;
@@ -156,16 +149,15 @@ static void server_loop(const char *socket_path, int debug,
exit(1);
}
- if (!debug) {
- create_daemon(pidfile_path);
- cleanup_pidfile = pidfile_path;
- cleanup_socket = socket_path;
- signal(SIGHUP, terminate_intr);
- signal(SIGINT, terminate_intr);
- signal(SIGPIPE, terminate_intr);
- signal(SIGTERM, terminate_intr);
- signal(SIGALRM, terminate_intr);
- }
+ if (fd_pidfile > 1)
+ close(fd_pidfile); /* Unlock the pid file */
+ cleanup_socket = socket_path;
+ if (!debug)
+ create_daemon();
+ signal(SIGHUP, terminate_intr);
+ signal(SIGINT, terminate_intr);
+ signal(SIGTERM, terminate_intr);
+ signal(SIGALRM, terminate_intr);
signal(SIGPIPE, SIG_IGN);
while (1) {
@@ -270,7 +262,7 @@ static void server_loop(const char *socket_path, int debug,
}
}
-static int call_daemon(const char *socket_path, int op, unsigned char *buf,
+static int call_daemon(const char *socket_path, int op, char *buf,
int buflen, int *num, const char **err_context)
{
char op_buf[8];
@@ -356,18 +348,55 @@ static int call_daemon(const char *socket_path, int op, unsigned char *buf,
return ret;
}
+static int create_pidfile(const char *socket_path, const char *pidfile_path,
+ int quiet)
+{
+ int fd, ret;
+ char buf[20];
+
+ fd = open(pidfile_path, O_CREAT | O_RDWR, 0664);
+ if (fd < 0) {
+ if (!quiet)
+ fprintf(stderr, "Failed to open/create %s: %s\n",
+ pidfile_path, strerror(errno));
+ exit(1);
+ }
+ cleanup_pidfile = pidfile_path;
+ cleanup_socket = 0;
+ signal(SIGALRM, terminate_intr);
+ alarm(30);
+ if (lockf(fd, F_LOCK, 0) < 0) {
+ if (!quiet)
+ fprintf(stderr, "Failed to lock %s: %s\n",
+ pidfile_path, strerror(errno));
+ exit(1);
+ }
+ ret = call_daemon(socket_path, 0, buf, sizeof(buf), 0, 0);
+ if (ret > 0) {
+ if (!quiet)
+ printf(_("uuidd daemon already running at pid %s\n"),
+ buf);
+ exit(1);
+ }
+ alarm(0);
+
+ sprintf(buf, "%d\n", getpid());
+ ftruncate(fd, 0);
+ write(fd, buf, strlen(buf));
+ return(fd);
+}
int main(int argc, char **argv)
{
const char *socket_path = UUIDD_SOCKET_PATH;
const char *pidfile_path = UUIDD_PIDFILE_PATH;
const char *err_context;
- unsigned char buf[1024], *cp;
+ char buf[1024], *cp;
char str[37], *tmp;
uuid_t uu;
uid_t uid;
gid_t gid;
- int i, c, ret;
+ int i, c, ret, fd_pidfile = -1;
int debug = 0, do_type = 0, do_kill = 0, num = 0;
int timeout = 0, quiet = 0, drop_privs = 0;
@@ -450,23 +479,23 @@ int main(int argc, char **argv)
if (ret != sizeof(uu) + sizeof(num))
goto unexpected_size;
- uuid_unparse(buf, str);
+ uuid_unparse((unsigned char *) buf, str);
printf(_("%s and subsequent %d UUID's\n"), str, num);
} else {
printf(_("List of UUID's:\n"));
cp = buf + 4;
- if (ret != sizeof(num) + num*sizeof(uu))
+ if (ret != (int) (sizeof(num) + num*sizeof(uu)))
goto unexpected_size;
for (i=0; i < num; i++, cp+=16) {
- uuid_unparse(cp, str);
+ uuid_unparse((unsigned char *) cp, str);
printf("\t%s\n", str);
}
}
exit(0);
}
if (do_type) {
- ret = call_daemon(socket_path, do_type, (unsigned char *) &uu,
+ ret = call_daemon(socket_path, do_type, (char *) &uu,
sizeof(uu), 0, &err_context);
if (ret < 0) {
printf(_("Error calling uuidd daemon (%s): %s\n"),
@@ -485,12 +514,9 @@ int main(int argc, char **argv)
exit(0);
}
- /*
- * Check to make sure there isn't another daemon running already
- */
- ret = call_daemon(socket_path, 0, buf, sizeof(buf), 0, 0);
- if (ret > 0) {
- if (do_kill && ((do_kill = atoi((char *) buf)) > 0)) {
+ if (do_kill) {
+ ret = call_daemon(socket_path, 0, buf, sizeof(buf), 0, 0);
+ if ((ret > 0) && ((do_kill = atoi((char *) buf)) > 0)) {
ret = kill(do_kill, SIGTERM);
if (ret < 0) {
if (!quiet)
@@ -503,16 +529,12 @@ int main(int argc, char **argv)
if (!quiet)
printf(_("Killed uuidd running at pid %d\n"),
do_kill);
- exit(0);
}
- if (!quiet)
- printf(_("uuidd daemon already running at pid %s\n"),
- buf);
- exit(1);
+ exit(0);
}
- if (do_kill)
- exit(0); /* Nothing to kill */
- server_loop(socket_path, debug, pidfile_path, timeout, quiet);
+ fd_pidfile = create_pidfile(socket_path, pidfile_path, quiet);
+
+ server_loop(socket_path, debug, fd_pidfile, timeout, quiet);
return 0;
}