aboutsummaryrefslogtreecommitdiffstats
path: root/src/Daemon.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'src/Daemon.cxx')
-rw-r--r--src/Daemon.cxx135
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