/* SPDX-License-Identifier: GPL-2.0 */ /** \file daemon.c Some helpers for programs that detach from the console. */ #include #include #include #include #include #include #include #include #include #include #include #include "gcc-compat.h" #include "err.h" #include "log.h" #include "str.h" #include "daemon.h" /** * Do the usual stuff to become a daemon. * * Fork, become session leader, dup fd 0, 1, 2 to /dev/null. * * \sa fork(2), setsid(2), dup(2). */ int daemon_init(void) { pid_t pid; int null, fd[2]; DSS_INFO_LOG(("daemonizing\n")); if (pipe(fd) < 0) goto err; pid = fork(); if (pid < 0) goto err; if (pid) { /* * The parent process exits once it has received one byte from * the reading end of the pipe. If the child exits before it * was able to complete its setup (acquire the lock on the * semaphore), the read() below will return zero. In this case * we let the parent die unsuccessfully. */ char c; int ret; close(fd[1]); ret = read(fd[0], &c, 1); if (ret <= 0) { DSS_EMERG_LOG(("child terminated unexpectedly\n")); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); } close(fd[0]); /* become session leader */ if (setsid() < 0) goto err; null = open("/dev/null", O_RDWR); if (null < 0) goto err; if (dup2(null, STDIN_FILENO) < 0) goto err; if (dup2(null, STDOUT_FILENO) < 0) goto err; if (dup2(null, STDERR_FILENO) < 0) goto err; close(null); return fd[1]; err: DSS_EMERG_LOG(("fatal: %s\n", strerror(errno))); exit(EXIT_FAILURE); } /** * fopen() the given file in append mode. * * \param logfile_name The name of the file to open. * * \return Either calls exit() or returns a valid file handle. */ FILE *open_log(const char *logfile_name) { FILE *logfile; assert(logfile_name); logfile = fopen(logfile_name, "a"); if (!logfile) { DSS_EMERG_LOG(("can not open %s: %s\n", logfile_name, strerror(errno))); exit(EXIT_FAILURE); } setlinebuf(logfile); return logfile; } /** * Close the log file of the daemon. * * \param logfile The log file handle. * * It's OK to call this with logfile == \p NULL. */ void close_log(FILE* logfile) { if (!logfile) return; DSS_INFO_LOG(("closing logfile\n")); fclose(logfile); } /** * Log the startup message. */ void log_welcome(int loglevel) { DSS_INFO_LOG(("***** welcome to dss ******\n")); DSS_DEBUG_LOG(("using loglevel %d\n", loglevel)); }