blob: 8300d1d0f0f619f62fc41243c7377c27481f280b [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001"""
2Python Daemonizing helper
3
Brad Bishopd7bf8c12018-02-25 22:55:05 -05004Originally based on code Copyright (C) 2005 Chad J. Schroeder but now heavily modified
5to allow a function to be daemonized and return for bitbake use by Richard Purdie
Patrick Williamsc124f4f2015-09-15 14:41:29 -05006"""
7
Brad Bishopd7bf8c12018-02-25 22:55:05 -05008import os
9import sys
10import io
11import traceback
Patrick Williamsc124f4f2015-09-15 14:41:29 -050012
13def createDaemon(function, logfile):
14 """
15 Detach a process from the controlling terminal and run it in the
16 background as a daemon, returning control to the caller.
17 """
18
19 try:
20 # Fork a child process so the parent can exit. This returns control to
21 # the command-line or shell. It also guarantees that the child will not
22 # be a process group leader, since the child receives a new process ID
23 # and inherits the parent's process group ID. This step is required
24 # to insure that the next call to os.setsid is successful.
25 pid = os.fork()
26 except OSError as e:
27 raise Exception("%s [%d]" % (e.strerror, e.errno))
28
29 if (pid == 0): # The first child.
30 # To become the session leader of this new session and the process group
31 # leader of the new process group, we call os.setsid(). The process is
32 # also guaranteed not to have a controlling terminal.
33 os.setsid()
Patrick Williamsc124f4f2015-09-15 14:41:29 -050034 try:
35 # Fork a second child and exit immediately to prevent zombies. This
36 # causes the second child process to be orphaned, making the init
37 # process responsible for its cleanup. And, since the first child is
38 # a session leader without a controlling terminal, it's possible for
39 # it to acquire one by opening a terminal in the future (System V-
40 # based systems). This second fork guarantees that the child is no
41 # longer a session leader, preventing the daemon from ever acquiring
42 # a controlling terminal.
43 pid = os.fork() # Fork a second child.
44 except OSError as e:
45 raise Exception("%s [%d]" % (e.strerror, e.errno))
46
Brad Bishopd7bf8c12018-02-25 22:55:05 -050047 if (pid != 0):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050048 # Parent (the first child) of the second child.
Brad Bishopd7bf8c12018-02-25 22:55:05 -050049 # exit() or _exit()?
50 # _exit is like exit(), but it doesn't call any functions registered
51 # with atexit (and on_exit) or any registered signal handlers. It also
52 # closes any open file descriptors. Using exit() may cause all stdio
53 # streams to be flushed twice and any temporary files may be unexpectedly
54 # removed. It's therefore recommended that child branches of a fork()
55 # and the parent branch(es) of a daemon use _exit().
Patrick Williamsc124f4f2015-09-15 14:41:29 -050056 os._exit(0)
57 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -050058 os.waitpid(pid, 0)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050059 return
60
Brad Bishopd7bf8c12018-02-25 22:55:05 -050061 # The second child.
Patrick Williamsc124f4f2015-09-15 14:41:29 -050062
Brad Bishopd7bf8c12018-02-25 22:55:05 -050063 # Replace standard fds with our own
Patrick Williamsc0f7c042017-02-23 20:41:17 -060064 si = open('/dev/null', 'r')
Patrick Williamsc124f4f2015-09-15 14:41:29 -050065 os.dup2(si.fileno(), sys.stdin.fileno())
Patrick Williamsc124f4f2015-09-15 14:41:29 -050066
Brad Bishopd7bf8c12018-02-25 22:55:05 -050067 try:
68 so = open(logfile, 'a+')
69 se = so
70 os.dup2(so.fileno(), sys.stdout.fileno())
71 os.dup2(se.fileno(), sys.stderr.fileno())
72 except io.UnsupportedOperation:
73 sys.stdout = open(logfile, 'a+')
74 sys.stderr = sys.stdout
Patrick Williamsc124f4f2015-09-15 14:41:29 -050075
Brad Bishopd7bf8c12018-02-25 22:55:05 -050076 try:
77 function()
78 except Exception as e:
79 traceback.print_exc()
80 finally:
81 bb.event.print_ui_queue()
82 os._exit(0)