From dd3258133e54bd2c3355b09f43059f56fab5ee14 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Wed, 19 Aug 2009 03:25:34 +0200 Subject: Fix daemonization and lockfile madness --- usbmuxd/main.c | 201 ++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 140 insertions(+), 61 deletions(-) diff --git a/usbmuxd/main.c b/usbmuxd/main.c index be7451f..6b3c881 100644 --- a/usbmuxd/main.c +++ b/usbmuxd/main.c @@ -33,7 +33,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include #include -#include +#include +#include #include #include #include @@ -44,7 +45,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "client.h" static const char *socket_path = "/var/run/usbmuxd"; -static const char *lockfile = "/var/run/usbmuxd.lock"; +static const char *lockfile = "/var/run/usbmuxd.pid"; int should_exit; @@ -55,6 +56,9 @@ static const char *drop_user = "usbmux"; static int opt_udev = 0; static int opt_exit = 0; static int exit_signal = 0; +static int daemon_pipe; + +static int report_to_parent = 0; int create_socket(void) { struct sockaddr_un bind_addr; @@ -191,25 +195,47 @@ int main_loop(int listenfd) /** * make this program run detached from the current console */ -static int daemonize() +static int daemonize(void) { pid_t pid; pid_t sid; + int pfd[2]; + int res; // already a daemon if (getppid() == 1) return 0; + if((res = pipe(pfd)) < 0) { + usbmuxd_log(LL_FATAL, "pipe() failed."); + return res; + } + pid = fork(); if (pid < 0) { - exit(EXIT_FAILURE); + usbmuxd_log(LL_FATAL, "fork() failed."); + return pid; } if (pid > 0) { // exit parent process - exit(EXIT_SUCCESS); + int status; + close(pfd[1]); + + if((res = read(pfd[0],&status,sizeof(int))) != sizeof(int)) { + fprintf(stderr, "usbmuxd: ERROR: Failed to get init status from child, check syslog for messages.\n"); + exit(1); + } + if(status != 0) + fprintf(stderr, "usbmuxd: ERROR: Child process exited with error %d, check syslog for messages.\n", status); + exit(status); } // At this point we are executing as the child process + // but we need to do one more fork + + daemon_pipe = pfd[1]; + close(pfd[0]); + report_to_parent = 1; // Change the file mode mask umask(0); @@ -217,23 +243,57 @@ static int daemonize() // Create a new SID for the child process sid = setsid(); if (sid < 0) { + usbmuxd_log(LL_FATAL, "setsid() failed."); return -1; } + + pid = fork(); + if (pid < 0) { + usbmuxd_log(LL_FATAL, "fork() failed (second)."); + return pid; + } + + if (pid > 0) { + // exit parent process + close(daemon_pipe); + exit(0); + } + // Change the current working directory. if ((chdir("/")) < 0) { + usbmuxd_log(LL_FATAL, "chdir() failed"); return -2; } // Redirect standard files to /dev/null if (!freopen("/dev/null", "r", stdin)) { - usbmuxd_log(LL_ERROR, "ERROR: redirection of stdin failed."); + usbmuxd_log(LL_FATAL, "Redirection of stdin failed."); + return -3; } if (!freopen("/dev/null", "w", stdout)) { - usbmuxd_log(LL_ERROR, "ERROR: redirection of stdout failed."); + usbmuxd_log(LL_FATAL, "Redirection of stdout failed."); + return -3; + } + + return 0; +} + +static int notify_parent(int status) +{ + int res; + + report_to_parent = 0; + if ((res = write(daemon_pipe, &status, sizeof(int))) != sizeof(int)) { + usbmuxd_log(LL_FATAL, "Could not notify parent!"); + if(res >= 0) + return -2; + else + return res; } + close(daemon_pipe); if (!freopen("/dev/null", "w", stderr)) { - usbmuxd_log(LL_ERROR, "ERROR: redirection of stderr failed."); + usbmuxd_log(LL_FATAL, "Redirection of stderr failed."); + return -1; } - return 0; } @@ -310,8 +370,9 @@ int main(int argc, char *argv[]) { int listenfd; int res = 0; - FILE *lfd = NULL; + int lfd; struct flock lock; + char pids[10]; parse_opts(argc, argv); @@ -333,60 +394,77 @@ int main(int argc, char *argv[]) set_signal_handlers(); - lfd = fopen(lockfile, "r"); - if (lfd) { - lock.l_type = 0; - lock.l_whence = SEEK_SET; - lock.l_start = 0; - lock.l_len = 0; - fcntl(fileno(lfd), F_GETLK, &lock); - fclose(lfd); - if (lock.l_type != F_UNLCK) { - if (opt_exit) { - if (lock.l_pid && !kill(lock.l_pid, 0)) { - usbmuxd_log(LL_NOTICE, "sending signal %d to instance with pid %d", exit_signal, lock.l_pid); - if (kill(lock.l_pid, exit_signal) < 0) { - usbmuxd_log(LL_FATAL, "Error: could not deliver signal %d to pid %d", exit_signal, lock.l_pid); - } - res = 0; - goto terminate; - } else { - usbmuxd_log(LL_ERROR, "Could not determine pid of the other running instance!"); + res = lfd = open(lockfile, O_WRONLY|O_CREAT, 0644); + if(res == -1) { + usbmuxd_log(LL_FATAL, "Could not open lockfile"); + goto terminate; + } + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + fcntl(lfd, F_GETLK, &lock); + close(lfd); + if (lock.l_type != F_UNLCK) { + if (opt_exit) { + if (lock.l_pid && !kill(lock.l_pid, 0)) { + usbmuxd_log(LL_NOTICE, "Sending signal %d to instance with pid %d", exit_signal, lock.l_pid); + res = 0; + if (kill(lock.l_pid, exit_signal) < 0) { + usbmuxd_log(LL_FATAL, "Could not deliver signal %d to pid %d", exit_signal, lock.l_pid); res = -1; - goto terminate; } + goto terminate; } else { - if (!opt_udev) { - usbmuxd_log(LL_ERROR, "Another instance is already running (pid %d). exiting.", lock.l_pid); - res = -1; - } else { - usbmuxd_log(LL_NOTICE, "Another instance is already running (pid %d). exiting.", lock.l_pid); - res = 0; - } + usbmuxd_log(LL_ERROR, "Could not determine pid of the other running instance!"); + res = -1; goto terminate; } + } else { + if (!opt_udev) { + usbmuxd_log(LL_ERROR, "Another instance is already running (pid %d). exiting.", lock.l_pid); + res = -1; + } else { + usbmuxd_log(LL_NOTICE, "Another instance is already running (pid %d). exiting.", lock.l_pid); + res = 0; + } + goto terminate; } } + unlink(lockfile); if (opt_exit) { usbmuxd_log(LL_NOTICE, "No running instance found, none killed. exiting."); goto terminate; } - // now open the lockfile and place the lock - lfd = fopen(lockfile, "w"); - if (lfd) { - lock.l_type = F_WRLCK; - lock.l_whence = SEEK_SET; - lock.l_start = 0; - lock.l_len = 0; - if ((res = fcntl(fileno(lfd), F_SETLK, &lock)) < 0) { - usbmuxd_log(LL_FATAL, "Lockfile locking failed!"); + if (!foreground) { + if ((res = daemonize()) < 0) { + fprintf(stderr, "usbmuxd: FATAL: Could not daemonize!\n"); + usbmuxd_log(LL_FATAL, "Could not daemonize!"); goto terminate; } - } else { - usbmuxd_log(LL_FATAL, "Lockfile open failed!"); - res = -1; + } + + // now open the lockfile and place the lock + res = lfd = open(lockfile, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644); + if(res < 0) { + usbmuxd_log(LL_FATAL, "Could not open lockfile"); + goto terminate; + } + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + if ((res = fcntl(lfd, F_SETLK, &lock)) < 0) { + usbmuxd_log(LL_FATAL, "Lockfile locking failed!"); + goto terminate; + } + sprintf(pids, "%d", getpid()); + if ((res = write(lfd, pids, strlen(pids))) != strlen(pids)) { + usbmuxd_log(LL_FATAL, "Could not write pidfile!"); + if(res >= 0) + res = -2; goto terminate; } @@ -400,7 +478,7 @@ int main(int argc, char *argv[]) struct passwd *pw = getpwnam(drop_user); if (!pw) { usbmuxd_log(LL_FATAL, "Dropping privileges failed, check if user '%s' exists!", drop_user); - res = 1; + res = -1; goto terminate; } @@ -420,12 +498,12 @@ int main(int argc, char *argv[]) // security check if (setuid(0) != -1) { usbmuxd_log(LL_FATAL, "Failed to drop privileges properly!"); - res = 1; + res = -1; goto terminate; } if (getuid() != pw->pw_uid || getgid() != pw->pw_gid) { usbmuxd_log(LL_FATAL, "Failed to drop privileges properly!"); - res = 1; + res = -1; goto terminate; } usbmuxd_log(LL_NOTICE, "Successfully dropped privileges to '%s'", drop_user); @@ -441,13 +519,9 @@ int main(int argc, char *argv[]) usbmuxd_log(LL_NOTICE, "Initialization complete"); - if (!foreground) { - if ((res = daemonize()) < 0) { - fprintf(stderr, "usbmuxd: FATAL: Could not daemonize!\n"); - usbmuxd_log(LL_FATAL, "Could not daemonize!"); + if (report_to_parent) + if((res = notify_parent(0)) < 0) goto terminate; - } - } res = main_loop(listenfd); if(res < 0) @@ -463,7 +537,12 @@ int main(int argc, char *argv[]) terminate: log_disable_syslog(); - if(res < 0) - return -res; - return 0; + if (res < 0) + res = -res; + else + res = 0; + if (report_to_parent) + notify_parent(res); + + return res; } -- cgit v1.1-32-gdbae