+def _RunInSeparateProcess(fn):
+ """Runs a function in a separate process.
+
+ Note: Only boolean return values are supported.
+
+ @type fn: callable
+ @param fn: Function to be called
+ @rtype: bool
+
+ """
+ pid = os.fork()
+ if pid == 0:
+ # Child process
+ try:
+ # Call function
+ result = int(bool(fn()))
+ assert result in (0, 1)
+ except: # pylint: disable-msg=W0702
+ logging.exception("Error while calling function in separate process")
+ # 0 and 1 are reserved for the return value
+ result = 33
+
+ os._exit(result) # pylint: disable-msg=W0212
+
+ # Parent process
+
+ # Avoid zombies and check exit code
+ (_, status) = os.waitpid(pid, 0)
+
+ if os.WIFSIGNALED(status):
+ signum = os.WTERMSIG(status)
+ exitcode = None
+ else:
+ signum = None
+ exitcode = os.WEXITSTATUS(status)
+
+ if not (exitcode in (0, 1) and signum is None):
+ logging.error("Child program failed (code=%s, signal=%s)",
+ exitcode, signum)
+ sys.exit(constants.EXIT_FAILURE)
+
+ return bool(exitcode)
+
+
+def CheckMasterd(options, args):
+ """Initial checks whether to run or exit with a failure.
+
+ """
+ if args: # masterd doesn't take any arguments
+ print >> sys.stderr, ("Usage: %s [-f] [-d]" % sys.argv[0])
+ sys.exit(constants.EXIT_FAILURE)
+
+ ssconf.CheckMaster(options.debug)
+
+ # If CheckMaster didn't fail we believe we are the master, but we have to
+ # confirm with the other nodes.
+ if options.no_voting:
+ if options.yes_do_it:
+ return
+
+ sys.stdout.write("The 'no voting' option has been selected.\n")
+ sys.stdout.write("This is dangerous, please confirm by"
+ " typing uppercase 'yes': ")
+ sys.stdout.flush()
+
+ confirmation = sys.stdin.readline().strip()
+ if confirmation != "YES":
+ print >> sys.stderr, "Aborting."
+ sys.exit(constants.EXIT_FAILURE)
+
+ return
+
+ # CheckAgreement uses RPC and threads, hence it needs to be run in a separate
+ # process before we call utils.Daemonize in the current process.
+ if not _RunInSeparateProcess(CheckAgreementWithRpc):
+ sys.exit(constants.EXIT_FAILURE)
+
+
+def ExecMasterd (options, args): # pylint: disable-msg=W0613
+ """Main master daemon function, executed with the PID file held.