2 * Copyright (C) 1995-2008, Index Data ApS
3 * See the file LICENSE for details.
5 * $Id: daemon.c,v 1.1 2008-02-18 17:07:06 adam Exp $
10 * \brief Unix daemon management
25 #include <sys/types.h>
30 #include <yaz/daemon.h>
32 #include <yaz/snprintf.h>
34 static void write_pidfile(int pid_fd)
39 yaz_snprintf(buf, sizeof(buf), "%ld", (long) getpid());
40 if (ftruncate(pid_fd, 0))
42 yaz_log(YLOG_FATAL|YLOG_ERRNO, "ftruncate");
45 if (write(pid_fd, buf, strlen(buf)) != strlen(buf))
47 yaz_log(YLOG_FATAL|YLOG_ERRNO, "write");
55 static void kill_child_handler(int num)
61 static void keepalive(void (*work)(void *data), void *data)
65 void (*old_sighup)(int);
66 void (*old_sigterm)(int);
68 /* keep signals in their original state and make sure that some signals
69 to parent process also gets sent to the child..
71 old_sighup = signal(SIGHUP, kill_child_handler);
72 old_sigterm = signal(SIGTERM, kill_child_handler);
78 if (p == (pid_t) (-1))
81 yaz_log(YLOG_FATAL|YLOG_ERRNO, "fork");
87 signal(SIGHUP, old_sighup); /* restore */
88 signal(SIGTERM, old_sigterm);/* restore */
94 /* enable signalling in kill_child_handler */
99 /* disable signalling in kill_child_handler */
104 yaz_log(YLOG_FATAL, "p1=%d != p=%d", p1, p);
108 if (WIFSIGNALED(status))
110 /* keep the child alive in case of errors, but _log_ */
111 switch(WTERMSIG(status)) {
113 yaz_log(YLOG_WARN, "Received SIGILL from child %ld", (long) p);
117 yaz_log(YLOG_WARN, "Received SIGABRT from child %ld", (long) p);
121 yaz_log(YLOG_WARN, "Received SIGSEGV from child %ld", (long) p);
125 yaz_log(YLOG_WARN, "Received SIGBUS from child %ld", (long) p);
129 yaz_log(YLOG_LOG, "Received SIGTERM from child %ld",
134 yaz_log(YLOG_WARN, "Received SIG %d from child %ld",
135 WTERMSIG(status), (long) p);
139 else if (status == 0)
140 cont = 0; /* child exited normally */
142 { /* child exited with error */
143 yaz_log(YLOG_LOG, "Exit %d from child %ld", status, (long) p);
146 if (cont) /* respawn slower as we get more errors */
152 int yaz_daemon(const char *progname,
154 void (*work)(void *data), void *data,
155 const char *pidfile, const char *uid)
159 /* open pidfile .. defer write until in child and after setuid */
162 pid_fd = open(pidfile, O_CREAT|O_RDWR, 0666);
165 yaz_log(YLOG_FATAL|YLOG_ERRNO, "open %s", pidfile);
170 if (flags & YAZ_DAEMON_DEBUG)
172 /* in debug mode.. it's quite simple */
173 write_pidfile(pid_fd);
178 /* running in production mode. */
181 /* OK to use the non-thread version here */
182 struct passwd *pw = getpwnam(uid);
185 yaz_log(YLOG_FATAL, "%s: Unknown user", uid);
188 if (setuid(pw->pw_uid) < 0)
190 yaz_log(YLOG_FATAL|YLOG_ERRNO, "setuid");
195 if (flags & YAZ_DAEMON_FORK)
197 /* create pipe so that parent waits until child has created
199 static int hand[2]; /* hand shake for child */
202 yaz_log(YLOG_FATAL|YLOG_ERRNO, "pipe");
216 int res = read(hand[0], dummy, 1);
217 if (res < 0 && errno != EINTR)
219 yaz_log(YLOG_FATAL|YLOG_ERRNO, "read fork handshake");
236 open("/dev/null", O_RDWR);
241 write_pidfile(pid_fd);
243 if (flags & YAZ_DAEMON_KEEPALIVE)
245 keepalive(work, data);
257 * indent-tabs-mode: nil
259 * vim: shiftwidth=4 tabstop=8 expandtab