Bump version.
[shibboleth/cpp-sp.git] / shibd / shibd.cpp
index 49cbd79..4c86dae 100644 (file)
@@ -143,10 +143,19 @@ int real_main(int preinit)
 \r
         if (!shar_checkonly) {\r
             // Run the listener.\r
-            if (!conf.getServiceProvider()->getListenerService()->run(unlink_socket, &shibd_shutdown)) {\r
-                fprintf(stderr, "listener failed to enter listen loop\n");\r
+            ListenerService* listener = conf.getServiceProvider()->getListenerService();\r
+            if (!listener->init(unlink_socket)) {\r
+                fprintf(stderr, "listener failed to initialize\n");\r
+                conf.term();\r
                 return -3;\r
             }\r
+            else if (!listener->run(&shibd_shutdown)) {\r
+                fprintf(stderr, "listener failed during service\n");\r
+                listener->term();\r
+                conf.term();\r
+                return -3;\r
+            }\r
+            listener->term();\r
         }\r
 \r
         conf.term();\r
@@ -158,6 +167,7 @@ int real_main(int preinit)
 \r
 int daemon_wait = 3;\r
 bool shibd_running = false;\r
+bool daemonize = true;\r
 \r
 static void term_handler(int arg)\r
 {\r
@@ -169,6 +179,11 @@ static void run_handler(int arg)
     shibd_running = true;\r
 }\r
 \r
+static void child_handler(int arg)\r
+{\r
+    // Terminate the parent's wait/sleep if the newly born daemon dies early.\r
+}\r
+\r
 static int setup_signals(void)\r
 {\r
     struct sigaction sa;\r
@@ -197,11 +212,20 @@ static int setup_signals(void)
         return -1;\r
     }\r
 \r
-    memset(&sa, 0, sizeof (sa));\r
-    sa.sa_handler = run_handler;\r
+    if (daemonize) {\r
+        memset(&sa, 0, sizeof (sa));\r
+        sa.sa_handler = run_handler;\r
 \r
-    if (sigaction(SIGUSR1, &sa, NULL) < 0) {\r
-        return -1;\r
+        if (sigaction(SIGUSR1, &sa, NULL) < 0) {\r
+            return -1;\r
+        }\r
+\r
+        memset(&sa, 0, sizeof (sa));\r
+        sa.sa_handler = child_handler;\r
+\r
+        if (sigaction(SIGCHLD, &sa, NULL) < 0) {\r
+            return -1;\r
+        }\r
     }\r
 \r
     return 0;\r
@@ -213,8 +237,9 @@ static void usage(char* whoami)
     fprintf(stderr, "  -d\tinstallation prefix to use.\n");\r
     fprintf(stderr, "  -c\tconfig file to use.\n");\r
     fprintf(stderr, "  -x\tXML schema catalogs to use.\n");\r
-    fprintf(stderr, "  -t\tcheck configuration file for problems.\n");\r
+    fprintf(stderr, "  -t\ttest configuration file for problems.\n");\r
     fprintf(stderr, "  -f\tforce removal of listener socket.\n");\r
+    fprintf(stderr, "  -F\tstay in the foreground.\n");\r
     fprintf(stderr, "  -p\tpid file to use.\n");\r
     fprintf(stderr, "  -w\tseconds to wait for successful daemonization.\n");\r
     fprintf(stderr, "  -v\tprint software version.\n");\r
@@ -226,7 +251,7 @@ static int parse_args(int argc, char* argv[])
 {\r
     int opt;\r
 \r
-    while ((opt = getopt(argc, argv, "d:c:x:p:w:ftvh")) > 0) {\r
+    while ((opt = getopt(argc, argv, "d:c:x:p:w:fFtvh")) > 0) {\r
         switch (opt) {\r
             case 'd':\r
                 shar_prefix=optarg;\r
@@ -240,8 +265,12 @@ static int parse_args(int argc, char* argv[])
             case 'f':\r
                 unlink_socket = true;\r
                 break;\r
+            case 'F':\r
+                daemonize = false;\r
+                break;\r
             case 't':\r
                 shar_checkonly=true;\r
+                daemonize=false;\r
                 break;\r
             case 'v':\r
                 shar_version=true;\r
@@ -292,9 +321,9 @@ int main(int argc, char *argv[])
         return -1;\r
     }\r
 \r
-    // We must fork() early, while we're single threaded.\r
-    // StorageService cleanup thread is about to start.\r
-    if (!shar_checkonly) {\r
+    if (daemonize) {\r
+        // We must fork() early, while we're single threaded.\r
+        // StorageService cleanup thread is about to start.\r
         switch (fork()) {\r
             case 0:\r
                 break;\r
@@ -316,39 +345,53 @@ int main(int argc, char *argv[])
     if (shar_checkonly)\r
         fprintf(stderr, "overall configuration is loadable, check console for non-fatal problems\n");\r
     else {\r
-        if (setsid() == -1) {\r
-            perror("setsid");\r
-            exit(EXIT_FAILURE);\r
-        }\r
-        if (chdir("/") == -1) {\r
-            perror("chdir to root");\r
-            exit(EXIT_FAILURE);\r
+        // Init the listener.\r
+        ListenerService* listener = conf.getServiceProvider()->getListenerService();\r
+        if (!listener->init(unlink_socket)) {\r
+            fprintf(stderr, "listener failed to initialize\n");\r
+            conf.term();\r
+            return -3;\r
         }\r
 \r
-        // Write the pid file\r
-        if (pidfile) {\r
-            FILE* pidf = fopen(pidfile, "w");\r
-            if (pidf) {\r
-                fprintf(pidf, "%d\n", getpid());\r
-                fclose(pidf);\r
-            } else {\r
-                perror(pidfile);  // keep running though\r
+        if (daemonize) {\r
+            if (setsid() == -1) {\r
+                perror("setsid");\r
+                exit(EXIT_FAILURE);\r
+            }\r
+            if (chdir("/") == -1) {\r
+                perror("chdir to root");\r
+                exit(EXIT_FAILURE);\r
             }\r
-        }\r
 \r
-        freopen("/dev/null", "r", stdin);\r
-        freopen("/dev/null", "w", stdout);\r
-        freopen("/dev/null", "w", stderr);\r
+            if (pidfile) {\r
+                FILE* pidf = fopen(pidfile, "w");\r
+                if (pidf) {\r
+                    fprintf(pidf, "%d\n", getpid());\r
+                    fclose(pidf);\r
+                }\r
+                else {\r
+                    perror(pidfile);\r
+                }\r
+            }\r
 \r
-        // Run the listener\r
-        if (!conf.getServiceProvider()->getListenerService()->setSignal(SIGUSR1)) {\r
-            fprintf(stderr, "listener failed to accept signaling hook\n");\r
-            return -3;\r
+            freopen("/dev/null", "r", stdin);\r
+            freopen("/dev/null", "w", stdout);\r
+            freopen("/dev/null", "w", stderr);\r
+\r
+            // Signal our parent that we are A-OK.\r
+            kill(getppid(), SIGUSR1);\r
         }\r
-        if (!conf.getServiceProvider()->getListenerService()->run(unlink_socket, &shibd_shutdown)) {\r
-            fprintf(stderr, "listener failed to enter listen loop\n");\r
+\r
+        // Run the listener.\r
+        if (!listener->run(&shibd_shutdown)) {\r
+            fprintf(stderr, "listener failure during service\n");\r
+            listener->term();\r
+            conf.term();\r
+            if (pidfile)\r
+                unlink(pidfile);\r
             return -3;\r
         }\r
+        listener->term();\r
     }\r
 \r
     conf.term();\r