-
Notifications
You must be signed in to change notification settings - Fork 0
/
daemon.py
120 lines (95 loc) · 3.38 KB
/
daemon.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import os
import sys
import atexit
from settings import configure_logging
LOG = configure_logging()
class Daemon:
def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
self.pidfile = os.path.expanduser(pidfile) # Use the user's home directory for the PID file
self.stdin = stdin
self.stdout = stdout
self.stderr = stderr
def daemonize(self):
try:
# Fork the current process
pid = os.fork()
if pid > 0:
# Exit the parent process
LOG.info("Exiting the parent Process")
sys.exit(0)
except OSError as e:
LOG.info(f"Failed to fork process: {e}\n")
sys.exit(1)
# Change the working directory to root
os.chdir("/")
# Detach from the parent environment
os.setsid()
# Set the file permissions
os.umask(0)
try:
# Fork again to prevent the process from acquiring a controlling terminal
pid = os.fork()
if pid > 0:
# Write the child process PID to the PID file
with open(self.pidfile, 'w') as f:
f.write(str(pid))
sys.exit(0)
except OSError as e:
LOG.info(f"Failed to fork process: {e}\n")
sys.exit(1)
# Redirect standard file descriptors to devnull or specified files
sys.stdout.flush()
sys.stderr.flush()
si = open(self.stdin, 'r')
so = open(self.stdout, 'a+')
se = open(self.stderr, 'a+')
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
# Register the exit function to remove the PID file
atexit.register(self._remove_pidfile)
def _remove_pidfile(self):
if os.path.exists(self.pidfile):
os.remove(self.pidfile)
def start(self):
# Check if the process is already running
if self.is_process_running():
LOG.info("Process is already running.")
sys.exit(1)
# Start the daemonization process
self.daemonize()
LOG.info("Deamon Started")
# Perform any additional setup or initialization here
# Execute the daemon main function
self.run()
def stop(self):
# Check if the process is not running
if not self.is_process_running():
LOG.info("Process is not running.")
sys.exit(1)
# Get the PID from the PID file
with open(self.pidfile, 'r') as f:
pid = int(f.read().strip())
try:
# Terminate the process
os.kill(pid, 15)
except OSError as e:
LOG.info(f"Failed to stop process: {e}")
sys.exit(1)
# Remove the PID file
self._remove_pidfile()
def restart(self):
# Stop the process
self.stop()
# Start the process
self.start()
def is_process_running(self):
if os.path.exists(self.pidfile):
with open(self.pidfile, 'r') as f:
pid = int(f.read().strip())
return os.path.exists(f"/proc/{pid}")
return False
def run(self):
# Override this method with the daemon's main functionality
# The daemon's main code goes here
pass