Simplify split_args().
[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 umask(0);
64 null = open("/dev/null", O_RDWR);
65 if (null < 0)
66 goto err;
67 if (dup2(null, STDIN_FILENO) < 0)
68 goto err;
69 if (dup2(null, STDOUT_FILENO) < 0)
70 goto err;
71 if (dup2(null, STDERR_FILENO) < 0)
72 goto err;
73 close(null);
74 return fd[1];
75 err:
76 DSS_EMERG_LOG(("fatal: %s\n", strerror(errno)));
77 exit(EXIT_FAILURE);
78 }
79
80 /**
81 * fopen() the given file in append mode.
82 *
83 * \param logfile_name The name of the file to open.
84 *
85 * \return Either calls exit() or returns a valid file handle.
86 */
87 FILE *open_log(const char *logfile_name)
88 {
89 FILE *logfile;
90
91 assert(logfile_name);
92 logfile = fopen(logfile_name, "a");
93 if (!logfile) {
94 DSS_EMERG_LOG(("can not open %s: %s\n", logfile_name,
95 strerror(errno)));
96 exit(EXIT_FAILURE);
97 }
98 setlinebuf(logfile);
99 return logfile;
100 }
101
102 /**
103 * Close the log file of the daemon.
104 *
105 * \param logfile The log file handle.
106 *
107 * It's OK to call this with logfile == \p NULL.
108 */
109 void close_log(FILE* logfile)
110 {
111 if (!logfile)
112 return;
113 DSS_INFO_LOG(("closing logfile\n"));
114 fclose(logfile);
115 }
116
117 /**
118 * Log the startup message.
119 */
120 void log_welcome(int loglevel)
121 {
122 DSS_INFO_LOG(("***** welcome to dss ******\n"));
123 DSS_DEBUG_LOG(("using loglevel %d\n", loglevel));
124 }