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