Ensure "tinc start" knows if the daemon really started succesfully.
authorGuus Sliepen <guus@tinc-vpn.org>
Wed, 20 May 2015 14:59:43 +0000 (16:59 +0200)
committerGuus Sliepen <guus@tinc-vpn.org>
Wed, 20 May 2015 14:59:43 +0000 (16:59 +0200)
We do this by creating an umbilical between the CLI and the daemon. The
daemon pipes log messages to the CLI until it starts the main loop. The
daemon then cuts the umbilical. The CLI copies all the received log
messages to stderr, and the last byte indicates whether the daemon
started succesfully or not, so the CLI can exit with a useful exit code.

src/logger.c
src/logger.h
src/tincctl.c
src/tincd.c

index 2defb23908c06cfb2e71de1bad6fb01bae6dcc69..8fbd3448204d342ddd28427d9db1fdc979f3cf4f 100644 (file)
@@ -37,7 +37,7 @@ static HANDLE loghandle = NULL;
 #endif
 static const char *logident = NULL;
 bool logcontrol = false;
-
+int umbilical = 0;
 
 static void real_logger(int level, int priority, const char *message) {
        char timestr[32] = "";
@@ -79,6 +79,11 @@ static void real_logger(int level, int priority, const char *message) {
                        case LOGMODE_NULL:
                                break;
                }
+
+               if(umbilical) {
+                       write(umbilical, message, strlen(message));
+                       write(umbilical, "\n", 1);
+               }
        }
 
        if(logcontrol) {
index 8f6902903a9ac68768ed4b9963bff46008d2caf7..252497bf984376d8a046d5769cab2f256cde5ab5 100644 (file)
@@ -69,6 +69,7 @@ enum {
 
 extern debug_t debug_level;
 extern bool logcontrol;
+extern int umbilical;
 extern void openlogger(const char *, logmode_t);
 extern void reopenlogger(void);
 extern void logger(int, int, const char *, ...) __attribute__ ((__format__(printf, 3, 4)));
index 46bf5bd5b034a147cd6f389a5822faa5d51ca8c6..c6d4aac51dfb853baf60a393a7199916aa74b3bf 100644 (file)
@@ -853,6 +853,13 @@ static int cmd_start(int argc, char *argv[]) {
        }
        return status;
 #else
+       int pfd[2] = {-1, -1};
+       if(pipe(pfd)) {
+               fprintf(stderr, "Could not create umbilical pipe: %s\n", strerror(errno));
+               free(nargv);
+               return 1;
+       }
+
        pid_t pid = fork();
        if(pid == -1) {
                fprintf(stderr, "Could not fork: %s\n", strerror(errno));
@@ -860,8 +867,15 @@ static int cmd_start(int argc, char *argv[]) {
                return 1;
        }
 
-       if(!pid)
+       if(!pid) {
+               close(pfd[0]);
+               char buf[100] = "";
+               snprintf(buf, sizeof buf, "%d", pfd[1]);
+               setenv("TINC_UMBILICAL", buf, true);
                exit(execvp(c, nargv));
+       } else {
+               close(pfd[1]);
+       }
 
        free(nargv);
 
@@ -869,12 +883,33 @@ static int cmd_start(int argc, char *argv[]) {
 #ifdef SIGINT
        signal(SIGINT, SIG_IGN);
 #endif
+
+       // Pass all log messages from the umbilical to stderr.
+       // A nul-byte right before closure means tincd started succesfully.
+       bool failure = true;
+       char buf[1024];
+       ssize_t len;
+
+       while((len = read(pfd[0], buf, sizeof buf)) > 0) {
+               failure = buf[len - 1];
+               if(!failure)
+                       len--;
+               write(2, buf, len);
+       }
+
+       if(len)
+               failure = true;
+
+       close(pfd[0]);
+
+       // Make sure the child process is really gone.
        result = waitpid(pid, &status, 0);
+
 #ifdef SIGINT
        signal(SIGINT, SIG_DFL);
 #endif
 
-       if(result != pid || !WIFEXITED(status) || WEXITSTATUS(status)) {
+       if(failure || result != pid || !WIFEXITED(status) || WEXITSTATUS(status)) {
                fprintf(stderr, "Error starting %s\n", c);
                return 1;
        }
index fb2a1557aa7fb0b59fd8e2d406c6cc0c189a5321..b62c8c1903a7cf30002b2a1a0ba57efd1f9ce2fa 100644 (file)
@@ -363,6 +363,14 @@ int main(int argc, char **argv) {
                logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "WSAStartup", winerror(GetLastError()));
                return 1;
        }
+#else
+       // Check if we got an umbilical fd from the process that started us
+       char *umbstr = getenv("TINC_UMBILICAL");
+       if(umbstr) {
+               umbilical = atoi(umbstr);
+               if(fcntl(umbilical, F_GETFL) < 0)
+                       umbilical = 0;
+       }
 #endif
 
        openlogger("tinc", use_logfile?LOGMODE_FILE:LOGMODE_STDERR);
@@ -466,6 +474,12 @@ int main2(int argc, char **argv) {
 
        logger(DEBUG_ALWAYS, LOG_NOTICE, "Ready");
 
+       if(umbilical) { // snip!
+               write(umbilical, "", 1);
+               close(umbilical);
+               umbilical = 0;
+       }
+
        try_outgoing_connections();
 
        status = main_loop();