This repository has been archived by the owner on Apr 26, 2024. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This has long been something I've wanted to do. Basically the `Daemonize` code is both too flexible and not flexible enough, in that it offers a bunch of features that we don't use (changing UID, closing FDs in the child, logging to syslog) and doesn't offer a bunch that we could do with (redirecting stdout/err to a file instead of /dev/null; having the parent not exit until the child is running). As a first step, I've lifted the Daemonize code and removed the bits we don't use. This should be a non-functional change. Fixing everything else will come later.
- Loading branch information
Showing
4 changed files
with
124 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Replace daemonize library with a local implementation. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright (c) 2012, 2013, 2014 Ilya Otyutskiy <[email protected]> | ||
# Copyright 2020 The Matrix.org Foundation C.I.C. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
import atexit | ||
import fcntl | ||
import logging | ||
import os | ||
import signal | ||
import sys | ||
|
||
|
||
def daemonize_process(pid_file: str, logger: logging.Logger, chdir: str = "/") -> None: | ||
"""daemonize the current process | ||
This calls fork(), and has the main process exit. When it returns we will be | ||
running in the child process. | ||
""" | ||
|
||
# If pidfile already exists, we should read pid from there; to overwrite it, if | ||
# locking will fail, because locking attempt somehow purges the file contents. | ||
if os.path.isfile(pid_file): | ||
with open(pid_file, "r") as pid_fh: | ||
old_pid = pid_fh.read() | ||
|
||
# Create a lockfile so that only one instance of this daemon is running at any time. | ||
try: | ||
lock_fh = open(pid_file, "w") | ||
except IOError: | ||
print("Unable to create the pidfile.") | ||
sys.exit(1) | ||
|
||
try: | ||
# Try to get an exclusive lock on the file. This will fail if another process | ||
# has the file locked. | ||
fcntl.flock(lock_fh, fcntl.LOCK_EX | fcntl.LOCK_NB) | ||
except IOError: | ||
print("Unable to lock on the pidfile.") | ||
# We need to overwrite the pidfile if we got here. | ||
# | ||
# XXX better to avoid overwriting it, surely. this looks racey as the pid file | ||
# could be created between us trying to read it and us trying to lock it. | ||
with open(pid_file, "w") as pid_fh: | ||
pid_fh.write(old_pid) | ||
sys.exit(1) | ||
|
||
# Fork, creating a new process for the child. | ||
process_id = os.fork() | ||
|
||
if process_id != 0: | ||
# parent process | ||
sys.exit(0) | ||
|
||
# This is the child process. Continue. | ||
|
||
# Stop listening for signals that the parent process receives. | ||
# This is done by getting a new process id. | ||
# setpgrp() is an alternative to setsid(). | ||
# setsid puts the process in a new parent group and detaches its controlling | ||
# terminal. | ||
|
||
os.setsid() | ||
|
||
# point stdin, stdout, stderr at /dev/null | ||
devnull = "/dev/null" | ||
if hasattr(os, "devnull"): | ||
# Python has set os.devnull on this system, use it instead as it might be | ||
# different than /dev/null. | ||
devnull = os.devnull | ||
|
||
devnull_fd = os.open(devnull, os.O_RDWR) | ||
os.dup2(devnull_fd, 0) | ||
os.dup2(devnull_fd, 1) | ||
os.dup2(devnull_fd, 2) | ||
os.close(devnull_fd) | ||
|
||
# Set umask to default to safe file permissions when running as a root daemon. 027 | ||
# is an octal number which we are typing as 0o27 for Python3 compatibility. | ||
os.umask(0o27) | ||
|
||
# Change to a known directory. If this isn't done, starting a daemon in a | ||
# subdirectory that needs to be deleted results in "directory busy" errors. | ||
os.chdir(chdir) | ||
|
||
try: | ||
lock_fh.write("%s" % (os.getpid())) | ||
lock_fh.flush() | ||
except IOError: | ||
logger.error("Unable to write pid to the pidfile.") | ||
print("Unable to write pid to the pidfile.") | ||
sys.exit(1) | ||
|
||
# write a log line on SIGTERM. | ||
def sigterm(signum, frame): | ||
logger.warning("Caught signal %s. Stopping daemon." % signum) | ||
sys.exit(0) | ||
|
||
signal.signal(signal.SIGTERM, sigterm) | ||
|
||
# Cleanup pid file at exit. | ||
def exit(): | ||
logger.warning("Stopping daemon.") | ||
os.remove(pid_file) | ||
sys.exit(0) | ||
|
||
atexit.register(exit) | ||
|
||
logger.warning("Starting daemon.") |