1# 2# Copyright BitBake Contributors 3# 4# SPDX-License-Identifier: GPL-2.0-only 5# 6 7""" 8Python Daemonizing helper 9 10Originally based on code Copyright (C) 2005 Chad J. Schroeder but now heavily modified 11to allow a function to be daemonized and return for bitbake use by Richard Purdie 12""" 13 14import os 15import sys 16import io 17import traceback 18 19import bb 20 21def createDaemon(function, logfile): 22 """ 23 Detach a process from the controlling terminal and run it in the 24 background as a daemon, returning control to the caller. 25 """ 26 27 # Ensure stdout/stderror are flushed before forking to avoid duplicate output 28 sys.stdout.flush() 29 sys.stderr.flush() 30 31 try: 32 # Fork a child process so the parent can exit. This returns control to 33 # the command-line or shell. It also guarantees that the child will not 34 # be a process group leader, since the child receives a new process ID 35 # and inherits the parent's process group ID. This step is required 36 # to insure that the next call to os.setsid is successful. 37 pid = os.fork() 38 except OSError as e: 39 raise Exception("%s [%d]" % (e.strerror, e.errno)) 40 41 if (pid == 0): # The first child. 42 # To become the session leader of this new session and the process group 43 # leader of the new process group, we call os.setsid(). The process is 44 # also guaranteed not to have a controlling terminal. 45 os.setsid() 46 try: 47 # Fork a second child and exit immediately to prevent zombies. This 48 # causes the second child process to be orphaned, making the init 49 # process responsible for its cleanup. And, since the first child is 50 # a session leader without a controlling terminal, it's possible for 51 # it to acquire one by opening a terminal in the future (System V- 52 # based systems). This second fork guarantees that the child is no 53 # longer a session leader, preventing the daemon from ever acquiring 54 # a controlling terminal. 55 pid = os.fork() # Fork a second child. 56 except OSError as e: 57 raise Exception("%s [%d]" % (e.strerror, e.errno)) 58 59 if (pid != 0): 60 # Parent (the first child) of the second child. 61 # exit() or _exit()? 62 # _exit is like exit(), but it doesn't call any functions registered 63 # with atexit (and on_exit) or any registered signal handlers. It also 64 # closes any open file descriptors, but doesn't flush any buffered output. 65 # Using exit() may cause all any temporary files to be unexpectedly 66 # removed. It's therefore recommended that child branches of a fork() 67 # and the parent branch(es) of a daemon use _exit(). 68 os._exit(0) 69 else: 70 os.waitpid(pid, 0) 71 return 72 73 # The second child. 74 75 # Replace standard fds with our own 76 with open('/dev/null', 'r') as si: 77 os.dup2(si.fileno(), sys.stdin.fileno()) 78 79 with open(logfile, 'a+') as so: 80 try: 81 os.dup2(so.fileno(), sys.stdout.fileno()) 82 os.dup2(so.fileno(), sys.stderr.fileno()) 83 except io.UnsupportedOperation: 84 sys.stdout = so 85 86 # Have stdout and stderr be the same so log output matches chronologically 87 # and there aren't two separate buffers 88 sys.stderr = sys.stdout 89 90 try: 91 function() 92 except Exception as e: 93 traceback.print_exc() 94 finally: 95 bb.event.print_ui_queue() 96 # os._exit() doesn't flush open files like os.exit() does. Manually flush 97 # stdout and stderr so that any logging output will be seen, particularly 98 # exception tracebacks. 99 sys.stdout.flush() 100 sys.stderr.flush() 101 os._exit(0) 102