From: Andre Noll Date: Thu, 16 Jun 2016 21:21:08 +0000 (+0200) Subject: run: Fix exit status in case another dss process is running. X-Git-Tag: v1.0.0~25^2~7 X-Git-Url: http://git.tue.mpg.de/?a=commitdiff_plain;h=6c63f45a9068107cfd80aa181134574dd9373c0b;p=dss.git run: Fix exit status in case another dss process is running. In daemon mode, we must acquire the semaphore lock in the child process because the child does not inherit semaphore adjustments. Currently the parent exits successfully after the fork, so the command appears to succeed even if the child dies immediately because it was unable to acquire the lock because another dss process is holding the lock. This commit introduces a mechanism which enables the parent to tell whether the child completed its setup successfully. We create a pipe prior to calling fork(2), and let the child write to one end of the pipe after setup is complete and just before it enters the main select loop. The parent reads from the other end of the pipe and exits once the read(2) call returns. If the child dies early, read(2) returns zero, indicating failure. --- diff --git a/daemon.c b/daemon.c index 86e8906..0b201a8 100644 --- a/daemon.c +++ b/daemon.c @@ -31,17 +31,36 @@ * * \sa fork(2), setsid(2), dup(2). */ -void daemon_init(void) +int daemon_init(void) { pid_t pid; - int null; + int null, fd[2]; DSS_INFO_LOG(("daemonizing\n")); + if (pipe(fd) < 0) + goto err; pid = fork(); if (pid < 0) goto err; - if (pid) - exit(EXIT_SUCCESS); /* parent exits */ + if (pid) { + /* + * The parent process exits once it has received one byte from + * the reading end of the pipe. If the child exits before it + * was able to complete its setup (acquire the lock on the + * semaphore), the read() below will return zero. In this case + * we let the parent die unsuccessfully. + */ + char c; + int ret; + close(fd[1]); + ret = read(fd[0], &c, 1); + if (ret <= 0) { + DSS_EMERG_LOG(("child terminated unexpectedly\n")); + exit(EXIT_FAILURE); + } + exit(EXIT_SUCCESS); + } + close(fd[0]); /* become session leader */ if (setsid() < 0) goto err; @@ -56,7 +75,7 @@ void daemon_init(void) if (dup2(null, STDERR_FILENO) < 0) goto err; close(null); - return; + return fd[1]; err: DSS_EMERG_LOG(("fatal: %s\n", strerror(errno))); exit(EXIT_FAILURE); diff --git a/daemon.h b/daemon.h index aead8e8..e36e37c 100644 --- a/daemon.h +++ b/daemon.h @@ -1,7 +1,7 @@ /** \file daemon.h exported symbols from daemon.c */ -void daemon_init(void); +int daemon_init(void); FILE *open_log(const char *logfile_name); void close_log(FILE* logfile); void log_welcome(int loglevel); diff --git a/dss.c b/dss.c index d0dab0d..6f0d759 100644 --- a/dss.c +++ b/dss.c @@ -1510,14 +1510,14 @@ static void lock_dss_or_die(void) static int com_run(void) { - int ret; + int ret, fd = -1; if (OPT_GIVEN(DSS, DRY_RUN)) { DSS_ERROR_LOG(("dry run not supported by this command\n")); return -E_SYNTAX; } if (OPT_GIVEN(RUN, DAEMON)) { - daemon_init(); + fd = daemon_init(); daemonized = true; logfile = open_log(OPT_STRING_VAL(RUN, LOGFILE)); } @@ -1526,6 +1526,16 @@ static int com_run(void) ret = install_sighandler(SIGHUP); if (ret < 0) return ret; + if (fd >= 0) { + ret = write(fd, "\0", 1); + if (ret != 1) { + DSS_ERROR_LOG(("write to daemon pipe returned %d\n", + ret)); + if (ret < 0) + return -ERRNO_TO_DSS_ERROR(errno); + return -E_BUG; + } + } ret = select_loop(); if (ret >= 0) /* impossible */ ret = -E_BUG;