Build courier-authlib 0.59.3-1hcoop1.
[hcoop/debian/courier-authlib.git] / liblock / lockdaemon.c
CommitLineData
d9898ee8 1/*
2** Copyright 2000-2006 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 <stdlib.h>
11#include <string.h>
12#include <unistd.h>
13#include <ctype.h>
14#include <errno.h>
15#if HAVE_FCNTL_H
16#include <fcntl.h>
17#endif
18#include <sys/types.h>
19#include "../numlib/numlib.h"
20#if HAVE_SYS_WAIT_H
21#include <sys/wait.h>
22#endif
23#ifndef WEXITSTATUS
24#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
25#endif
26#ifndef WIFEXITED
27#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
28#endif
29#if HAVE_SYS_IOCTL_H
30#include <sys/ioctl.h>
31#endif
32
33#define exit(_a_) _exit(_a_)
34
35static const char rcsid[]="$Id: lockdaemon.c,v 1.10 2006/05/28 15:29:52 mrsam Exp $";
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
58 ** succesfully 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
111static int start1(const char *lockfile, int fd)
112{
113int lockfd;
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 (lockfd < 0)
149 {
150 perror(lockfile);
151 exit(1);
152 }
153
154#ifdef FD_CLOEXEC
155 if (fcntl(lockfd, F_SETFD, FD_CLOEXEC) < 0)
156 {
157 perror("fcntl");
158 close(lockfd);
159 exit(1);
160 }
161#endif
162
163 if (ll_lock_ex_test(lockfd))
164 {
165 if (write(fd, "", 1) != 1)
166 exit(1); /* Shouldn't happen */
167
168 close(fd);
169 exit (0); /* Already running, pretend success */
170 }
171
172 /*
173 ** Return >0 to main, so it can continue main's setup.
174 */
175
176 return (fd);
177}
178
179int ll_daemon_resetio()
180{
181int i;
182
183 close(0);
184 if (open("/dev/null", O_RDONLY) != 0)
185 return (-1);
186
187 close(1);
188 i=open(CONSOLE, O_WRONLY);
189 if (i < 0) i=open("/dev/null", O_WRONLY);
190 if (i != 1) return (-1);
191
192 close(2);
193 i=open(CONSOLE, O_WRONLY);
194 if (i < 0) i=open("/dev/null", O_WRONLY);
195 if (i != 2) return (-1);
196 return (0);
197}
198
199void ll_daemon_started(const char *pidfile, int fd)
200{
201char buf[NUMBUFSIZE+1];
202char *p=strcat(libmail_str_pid_t(getpid(), buf), "\n");
203FILE *fp;
204
205 unlink(pidfile);
206 if ((fp=fopen(pidfile, "w")) == NULL ||
207 fprintf(fp, "%s", p) < 0 || fflush(fp) < 0 || fclose(fp))
208 {
209 perror(pidfile);
210 exit(1);
211 }
212
213 if (write(fd, "", 1) != 1) /* Signal waiting parent */
214 exit(1); /* Shouldn't happen */
215 close(fd);
216}
217
218static void stop1(const char *, const char *);
219
220int ll_daemon_stop(const char *lockfile, const char *pidfile)
221{
222pid_t p, p2;
223int waitstat;
224
225 /*
226 ** We fork, and the child process attempts to stop the daemon,
227 ** then communicates the success to us, via its exit code.
228 */
229
230 signal(SIGCHLD, SIG_DFL);
231 if ((p=fork()) == -1)
232 {
233 perror("fork");
234 return (1);
235 }
236 if (p == 0) stop1(lockfile, pidfile);
237
238 while ((p2=wait(&waitstat)) != p)
239 ;
240
241 if (WIFEXITED(waitstat))
242 return (WEXITSTATUS(waitstat));
243 return (0);
244}
245
246/*
247** The child process forks too. The parent process goes in a loop,
248** trying to kill the daemon process.
249**
250** The child process attempts to lock the lock file. When it
251** succeeds, it exits. When the child process exits, the parent
252** process kills itself.
253*/
254
255static RETSIGTYPE sigexit(int signum)
256{
257 kill(getpid(), SIGKILL);
258#if RETSIGTYPE != void
259 return (0);
260#endif
261}
262
263static void stop1(const char *lockfile, const char *pidfile)
264{
265int lockfd;
266pid_t p;
267
268 if ((lockfd=open(lockfile, O_RDWR|O_CREAT, 0600)) < 0)
269 {
270 perror(lockfile);
271 exit(1);
272 }
273
274 if ( ll_lock_ex_test(lockfd) == 0) /* No daemon process running */
275 {
276 close(lockfd);
277 exit (0); /* That was easy! */
278 }
279
280 signal(SIGCHLD, sigexit);
281
282 if ((p=fork()) == -1)
283 {
284 perror("fork");
285 exit(1);
286 }
287
288 if (p) /* Parent - first sends a SIGTERM, then a SIGKILL */
289 {
290 int signum=SIGTERM;
291
292 close(lockfd);
293 for (;; sleep(10))
294 {
295 FILE *fp;
296 int c;
297
298 if ((fp=fopen(pidfile, "r")) == NULL)
299 continue;
300
301 p=0;
302
303 while ((c=getc(fp)) != EOF && c != '\n')
304 {
305 if (isdigit(c))
306 p=p*10+(c-'0');
307 }
308
309 fclose(fp);
310 if (p)
311 kill(p, signum);
312 signum=SIGKILL;
313 }
314 }
315
316 if (ll_lock_ex(lockfd))
317 perror("lock");
318 close(lockfd);
319 exit(0);
320}
321
322int ll_daemon_restart(const char *lockfile, const char *pidfile)
323{
324int lockfd;
325pid_t p;
326FILE *fp;
327int c;
328
329 if ((lockfd=open(lockfile, O_RDWR|O_CREAT, 0600)) < 0)
330 {
331 perror(lockfile);
332 return (1);
333 }
334
335 if ( ll_lock_ex_test(lockfd) == 0) /* No daemon process running */
336 {
337 close(lockfd);
338 return (0); /* That was easy! */
339 }
340 close(lockfd);
341
342 if ((fp=fopen(pidfile, "r")) == NULL)
343 return (0);
344
345 p=0;
346
347 while ((c=getc(fp)) != EOF && c != '\n')
348 {
349 if (isdigit(c))
350 p=p*10+(c-'0');
351 }
352
353 fclose(fp);
354 if (p)
355 kill(p, SIGHUP);
356 return (0);
357}
358