]> git.tuebingen.mpg.de Git - dss.git/blob - daemon.c
ad73061c14ec5916284f2ab67438306d6484827d
[dss.git] / daemon.c
1 /* SPDX-License-Identifier: GPL-2.0 */
2
3 /** \file daemon.c Some helpers for programs that detach from the console. */
4
5 #include <string.h>
6 #include <stdlib.h>
7 #include <pwd.h>
8 #include <errno.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <grp.h>
12 #include <assert.h>
13 #include <unistd.h>
14 #include <fcntl.h>
15 #include <stdio.h>
16
17 #include "gcc-compat.h"
18 #include "err.h"
19 #include "log.h"
20 #include "str.h"
21 #include "daemon.h"
22
23 /**
24  * Do the usual stuff to become a daemon.
25  *
26  * Fork, become session leader, dup fd 0, 1, 2 to /dev/null.
27  *
28  * \sa fork(2), setsid(2), dup(2).
29  */
30 int daemon_init(void)
31 {
32         pid_t pid;
33         int null, fd[2];
34
35         DSS_INFO_LOG(("daemonizing\n"));
36         if (pipe(fd) < 0)
37                 goto err;
38         pid = fork();
39         if (pid < 0)
40                 goto err;
41         if (pid) {
42                 /*
43                  * The parent process exits once it has received one byte from
44                  * the reading end of the pipe. If the child exits before it
45                  * was able to complete its setup (acquire the lock on the
46                  * semaphore), the read() below will return zero. In this case
47                  * we let the parent die unsuccessfully.
48                  */
49                 char c;
50                 int ret;
51                 close(fd[1]);
52                 ret = read(fd[0], &c, 1);
53                 if (ret <= 0) {
54                         DSS_EMERG_LOG(("child terminated unexpectedly\n"));
55                         exit(EXIT_FAILURE);
56                 }
57                 exit(EXIT_SUCCESS);
58         }
59         close(fd[0]);
60         /* become session leader */
61         if (setsid() < 0)
62                 goto err;
63         null = open("/dev/null", O_RDWR);
64         if (null < 0)
65                 goto err;
66         if (dup2(null, STDIN_FILENO) < 0)
67                 goto err;
68         if (dup2(null, STDOUT_FILENO) < 0)
69                 goto err;
70         if (dup2(null, STDERR_FILENO) < 0)
71                 goto err;
72         close(null);
73         return fd[1];
74 err:
75         DSS_EMERG_LOG(("fatal: %s\n", strerror(errno)));
76         exit(EXIT_FAILURE);
77 }
78
79 /**
80  * fopen() the given file in append mode.
81  *
82  * \param logfile_name The name of the file to open.
83  *
84  * \return Either calls exit() or returns a valid file handle.
85  */
86 FILE *open_log(const char *logfile_name)
87 {
88         FILE *logfile;
89
90         assert(logfile_name);
91         logfile = fopen(logfile_name, "a");
92         if (!logfile) {
93                 DSS_EMERG_LOG(("can not open %s: %s\n", logfile_name,
94                         strerror(errno)));
95                 exit(EXIT_FAILURE);
96         }
97         setlinebuf(logfile);
98         return logfile;
99 }
100
101 /**
102  * Close the log file of the daemon.
103  *
104  * \param logfile The log file handle.
105  *
106  * It's OK to call this with logfile == \p NULL.
107  */
108 void close_log(FILE* logfile)
109 {
110         if (!logfile)
111                 return;
112         DSS_INFO_LOG(("closing logfile\n"));
113         fclose(logfile);
114 }
115
116 /**
117  * Log the startup message.
118  */
119 void log_welcome(int loglevel)
120 {
121         DSS_INFO_LOG(("***** welcome to dss ******\n"));
122         DSS_DEBUG_LOG(("using loglevel %d\n", loglevel));
123 }