Added option -D which puts pazpar2 in background. This improves the
authorAdam Dickmeiss <adam@indexdata.dk>
Mon, 18 Jun 2007 11:10:20 +0000 (11:10 +0000)
committerAdam Dickmeiss <adam@indexdata.dk>
Mon, 18 Jun 2007 11:10:20 +0000 (11:10 +0000)
startup process when pazpar2 is used in start scripts such as Debian's
start-stop-daemon. Without -D, pazpar2 would have to be started using
-b for start-stop-daemon. Refer to man page start-stop-daemon(8).
This change also makes pazpar2 change uid before the daemon is running.
We just ensure that HTTP binding and YAZ log files, PID files are dealt with
before any setuid takes place.. Pazpar2 makes log entry with version
info. The daemon mode refuses to start if -l is not given. This is to ensure
that logfile output is not dumped to /dev/null by accident.

src/pazpar2.c
src/pazpar2.h
src/process.c

index e3d6627..cacd539 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pazpar2.c,v 1.89 2007-06-12 13:02:38 adam Exp $
+/* $Id: pazpar2.c,v 1.90 2007-06-18 11:10:20 adam Exp $
    Copyright (c) 2006-2007, Index Data.
 
 This file is part of Pazpar2.
@@ -52,7 +52,9 @@ void child_handler(void *data)
 
 int main(int argc, char **argv)
 {
+    int daemon = 0;
     int ret;
+    int log_file_in_use = 0;
     char *arg;
     const char *pidfile = "pazpar2.pid";
     const char *uid = 0;
@@ -62,7 +64,7 @@ int main(int argc, char **argv)
 
     yaz_log_init_prefix("pazpar2");
 
-    while ((ret = options("f:h:p:t:u:l:dX", argv, argc, &arg)) != -2)
+    while ((ret = options("f:h:p:t:u:l:dDX", argv, argc, &arg)) != -2)
     {
        switch (ret)
         {
@@ -87,6 +89,10 @@ int main(int argc, char **argv)
             break;
         case 'l':
             yaz_log_init_file(arg);
+            log_file_in_use = 1;
+            break;
+        case 'D':
+            daemon = 1;
             break;
         case 'X':
             global_parameters.debug_mode = 1;
@@ -99,6 +105,7 @@ int main(int argc, char **argv)
                     "    -t settings\n"
                     "    -u uid\n"
                     "    -d                      (show internal records)\n"
+                    "    -D                      Daemon mode (background)\n"
                     "    -l file                 log to file\n"
                     "    -X                      debug mode\n"
                 );
@@ -106,6 +113,13 @@ int main(int argc, char **argv)
        }
     }
 
+    yaz_log(YLOG_LOG, "Pazpar2 %s started", VERSION);
+    if (daemon && !log_file_in_use)
+    {
+        yaz_log(YLOG_FATAL, "Logfile must be given (option -l) for daemon "
+                "mode");
+        exit(1);
+    }
     if (!config)
     {
         yaz_log(YLOG_FATAL, "Load config with -f");
@@ -114,7 +128,7 @@ int main(int argc, char **argv)
     global_parameters.server = config->servers;
 
     start_http_listener();
-    pazpar2_process(global_parameters.debug_mode,
+    pazpar2_process(global_parameters.debug_mode, daemon,
                     child_handler, 0 /* child_data */,
                     pidfile, uid);
     return 0;
