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