Ensure "tinc start" knows if the daemon really started succesfully.

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.
This commit is contained in:
Guus Sliepen 2015-05-20 16:59:43 +02:00
parent 7f96ef081d
commit 11868b890d
4 changed files with 58 additions and 3 deletions

View 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) {

View 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)));

View 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;
}

View 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();