diff options
Diffstat (limited to 'src/Daemon.cxx')
-rw-r--r-- | src/Daemon.cxx | 135 |
1 files changed, 78 insertions, 57 deletions
diff --git a/src/Daemon.cxx b/src/Daemon.cxx index 557c47777..490b2def5 100644 --- a/src/Daemon.cxx +++ b/src/Daemon.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * Copyright (C) 2003-2014 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -23,19 +23,15 @@ #include "fs/AllocatedPath.hxx" #include "fs/FileSystem.hxx" #include "util/Domain.hxx" +#include "PidFile.hxx" #include "Log.hxx" -#include <glib.h> - -#include <stdio.h> #include <stdlib.h> #include <unistd.h> -#include <string.h> -#include <sys/types.h> -#include <sys/stat.h> #include <fcntl.h> #ifndef WIN32 +#include <sys/wait.h> #include <signal.h> #include <pwd.h> #include <grp.h> @@ -60,6 +56,11 @@ static AllocatedPath pidfile = AllocatedPath::Null(); /* whether "group" conf. option was given */ static bool had_group = false; +/** + * The write end of a pipe that is used to notify the parent process + * that initialization has finished and that it should detach. + */ +static int detach_fd = -1; void daemonize_kill(void) @@ -135,73 +136,93 @@ daemonize_set_user(void) } } -static void -daemonize_detach(void) +void +daemonize_begin(bool detach) { + /* release the current working directory */ + if (chdir("/") < 0) + FatalError("problems changing to root directory"); + + if (!detach) + /* the rest of this function deals with detaching the + process */ + return; + + /* do this before daemonizing so we can fail gracefully if we + can't write to the pid file */ + PidFile pidfile2(pidfile); + /* flush all file handles before duplicating the buffers */ fflush(nullptr); -#ifdef HAVE_DAEMON + /* create a pipe to synchronize the parent and the child */ - if (daemon(0, 1)) - FatalSystemError("daemon() failed"); + int fds[2]; + if (pipe(fds) < 0) + FatalSystemError("pipe() failed"); -#elif defined(HAVE_FORK) + /* move to a child process */ - /* detach from parent process */ - - switch (fork()) { - case -1: + pid_t pid = fork(); + if (pid < 0) FatalSystemError("fork() failed"); - case 0: - break; - default: - /* exit the parent process */ - _exit(EXIT_SUCCESS); + + if (pid == 0) { + /* in the child process */ + + pidfile2.Close(); + close(fds[0]); + detach_fd = fds[1]; + + /* detach from the current session */ + setsid(); + + /* continue starting MPD */ + return; } - /* release the current working directory */ + /* in the parent process */ - if (chdir("/") < 0) - FatalError("problems changing to root directory"); + close(fds[1]); - /* detach from the current session */ + int result; + ssize_t nbytes = read(fds[0], &result, sizeof(result)); + if (nbytes == (ssize_t)sizeof(result)) { + /* the child process was successful */ + pidfile2.Write(pid); + exit(EXIT_SUCCESS); + } - setsid(); + /* something bad happened in the child process */ -#else - FatalError("no support for daemonizing"); -#endif + pidfile2.Delete(pidfile); + + int status; + pid_t pid2 = waitpid(pid, &status, 0); + if (pid2 < 0) + FatalSystemError("waitpid() failed"); + + if (WIFSIGNALED(status)) + FormatFatalError("MPD died from signal %d%s", WTERMSIG(status), + WCOREDUMP(status) ? " (core dumped)" : ""); - LogDebug(daemon_domain, "daemonized"); + exit(WEXITSTATUS(status)); } void -daemonize(bool detach) +daemonize_commit() { - FILE *fp = nullptr; - - if (!pidfile.IsNull()) { - /* do this before daemon'izing so we can fail gracefully if we can't - * write to the pid file */ - LogDebug(daemon_domain, "opening pid file"); - fp = FOpen(pidfile, "w+"); - if (!fp) { - const std::string utf8 = pidfile.ToUTF8(); - FormatFatalSystemError("Failed to create pid file \"%s\"", - pidfile.c_str()); - } - } - - if (detach) - daemonize_detach(); - - if (!pidfile.IsNull()) { - LogDebug(daemon_domain, "writing pid file"); - fprintf(fp, "%lu\n", (unsigned long)getpid()); - fclose(fp); - } + if (detach_fd >= 0) { + /* tell the parent process to let go of us and exit + indicating success */ + int result = 0; + write(detach_fd, &result, sizeof(result)); + close(detach_fd); + } else + /* the pidfile was not written by the parent because + there is no parent - do it now */ + PidFile(pidfile).Write(); } void @@ -215,10 +236,10 @@ daemonize_init(const char *user, const char *group, AllocatedPath &&_pidfile) user_uid = pwd->pw_uid; user_gid = pwd->pw_gid; - user_name = g_strdup(user); + user_name = strdup(user); /* this is needed by libs such as arts */ - g_setenv("HOME", pwd->pw_dir, true); + setenv("HOME", pwd->pw_dir, true); } if (group) { @@ -241,7 +262,7 @@ daemonize_finish(void) pidfile = AllocatedPath::Null(); } - g_free(user_name); + free(user_name); } #endif |