diff --git a/radicale/__main__.py b/radicale/__main__.py index bd096475..547abe19 100644 --- a/radicale/__main__.py +++ b/radicale/__main__.py @@ -99,14 +99,30 @@ def run(): # Fork if Radicale is launched as daemon if config.getboolean("server", "daemon"): - if os.path.exists(config.get("server", "pid")): - raise OSError("PID file exists: %s" % config.get("server", "pid")) + # Check and create PID file in a race-free manner + if config.get("server", "pid"): + try: + pid_fd = os.open(config.get("server", "pid"), + os.O_CREAT | os.O_EXCL | os.O_WRONLY) + except: + raise OSError("PID file exists: %s" % + config.get("server", "pid")) pid = os.fork() if pid: sys.exit() - elif config.get("server", "pid"): - open(config.get("server", "pid"), "w").write(str(os.getpid())) - sys.stdout = sys.stderr = open(os.devnull, "w") + # Write PID + if config.get("server", "pid"): + with os.fdopen(pid_fd, "w") as pid_file: + pid_file.write(str(os.getpid())) + # Decouple environment + os.umask(0) + os.chdir("/") + os.setsid() + with open(os.devnull, "r") as null_in: + os.dup2(null_in.fileno(), sys.stdin.fileno()) + with open(os.devnull, "w") as null_out: + os.dup2(null_out.fileno(), sys.stdout.fileno()) + os.dup2(null_out.fileno(), sys.stderr.fileno()) # Register exit function def cleanup():