src/server/daemon/main.c

changeset 443
ef3c8a0e1fee
parent 434
ff576305ae6e
child 444
96d2ba2f28db
--- a/src/server/daemon/main.c	Sun Nov 27 10:20:10 2022 +0100
+++ b/src/server/daemon/main.c	Sun Nov 27 13:33:30 2022 +0100
@@ -35,6 +35,7 @@
 #include <pthread.h>
 #include <fcntl.h>
 #include <poll.h>
+#include <semaphore.h>
 
 #include "../util/pool.h"
 #include "../public/nsapi.h"
@@ -112,10 +113,40 @@
 static size_t log_pipe_stdout_tmp_pos = 0;
 static size_t log_pipe_stderr_tmp_pos = 0;
 
+// pipe used for startup
+// after fork, the parent process waits, until the daemon is fully started
+// to get potential error and log messages
+static int daemon_start_pipe[2];
+
+// used for sending log messages from the daemon process to the parent process
+// in the startup phase
+static int parent_log_pipe[2];
+
+static LogDup startup_log;
+
+static void finish_daemon_startup(int status) {
+    if(status != 0) {
+        log_ereport(LOG_FAILURE, "daemon startup failed");
+        if(status > 127) {
+            status = 127;
+        }
+    }
+    char s = (char)status;
+    
+    // notify parent process about startup status
+    write(daemon_start_pipe[1], &s, 1);
+    close(daemon_start_pipe[1]);
+    
+    // remove logdup
+    log_remove_logdup(&startup_log);
+    close(parent_log_pipe[0]);
+    close(parent_log_pipe[1]);
+}
+
 static int log_pipe(const char *name, int fd, char *buf, size_t *pos) {
     ssize_t r = read(fd, log_pipe_readbuf, 2);
     if(r <= 0) {
-        return 1;
+        return r == 0 ? 0 : 1;
     }
     
     char *tmp = buf;
@@ -170,6 +201,7 @@
         // check stdout
         if(fds[0].revents & POLLIN) {
             if(log_pipe("stdout", fds[0].fd, log_pipe_stdout_buf, &log_pipe_stdout_tmp_pos)) {
+                log_ereport(LOG_WARN, "log_pipe stdout failed");
                 break;
             }
         }
@@ -177,6 +209,7 @@
         // check stderr
         if(fds[1].revents & POLLIN) {
             if(log_pipe("stderr", fds[0].fd, log_pipe_stderr_buf, &log_pipe_stderr_tmp_pos)) {
+                log_ereport(LOG_WARN, "log_pipe stderr failed");
                 break;
             }
         }
@@ -187,6 +220,37 @@
     return NULL;
 }
 
+
+// read (blocking) 1 byte from daemon_start_pipe and return the value
+// this is used to wait in the parent process, until the daemon process
+// is started
+// the returning byte is used as the process return value
+static int main_daemon_startup_wait(void) {
+    // receive log messages from daemon
+    char buf[2048];
+    ssize_t r;
+    while((r = read(parent_log_pipe[0], buf, 2048)) > 0) {
+        ssize_t pos = 0;
+        while(r > 0) {
+            ssize_t w = write(STDOUT_FILENO, buf+pos, r-pos);
+            pos += w;
+            r -= w;
+            break;
+        }
+    }
+    // log pipe closed, daemon_start_pipe should contain the status code now
+    
+    char ret;
+    if(read(daemon_start_pipe[0], &ret, 1) != 1) {
+        return 255;
+    }
+    return ret;
+}
+
+static void startup_log_write(void *cookie, char *msg, size_t length) {
+    write(parent_log_pipe[1], msg, length);
+}
+
 int main(int argc, char **argv) {
     //test();
     
@@ -199,24 +263,50 @@
             break;
         }
     }
+    
+    if(init_logging()) {
+        fprintf(stderr, "OOM\n");
+        return 1;
+    }
+    
+    is_daemon = 1;
     if(is_daemon) {
+        // initialize startup pipes
+        if(pipe(daemon_start_pipe)) {
+            perror("pipe");
+            return EXIT_FAILURE;
+        }
+        if(pipe(parent_log_pipe)) {
+            perror("pipe");
+            return EXIT_FAILURE;
+        }
+        
+        log_ereport(LOG_INFORM, "start daemon");
+        
+        // register parent process as LogDup to receive startup log messages
+        // in the parent process, because stdout/stderr will be closed
+        // after fork
+        startup_log.write = startup_log_write;
+        log_add_logdup(&startup_log);
+        
         // create daemon
         pid_t pid = fork();
         if(pid < 0) {
+            perror("fork");
             return EXIT_FAILURE;
         } else if(pid > 0) {
-            return EXIT_SUCCESS;
+            close(daemon_start_pipe[1]);
+            close(parent_log_pipe[1]);
+            return main_daemon_startup_wait();
         }
 
         if(setsid() < 0) {
             fprintf(stderr, "setsid failed\n");
             return EXIT_FAILURE;
         }
-        printf("start daemon\n");
-
-        for(int i=0;i<3;i++) {
-            close(i);
-        }
+        
+        // close read-end of pipe in the daemon process
+        close(daemon_start_pipe[0]);
 
         // stdio redirection
         // create pipes
@@ -229,9 +319,14 @@
             return EXIT_FAILURE;
         }
         
+        for(int i=0;i<3;i++) {
+            close(i);
+        }
+        
         dup2(std_out[1], 1);
-        dup2(std_err[1], 2);
-        close(std_err[1]);
+        //dup2(std_err[1], 2);
+        close(std_out[1]);
+        //close(std_err[1]);
         
         // set log thread stack size
         pthread_attr_t tattr;
@@ -265,6 +360,9 @@
     }
 
     status = webserver_run();
+    if(is_daemon) {
+        finish_daemon_startup(status);
+    }
     if(status != 0) {
         log_ereport(LOG_FAILURE, "cannot run server.");
         return EXIT_FAILURE;

mercurial