index 58de6e9..38f566b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pazpar2.h,v 1.42 2007-06-15 19:35:17 adam Exp $
+/* $Id: pazpar2.h,v 1.43 2007-06-18 11:10:20 adam Exp $
    Copyright (c) 2006-2007, Index Data.
 
 This file is part of Pazpar2.
@@ -199,7 +199,7 @@ struct record *ingest_record(struct client *cl, Z_External *rec,
 void session_alert_watch(struct session *s, int what);
 void pull_terms(NMEM nmem, struct ccl_rpn_node *n, char **termlist, int *num);
 
-int pazpar2_process(int debug,
+int pazpar2_process(int debug, int daemon,
                     void (*work)(void *data), void *data,
                     const char *pidfile, const char *uid);
 
index 4f7ce94..9c11106 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.2 2007-06-12 13:02:38 adam Exp $
+/* $Id: process.c,v 1.3 2007-06-18 11:10:20 adam Exp $
    Copyright (c) 2006-2007, Index Data.
 
 This file is part of Pazpar2.
@@ -24,12 +24,15 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #endif
 
 #include <signal.h>
+#include <errno.h>
 #include <unistd.h>
 #include <assert.h>
 #include <stdlib.h>
 #include <signal.h>
 #include <sys/wait.h>
 #include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
 #include <pwd.h>
 
 #include <yaz/log.h>
@@ -58,17 +61,15 @@ void kill_child_handler(int num)
         kill(child_pid, num);
 }
 
-int pazpar2_process(int debug, 
+int pazpar2_process(int debug, int daemon,
                     void (*work)(void *data), void *data,
                     const char *pidfile, const char *uid /* not yet used */)
 {
-    struct passwd *pw = 0;
     int run = 1;
     int cont = 1;
     void (*old_sighup)(int);
     void (*old_sigterm)(int);
 
-
     if (debug)
     {
         /* in debug mode.. it's quite simple */
@@ -77,24 +78,72 @@ int pazpar2_process(int debug,
         exit(0);
     }
     
+    write_pidfile(pidfile);
     /* running in production mode. */
     if (uid)
     {
-        yaz_log(YLOG_LOG, "getpwnam");
-        // OK to use the non-thread version here
-        if (!(pw = getpwnam(uid)))
+        /* OK to use the non-thread version here */
+        struct passwd *pw = getpwnam(uid);
+        if (!pw)
         {
             yaz_log(YLOG_FATAL, "%s: Unknown user", uid);
             exit(1);
         }
+        if (setuid(pw->pw_uid) < 0)
+        {
+            yaz_log(YLOG_FATAL|YLOG_ERRNO, "setuid");
+            exit(1);
+        }
     }
-    
 
+    if (daemon)
+    {
+        /* create pipe so that parent waits until child has created
+           PID (or failed) */
+        static int hand[2]; /* hand shake for child */
+        if (pipe(hand) < 0)
+        {
+            yaz_log(YLOG_FATAL|YLOG_ERRNO, "pipe");
+            return 1;
+        }
+        switch (fork())
+        {
+        case 0: 
+            break;
+        case -1:
+            return 1;
+        default:
+            close(hand[1]);
+            while(1)
+            {
+                char dummy[1];
+                int res = read(hand[0], dummy, 1);
+                if (res < 0 && errno != EINTR)
+                {
+                    yaz_log(YLOG_FATAL|YLOG_ERRNO, "read fork handshake");
+                    break;
+                }
+                else if (res >= 0)
+                    break;
+            }
+            close(hand[0]);
+            _exit(0);
+        }
+        /* child */
+        close(hand[0]);
+        if (setsid() < 0)
+            return 1;
+        
+        close(0);
+        close(1);
+        close(2);
+        open("/dev/null", O_RDWR);
+        dup(0); dup(0);
+        close(hand[1]);
+    }
     /* keep signals in their original state and make sure that some signals
-       to parent process also gets sent to the child.. Normally this
-       should not happen. We want the _child_ process to be terminated
-       normally. However, if the parent process is terminated, we
-       kill the child too */
+       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)
@@ -114,17 +163,6 @@ int pazpar2_process(int debug,
             signal(SIGHUP, old_sighup);  /* restore */
             signal(SIGTERM, old_sigterm);/* restore */
 
-            write_pidfile(pidfile);
-
-            if (pw)
-            {
-                if (setuid(pw->pw_uid) < 0)
-                {
-                    yaz_log(YLOG_FATAL|YLOG_ERRNO, "setuid");
-                    exit(1);
-                }
-            }
-
             work(data);
             exit(0);
         }
@@ -133,7 +171,6 @@ int pazpar2_process(int debug,
         child_pid = p;
         
         p1 = wait(&status);
-        yaz_log_reopen();
 
         /* disable signalling in kill_child_handler */
         child_pid = 0;