Imported upstream version 0.60.1
[hcoop/debian/courier-authlib.git] / liblock / lockdaemon.c
1 /*
2 ** Copyright 2000-2007 Double Precision, Inc. See COPYING for
3 ** distribution information.
4 */
5
6 #include "config.h"
7 #include "liblock.h"
8 #include <stdio.h>
9 #include <signal.h>
10 #include <limits.h>
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
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
56 #define exit(_a_) _exit(_a_)
57
58 static const char rcsid[]="$Id: lockdaemon.c,v 1.13 2007/09/26 02:36:59 mrsam Exp $";
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
171 if (lockfd < 0 || dup2(lockfd, OPEN_MAX-1) != OPEN_MAX-1)
172 {
173 perror(lockfile);
174 exit(1);
175 }
176
177 close(lockfd);
178 lockfd=OPEN_MAX-1;
179
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