summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/daemonize.py
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/lib/bb/daemonize.py')
-rw-r--r--bitbake/lib/bb/daemonize.py295
1 files changed, 147 insertions, 148 deletions
diff --git a/bitbake/lib/bb/daemonize.py b/bitbake/lib/bb/daemonize.py
index 1a8bb379f4..a944af2238 100644
--- a/bitbake/lib/bb/daemonize.py
+++ b/bitbake/lib/bb/daemonize.py
@@ -3,17 +3,17 @@ Python Deamonizing helper
3 3
4Configurable daemon behaviors: 4Configurable daemon behaviors:
5 5
6 1.) The current working directory set to the "/" directory. 6 1.) The current working directory set to the "/" directory.
7 2.) The current file creation mode mask set to 0. 7 2.) The current file creation mode mask set to 0.
8 3.) Close all open files (1024). 8 3.) Close all open files (1024).
9 4.) Redirect standard I/O streams to "/dev/null". 9 4.) Redirect standard I/O streams to "/dev/null".
10 10
11A failed call to fork() now raises an exception. 11A failed call to fork() now raises an exception.
12 12
13References: 13References:
14 1) Advanced Programming in the Unix Environment: W. Richard Stevens 14 1) Advanced Programming in the Unix Environment: W. Richard Stevens
15 2) Unix Programming Frequently Asked Questions: 15 2) Unix Programming Frequently Asked Questions:
16 http://www.erlenstar.demon.co.uk/unix/faq_toc.html 16 http://www.erlenstar.demon.co.uk/unix/faq_toc.html
17 17
18Modified to allow a function to be daemonized and return for 18Modified to allow a function to be daemonized and return for
19bitbake use by Richard Purdie 19bitbake use by Richard Purdie
@@ -24,8 +24,8 @@ __copyright__ = "Copyright (C) 2005 Chad J. Schroeder"
24__version__ = "0.2" 24__version__ = "0.2"
25 25
26# Standard Python modules. 26# Standard Python modules.
27import os # Miscellaneous OS interfaces. 27import os # Miscellaneous OS interfaces.
28import sys # System-specific parameters and functions. 28import sys # System-specific parameters and functions.
29 29
30# Default daemon parameters. 30# Default daemon parameters.
31# File mode creation mask of the daemon. 31# File mode creation mask of the daemon.
@@ -37,155 +37,154 @@ MAXFD = 1024
37 37
38# The standard I/O file descriptors are redirected to /dev/null by default. 38# The standard I/O file descriptors are redirected to /dev/null by default.
39if (hasattr(os, "devnull")): 39if (hasattr(os, "devnull")):
40 REDIRECT_TO = os.devnull 40 REDIRECT_TO = os.devnull
41else: 41else:
42 REDIRECT_TO = "/dev/null" 42 REDIRECT_TO = "/dev/null"
43 43
44def createDaemon(function, logfile): 44def createDaemon(function, logfile):
45 """ 45 """
46 Detach a process from the controlling terminal and run it in the 46 Detach a process from the controlling terminal and run it in the
47 background as a daemon, returning control to the caller. 47 background as a daemon, returning control to the caller.
48 """ 48 """
49 49
50 try: 50 try:
51 # Fork a child process so the parent can exit. This returns control to 51 # Fork a child process so the parent can exit. This returns control to
52 # the command-line or shell. It also guarantees that the child will not 52 # the command-line or shell. It also guarantees that the child will not
53 # be a process group leader, since the child receives a new process ID 53 # be a process group leader, since the child receives a new process ID
54 # and inherits the parent's process group ID. This step is required 54 # and inherits the parent's process group ID. This step is required
55 # to insure that the next call to os.setsid is successful. 55 # to insure that the next call to os.setsid is successful.
56 pid = os.fork() 56 pid = os.fork()
57 except OSError, e: 57 except OSError, e:
58 raise Exception, "%s [%d]" % (e.strerror, e.errno) 58 raise Exception, "%s [%d]" % (e.strerror, e.errno)
59 59
60 if (pid == 0): # The first child. 60 if (pid == 0): # The first child.
61 # To become the session leader of this new session and the process group 61 # To become the session leader of this new session and the process group
62 # leader of the new process group, we call os.setsid(). The process is 62 # leader of the new process group, we call os.setsid(). The process is
63 # also guaranteed not to have a controlling terminal. 63 # also guaranteed not to have a controlling terminal.
64 os.setsid() 64 os.setsid()
65 65
66 # Is ignoring SIGHUP necessary? 66 # Is ignoring SIGHUP necessary?
67 # 67 #
68 # It's often suggested that the SIGHUP signal should be ignored before 68 # It's often suggested that the SIGHUP signal should be ignored before
69 # the second fork to avoid premature termination of the process. The 69 # the second fork to avoid premature termination of the process. The
70 # reason is that when the first child terminates, all processes, e.g. 70 # reason is that when the first child terminates, all processes, e.g.
71 # the second child, in the orphaned group will be sent a SIGHUP. 71 # the second child, in the orphaned group will be sent a SIGHUP.
72 # 72 #
73 # "However, as part of the session management system, there are exactly 73 # "However, as part of the session management system, there are exactly
74 # two cases where SIGHUP is sent on the death of a process: 74 # two cases where SIGHUP is sent on the death of a process:
75 # 75 #
76 # 1) When the process that dies is the session leader of a session that 76 # 1) When the process that dies is the session leader of a session that
77 # is attached to a terminal device, SIGHUP is sent to all processes 77 # is attached to a terminal device, SIGHUP is sent to all processes
78 # in the foreground process group of that terminal device. 78 # in the foreground process group of that terminal device.
79 # 2) When the death of a process causes a process group to become 79 # 2) When the death of a process causes a process group to become
80 # orphaned, and one or more processes in the orphaned group are 80 # orphaned, and one or more processes in the orphaned group are
81 # stopped, then SIGHUP and SIGCONT are sent to all members of the 81 # stopped, then SIGHUP and SIGCONT are sent to all members of the
82 # orphaned group." [2] 82 # orphaned group." [2]
83 # 83 #
84 # The first case can be ignored since the child is guaranteed not to have 84 # The first case can be ignored since the child is guaranteed not to have
85 # a controlling terminal. The second case isn't so easy to dismiss. 85 # a controlling terminal. The second case isn't so easy to dismiss.
86 # The process group is orphaned when the first child terminates and 86 # The process group is orphaned when the first child terminates and
87 # POSIX.1 requires that every STOPPED process in an orphaned process 87 # POSIX.1 requires that every STOPPED process in an orphaned process
88 # group be sent a SIGHUP signal followed by a SIGCONT signal. Since the 88 # group be sent a SIGHUP signal followed by a SIGCONT signal. Since the
89 # second child is not STOPPED though, we can safely forego ignoring the 89 # second child is not STOPPED though, we can safely forego ignoring the
90 # SIGHUP signal. In any case, there are no ill-effects if it is ignored. 90 # SIGHUP signal. In any case, there are no ill-effects if it is ignored.
91 # 91 #
92 # import signal # Set handlers for asynchronous events. 92 # import signal # Set handlers for asynchronous events.
93 # signal.signal(signal.SIGHUP, signal.SIG_IGN) 93 # signal.signal(signal.SIGHUP, signal.SIG_IGN)
94 94
95 try: 95 try:
96 # Fork a second child and exit immediately to prevent zombies. This 96 # Fork a second child and exit immediately to prevent zombies. This
97 # causes the second child process to be orphaned, making the init 97 # causes the second child process to be orphaned, making the init
98 # process responsible for its cleanup. And, since the first child is 98 # process responsible for its cleanup. And, since the first child is
99 # a session leader without a controlling terminal, it's possible for 99 # a session leader without a controlling terminal, it's possible for
100 # it to acquire one by opening a terminal in the future (System V- 100 # it to acquire one by opening a terminal in the future (System V-
101 # based systems). This second fork guarantees that the child is no 101 # based systems). This second fork guarantees that the child is no
102 # longer a session leader, preventing the daemon from ever acquiring 102 # longer a session leader, preventing the daemon from ever acquiring
103 # a controlling terminal. 103 # a controlling terminal.
104 pid = os.fork() # Fork a second child. 104 pid = os.fork() # Fork a second child.
105 except OSError, e: 105 except OSError, e:
106 raise Exception, "%s [%d]" % (e.strerror, e.errno) 106 raise Exception, "%s [%d]" % (e.strerror, e.errno)
107 107
108 if (pid == 0): # The second child. 108 if (pid == 0): # The second child.
109 # We probably don't want the file mode creation mask inherited from 109 # We probably don't want the file mode creation mask inherited from
110 # the parent, so we give the child complete control over permissions. 110 # the parent, so we give the child complete control over permissions.
111 if UMASK is not None: 111 if UMASK is not None:
112 os.umask(UMASK) 112 os.umask(UMASK)
113 else: 113 else:
114 # Parent (the first child) of the second child. 114 # Parent (the first child) of the second child.
115 os._exit(0) 115 os._exit(0)
116 else: 116 else:
117 # exit() or _exit()? 117 # exit() or _exit()?
118 # _exit is like exit(), but it doesn't call any functions registered 118 # _exit is like exit(), but it doesn't call any functions registered
119 # with atexit (and on_exit) or any registered signal handlers. It also 119 # with atexit (and on_exit) or any registered signal handlers. It also
120 # closes any open file descriptors. Using exit() may cause all stdio 120 # closes any open file descriptors. Using exit() may cause all stdio
121 # streams to be flushed twice and any temporary files may be unexpectedly 121 # streams to be flushed twice and any temporary files may be unexpectedly
122 # removed. It's therefore recommended that child branches of a fork() 122 # removed. It's therefore recommended that child branches of a fork()
123 # and the parent branch(es) of a daemon use _exit(). 123 # and the parent branch(es) of a daemon use _exit().
124 return 124 return
125 125
126 # Close all open file descriptors. This prevents the child from keeping 126 # Close all open file descriptors. This prevents the child from keeping
127 # open any file descriptors inherited from the parent. There is a variety 127 # open any file descriptors inherited from the parent. There is a variety
128 # of methods to accomplish this task. Three are listed below. 128 # of methods to accomplish this task. Three are listed below.
129 # 129 #
130 # Try the system configuration variable, SC_OPEN_MAX, to obtain the maximum 130 # Try the system configuration variable, SC_OPEN_MAX, to obtain the maximum
131 # number of open file descriptors to close. If it doesn't exists, use 131 # number of open file descriptors to close. If it doesn't exists, use
132 # the default value (configurable). 132 # the default value (configurable).
133 # 133 #
134 # try: 134 # try:
135 # maxfd = os.sysconf("SC_OPEN_MAX") 135 # maxfd = os.sysconf("SC_OPEN_MAX")
136 # except (AttributeError, ValueError): 136 # except (AttributeError, ValueError):
137 # maxfd = MAXFD 137 # maxfd = MAXFD
138 # 138 #
139 # OR 139 # OR
140 # 140 #
141 # if (os.sysconf_names.has_key("SC_OPEN_MAX")): 141 # if (os.sysconf_names.has_key("SC_OPEN_MAX")):
142 # maxfd = os.sysconf("SC_OPEN_MAX") 142 # maxfd = os.sysconf("SC_OPEN_MAX")
143 # else: 143 # else:
144 # maxfd = MAXFD 144 # maxfd = MAXFD
145 # 145 #
146 # OR 146 # OR
147 # 147 #
148 # Use the getrlimit method to retrieve the maximum file descriptor number 148 # Use the getrlimit method to retrieve the maximum file descriptor number
149 # that can be opened by this process. If there is not limit on the 149 # that can be opened by this process. If there is not limit on the
150 # resource, use the default value. 150 # resource, use the default value.
151 # 151 #
152 import resource # Resource usage information. 152 import resource # Resource usage information.
153 maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1] 153 maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
154 if (maxfd == resource.RLIM_INFINITY): 154 if (maxfd == resource.RLIM_INFINITY):
155 maxfd = MAXFD 155 maxfd = MAXFD
156 156
157 # Iterate through and close all file descriptors. 157 # Iterate through and close all file descriptors.
158# for fd in range(0, maxfd): 158# for fd in range(0, maxfd):
159# try: 159# try:
160# os.close(fd) 160# os.close(fd)
161# except OSError: # ERROR, fd wasn't open to begin with (ignored) 161# except OSError: # ERROR, fd wasn't open to begin with (ignored)
162# pass 162# pass
163 163
164 # Redirect the standard I/O file descriptors to the specified file. Since 164 # Redirect the standard I/O file descriptors to the specified file. Since
165 # the daemon has no controlling terminal, most daemons redirect stdin, 165 # the daemon has no controlling terminal, most daemons redirect stdin,
166 # stdout, and stderr to /dev/null. This is done to prevent side-effects 166 # stdout, and stderr to /dev/null. This is done to prevent side-effects
167 # from reads and writes to the standard I/O file descriptors. 167 # from reads and writes to the standard I/O file descriptors.
168 168
169 # This call to open is guaranteed to return the lowest file descriptor, 169 # This call to open is guaranteed to return the lowest file descriptor,
170 # which will be 0 (stdin), since it was closed above. 170 # which will be 0 (stdin), since it was closed above.
171# os.open(REDIRECT_TO, os.O_RDWR) # standard input (0) 171# os.open(REDIRECT_TO, os.O_RDWR) # standard input (0)
172 172
173 # Duplicate standard input to standard output and standard error. 173 # Duplicate standard input to standard output and standard error.
174# os.dup2(0, 1) # standard output (1) 174# os.dup2(0, 1) # standard output (1)
175# os.dup2(0, 2) # standard error (2) 175# os.dup2(0, 2) # standard error (2)
176 176
177 177
178 si = file('/dev/null', 'r') 178 si = file('/dev/null', 'r')
179 so = file(logfile, 'w') 179 so = file(logfile, 'w')
180 se = so 180 se = so
181 181
182 182
183 # Replace those fds with our own 183 # Replace those fds with our own
184 os.dup2(si.fileno(), sys.stdin.fileno()) 184 os.dup2(si.fileno(), sys.stdin.fileno())
185 os.dup2(so.fileno(), sys.stdout.fileno()) 185 os.dup2(so.fileno(), sys.stdout.fileno())
186 os.dup2(se.fileno(), sys.stderr.fileno()) 186 os.dup2(se.fileno(), sys.stderr.fileno())
187 187
188 function() 188 function()
189
190 os._exit(0)
191 189
190 os._exit(0)