d9898ee8 |
1 | /* |
dd184caf |
2 | ** Copyright 2000-2007 Double Precision, Inc. See COPYING for |
d9898ee8 |
3 | ** distribution information. |
4 | */ |
5 | |
6 | #include "config.h" |
7 | #include "liblock.h" |
8 | #include <stdio.h> |
9 | #include <signal.h> |
dd184caf |
10 | #include <limits.h> |
d9898ee8 |
11 | #include <stdlib.h> |
12 | #include <string.h> |
13 | #include <unistd.h> |
14 | #include <ctype.h> |
15 | #include <errno.h> |
16 | #if HAVE_FCNTL_H |
17 | #include <fcntl.h> |
18 | #endif |
19 | #include <sys/types.h> |
20 | #include "../numlib/numlib.h" |
21 | #if HAVE_SYS_WAIT_H |
22 | #include <sys/wait.h> |
23 | #endif |
24 | #ifndef WEXITSTATUS |
25 | #define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) |
26 | #endif |
27 | #ifndef WIFEXITED |
28 | #define WIFEXITED(stat_val) (((stat_val) & 255) == 0) |
29 | #endif |
30 | #if HAVE_SYS_IOCTL_H |
31 | #include <sys/ioctl.h> |
32 | #endif |
33 | |
dd184caf |
34 | #ifndef OPEN_MAX |
35 | #ifdef HAVE_SYSCONF |
36 | #ifdef _SC_OPEN_MAX |
37 | #define OPEN_MAX (my_open_max()) |
38 | |
39 | static int my_open_max() |
40 | { |
41 | long n=sysconf(_SC_OPEN_MAX); |
42 | |
43 | if (n == -1) |
44 | n=64; |
45 | return n; |
46 | } |
47 | |
48 | #endif |
49 | #endif |
50 | #endif |
51 | |
52 | #ifndef OPEN_MAX |
53 | #define OPEN_MAX 64 |
54 | #endif |
55 | |
d9898ee8 |
56 | #define exit(_a_) _exit(_a_) |
57 | |
dd184caf |
58 | static const char rcsid[]="$Id: lockdaemon.c,v 1.13 2007/09/26 02:36:59 mrsam Exp $"; |
d9898ee8 |
59 | |
60 | static int start1(const char *, int); |
61 | |
62 | #define CONSOLE "/dev/null" |
63 | |
64 | int ll_daemon_start(const char *lockfile) |
65 | { |
66 | pid_t p; |
67 | int pipefd[2]; |
68 | char c; |
69 | int i; |
70 | |
71 | /* |
72 | ** Close any open file descriptors. |
73 | */ |
74 | |
75 | for (i=3; i < 256; i++) |
76 | close(i); |
77 | |
78 | /* |
79 | ** We fork, and set up a pipe from the child process. If we read |
80 | ** a single 0 byte from the pipe, it means that the child has |
81 | ** succesfully initialized, and will return to main, so we exit(0). |
82 | ** If we do not read a single 0 byte from the pipe, it means that |
83 | ** there was an initialization error, so we return -1 to main. |
84 | */ |
85 | |
86 | if (pipe(pipefd) < 0) |
87 | { |
88 | perror("pipe"); |
89 | return (-1); |
90 | } |
91 | |
92 | if ((p=fork()) == -1) |
93 | { |
94 | close(pipefd[0]); |
95 | close(pipefd[1]); |
96 | perror("fork"); |
97 | return (-1); |
98 | } |
99 | |
100 | if (p == 0) |
101 | { |
102 | close(pipefd[0]); |
103 | |
104 | /* |
105 | ** We fork once more, so that the daemon process will not |
106 | ** be the child process of anyone. |
107 | */ |
108 | |
109 | p=fork(); |
110 | if (p == -1) |
111 | { |
112 | perror("fork"); |
113 | exit(0); |
114 | } |
115 | if (p) |
116 | exit(0); |
117 | |
118 | /* |
119 | ** Continue initialization in start1() |
120 | */ |
121 | return (start1(lockfile, pipefd[1])); |
122 | } |
123 | |
124 | close(pipefd[1]); |
125 | if (read(pipefd[0], &c, 1) <= 0) |
126 | c=1; |
127 | close(pipefd[0]); |
128 | if (c == 0) |
129 | exit (0); /* Successful start of daemon */ |
130 | errno=EAGAIN; |
131 | return (-1); |
132 | } |
133 | |
134 | static int start1(const char *lockfile, int fd) |
135 | { |
136 | int lockfd; |
137 | |
138 | #if HAVE_SETPGRP |
139 | #if SETPGRP_VOID |
140 | setpgrp(); |
141 | #else |
142 | setpgrp(0, 0); |
143 | #endif |
144 | #endif |
145 | #ifdef TIOCNOTTY |
146 | |
147 | { |
148 | int fd=open("/dev/tty", O_RDWR); |
149 | |
150 | if (fd >= 0) |
151 | { |
152 | ioctl(fd, TIOCNOTTY, 0); |
153 | close(fd); |
154 | } |
155 | } |
156 | #endif |
157 | |
158 | |
159 | /* Attempt to obtain a lock */ |
160 | |
161 | lockfd=open(lockfile, O_RDWR|O_CREAT, 0600); |
162 | |
163 | if (lockfd < 0) |
164 | { |
165 | /* Perhaps an upgraded daemon runs under new uid? */ |
166 | |
167 | unlink(lockfile); |
168 | lockfd=open(lockfile, O_RDWR|O_CREAT, 0600); |
169 | } |
170 | |
dd184caf |
171 | if (lockfd < 0 || dup2(lockfd, OPEN_MAX-1) != OPEN_MAX-1) |
d9898ee8 |
172 | { |
173 | perror(lockfile); |
174 | exit(1); |
175 | } |
176 | |
dd184caf |
177 | close(lockfd); |
178 | lockfd=OPEN_MAX-1; |
179 | |
d9898ee8 |
180 | #ifdef FD_CLOEXEC |
181 | if (fcntl(lockfd, F_SETFD, FD_CLOEXEC) < 0) |
182 | { |
183 | perror("fcntl"); |
184 | close(lockfd); |
185 | exit(1); |
186 | } |
187 | #endif |
188 | |
189 | if (ll_lock_ex_test(lockfd)) |
190 | { |
191 | if (write(fd, "", 1) != 1) |
192 | exit(1); /* Shouldn't happen */ |
193 | |
194 | close(fd); |
195 | exit (0); /* Already running, pretend success */ |
196 | } |
197 | |
198 | /* |
199 | ** Return >0 to main, so it can continue main's setup. |
200 | */ |
201 | |
202 | return (fd); |
203 | } |
204 | |
205 | int ll_daemon_resetio() |
206 | { |
207 | int i; |
208 | |
209 | close(0); |
210 | if (open("/dev/null", O_RDONLY) != 0) |
211 | return (-1); |
212 | |
213 | close(1); |
214 | i=open(CONSOLE, O_WRONLY); |
215 | if (i < 0) i=open("/dev/null", O_WRONLY); |
216 | if (i != 1) return (-1); |
217 | |
218 | close(2); |
219 | i=open(CONSOLE, O_WRONLY); |
220 | if (i < 0) i=open("/dev/null", O_WRONLY); |
221 | if (i != 2) return (-1); |
222 | return (0); |
223 | } |
224 | |
225 | void ll_daemon_started(const char *pidfile, int fd) |
226 | { |
227 | char buf[NUMBUFSIZE+1]; |
228 | char *p=strcat(libmail_str_pid_t(getpid(), buf), "\n"); |
229 | FILE *fp; |
230 | |
231 | unlink(pidfile); |
232 | if ((fp=fopen(pidfile, "w")) == NULL || |
233 | fprintf(fp, "%s", p) < 0 || fflush(fp) < 0 || fclose(fp)) |
234 | { |
235 | perror(pidfile); |
236 | exit(1); |
237 | } |
238 | |
239 | if (write(fd, "", 1) != 1) /* Signal waiting parent */ |
240 | exit(1); /* Shouldn't happen */ |
241 | close(fd); |
242 | } |
243 | |
244 | static void stop1(const char *, const char *); |
245 | |
246 | int ll_daemon_stop(const char *lockfile, const char *pidfile) |
247 | { |
248 | pid_t p, p2; |
249 | int waitstat; |
250 | |
251 | /* |
252 | ** We fork, and the child process attempts to stop the daemon, |
253 | ** then communicates the success to us, via its exit code. |
254 | */ |
255 | |
256 | signal(SIGCHLD, SIG_DFL); |
257 | if ((p=fork()) == -1) |
258 | { |
259 | perror("fork"); |
260 | return (1); |
261 | } |
262 | if (p == 0) stop1(lockfile, pidfile); |
263 | |
264 | while ((p2=wait(&waitstat)) != p) |
265 | ; |
266 | |
267 | if (WIFEXITED(waitstat)) |
268 | return (WEXITSTATUS(waitstat)); |
269 | return (0); |
270 | } |
271 | |
272 | /* |
273 | ** The child process forks too. The parent process goes in a loop, |
274 | ** trying to kill the daemon process. |
275 | ** |
276 | ** The child process attempts to lock the lock file. When it |
277 | ** succeeds, it exits. When the child process exits, the parent |
278 | ** process kills itself. |
279 | */ |
280 | |
281 | static RETSIGTYPE sigexit(int signum) |
282 | { |
283 | kill(getpid(), SIGKILL); |
284 | #if RETSIGTYPE != void |
285 | return (0); |
286 | #endif |
287 | } |
288 | |
289 | static void stop1(const char *lockfile, const char *pidfile) |
290 | { |
291 | int lockfd; |
292 | pid_t p; |
293 | |
294 | if ((lockfd=open(lockfile, O_RDWR|O_CREAT, 0600)) < 0) |
295 | { |
296 | perror(lockfile); |
297 | exit(1); |
298 | } |
299 | |
300 | if ( ll_lock_ex_test(lockfd) == 0) /* No daemon process running */ |
301 | { |
302 | close(lockfd); |
303 | exit (0); /* That was easy! */ |
304 | } |
305 | |
306 | signal(SIGCHLD, sigexit); |
307 | |
308 | if ((p=fork()) == -1) |
309 | { |
310 | perror("fork"); |
311 | exit(1); |
312 | } |
313 | |
314 | if (p) /* Parent - first sends a SIGTERM, then a SIGKILL */ |
315 | { |
316 | int signum=SIGTERM; |
317 | |
318 | close(lockfd); |
319 | for (;; sleep(10)) |
320 | { |
321 | FILE *fp; |
322 | int c; |
323 | |
324 | if ((fp=fopen(pidfile, "r")) == NULL) |
325 | continue; |
326 | |
327 | p=0; |
328 | |
329 | while ((c=getc(fp)) != EOF && c != '\n') |
330 | { |
331 | if (isdigit(c)) |
332 | p=p*10+(c-'0'); |
333 | } |
334 | |
335 | fclose(fp); |
336 | if (p) |
337 | kill(p, signum); |
338 | signum=SIGKILL; |
339 | } |
340 | } |
341 | |
342 | if (ll_lock_ex(lockfd)) |
343 | perror("lock"); |
344 | close(lockfd); |
345 | exit(0); |
346 | } |
347 | |
348 | int ll_daemon_restart(const char *lockfile, const char *pidfile) |
349 | { |
350 | int lockfd; |
351 | pid_t p; |
352 | FILE *fp; |
353 | int c; |
354 | |
355 | if ((lockfd=open(lockfile, O_RDWR|O_CREAT, 0600)) < 0) |
356 | { |
357 | perror(lockfile); |
358 | return (1); |
359 | } |
360 | |
361 | if ( ll_lock_ex_test(lockfd) == 0) /* No daemon process running */ |
362 | { |
363 | close(lockfd); |
364 | return (0); /* That was easy! */ |
365 | } |
366 | close(lockfd); |
367 | |
368 | if ((fp=fopen(pidfile, "r")) == NULL) |
369 | return (0); |
370 | |
371 | p=0; |
372 | |
373 | while ((c=getc(fp)) != EOF && c != '\n') |
374 | { |
375 | if (isdigit(c)) |
376 | p=p*10+(c-'0'); |
377 | } |
378 | |
379 | fclose(fp); |
380 | if (p) |
381 | kill(p, SIGHUP); |
382 | return (0); |
383 | } |
384 | |