From 0a09804821fd7d77d089c47c57ff277bff60b891 Mon Sep 17 00:00:00 2001 From: Unrud Date: Tue, 22 Dec 2015 06:49:33 +0100 Subject: [PATCH 1/4] Close PID file --- radicale/__main__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/radicale/__main__.py b/radicale/__main__.py index bd09647..b2f39db 100644 --- a/radicale/__main__.py +++ b/radicale/__main__.py @@ -105,7 +105,8 @@ def run(): if pid: sys.exit() elif config.get("server", "pid"): - open(config.get("server", "pid"), "w").write(str(os.getpid())) + with open(config.get("server", "pid"), "w") as pid_file: + pid_file.write(str(os.getpid())) sys.stdout = sys.stderr = open(os.devnull, "w") # Register exit function From 3a9238f6709b54a8d3c9a168c2488569198ed790 Mon Sep 17 00:00:00 2001 From: Unrud Date: Tue, 22 Dec 2015 06:55:17 +0100 Subject: [PATCH 2/4] Check and create PID file in a race-free manner --- radicale/__main__.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/radicale/__main__.py b/radicale/__main__.py index b2f39db..879603b 100644 --- a/radicale/__main__.py +++ b/radicale/__main__.py @@ -99,13 +99,20 @@ 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"): - with open(config.get("server", "pid"), "w") as pid_file: + # Write PID + if config.get("server", "pid"): + with os.fdopen(pid_fd, "w") as pid_file: pid_file.write(str(os.getpid())) sys.stdout = sys.stderr = open(os.devnull, "w") From ecb8ad747e20a4fe7507d3b19e8641a0321e2ae9 Mon Sep 17 00:00:00 2001 From: Unrud Date: Tue, 22 Dec 2015 06:58:58 +0100 Subject: [PATCH 3/4] Decouple the daemon from its parent environment --- radicale/__main__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/radicale/__main__.py b/radicale/__main__.py index 879603b..6e47ee8 100644 --- a/radicale/__main__.py +++ b/radicale/__main__.py @@ -114,6 +114,10 @@ def run(): 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() sys.stdout = sys.stderr = open(os.devnull, "w") # Register exit function From 367ca6fcbf19507da8ba4a40713eb9d86a90d529 Mon Sep 17 00:00:00 2001 From: Unrud Date: Tue, 22 Dec 2015 07:03:51 +0100 Subject: [PATCH 4/4] Replace standard file descriptors of daemon Overwriting ```sys.stdout``` and ```sys.stderr``` is not sufficient. (e.g. the logger still uses the old file descriptors) --- radicale/__main__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/radicale/__main__.py b/radicale/__main__.py index 6e47ee8..547abe1 100644 --- a/radicale/__main__.py +++ b/radicale/__main__.py @@ -118,7 +118,11 @@ def run(): os.umask(0) os.chdir("/") os.setsid() - sys.stdout = sys.stderr = open(os.devnull, "w") + 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():