diff --git a/lib/daemon.py b/lib/daemon.py index eceeac4061f40a620edfb471abcb8ef4c6722748..ba5f17504134e6148e22506cf9ec85a74bd1a179 100644 --- a/lib/daemon.py +++ b/lib/daemon.py @@ -624,22 +624,34 @@ def GenericMain(daemon_name, optionparser, if options.fork: utils.CloseFDs() - utils.Daemonize(logfile=constants.DAEMONS_LOGFILES[daemon_name]) + wpipe = utils.Daemonize(logfile=constants.DAEMONS_LOGFILES[daemon_name]) + else: + wpipe = None utils.WritePidFile(utils.DaemonPidFileName(daemon_name)) try: - utils.SetupLogging(logfile=constants.DAEMONS_LOGFILES[daemon_name], - debug=options.debug, - stderr_logging=not options.fork, - multithreaded=multithreaded, - program=daemon_name, - syslog=options.syslog, - console_logging=console_logging) - logging.info("%s daemon startup", daemon_name) - if callable(prepare_fn): - prep_results = prepare_fn(options, args) - else: - prep_results = None + try: + utils.SetupLogging(logfile=constants.DAEMONS_LOGFILES[daemon_name], + debug=options.debug, + stderr_logging=not options.fork, + multithreaded=multithreaded, + program=daemon_name, + syslog=options.syslog, + console_logging=console_logging) + if callable(prepare_fn): + prep_results = prepare_fn(options, args) + else: + prep_results = None + logging.info("%s daemon startup", daemon_name) + except Exception, err: + if wpipe is not None: + os.write(wpipe, str(err)) + raise + + if wpipe is not None: + # we're done with the preparation phase, we close the pipe to + # let the parent know it's safe to exit + os.close(wpipe) exec_fn(options, args, prep_results) finally: diff --git a/lib/utils.py b/lib/utils.py index 9e04d980e0bcc59168c298e238ff50b4deb0f62e..54588cf89ffcc3592a11190d1e2463f9da959b16 100644 --- a/lib/utils.py +++ b/lib/utils.py @@ -348,8 +348,8 @@ def StartDaemon(cmd, env=None, cwd="/", output=None, output_fd=None, finally: _CloseFDNoErr(errpipe_write) - # Wait for daemon to be started (or an error message to arrive) and read - # up to 100 KB as an error message + # Wait for daemon to be started (or an error message to + # arrive) and read up to 100 KB as an error message errormsg = RetryOnSignal(os.read, errpipe_read, 100 * 1024) finally: _CloseFDNoErr(errpipe_read) @@ -2146,6 +2146,12 @@ def Daemonize(logfile): # pylint: disable-msg=W0212 # yes, we really want os._exit + # TODO: do another attempt to merge Daemonize and StartDaemon, or at + # least abstract the pipe functionality between them + + # Create pipe for sending error messages + (rpipe, wpipe) = os.pipe() + # this might fail pid = os.fork() if (pid == 0): # The first child. @@ -2154,15 +2160,24 @@ def Daemonize(logfile): # this might fail pid = os.fork() # Fork a second child. if (pid == 0): # The second child. - pass # nothing special to do in the child + _CloseFDNoErr(rpipe) else: # exit() or _exit()? See below. os._exit(0) # Exit parent (the first child) of the second child. else: - os._exit(0) # Exit parent of the first child. + _CloseFDNoErr(wpipe) + # Wait for daemon to be started (or an error message to + # arrive) and read up to 100 KB as an error message + errormsg = RetryOnSignal(os.read, rpipe, 100 * 1024) + if errormsg: + sys.stderr.write("Error when starting daemon process: %r\n" % errormsg) + rcode = 1 + else: + rcode = 0 + os._exit(rcode) # Exit parent of the first child. SetupDaemonFDs(logfile, None) - return 0 + return wpipe def DaemonPidFileName(name):