1 /*
2 daemoninze.c - functions for properly daemonising an application
3
4 Copyright (C) 2014-2015 Arthur de Jong
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA
20 */
21
22 #include "config.h"
23
24 #include <unistd.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #ifdef HAVE_PTHREAD_H
33 #include <pthread.h>
34 #endif /* HAVE_PTHREAD_H */
35
36 #include "daemonize.h"
37 #include "log.h"
38
39 /* the write end of a pipe that is used to signal the fact that the child
40 process has finished initialising (see daemonize_daemon() and
41 daemonize_ready() for details) */
42 static int daemonizefd = -1;
43
daemonize_closefds(void)44 void daemonize_closefds(void)
45 {
46 int i;
47 /* close all file descriptors (except stdin/out/err) */
48 i = sysconf(_SC_OPEN_MAX) - 1;
49 /* if the system does not have OPEN_MAX just close the first 32 and
50 hope we closed enough */
51 if (i < 0)
52 i = 32;
53 for (; i > 3; i--)
54 close(i);
55 }
56
daemonize_redirect_stdio(void)57 void daemonize_redirect_stdio(void)
58 {
59 /* close stdin, stdout and stderr */
60 (void)close(0); /* stdin */
61 (void)close(1); /* stdout */
62 (void)close(2); /* stderr */
63 /* reconnect to /dev/null */
64 (void)open("/dev/null", O_RDWR); /* stdin, fd=0 */
65 (void)dup(0); /* stdout, fd=1 */
66 (void)dup(0); /* stderr, fd=2 */
67 }
68
69 /* try to fill the buffer until EOF or error */
read_response(int fd,char * buffer,size_t bufsz)70 static int read_response(int fd, char *buffer, size_t bufsz)
71 {
72 int rc;
73 size_t r = 0;
74 while (r < bufsz)
75 {
76 rc = read(fd, buffer + r, bufsz - r);
77 if (rc == 0)
78 break;
79 else if (rc > 0)
80 r += rc;
81 else if ((errno == EINTR) || (errno == EAGAIN))
82 continue; /* ignore these errors and try again */
83 else
84 {
85 log_log(LOG_ERR, "read_response(): read() failed: %s", strerror(errno));
86 return -1;
87 }
88 }
89 return r;
90 }
91
92 /* The parent process calling daemonize_daemon() will end up here on success */
wait_for_response(int fd)93 static int wait_for_response(int fd)
94 {
95 int i, l, rc;
96 char buffer[1024];
97 /* read return code */
98 errno = 0;
99 i = read_response(fd, (void *)&rc, sizeof(int));
100 log_log(LOG_DEBUG, "DEBUG: wait_for_response(): i=%d, rc=%d", i, rc);
101 if (i != sizeof(int))
102 {
103 log_log(LOG_ERR, "wait_for_response(): read_response() returned %d (expected %d)",
104 i, (int)sizeof(int));
105 if (errno == 0)
106 #ifdef ENODATA
107 errno = ENODATA;
108 #else
109 errno = ENOATTR;
110 #endif
111 return -1;
112 }
113 /* read string length */
114 i = read_response(fd, (void *)&l, sizeof(int));
115 log_log(LOG_DEBUG, "DEBUG: wait_for_response(): i=%d, l=%d", i, l);
116 if ((i != sizeof(int)) || (l <= 0))
117 _exit(rc);
118 /* read string */
119 if ((size_t)l > (sizeof(buffer) - 1))
120 l = sizeof(buffer) - 1;
121 i = read_response(fd, buffer, l);
122 buffer[l] = '\0';
123 if (i == l)
124 fprintf(stderr, "%s", buffer);
125 _exit(rc);
126 }
127
closefd(void)128 static void closefd(void)
129 {
130 if (daemonizefd >= 0)
131 {
132 close(daemonizefd);
133 daemonizefd = -1;
134 }
135 }
136
daemonize_daemon(void)137 int daemonize_daemon(void)
138 {
139 int pipefds[2];
140 int i;
141 /* set up a pipe for communication */
142 if (pipe(pipefds) < 0)
143 {
144 log_log(LOG_ERR, "pipe() failed: %s", strerror(errno));
145 return -1;
146 }
147 /* set O_NONBLOCK on the write end to ensure that a call to
148 daemonize_ready() will not lock the application */
149 if ((i = fcntl(pipefds[1], F_GETFL, 0)) < 0)
150 {
151 log_log(LOG_ERR, "fcntl() failed: %s", strerror(errno));
152 close(pipefds[0]);
153 close(pipefds[1]);
154 return -1;
155 }
156 if (fcntl(pipefds[1], F_SETFL, i | O_NONBLOCK) < 0)
157 {
158 log_log(LOG_ERR, "fcntl() failed: %s", strerror(errno));
159 close(pipefds[0]);
160 close(pipefds[1]);
161 return -1;
162 }
163 /* fork() and exit() to detach from the parent process */
164 switch (fork())
165 {
166 case 0:
167 /* we are the child, close read end of pipe */
168 close(pipefds[0]);
169 break;
170 case -1:
171 /* we are the parent, but have an error */
172 log_log(LOG_ERR, "fork() failed: %s", strerror(errno));
173 close(pipefds[0]);
174 close(pipefds[1]);
175 return -1;
176 default:
177 /* we are the parent, close write end and wait for information */
178 close(pipefds[1]);
179 return wait_for_response(pipefds[0]);
180 }
181 /* become process leader */
182 if (setsid() < 0)
183 {
184 log_log(LOG_ERR, "setsid() failed: %s", strerror(errno));
185 close(pipefds[1]);
186 _exit(EXIT_FAILURE);
187 }
188 /* fork again so we cannot allocate a pty */
189 switch (fork())
190 {
191 case 0:
192 /* we are the child */
193 break;
194 case -1:
195 /* we are the parent, but have an error */
196 log_log(LOG_ERR, "fork() failed: %s", strerror(errno));
197 close(pipefds[1]);
198 _exit(EXIT_FAILURE);
199 default:
200 /* we are the parent and we're done */
201 close(pipefds[1]);
202 _exit(EXIT_SUCCESS);
203 }
204 daemonizefd = pipefds[1];
205 /* close the file descriptor on exec (ignore errors) */
206 fcntl(daemonizefd, F_SETFD, FD_CLOEXEC);
207 #ifdef HAVE_PTHREAD_ATFORK
208 /* handle any other forks by closing daemonizefd first */
209 (void)pthread_atfork(NULL, NULL, closefd);
210 #endif /* HAVE_PTHREAD_ATFORK */
211 return 0;
212 }
213
daemonize_ready(int status,const char * message)214 void daemonize_ready(int status, const char *message)
215 {
216 int l;
217 if (daemonizefd >= 0)
218 {
219 /* we ignore any errors writing */
220 (void)write(daemonizefd, &status, sizeof(int));
221 if ((message == NULL) || (message[0] == '\0'))
222 {
223 l = 0;
224 (void)write(daemonizefd, &l, sizeof(int));
225 }
226 else
227 {
228 l = strlen(message);
229 (void)write(daemonizefd, &l, sizeof(int));
230 (void)write(daemonizefd, message, l);
231 }
232 (void)close(daemonizefd);
233 daemonizefd = -1;
234 }
235 }
236