Merge branch 'debian'
[hcoop/debian/courier-authlib.git] / libs / liblock / lockdaemon.c
CommitLineData
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
34#define exit(_a_) _exit(_a_)
35
d9898ee8 36
37static int start1(const char *, int);
38
39#define CONSOLE "/dev/null"
40
41int ll_daemon_start(const char *lockfile)
42{
43pid_t p;
44int pipefd[2];
45char c;
46int 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
b0322a85 58 ** successfully initialized, and will return to main, so we exit(0).
d9898ee8 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
111static int start1(const char *lockfile, int fd)
112{
84870c69 113int lockfd, maxfd;
d9898ee8 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
84870c69 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)
d9898ee8 162 {
163 perror(lockfile);
164 exit(1);
165 }
166
dd184caf 167 close(lockfd);
84870c69 168 lockfd=maxfd;
dd184caf 169
d9898ee8 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
195int ll_daemon_resetio()
196{
197int 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
215void ll_daemon_started(const char *pidfile, int fd)
216{
217char buf[NUMBUFSIZE+1];
218char *p=strcat(libmail_str_pid_t(getpid(), buf), "\n");
219FILE *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
234static void stop1(const char *, const char *);
235
236int ll_daemon_stop(const char *lockfile, const char *pidfile)
237{
238pid_t p, p2;
239int 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
271static RETSIGTYPE sigexit(int signum)
272{
273 kill(getpid(), SIGKILL);
274#if RETSIGTYPE != void
275 return (0);
276#endif
277}
278
279static void stop1(const char *lockfile, const char *pidfile)
280{
281int lockfd;
282pid_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
338int ll_daemon_restart(const char *lockfile, const char *pidfile)
339{
340int lockfd;
341pid_t p;
342FILE *fp;
343int 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