/*******************************************************************************
* Copyright (C) 2004-2008 Intel Corp. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corp. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Intel Corp. OR THE CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef DAEMON
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cerrno>
#include <csignal>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <syslog.h>
#include <pwd.h>
#include "daemonize.h"
static RETSIGTYPE child_handler(int signum)
{
switch (signum) {
case SIGALRM:
exit(EXIT_FAILURE);
break;
case SIGUSR1:
exit(EXIT_SUCCESS);
break;
case SIGCHLD:
exit(EXIT_FAILURE);
break;
}
}
void daemonize()
{
pid_t pid, sid, parent;
/* Drop user if there is one, and we were run as root */
if (getuid() == 0 || geteuid() == 0) {
struct passwd *pw = getpwnam(RUN_AS_USER);
if (pw) {
//syslog(LOG_NOTICE, "setting user to " RUN_AS_USER);
setuid(pw->pw_uid);
}
}
/* Trap signals that we expect to recieve */
signal(SIGCHLD, child_handler);
signal(SIGUSR1, child_handler);
signal(SIGALRM, child_handler);
/* Fork off the parent process */
pid = fork();
if (pid < 0) {
syslog(LOG_ERR, "unable to fork daemon, code=%d (%s)",
errno, strerror(errno));
exit(EXIT_FAILURE);
}
/* If we got a good PID, then we can exit the parent process. */
if (pid > 0) {
/* Wait for confirmation from the child via SIGTERM or SIGCHLD, or
for two seconds to elapse (SIGALRM). pause() should not return. */
alarm(2);
pause();
exit(EXIT_FAILURE);
}
/* At this point we are executing as the child process */
parent = getppid();
signal(SIGCHLD, SIG_DFL);
signal(SIGUSR1, SIG_DFL);
signal(SIGALRM, SIG_DFL);
setTerminationHandler();
/* Create a new SID for the child process */
sid = setsid();
if (sid < 0) {
syslog(LOG_ERR,
"unable to create a new session, code %d (%s)",
errno, strerror(errno));
exit(EXIT_FAILURE);
}
/* Change the current working directory. This prevents the current
directory from being locked; hence not being able to remove it. */
if ((chdir("/")) < 0) {
syslog(LOG_ERR,
"unable to change directory to %s, code %d (%s)",
"/", errno, strerror(errno));
exit(EXIT_FAILURE);
}
/* Redirect standard files to /dev/null */
freopen("/dev/null", "r", stdin);
freopen("/dev/null", "w", stdout);
freopen("/dev/null", "w", stderr);
/* Tell the parent process that we are A-okay */
kill(parent, SIGUSR1);
}
#endif //DAEMON