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