X-Git-Url: http://git.indexdata.com/?p=yaz-moved-to-github.git;a=blobdiff_plain;f=src%2Fdaemon.c;h=3a8bb428ac287e5e5b17ba60fa73e022feadd5e6;hp=5f5ffc5f57e4bbf8bb8d05afbbb41c2a4eb228b4;hb=f16fe49dbe30ef1e846958a09c0d2924a24c9be5;hpb=2788a4851b551e1a3efb320a2878b809f2d8a9d7 diff --git a/src/daemon.c b/src/daemon.c index 5f5ffc5..3a8bb42 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -1,5 +1,5 @@ /* This file is part of the YAZ toolkit. - * Copyright (C) 1995-2009 Index Data + * Copyright (C) Index Data * See the file LICENSE for details. */ @@ -33,6 +33,10 @@ #include #endif +#if HAVE_SYS_PRCTL_H +#include +#endif + #include #include #include @@ -49,7 +53,7 @@ static void write_pidfile(int pid_fd) yaz_log(YLOG_FATAL|YLOG_ERRNO, "ftruncate"); exit(1); } - if (write(pid_fd, buf, strlen(buf)) != strlen(buf)) + if (write(pid_fd, buf, strlen(buf)) != (int) strlen(buf)) { yaz_log(YLOG_FATAL|YLOG_ERRNO, "write"); exit(1); @@ -58,79 +62,118 @@ static void write_pidfile(int pid_fd) } } +int child_got_signal_from_us = 0; pid_t child_pid = 0; -static void kill_child_handler(int num) +static void normal_stop_handler(int num) { if (child_pid) + { + /* relay signal to child */ + child_got_signal_from_us = 1; kill(child_pid, num); + } +} + +static void sigusr2_handler(int num) +{ } +static pid_t keepalive_pid = 0; + static void keepalive(void (*work)(void *data), void *data) { + int no_sigill = 0; + int no_sigabrt = 0; + int no_sigsegv = 0; + int no_sigbus = 0; int run = 1; int cont = 1; void (*old_sighup)(int); void (*old_sigterm)(int); - + void (*old_sigusr1)(int); + struct sigaction sa2, sa1; + + keepalive_pid = getpid(); + /* keep signals in their original state and make sure that some signals - to parent process also gets sent to the child.. - */ - old_sighup = signal(SIGHUP, kill_child_handler); - old_sigterm = signal(SIGTERM, kill_child_handler); - while (cont) + to parent process also gets sent to the child.. */ + old_sighup = signal(SIGHUP, normal_stop_handler); + old_sigterm = signal(SIGTERM, normal_stop_handler); + old_sigusr1 = signal(SIGUSR1, normal_stop_handler); + + sigemptyset(&sa2.sa_mask); + sa2.sa_handler = sigusr2_handler; + sa2.sa_flags = 0; + sigaction(SIGUSR2, &sa2, &sa1); + + while (cont && !child_got_signal_from_us) { pid_t p = fork(); pid_t p1; int status; if (p == (pid_t) (-1)) { - yaz_log(YLOG_FATAL|YLOG_ERRNO, "fork"); exit(1); } else if (p == 0) { - /* child */ + /* child */ signal(SIGHUP, old_sighup); /* restore */ signal(SIGTERM, old_sigterm);/* restore */ - + signal(SIGUSR1, old_sigusr1);/* restore */ + sigaction(SIGUSR2, &sa1, NULL); + work(data); exit(0); } - + /* enable signalling in kill_child_handler */ child_pid = p; - - p1 = wait(&status); - + + p1 = waitpid(p, &status, 0); + /* disable signalling in kill_child_handler */ child_pid = 0; - + + if (p1 == (pid_t)(-1)) + { + if (errno != EINTR) + { + yaz_log(YLOG_FATAL|YLOG_ERRNO, "waitpid"); + break; + } + continue; + } if (p1 != p) { yaz_log(YLOG_FATAL, "p1=%d != p=%d", p1, p); - exit(1); + break; } - if (WIFSIGNALED(status)) { /* keep the child alive in case of errors, but _log_ */ - switch(WTERMSIG(status)) { + switch (WTERMSIG(status)) + { case SIGILL: yaz_log(YLOG_WARN, "Received SIGILL from child %ld", (long) p); cont = 1; + no_sigill++; break; case SIGABRT: yaz_log(YLOG_WARN, "Received SIGABRT from child %ld", (long) p); cont = 1; + no_sigabrt++; break ; case SIGSEGV: yaz_log(YLOG_WARN, "Received SIGSEGV from child %ld", (long) p); cont = 1; + ++no_sigsegv; break; - case SIGBUS: + case SIGBUS: yaz_log(YLOG_WARN, "Received SIGBUS from child %ld", (long) p); cont = 1; + no_sigbus++; break; case SIGTERM: yaz_log(YLOG_LOG, "Received SIGTERM from child %ld", @@ -143,20 +186,40 @@ static void keepalive(void (*work)(void *data), void *data) cont = 0; } } - else if (status == 0) - cont = 0; /* child exited normally */ - else - { /* child exited with error */ - yaz_log(YLOG_LOG, "Exit %d from child %ld", status, (long) p); + else if (WIFEXITED(status)) + { cont = 0; + if (WEXITSTATUS(status) != 0) + { /* child exited with error */ + yaz_log(YLOG_LOG, "Exit %d from child %ld", + WEXITSTATUS(status), (long) p); + } } if (cont) /* respawn slower as we get more errors */ sleep(1 + run/5); run++; } + if (no_sigill) + yaz_log(YLOG_WARN, "keepalive stop. %d SIGILL signal(s)", no_sigill); + if (no_sigabrt) + yaz_log(YLOG_WARN, "keepalive stop. %d SIGABRT signal(s)", no_sigabrt); + if (no_sigsegv) + yaz_log(YLOG_WARN, "keepalive stop. %d SIGSEGV signal(s)", no_sigsegv); + if (no_sigbus) + yaz_log(YLOG_WARN, "keepalive stop. %d SIGBUS signal(s)", no_sigbus); + yaz_log(YLOG_LOG, "keepalive stop"); } #endif +void yaz_daemon_stop(void) +{ +#if HAVE_PWD_H + if (keepalive_pid) + kill(keepalive_pid, SIGUSR2); /* invoke immediate_exit_handler */ +#endif +} + + int yaz_daemon(const char *progname, unsigned int flags, void (*work)(void *data), void *data, @@ -199,6 +262,13 @@ int yaz_daemon(const char *progname, yaz_log(YLOG_FATAL|YLOG_ERRNO, "setuid"); exit(1); } + /* Linux don't produce core dumps evern if the limit is right and + files are writable.. This fixes this. See prctl(2) */ +#if HAVE_SYS_PRCTL_H +#ifdef PR_SET_DUMPABLE + prctl(PR_SET_DUMPABLE, 1, 0, 0); +#endif +#endif } if (flags & YAZ_DAEMON_FORK) @@ -213,7 +283,7 @@ int yaz_daemon(const char *progname, } switch (fork()) { - case 0: + case 0: break; case -1: return 1; @@ -238,7 +308,7 @@ int yaz_daemon(const char *progname, close(hand[0]); if (setsid() < 0) return 1; - + close(0); close(1); close(2); @@ -270,7 +340,9 @@ int yaz_daemon(const char *progname, /* * Local variables: * c-basic-offset: 4 + * c-file-style: "Stroustrup" * indent-tabs-mode: nil * End: * vim: shiftwidth=4 tabstop=8 expandtab */ +