You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by tr...@apache.org on 2014/07/23 23:18:27 UTC

svn commit: r1612946 - /qpid/dispatch/trunk/router/src/main.c

Author: tross
Date: Wed Jul 23 21:18:26 2014
New Revision: 1612946

URL: http://svn.apache.org/r1612946
Log:
DISPATCH-63 - Added daemon mode to the main module.

Modified:
    qpid/dispatch/trunk/router/src/main.c

Modified: qpid/dispatch/trunk/router/src/main.c
URL: http://svn.apache.org/viewvc/qpid/dispatch/trunk/router/src/main.c?rev=1612946&r1=1612945&r2=1612946&view=diff
==============================================================================
--- qpid/dispatch/trunk/router/src/main.c (original)
+++ qpid/dispatch/trunk/router/src/main.c Wed Jul 23 21:18:26 2014
@@ -21,6 +21,9 @@
 #include <qpid/dispatch.h>
 #include <signal.h>
 #include <sys/types.h>
+#include <sys/stat.h>
+#include <pwd.h>
+#include <fcntl.h>
 #include <unistd.h>
 #include <getopt.h>
 #include "config.h"
@@ -76,29 +79,210 @@ static void server_signal_handler(void* 
     qd_server_resume(dispatch);
 }
 
-static void check() {
+static void check(int fd) {
     if (qd_error_code()) {
 	qd_log(log_source, QD_LOG_CRITICAL, "Router start-up failed: %s", qd_error_message());
+    if (fd > 0)
+        write(fd, "X", 1);
 	exit(1);
     }
 }
 
+
+static void main_process(const char *config_path, const char *python_pkgdir, const char *qpid_dispatch_lib, int fd)
+{
+    qd_error_clear();
+    dispatch = qd_dispatch(python_pkgdir, qpid_dispatch_lib);
+    check(fd);
+    log_source = qd_log_source("MAIN"); /* Logging is initialized by qd_dispatch. */
+    qd_dispatch_load_config(dispatch, config_path);
+    check(fd);
+
+    (void)server_signal_handler; (void)thread_start_handler;(void)signal_handler;
+    qd_server_set_signal_handler(dispatch, server_signal_handler, 0);
+    qd_server_set_start_handler(dispatch, thread_start_handler, 0);
+
+    signal(SIGHUP,  signal_handler);
+    signal(SIGQUIT, signal_handler);
+    signal(SIGTERM, signal_handler);
+    signal(SIGINT,  signal_handler);
+
+    if (fd > 0) {
+        write(fd, "0", 1); // Success signal
+        close(fd);
+    }
+
+    qd_server_run(dispatch);
+    qd_dispatch_free(dispatch);
+
+    if (exit_with_sigint) {
+        signal(SIGINT, SIG_DFL);
+        kill(getpid(), SIGINT);
+    }
+}
+
+
+static void daemon_process(const char *config_path, const char *python_pkgdir, const char *qpid_dispatch_lib,
+                           const char *pidfile, const char *user)
+{
+    int pipefd[2];
+
+    //
+    // This daemonization process is based on that outlined in the
+    // "daemon" manpage from Linux.
+    //
+
+    //
+    // Create an unnamed pipe for communication from the daemon to the main process
+    //
+    if (pipe(pipefd) < 0) {
+        perror("Error creating inter-process pipe");
+        exit(1);
+    }
+
+    //
+    // First fork
+    //
+    pid_t pid = fork();
+    if (pid == 0) {
+        //
+        // Child Process
+        //
+
+        //
+        // Detach any terminals and create an independent session
+        //
+        if (setsid() < 0) {
+            write(pipefd[1], "1", 1);
+            exit(0);
+        }
+
+        //
+        // Second fork
+        //
+        pid_t pid2 = fork();
+        if (pid2 == 0) {
+            close(pipefd[0]); // Close read end.
+
+            //
+            // Assign stdin, stdout, and stderr to /dev/null
+            //
+            close(2);
+            close(1);
+            close(0);
+            int fd = open("/dev/null", O_RDWR);
+            if (fd != 0) {
+                write(pipefd[1], "2", 1);
+                exit(0);
+            }
+            if (dup(fd) < 0) {
+                write(pipefd[1], "3", 1);
+                exit(0);
+            }
+            if (dup(fd) < 0) {
+                write(pipefd[1], "4", 1);
+                exit(0);
+            }
+
+            //
+            // Set the umask to 0
+            //
+            if (umask(0) < 0) {
+                write(pipefd[1], "5", 1);
+                exit(0);
+            }
+
+            //
+            // Set the current directory to "/" to avoid blocking
+            // mount points
+            //
+            if (chdir("/") < 0) {
+                write(pipefd[1], "6", 1);
+                exit(0);
+            }
+
+            //
+            // If a pidfile was provided, write the daemon pid there.
+            //
+            if (pidfile) {
+                FILE *pf = fopen(pidfile, "w");
+                if (pf == 0) {
+                    write(pipefd[1], "7", 1);
+                    exit(0);
+                }
+                fprintf(pf, "%d\n", getpid());
+                fclose(pf);
+            }
+
+            //
+            // If a user was provided, drop privileges to the user's
+            // privilege level.
+            //
+            if (user) {
+                struct passwd *pwd = getpwnam(user);
+                if (pwd == 0) {
+                    write(pipefd[1], "8", 1);
+                    exit(0);
+                }
+                if (setuid(pwd->pw_uid) < 0) {
+                    write(pipefd[1], "9", 1);
+                    exit(0);
+                }
+                if (setgid(pwd->pw_gid) < 0) {
+                    write(pipefd[1], "A", 1);
+                    exit(0);
+                }
+            }
+
+            main_process(config_path, python_pkgdir, qpid_dispatch_lib, pipefd[1]);
+        } else
+            //
+            // Exit first child
+            //
+            exit(0);
+    } else {
+        //
+        // Parent Process
+        // Wait for a success signal ('0') from the daemon process.
+        // If we get success, exit with 0.  Otherwise, exit with 1.
+        //
+        char code;
+        close(pipefd[1]); // Close write end.
+        if (read(pipefd[0], &code, 1) < 0) {
+            perror("Error reading inter-process pipe");
+            exit(1);
+        }
+
+        if (code == '0')
+            exit(0);
+        fprintf(stderr, "Error occurred during daemon initialization, please see logs.  [code=%c]\n", code);
+        exit(1);
+    }
+}
+
+
 int main(int argc, char **argv)
 {
 #define DEFAULT_DISPATCH_PYTHON_DIR QPID_DISPATCH_HOME_INSTALLED "/python"
     const char *config_path   = DEFAULT_CONFIG_PATH;
     const char *python_pkgdir = DEFAULT_DISPATCH_PYTHON_DIR;
     const char *qpid_dispatch_lib = QPID_DISPATCH_LIB;
+    const char *pidfile = 0;
+    const char *user    = 0;
+    bool        daemon_mode = false;
 
     static struct option long_options[] = {
     {"config",  required_argument, 0, 'c'},
     {"include", required_argument, 0, 'I'},
+    {"daemon",  no_argument,       0, 'd'},
+    {"pidfile", required_argument, 0, 'P'},
+    {"user",    required_argument, 0, 'U'},
     {"help",    no_argument,       0, 'h'},
     {0,         0,                 0,  0}
     };
 
     while (1) {
-        int c = getopt_long(argc, argv, "c:I:h", long_options, 0);
+        int c = getopt_long(argc, argv, "c:I:dP:U:h", long_options, 0);
         if (c == -1)
             break;
 
@@ -111,12 +295,27 @@ int main(int argc, char **argv)
             python_pkgdir = optarg;
             break;
 
+        case 'd' :
+            daemon_mode = true;
+            break;
+
+        case 'P' :
+            pidfile = optarg;
+            break;
+
+        case 'U' :
+            user = optarg;
+            break;
+
         case 'h' :
-            printf("Usage: %s [OPTION]\n\n", argv[0]);
+            printf("Usage: %s [OPTIONS]\n\n", argv[0]);
             printf("  -c, --config=PATH (%s)\n", DEFAULT_CONFIG_PATH);
             printf("                             Load configuration from file at PATH\n");
             printf("  -I, --include=PATH (%s)\n", DEFAULT_DISPATCH_PYTHON_DIR);
             printf("                             Location of Dispatch's Python library\n");
+            printf("  -d, --daemon               Run process as a SysV-style daemon\n");
+            printf("  -P, --pidfile              If daemon, the file for the stored daemon pid\n");
+            printf("  -U, --user                 If daemon, the username to run as\n");
             printf("  -h, --help                 Print this help\n");
             exit(0);
 
@@ -125,30 +324,12 @@ int main(int argc, char **argv)
         }
     }
 
-
-    qd_error_clear();
-    dispatch = qd_dispatch(python_pkgdir, qpid_dispatch_lib);
-    check();
-    log_source = qd_log_source("MAIN"); /* Logging is initialized by qd_dispatch. */
-    qd_dispatch_load_config(dispatch, config_path);
-    check();
-
-    (void)server_signal_handler; (void)thread_start_handler;(void)signal_handler;
-    qd_server_set_signal_handler(dispatch, server_signal_handler, 0);
-    qd_server_set_start_handler(dispatch, thread_start_handler, 0);
-
-    signal(SIGHUP,  signal_handler);
-    signal(SIGQUIT, signal_handler);
-    signal(SIGTERM, signal_handler);
-    signal(SIGINT,  signal_handler);
-
-    qd_server_run(dispatch);
-    qd_dispatch_free(dispatch);
-
-    if (exit_with_sigint) {
-        signal(SIGINT, SIG_DFL);
-        kill(getpid(), SIGINT);
-    }
+    if (daemon_mode)
+        daemon_process(config_path, python_pkgdir, qpid_dispatch_lib, pidfile, user);
+    else
+        main_process(config_path, python_pkgdir, qpid_dispatch_lib, -1);
 
     return 0;
 }
+
+



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org