#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include "error.h"
#include "daemon.h"
/* daemon ***********************************************************
*/
int
daemon(const char* rootDir, const char* pidFile)
{
int rc;
int maxfd;
int fd;
char s[32];
/* fork() so the parent can exit, this returns control to the command
line or shell invoking our program. This step is required so that
the new process is guaranteed not to be a process group leader. The
next step, setsid(), fails if we're a process group leader.
*/
rc = fork();
if (rc < 0)
stopOnError("daemon(): unable to fork()");
if (rc > 0)
exit(EXIT_SUCCESS); /* End parent process. */
/* setsid() to become a process group and session group leader. Since
a controlling terminal is associated with a session, and this new
session has not yet acquired a controlling terminal our process now
has no controlling terminal, which is a good thing for daemons.
*/
rc = setsid();
if (rc == -1)
stopOnError("daemon(): unable to setsid()");
/* fork() again so the parent (the session group leader) can exit. This
means that we, as a non-session group leader, can never regain a
controlling terminal.
*/
rc = fork();
if (rc < 0)
stopOnError("daemon(): unable to fork()");
if (rc > 0)
exit(EXIT_SUCCESS); /* End parent process. */
/* chdir("/") to ensure that our process doesn't keep any directory
in use. Failure to do this could make it so that an administrator
couldn't unmount a filesystem, because it was our current directory.
*/
if (rootDir != NULL)
{
rc = chdir(rootDir);
if (rc == -1)
stopOnError("daemon(): unable to chdir()");
}
/* We close all open file descriptors that may have been inherited
from the parent process. This is to reduce the resources we use.
*/
maxfd = sysconf(_SC_OPEN_MAX);
for (fd = maxfd - 1; fd >= 0; fd--)
close(fd); /* Ignore errors. */
/* Establish new open descriptors for stdin, stdout, and stderr. Even if
we don't plan to use them, it is still a good idea to have them open.
*/
fd = open("/dev/null", O_RDWR); /* stdin - file handle 0. */
dup(fd); /* stdout - file handle 1. */
dup(fd); /* stderr - file handle 2. */
/* Write pid-file.
*/
if (pidFile != NULL)
{
sprintf(s, "%u\n", getpid());
fd = open(pidFile, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR );
if (fd == -1)
stopOnError("daemon(): unable to create pid-file");
if (write(fd, s, strlen(s)) == -1)
stopOnError("daemon(): unable to write pid-file");
close(fd);
}
return 0;
}