diff -r 05c2b62448b1 -r ef3c8a0e1fee src/server/daemon/main.c --- 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 #include #include +#include #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;