Statistics
| Branch: | Tag: | Revision:

root / lib / utils / process.py @ adec726e

History | View | Annotate | Download (30.1 kB)

1 a4ccecf6 Michael Hanselmann
#
2 a4ccecf6 Michael Hanselmann
#
3 a4ccecf6 Michael Hanselmann
4 21864565 Iustin Pop
# Copyright (C) 2006, 2007, 2010, 2011, 2012 Google Inc.
5 a4ccecf6 Michael Hanselmann
#
6 a4ccecf6 Michael Hanselmann
# This program is free software; you can redistribute it and/or modify
7 a4ccecf6 Michael Hanselmann
# it under the terms of the GNU General Public License as published by
8 a4ccecf6 Michael Hanselmann
# the Free Software Foundation; either version 2 of the License, or
9 a4ccecf6 Michael Hanselmann
# (at your option) any later version.
10 a4ccecf6 Michael Hanselmann
#
11 a4ccecf6 Michael Hanselmann
# This program is distributed in the hope that it will be useful, but
12 a4ccecf6 Michael Hanselmann
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 a4ccecf6 Michael Hanselmann
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 a4ccecf6 Michael Hanselmann
# General Public License for more details.
15 a4ccecf6 Michael Hanselmann
#
16 a4ccecf6 Michael Hanselmann
# You should have received a copy of the GNU General Public License
17 a4ccecf6 Michael Hanselmann
# along with this program; if not, write to the Free Software
18 a4ccecf6 Michael Hanselmann
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 a4ccecf6 Michael Hanselmann
# 02110-1301, USA.
20 a4ccecf6 Michael Hanselmann
21 a4ccecf6 Michael Hanselmann
"""Utility functions for processes.
22 a4ccecf6 Michael Hanselmann

23 a4ccecf6 Michael Hanselmann
"""
24 a4ccecf6 Michael Hanselmann
25 a4ccecf6 Michael Hanselmann
26 a4ccecf6 Michael Hanselmann
import os
27 a4ccecf6 Michael Hanselmann
import sys
28 a4ccecf6 Michael Hanselmann
import subprocess
29 a4ccecf6 Michael Hanselmann
import errno
30 a4ccecf6 Michael Hanselmann
import select
31 a4ccecf6 Michael Hanselmann
import logging
32 a4ccecf6 Michael Hanselmann
import signal
33 a4ccecf6 Michael Hanselmann
import resource
34 a4ccecf6 Michael Hanselmann
35 a4ccecf6 Michael Hanselmann
from cStringIO import StringIO
36 a4ccecf6 Michael Hanselmann
37 a4ccecf6 Michael Hanselmann
from ganeti import errors
38 a4ccecf6 Michael Hanselmann
from ganeti import constants
39 110f49ef Michael Hanselmann
from ganeti import compat
40 a4ccecf6 Michael Hanselmann
41 a4ccecf6 Michael Hanselmann
from ganeti.utils import retry as utils_retry
42 a4ccecf6 Michael Hanselmann
from ganeti.utils import wrapper as utils_wrapper
43 a4ccecf6 Michael Hanselmann
from ganeti.utils import text as utils_text
44 a4ccecf6 Michael Hanselmann
from ganeti.utils import io as utils_io
45 a4ccecf6 Michael Hanselmann
from ganeti.utils import algo as utils_algo
46 a4ccecf6 Michael Hanselmann
47 a4ccecf6 Michael Hanselmann
48 a4ccecf6 Michael Hanselmann
#: when set to True, L{RunCmd} is disabled
49 a4ccecf6 Michael Hanselmann
_no_fork = False
50 a4ccecf6 Michael Hanselmann
51 a4ccecf6 Michael Hanselmann
(_TIMEOUT_NONE,
52 a4ccecf6 Michael Hanselmann
 _TIMEOUT_TERM,
53 a4ccecf6 Michael Hanselmann
 _TIMEOUT_KILL) = range(3)
54 a4ccecf6 Michael Hanselmann
55 a4ccecf6 Michael Hanselmann
56 a4ccecf6 Michael Hanselmann
def DisableFork():
57 a4ccecf6 Michael Hanselmann
  """Disables the use of fork(2).
58 a4ccecf6 Michael Hanselmann

59 a4ccecf6 Michael Hanselmann
  """
60 b459a848 Andrea Spadaccini
  global _no_fork # pylint: disable=W0603
61 a4ccecf6 Michael Hanselmann
62 a4ccecf6 Michael Hanselmann
  _no_fork = True
63 a4ccecf6 Michael Hanselmann
64 a4ccecf6 Michael Hanselmann
65 a4ccecf6 Michael Hanselmann
class RunResult(object):
66 a4ccecf6 Michael Hanselmann
  """Holds the result of running external programs.
67 a4ccecf6 Michael Hanselmann

68 a4ccecf6 Michael Hanselmann
  @type exit_code: int
69 a4ccecf6 Michael Hanselmann
  @ivar exit_code: the exit code of the program, or None (if the program
70 a4ccecf6 Michael Hanselmann
      didn't exit())
71 a4ccecf6 Michael Hanselmann
  @type signal: int or None
72 a4ccecf6 Michael Hanselmann
  @ivar signal: the signal that caused the program to finish, or None
73 a4ccecf6 Michael Hanselmann
      (if the program wasn't terminated by a signal)
74 a4ccecf6 Michael Hanselmann
  @type stdout: str
75 a4ccecf6 Michael Hanselmann
  @ivar stdout: the standard output of the program
76 a4ccecf6 Michael Hanselmann
  @type stderr: str
77 a4ccecf6 Michael Hanselmann
  @ivar stderr: the standard error of the program
78 a4ccecf6 Michael Hanselmann
  @type failed: boolean
79 a4ccecf6 Michael Hanselmann
  @ivar failed: True in case the program was
80 a4ccecf6 Michael Hanselmann
      terminated by a signal or exited with a non-zero exit code
81 a4ccecf6 Michael Hanselmann
  @ivar fail_reason: a string detailing the termination reason
82 a4ccecf6 Michael Hanselmann

83 a4ccecf6 Michael Hanselmann
  """
84 a4ccecf6 Michael Hanselmann
  __slots__ = ["exit_code", "signal", "stdout", "stderr",
85 a4ccecf6 Michael Hanselmann
               "failed", "fail_reason", "cmd"]
86 a4ccecf6 Michael Hanselmann
87 a4ccecf6 Michael Hanselmann
  def __init__(self, exit_code, signal_, stdout, stderr, cmd, timeout_action,
88 a4ccecf6 Michael Hanselmann
               timeout):
89 a4ccecf6 Michael Hanselmann
    self.cmd = cmd
90 a4ccecf6 Michael Hanselmann
    self.exit_code = exit_code
91 a4ccecf6 Michael Hanselmann
    self.signal = signal_
92 a4ccecf6 Michael Hanselmann
    self.stdout = stdout
93 a4ccecf6 Michael Hanselmann
    self.stderr = stderr
94 a4ccecf6 Michael Hanselmann
    self.failed = (signal_ is not None or exit_code != 0)
95 a4ccecf6 Michael Hanselmann
96 a4ccecf6 Michael Hanselmann
    fail_msgs = []
97 a4ccecf6 Michael Hanselmann
    if self.signal is not None:
98 a4ccecf6 Michael Hanselmann
      fail_msgs.append("terminated by signal %s" % self.signal)
99 a4ccecf6 Michael Hanselmann
    elif self.exit_code is not None:
100 a4ccecf6 Michael Hanselmann
      fail_msgs.append("exited with exit code %s" % self.exit_code)
101 a4ccecf6 Michael Hanselmann
    else:
102 a4ccecf6 Michael Hanselmann
      fail_msgs.append("unable to determine termination reason")
103 a4ccecf6 Michael Hanselmann
104 a4ccecf6 Michael Hanselmann
    if timeout_action == _TIMEOUT_TERM:
105 a4ccecf6 Michael Hanselmann
      fail_msgs.append("terminated after timeout of %.2f seconds" % timeout)
106 a4ccecf6 Michael Hanselmann
    elif timeout_action == _TIMEOUT_KILL:
107 a4ccecf6 Michael Hanselmann
      fail_msgs.append(("force termination after timeout of %.2f seconds"
108 a4ccecf6 Michael Hanselmann
                        " and linger for another %.2f seconds") %
109 a4ccecf6 Michael Hanselmann
                       (timeout, constants.CHILD_LINGER_TIMEOUT))
110 a4ccecf6 Michael Hanselmann
111 a4ccecf6 Michael Hanselmann
    if fail_msgs and self.failed:
112 a4ccecf6 Michael Hanselmann
      self.fail_reason = utils_text.CommaJoin(fail_msgs)
113 2f18052f Michael Hanselmann
    else:
114 2f18052f Michael Hanselmann
      self.fail_reason = None
115 a4ccecf6 Michael Hanselmann
116 a4ccecf6 Michael Hanselmann
    if self.failed:
117 a4ccecf6 Michael Hanselmann
      logging.debug("Command '%s' failed (%s); output: %s",
118 a4ccecf6 Michael Hanselmann
                    self.cmd, self.fail_reason, self.output)
119 a4ccecf6 Michael Hanselmann
120 a4ccecf6 Michael Hanselmann
  def _GetOutput(self):
121 a4ccecf6 Michael Hanselmann
    """Returns the combined stdout and stderr for easier usage.
122 a4ccecf6 Michael Hanselmann

123 a4ccecf6 Michael Hanselmann
    """
124 a4ccecf6 Michael Hanselmann
    return self.stdout + self.stderr
125 a4ccecf6 Michael Hanselmann
126 a4ccecf6 Michael Hanselmann
  output = property(_GetOutput, None, None, "Return full output")
127 a4ccecf6 Michael Hanselmann
128 a4ccecf6 Michael Hanselmann
129 a4ccecf6 Michael Hanselmann
def _BuildCmdEnvironment(env, reset):
130 a4ccecf6 Michael Hanselmann
  """Builds the environment for an external program.
131 a4ccecf6 Michael Hanselmann

132 a4ccecf6 Michael Hanselmann
  """
133 a4ccecf6 Michael Hanselmann
  if reset:
134 a4ccecf6 Michael Hanselmann
    cmd_env = {}
135 a4ccecf6 Michael Hanselmann
  else:
136 a4ccecf6 Michael Hanselmann
    cmd_env = os.environ.copy()
137 a4ccecf6 Michael Hanselmann
    cmd_env["LC_ALL"] = "C"
138 a4ccecf6 Michael Hanselmann
139 a4ccecf6 Michael Hanselmann
  if env is not None:
140 a4ccecf6 Michael Hanselmann
    cmd_env.update(env)
141 a4ccecf6 Michael Hanselmann
142 a4ccecf6 Michael Hanselmann
  return cmd_env
143 a4ccecf6 Michael Hanselmann
144 a4ccecf6 Michael Hanselmann
145 a4ccecf6 Michael Hanselmann
def RunCmd(cmd, env=None, output=None, cwd="/", reset_env=False,
146 d6491981 René Nussbaumer
           interactive=False, timeout=None, noclose_fds=None,
147 09b72783 Michael Hanselmann
           input_fd=None, postfork_fn=None):
148 a4ccecf6 Michael Hanselmann
  """Execute a (shell) command.
149 a4ccecf6 Michael Hanselmann

150 a4ccecf6 Michael Hanselmann
  The command should not read from its standard input, as it will be
151 a4ccecf6 Michael Hanselmann
  closed.
152 a4ccecf6 Michael Hanselmann

153 a4ccecf6 Michael Hanselmann
  @type cmd: string or list
154 a4ccecf6 Michael Hanselmann
  @param cmd: Command to run
155 a4ccecf6 Michael Hanselmann
  @type env: dict
156 a4ccecf6 Michael Hanselmann
  @param env: Additional environment variables
157 a4ccecf6 Michael Hanselmann
  @type output: str
158 a4ccecf6 Michael Hanselmann
  @param output: if desired, the output of the command can be
159 a4ccecf6 Michael Hanselmann
      saved in a file instead of the RunResult instance; this
160 a4ccecf6 Michael Hanselmann
      parameter denotes the file name (if not None)
161 a4ccecf6 Michael Hanselmann
  @type cwd: string
162 a4ccecf6 Michael Hanselmann
  @param cwd: if specified, will be used as the working
163 a4ccecf6 Michael Hanselmann
      directory for the command; the default will be /
164 a4ccecf6 Michael Hanselmann
  @type reset_env: boolean
165 a4ccecf6 Michael Hanselmann
  @param reset_env: whether to reset or keep the default os environment
166 a4ccecf6 Michael Hanselmann
  @type interactive: boolean
167 eee68d57 Agata Murawska
  @param interactive: whether we pipe stdin, stdout and stderr
168 a4ccecf6 Michael Hanselmann
                      (default behaviour) or run the command interactive
169 a4ccecf6 Michael Hanselmann
  @type timeout: int
170 a4ccecf6 Michael Hanselmann
  @param timeout: If not None, timeout in seconds until child process gets
171 a4ccecf6 Michael Hanselmann
                  killed
172 7b0bf9cd Apollon Oikonomopoulos
  @type noclose_fds: list
173 7b0bf9cd Apollon Oikonomopoulos
  @param noclose_fds: list of additional (fd >=3) file descriptors to leave
174 7b0bf9cd Apollon Oikonomopoulos
                      open for the child process
175 d5d76ab2 Michael Hanselmann
  @type input_fd: C{file}-like object or numeric file descriptor
176 d5d76ab2 Michael Hanselmann
  @param input_fd: File descriptor for process' standard input
177 09b72783 Michael Hanselmann
  @type postfork_fn: Callable receiving PID as parameter
178 09b72783 Michael Hanselmann
  @param postfork_fn: Callback run after fork but before timeout
179 a4ccecf6 Michael Hanselmann
  @rtype: L{RunResult}
180 a4ccecf6 Michael Hanselmann
  @return: RunResult instance
181 a4ccecf6 Michael Hanselmann
  @raise errors.ProgrammerError: if we call this when forks are disabled
182 a4ccecf6 Michael Hanselmann

183 a4ccecf6 Michael Hanselmann
  """
184 a4ccecf6 Michael Hanselmann
  if _no_fork:
185 a4ccecf6 Michael Hanselmann
    raise errors.ProgrammerError("utils.RunCmd() called with fork() disabled")
186 a4ccecf6 Michael Hanselmann
187 a4ccecf6 Michael Hanselmann
  if output and interactive:
188 a4ccecf6 Michael Hanselmann
    raise errors.ProgrammerError("Parameters 'output' and 'interactive' can"
189 a4ccecf6 Michael Hanselmann
                                 " not be provided at the same time")
190 a4ccecf6 Michael Hanselmann
191 d5d76ab2 Michael Hanselmann
  if not (output is None or input_fd is None):
192 d5d76ab2 Michael Hanselmann
    # The current logic in "_RunCmdFile", which is used when output is defined,
193 d5d76ab2 Michael Hanselmann
    # does not support input files (not hard to implement, though)
194 d5d76ab2 Michael Hanselmann
    raise errors.ProgrammerError("Parameters 'output' and 'input_fd' can"
195 d5d76ab2 Michael Hanselmann
                                 " not be used at the same time")
196 d5d76ab2 Michael Hanselmann
197 a4ccecf6 Michael Hanselmann
  if isinstance(cmd, basestring):
198 a4ccecf6 Michael Hanselmann
    strcmd = cmd
199 a4ccecf6 Michael Hanselmann
    shell = True
200 a4ccecf6 Michael Hanselmann
  else:
201 a4ccecf6 Michael Hanselmann
    cmd = [str(val) for val in cmd]
202 a4ccecf6 Michael Hanselmann
    strcmd = utils_text.ShellQuoteArgs(cmd)
203 a4ccecf6 Michael Hanselmann
    shell = False
204 a4ccecf6 Michael Hanselmann
205 a4ccecf6 Michael Hanselmann
  if output:
206 21864565 Iustin Pop
    logging.info("RunCmd %s, output file '%s'", strcmd, output)
207 a4ccecf6 Michael Hanselmann
  else:
208 21864565 Iustin Pop
    logging.info("RunCmd %s", strcmd)
209 a4ccecf6 Michael Hanselmann
210 a4ccecf6 Michael Hanselmann
  cmd_env = _BuildCmdEnvironment(env, reset_env)
211 a4ccecf6 Michael Hanselmann
212 a4ccecf6 Michael Hanselmann
  try:
213 a4ccecf6 Michael Hanselmann
    if output is None:
214 a4ccecf6 Michael Hanselmann
      out, err, status, timeout_action = _RunCmdPipe(cmd, cmd_env, shell, cwd,
215 7b0bf9cd Apollon Oikonomopoulos
                                                     interactive, timeout,
216 d5d76ab2 Michael Hanselmann
                                                     noclose_fds, input_fd,
217 09b72783 Michael Hanselmann
                                                     postfork_fn=postfork_fn)
218 a4ccecf6 Michael Hanselmann
    else:
219 09b72783 Michael Hanselmann
      if postfork_fn:
220 09b72783 Michael Hanselmann
        raise errors.ProgrammerError("postfork_fn is not supported if output"
221 09b72783 Michael Hanselmann
                                     " should be captured")
222 d5d76ab2 Michael Hanselmann
      assert input_fd is None
223 a4ccecf6 Michael Hanselmann
      timeout_action = _TIMEOUT_NONE
224 7b0bf9cd Apollon Oikonomopoulos
      status = _RunCmdFile(cmd, cmd_env, shell, output, cwd, noclose_fds)
225 a4ccecf6 Michael Hanselmann
      out = err = ""
226 a4ccecf6 Michael Hanselmann
  except OSError, err:
227 a4ccecf6 Michael Hanselmann
    if err.errno == errno.ENOENT:
228 a4ccecf6 Michael Hanselmann
      raise errors.OpExecError("Can't execute '%s': not found (%s)" %
229 a4ccecf6 Michael Hanselmann
                               (strcmd, err))
230 a4ccecf6 Michael Hanselmann
    else:
231 a4ccecf6 Michael Hanselmann
      raise
232 a4ccecf6 Michael Hanselmann
233 a4ccecf6 Michael Hanselmann
  if status >= 0:
234 a4ccecf6 Michael Hanselmann
    exitcode = status
235 a4ccecf6 Michael Hanselmann
    signal_ = None
236 a4ccecf6 Michael Hanselmann
  else:
237 a4ccecf6 Michael Hanselmann
    exitcode = None
238 a4ccecf6 Michael Hanselmann
    signal_ = -status
239 a4ccecf6 Michael Hanselmann
240 a4ccecf6 Michael Hanselmann
  return RunResult(exitcode, signal_, out, err, strcmd, timeout_action, timeout)
241 a4ccecf6 Michael Hanselmann
242 a4ccecf6 Michael Hanselmann
243 a4ccecf6 Michael Hanselmann
def SetupDaemonEnv(cwd="/", umask=077):
244 a4ccecf6 Michael Hanselmann
  """Setup a daemon's environment.
245 a4ccecf6 Michael Hanselmann

246 a4ccecf6 Michael Hanselmann
  This should be called between the first and second fork, due to
247 a4ccecf6 Michael Hanselmann
  setsid usage.
248 a4ccecf6 Michael Hanselmann

249 a4ccecf6 Michael Hanselmann
  @param cwd: the directory to which to chdir
250 a4ccecf6 Michael Hanselmann
  @param umask: the umask to setup
251 a4ccecf6 Michael Hanselmann

252 a4ccecf6 Michael Hanselmann
  """
253 a4ccecf6 Michael Hanselmann
  os.chdir(cwd)
254 a4ccecf6 Michael Hanselmann
  os.umask(umask)
255 a4ccecf6 Michael Hanselmann
  os.setsid()
256 a4ccecf6 Michael Hanselmann
257 a4ccecf6 Michael Hanselmann
258 a4ccecf6 Michael Hanselmann
def SetupDaemonFDs(output_file, output_fd):
259 a4ccecf6 Michael Hanselmann
  """Setups up a daemon's file descriptors.
260 a4ccecf6 Michael Hanselmann

261 a4ccecf6 Michael Hanselmann
  @param output_file: if not None, the file to which to redirect
262 a4ccecf6 Michael Hanselmann
      stdout/stderr
263 a4ccecf6 Michael Hanselmann
  @param output_fd: if not None, the file descriptor for stdout/stderr
264 a4ccecf6 Michael Hanselmann

265 a4ccecf6 Michael Hanselmann
  """
266 a4ccecf6 Michael Hanselmann
  # check that at most one is defined
267 a4ccecf6 Michael Hanselmann
  assert [output_file, output_fd].count(None) >= 1
268 a4ccecf6 Michael Hanselmann
269 a4ccecf6 Michael Hanselmann
  # Open /dev/null (read-only, only for stdin)
270 a4ccecf6 Michael Hanselmann
  devnull_fd = os.open(os.devnull, os.O_RDONLY)
271 a4ccecf6 Michael Hanselmann
272 638ac34b Michael Hanselmann
  output_close = True
273 638ac34b Michael Hanselmann
274 a4ccecf6 Michael Hanselmann
  if output_fd is not None:
275 638ac34b Michael Hanselmann
    output_close = False
276 a4ccecf6 Michael Hanselmann
  elif output_file is not None:
277 a4ccecf6 Michael Hanselmann
    # Open output file
278 a4ccecf6 Michael Hanselmann
    try:
279 a4ccecf6 Michael Hanselmann
      output_fd = os.open(output_file,
280 a4ccecf6 Michael Hanselmann
                          os.O_WRONLY | os.O_CREAT | os.O_APPEND, 0600)
281 a4ccecf6 Michael Hanselmann
    except EnvironmentError, err:
282 a4ccecf6 Michael Hanselmann
      raise Exception("Opening output file failed: %s" % err)
283 a4ccecf6 Michael Hanselmann
  else:
284 a4ccecf6 Michael Hanselmann
    output_fd = os.open(os.devnull, os.O_WRONLY)
285 a4ccecf6 Michael Hanselmann
286 a4ccecf6 Michael Hanselmann
  # Redirect standard I/O
287 a4ccecf6 Michael Hanselmann
  os.dup2(devnull_fd, 0)
288 a4ccecf6 Michael Hanselmann
  os.dup2(output_fd, 1)
289 a4ccecf6 Michael Hanselmann
  os.dup2(output_fd, 2)
290 a4ccecf6 Michael Hanselmann
291 638ac34b Michael Hanselmann
  if devnull_fd > 2:
292 638ac34b Michael Hanselmann
    utils_wrapper.CloseFdNoError(devnull_fd)
293 638ac34b Michael Hanselmann
294 638ac34b Michael Hanselmann
  if output_close and output_fd > 2:
295 638ac34b Michael Hanselmann
    utils_wrapper.CloseFdNoError(output_fd)
296 638ac34b Michael Hanselmann
297 a4ccecf6 Michael Hanselmann
298 a4ccecf6 Michael Hanselmann
def StartDaemon(cmd, env=None, cwd="/", output=None, output_fd=None,
299 a4ccecf6 Michael Hanselmann
                pidfile=None):
300 a4ccecf6 Michael Hanselmann
  """Start a daemon process after forking twice.
301 a4ccecf6 Michael Hanselmann

302 a4ccecf6 Michael Hanselmann
  @type cmd: string or list
303 a4ccecf6 Michael Hanselmann
  @param cmd: Command to run
304 a4ccecf6 Michael Hanselmann
  @type env: dict
305 a4ccecf6 Michael Hanselmann
  @param env: Additional environment variables
306 a4ccecf6 Michael Hanselmann
  @type cwd: string
307 a4ccecf6 Michael Hanselmann
  @param cwd: Working directory for the program
308 a4ccecf6 Michael Hanselmann
  @type output: string
309 a4ccecf6 Michael Hanselmann
  @param output: Path to file in which to save the output
310 a4ccecf6 Michael Hanselmann
  @type output_fd: int
311 a4ccecf6 Michael Hanselmann
  @param output_fd: File descriptor for output
312 a4ccecf6 Michael Hanselmann
  @type pidfile: string
313 a4ccecf6 Michael Hanselmann
  @param pidfile: Process ID file
314 a4ccecf6 Michael Hanselmann
  @rtype: int
315 a4ccecf6 Michael Hanselmann
  @return: Daemon process ID
316 a4ccecf6 Michael Hanselmann
  @raise errors.ProgrammerError: if we call this when forks are disabled
317 a4ccecf6 Michael Hanselmann

318 a4ccecf6 Michael Hanselmann
  """
319 a4ccecf6 Michael Hanselmann
  if _no_fork:
320 a4ccecf6 Michael Hanselmann
    raise errors.ProgrammerError("utils.StartDaemon() called with fork()"
321 a4ccecf6 Michael Hanselmann
                                 " disabled")
322 a4ccecf6 Michael Hanselmann
323 a4ccecf6 Michael Hanselmann
  if output and not (bool(output) ^ (output_fd is not None)):
324 a4ccecf6 Michael Hanselmann
    raise errors.ProgrammerError("Only one of 'output' and 'output_fd' can be"
325 a4ccecf6 Michael Hanselmann
                                 " specified")
326 a4ccecf6 Michael Hanselmann
327 a4ccecf6 Michael Hanselmann
  if isinstance(cmd, basestring):
328 a4ccecf6 Michael Hanselmann
    cmd = ["/bin/sh", "-c", cmd]
329 a4ccecf6 Michael Hanselmann
330 a4ccecf6 Michael Hanselmann
  strcmd = utils_text.ShellQuoteArgs(cmd)
331 a4ccecf6 Michael Hanselmann
332 a4ccecf6 Michael Hanselmann
  if output:
333 a4ccecf6 Michael Hanselmann
    logging.debug("StartDaemon %s, output file '%s'", strcmd, output)
334 a4ccecf6 Michael Hanselmann
  else:
335 a4ccecf6 Michael Hanselmann
    logging.debug("StartDaemon %s", strcmd)
336 a4ccecf6 Michael Hanselmann
337 a4ccecf6 Michael Hanselmann
  cmd_env = _BuildCmdEnvironment(env, False)
338 a4ccecf6 Michael Hanselmann
339 a4ccecf6 Michael Hanselmann
  # Create pipe for sending PID back
340 a4ccecf6 Michael Hanselmann
  (pidpipe_read, pidpipe_write) = os.pipe()
341 a4ccecf6 Michael Hanselmann
  try:
342 a4ccecf6 Michael Hanselmann
    try:
343 a4ccecf6 Michael Hanselmann
      # Create pipe for sending error messages
344 a4ccecf6 Michael Hanselmann
      (errpipe_read, errpipe_write) = os.pipe()
345 a4ccecf6 Michael Hanselmann
      try:
346 a4ccecf6 Michael Hanselmann
        try:
347 a4ccecf6 Michael Hanselmann
          # First fork
348 a4ccecf6 Michael Hanselmann
          pid = os.fork()
349 a4ccecf6 Michael Hanselmann
          if pid == 0:
350 a4ccecf6 Michael Hanselmann
            try:
351 a4ccecf6 Michael Hanselmann
              # Child process, won't return
352 a4ccecf6 Michael Hanselmann
              _StartDaemonChild(errpipe_read, errpipe_write,
353 a4ccecf6 Michael Hanselmann
                                pidpipe_read, pidpipe_write,
354 a4ccecf6 Michael Hanselmann
                                cmd, cmd_env, cwd,
355 a4ccecf6 Michael Hanselmann
                                output, output_fd, pidfile)
356 a4ccecf6 Michael Hanselmann
            finally:
357 a4ccecf6 Michael Hanselmann
              # Well, maybe child process failed
358 b459a848 Andrea Spadaccini
              os._exit(1) # pylint: disable=W0212
359 a4ccecf6 Michael Hanselmann
        finally:
360 a4ccecf6 Michael Hanselmann
          utils_wrapper.CloseFdNoError(errpipe_write)
361 a4ccecf6 Michael Hanselmann
362 a4ccecf6 Michael Hanselmann
        # Wait for daemon to be started (or an error message to
363 a4ccecf6 Michael Hanselmann
        # arrive) and read up to 100 KB as an error message
364 a4ccecf6 Michael Hanselmann
        errormsg = utils_wrapper.RetryOnSignal(os.read, errpipe_read,
365 a4ccecf6 Michael Hanselmann
                                               100 * 1024)
366 a4ccecf6 Michael Hanselmann
      finally:
367 a4ccecf6 Michael Hanselmann
        utils_wrapper.CloseFdNoError(errpipe_read)
368 a4ccecf6 Michael Hanselmann
    finally:
369 a4ccecf6 Michael Hanselmann
      utils_wrapper.CloseFdNoError(pidpipe_write)
370 a4ccecf6 Michael Hanselmann
371 a4ccecf6 Michael Hanselmann
    # Read up to 128 bytes for PID
372 a4ccecf6 Michael Hanselmann
    pidtext = utils_wrapper.RetryOnSignal(os.read, pidpipe_read, 128)
373 a4ccecf6 Michael Hanselmann
  finally:
374 a4ccecf6 Michael Hanselmann
    utils_wrapper.CloseFdNoError(pidpipe_read)
375 a4ccecf6 Michael Hanselmann
376 a4ccecf6 Michael Hanselmann
  # Try to avoid zombies by waiting for child process
377 a4ccecf6 Michael Hanselmann
  try:
378 a4ccecf6 Michael Hanselmann
    os.waitpid(pid, 0)
379 a4ccecf6 Michael Hanselmann
  except OSError:
380 a4ccecf6 Michael Hanselmann
    pass
381 a4ccecf6 Michael Hanselmann
382 a4ccecf6 Michael Hanselmann
  if errormsg:
383 a4ccecf6 Michael Hanselmann
    raise errors.OpExecError("Error when starting daemon process: %r" %
384 a4ccecf6 Michael Hanselmann
                             errormsg)
385 a4ccecf6 Michael Hanselmann
386 a4ccecf6 Michael Hanselmann
  try:
387 a4ccecf6 Michael Hanselmann
    return int(pidtext)
388 a4ccecf6 Michael Hanselmann
  except (ValueError, TypeError), err:
389 a4ccecf6 Michael Hanselmann
    raise errors.OpExecError("Error while trying to parse PID %r: %s" %
390 a4ccecf6 Michael Hanselmann
                             (pidtext, err))
391 a4ccecf6 Michael Hanselmann
392 a4ccecf6 Michael Hanselmann
393 a4ccecf6 Michael Hanselmann
def _StartDaemonChild(errpipe_read, errpipe_write,
394 a4ccecf6 Michael Hanselmann
                      pidpipe_read, pidpipe_write,
395 a4ccecf6 Michael Hanselmann
                      args, env, cwd,
396 a4ccecf6 Michael Hanselmann
                      output, fd_output, pidfile):
397 a4ccecf6 Michael Hanselmann
  """Child process for starting daemon.
398 a4ccecf6 Michael Hanselmann

399 a4ccecf6 Michael Hanselmann
  """
400 a4ccecf6 Michael Hanselmann
  try:
401 a4ccecf6 Michael Hanselmann
    # Close parent's side
402 a4ccecf6 Michael Hanselmann
    utils_wrapper.CloseFdNoError(errpipe_read)
403 a4ccecf6 Michael Hanselmann
    utils_wrapper.CloseFdNoError(pidpipe_read)
404 a4ccecf6 Michael Hanselmann
405 a4ccecf6 Michael Hanselmann
    # First child process
406 a4ccecf6 Michael Hanselmann
    SetupDaemonEnv()
407 a4ccecf6 Michael Hanselmann
408 a4ccecf6 Michael Hanselmann
    # And fork for the second time
409 a4ccecf6 Michael Hanselmann
    pid = os.fork()
410 a4ccecf6 Michael Hanselmann
    if pid != 0:
411 a4ccecf6 Michael Hanselmann
      # Exit first child process
412 b459a848 Andrea Spadaccini
      os._exit(0) # pylint: disable=W0212
413 a4ccecf6 Michael Hanselmann
414 a4ccecf6 Michael Hanselmann
    # Make sure pipe is closed on execv* (and thereby notifies
415 a4ccecf6 Michael Hanselmann
    # original process)
416 a4ccecf6 Michael Hanselmann
    utils_wrapper.SetCloseOnExecFlag(errpipe_write, True)
417 a4ccecf6 Michael Hanselmann
418 a4ccecf6 Michael Hanselmann
    # List of file descriptors to be left open
419 a4ccecf6 Michael Hanselmann
    noclose_fds = [errpipe_write]
420 a4ccecf6 Michael Hanselmann
421 a4ccecf6 Michael Hanselmann
    # Open PID file
422 a4ccecf6 Michael Hanselmann
    if pidfile:
423 a4ccecf6 Michael Hanselmann
      fd_pidfile = utils_io.WritePidFile(pidfile)
424 a4ccecf6 Michael Hanselmann
425 a4ccecf6 Michael Hanselmann
      # Keeping the file open to hold the lock
426 a4ccecf6 Michael Hanselmann
      noclose_fds.append(fd_pidfile)
427 a4ccecf6 Michael Hanselmann
428 a4ccecf6 Michael Hanselmann
      utils_wrapper.SetCloseOnExecFlag(fd_pidfile, False)
429 a4ccecf6 Michael Hanselmann
    else:
430 a4ccecf6 Michael Hanselmann
      fd_pidfile = None
431 a4ccecf6 Michael Hanselmann
432 a4ccecf6 Michael Hanselmann
    SetupDaemonFDs(output, fd_output)
433 a4ccecf6 Michael Hanselmann
434 a4ccecf6 Michael Hanselmann
    # Send daemon PID to parent
435 a4ccecf6 Michael Hanselmann
    utils_wrapper.RetryOnSignal(os.write, pidpipe_write, str(os.getpid()))
436 a4ccecf6 Michael Hanselmann
437 a4ccecf6 Michael Hanselmann
    # Close all file descriptors except stdio and error message pipe
438 a4ccecf6 Michael Hanselmann
    CloseFDs(noclose_fds=noclose_fds)
439 a4ccecf6 Michael Hanselmann
440 a4ccecf6 Michael Hanselmann
    # Change working directory
441 a4ccecf6 Michael Hanselmann
    os.chdir(cwd)
442 a4ccecf6 Michael Hanselmann
443 a4ccecf6 Michael Hanselmann
    if env is None:
444 a4ccecf6 Michael Hanselmann
      os.execvp(args[0], args)
445 a4ccecf6 Michael Hanselmann
    else:
446 a4ccecf6 Michael Hanselmann
      os.execvpe(args[0], args, env)
447 b459a848 Andrea Spadaccini
  except: # pylint: disable=W0702
448 a4ccecf6 Michael Hanselmann
    try:
449 a4ccecf6 Michael Hanselmann
      # Report errors to original process
450 a4ccecf6 Michael Hanselmann
      WriteErrorToFD(errpipe_write, str(sys.exc_info()[1]))
451 b459a848 Andrea Spadaccini
    except: # pylint: disable=W0702
452 a4ccecf6 Michael Hanselmann
      # Ignore errors in error handling
453 a4ccecf6 Michael Hanselmann
      pass
454 a4ccecf6 Michael Hanselmann
455 b459a848 Andrea Spadaccini
  os._exit(1) # pylint: disable=W0212
456 a4ccecf6 Michael Hanselmann
457 a4ccecf6 Michael Hanselmann
458 a4ccecf6 Michael Hanselmann
def WriteErrorToFD(fd, err):
459 a4ccecf6 Michael Hanselmann
  """Possibly write an error message to a fd.
460 a4ccecf6 Michael Hanselmann

461 a4ccecf6 Michael Hanselmann
  @type fd: None or int (file descriptor)
462 a4ccecf6 Michael Hanselmann
  @param fd: if not None, the error will be written to this fd
463 a4ccecf6 Michael Hanselmann
  @param err: string, the error message
464 a4ccecf6 Michael Hanselmann

465 a4ccecf6 Michael Hanselmann
  """
466 a4ccecf6 Michael Hanselmann
  if fd is None:
467 a4ccecf6 Michael Hanselmann
    return
468 a4ccecf6 Michael Hanselmann
469 a4ccecf6 Michael Hanselmann
  if not err:
470 a4ccecf6 Michael Hanselmann
    err = "<unknown error>"
471 a4ccecf6 Michael Hanselmann
472 a4ccecf6 Michael Hanselmann
  utils_wrapper.RetryOnSignal(os.write, fd, err)
473 a4ccecf6 Michael Hanselmann
474 a4ccecf6 Michael Hanselmann
475 a4ccecf6 Michael Hanselmann
def _CheckIfAlive(child):
476 a4ccecf6 Michael Hanselmann
  """Raises L{utils_retry.RetryAgain} if child is still alive.
477 a4ccecf6 Michael Hanselmann

478 a4ccecf6 Michael Hanselmann
  @raises utils_retry.RetryAgain: If child is still alive
479 a4ccecf6 Michael Hanselmann

480 a4ccecf6 Michael Hanselmann
  """
481 a4ccecf6 Michael Hanselmann
  if child.poll() is None:
482 a4ccecf6 Michael Hanselmann
    raise utils_retry.RetryAgain()
483 a4ccecf6 Michael Hanselmann
484 a4ccecf6 Michael Hanselmann
485 a4ccecf6 Michael Hanselmann
def _WaitForProcess(child, timeout):
486 a4ccecf6 Michael Hanselmann
  """Waits for the child to terminate or until we reach timeout.
487 a4ccecf6 Michael Hanselmann

488 a4ccecf6 Michael Hanselmann
  """
489 a4ccecf6 Michael Hanselmann
  try:
490 a4ccecf6 Michael Hanselmann
    utils_retry.Retry(_CheckIfAlive, (1.0, 1.2, 5.0), max(0, timeout),
491 a4ccecf6 Michael Hanselmann
                      args=[child])
492 a4ccecf6 Michael Hanselmann
  except utils_retry.RetryTimeout:
493 a4ccecf6 Michael Hanselmann
    pass
494 a4ccecf6 Michael Hanselmann
495 a4ccecf6 Michael Hanselmann
496 7b0bf9cd Apollon Oikonomopoulos
def _RunCmdPipe(cmd, env, via_shell, cwd, interactive, timeout, noclose_fds,
497 09b72783 Michael Hanselmann
                input_fd, postfork_fn=None,
498 09b72783 Michael Hanselmann
                _linger_timeout=constants.CHILD_LINGER_TIMEOUT):
499 a4ccecf6 Michael Hanselmann
  """Run a command and return its output.
500 a4ccecf6 Michael Hanselmann

501 a4ccecf6 Michael Hanselmann
  @type  cmd: string or list
502 a4ccecf6 Michael Hanselmann
  @param cmd: Command to run
503 a4ccecf6 Michael Hanselmann
  @type env: dict
504 a4ccecf6 Michael Hanselmann
  @param env: The environment to use
505 a4ccecf6 Michael Hanselmann
  @type via_shell: bool
506 a4ccecf6 Michael Hanselmann
  @param via_shell: if we should run via the shell
507 a4ccecf6 Michael Hanselmann
  @type cwd: string
508 a4ccecf6 Michael Hanselmann
  @param cwd: the working directory for the program
509 a4ccecf6 Michael Hanselmann
  @type interactive: boolean
510 a4ccecf6 Michael Hanselmann
  @param interactive: Run command interactive (without piping)
511 a4ccecf6 Michael Hanselmann
  @type timeout: int
512 a4ccecf6 Michael Hanselmann
  @param timeout: Timeout after the programm gets terminated
513 7b0bf9cd Apollon Oikonomopoulos
  @type noclose_fds: list
514 7b0bf9cd Apollon Oikonomopoulos
  @param noclose_fds: list of additional (fd >=3) file descriptors to leave
515 7b0bf9cd Apollon Oikonomopoulos
                      open for the child process
516 d5d76ab2 Michael Hanselmann
  @type input_fd: C{file}-like object or numeric file descriptor
517 d5d76ab2 Michael Hanselmann
  @param input_fd: File descriptor for process' standard input
518 09b72783 Michael Hanselmann
  @type postfork_fn: Callable receiving PID as parameter
519 09b72783 Michael Hanselmann
  @param postfork_fn: Function run after fork but before timeout
520 a4ccecf6 Michael Hanselmann
  @rtype: tuple
521 a4ccecf6 Michael Hanselmann
  @return: (out, err, status)
522 a4ccecf6 Michael Hanselmann

523 a4ccecf6 Michael Hanselmann
  """
524 a4ccecf6 Michael Hanselmann
  poller = select.poll()
525 a4ccecf6 Michael Hanselmann
526 a4ccecf6 Michael Hanselmann
  if interactive:
527 d5d76ab2 Michael Hanselmann
    stderr = None
528 d5d76ab2 Michael Hanselmann
    stdout = None
529 d5d76ab2 Michael Hanselmann
  else:
530 d5d76ab2 Michael Hanselmann
    stderr = subprocess.PIPE
531 d5d76ab2 Michael Hanselmann
    stdout = subprocess.PIPE
532 d5d76ab2 Michael Hanselmann
533 d5d76ab2 Michael Hanselmann
  if input_fd:
534 d5d76ab2 Michael Hanselmann
    stdin = input_fd
535 d5d76ab2 Michael Hanselmann
  elif interactive:
536 d5d76ab2 Michael Hanselmann
    stdin = None
537 d5d76ab2 Michael Hanselmann
  else:
538 d5d76ab2 Michael Hanselmann
    stdin = subprocess.PIPE
539 a4ccecf6 Michael Hanselmann
540 7b0bf9cd Apollon Oikonomopoulos
  if noclose_fds:
541 7b0bf9cd Apollon Oikonomopoulos
    preexec_fn = lambda: CloseFDs(noclose_fds)
542 7b0bf9cd Apollon Oikonomopoulos
    close_fds = False
543 7b0bf9cd Apollon Oikonomopoulos
  else:
544 7b0bf9cd Apollon Oikonomopoulos
    preexec_fn = None
545 7b0bf9cd Apollon Oikonomopoulos
    close_fds = True
546 7b0bf9cd Apollon Oikonomopoulos
547 a4ccecf6 Michael Hanselmann
  child = subprocess.Popen(cmd, shell=via_shell,
548 a4ccecf6 Michael Hanselmann
                           stderr=stderr,
549 a4ccecf6 Michael Hanselmann
                           stdout=stdout,
550 a4ccecf6 Michael Hanselmann
                           stdin=stdin,
551 7b0bf9cd Apollon Oikonomopoulos
                           close_fds=close_fds, env=env,
552 7b0bf9cd Apollon Oikonomopoulos
                           cwd=cwd,
553 7b0bf9cd Apollon Oikonomopoulos
                           preexec_fn=preexec_fn)
554 a4ccecf6 Michael Hanselmann
555 09b72783 Michael Hanselmann
  if postfork_fn:
556 09b72783 Michael Hanselmann
    postfork_fn(child.pid)
557 d6491981 René Nussbaumer
558 a4ccecf6 Michael Hanselmann
  out = StringIO()
559 a4ccecf6 Michael Hanselmann
  err = StringIO()
560 a4ccecf6 Michael Hanselmann
561 a4ccecf6 Michael Hanselmann
  linger_timeout = None
562 a4ccecf6 Michael Hanselmann
563 a4ccecf6 Michael Hanselmann
  if timeout is None:
564 a4ccecf6 Michael Hanselmann
    poll_timeout = None
565 a4ccecf6 Michael Hanselmann
  else:
566 a4ccecf6 Michael Hanselmann
    poll_timeout = utils_algo.RunningTimeout(timeout, True).Remaining
567 a4ccecf6 Michael Hanselmann
568 a4ccecf6 Michael Hanselmann
  msg_timeout = ("Command %s (%d) run into execution timeout, terminating" %
569 a4ccecf6 Michael Hanselmann
                 (cmd, child.pid))
570 a4ccecf6 Michael Hanselmann
  msg_linger = ("Command %s (%d) run into linger timeout, killing" %
571 a4ccecf6 Michael Hanselmann
                (cmd, child.pid))
572 a4ccecf6 Michael Hanselmann
573 a4ccecf6 Michael Hanselmann
  timeout_action = _TIMEOUT_NONE
574 a4ccecf6 Michael Hanselmann
575 d5d76ab2 Michael Hanselmann
  # subprocess: "If the stdin argument is PIPE, this attribute is a file object
576 d5d76ab2 Michael Hanselmann
  # that provides input to the child process. Otherwise, it is None."
577 d5d76ab2 Michael Hanselmann
  assert (stdin == subprocess.PIPE) ^ (child.stdin is None), \
578 d5d76ab2 Michael Hanselmann
    "subprocess' stdin did not behave as documented"
579 d5d76ab2 Michael Hanselmann
580 a4ccecf6 Michael Hanselmann
  if not interactive:
581 d5d76ab2 Michael Hanselmann
    if child.stdin is not None:
582 d5d76ab2 Michael Hanselmann
      child.stdin.close()
583 a4ccecf6 Michael Hanselmann
    poller.register(child.stdout, select.POLLIN)
584 a4ccecf6 Michael Hanselmann
    poller.register(child.stderr, select.POLLIN)
585 a4ccecf6 Michael Hanselmann
    fdmap = {
586 a4ccecf6 Michael Hanselmann
      child.stdout.fileno(): (out, child.stdout),
587 a4ccecf6 Michael Hanselmann
      child.stderr.fileno(): (err, child.stderr),
588 a4ccecf6 Michael Hanselmann
      }
589 a4ccecf6 Michael Hanselmann
    for fd in fdmap:
590 a4ccecf6 Michael Hanselmann
      utils_wrapper.SetNonblockFlag(fd, True)
591 a4ccecf6 Michael Hanselmann
592 a4ccecf6 Michael Hanselmann
    while fdmap:
593 a4ccecf6 Michael Hanselmann
      if poll_timeout:
594 a4ccecf6 Michael Hanselmann
        pt = poll_timeout() * 1000
595 a4ccecf6 Michael Hanselmann
        if pt < 0:
596 a4ccecf6 Michael Hanselmann
          if linger_timeout is None:
597 a4ccecf6 Michael Hanselmann
            logging.warning(msg_timeout)
598 a4ccecf6 Michael Hanselmann
            if child.poll() is None:
599 a4ccecf6 Michael Hanselmann
              timeout_action = _TIMEOUT_TERM
600 a4ccecf6 Michael Hanselmann
              utils_wrapper.IgnoreProcessNotFound(os.kill, child.pid,
601 a4ccecf6 Michael Hanselmann
                                                  signal.SIGTERM)
602 a4ccecf6 Michael Hanselmann
            linger_timeout = \
603 a4ccecf6 Michael Hanselmann
              utils_algo.RunningTimeout(_linger_timeout, True).Remaining
604 a4ccecf6 Michael Hanselmann
          pt = linger_timeout() * 1000
605 a4ccecf6 Michael Hanselmann
          if pt < 0:
606 a4ccecf6 Michael Hanselmann
            break
607 a4ccecf6 Michael Hanselmann
      else:
608 a4ccecf6 Michael Hanselmann
        pt = None
609 a4ccecf6 Michael Hanselmann
610 a4ccecf6 Michael Hanselmann
      pollresult = utils_wrapper.RetryOnSignal(poller.poll, pt)
611 a4ccecf6 Michael Hanselmann
612 a4ccecf6 Michael Hanselmann
      for fd, event in pollresult:
613 a4ccecf6 Michael Hanselmann
        if event & select.POLLIN or event & select.POLLPRI:
614 a4ccecf6 Michael Hanselmann
          data = fdmap[fd][1].read()
615 a4ccecf6 Michael Hanselmann
          # no data from read signifies EOF (the same as POLLHUP)
616 a4ccecf6 Michael Hanselmann
          if not data:
617 a4ccecf6 Michael Hanselmann
            poller.unregister(fd)
618 a4ccecf6 Michael Hanselmann
            del fdmap[fd]
619 a4ccecf6 Michael Hanselmann
            continue
620 a4ccecf6 Michael Hanselmann
          fdmap[fd][0].write(data)
621 a4ccecf6 Michael Hanselmann
        if (event & select.POLLNVAL or event & select.POLLHUP or
622 a4ccecf6 Michael Hanselmann
            event & select.POLLERR):
623 a4ccecf6 Michael Hanselmann
          poller.unregister(fd)
624 a4ccecf6 Michael Hanselmann
          del fdmap[fd]
625 a4ccecf6 Michael Hanselmann
626 a4ccecf6 Michael Hanselmann
  if timeout is not None:
627 a4ccecf6 Michael Hanselmann
    assert callable(poll_timeout)
628 a4ccecf6 Michael Hanselmann
629 a4ccecf6 Michael Hanselmann
    # We have no I/O left but it might still run
630 a4ccecf6 Michael Hanselmann
    if child.poll() is None:
631 a4ccecf6 Michael Hanselmann
      _WaitForProcess(child, poll_timeout())
632 a4ccecf6 Michael Hanselmann
633 a4ccecf6 Michael Hanselmann
    # Terminate if still alive after timeout
634 a4ccecf6 Michael Hanselmann
    if child.poll() is None:
635 a4ccecf6 Michael Hanselmann
      if linger_timeout is None:
636 a4ccecf6 Michael Hanselmann
        logging.warning(msg_timeout)
637 a4ccecf6 Michael Hanselmann
        timeout_action = _TIMEOUT_TERM
638 a4ccecf6 Michael Hanselmann
        utils_wrapper.IgnoreProcessNotFound(os.kill, child.pid, signal.SIGTERM)
639 a4ccecf6 Michael Hanselmann
        lt = _linger_timeout
640 a4ccecf6 Michael Hanselmann
      else:
641 a4ccecf6 Michael Hanselmann
        lt = linger_timeout()
642 a4ccecf6 Michael Hanselmann
      _WaitForProcess(child, lt)
643 a4ccecf6 Michael Hanselmann
644 a4ccecf6 Michael Hanselmann
    # Okay, still alive after timeout and linger timeout? Kill it!
645 a4ccecf6 Michael Hanselmann
    if child.poll() is None:
646 a4ccecf6 Michael Hanselmann
      timeout_action = _TIMEOUT_KILL
647 a4ccecf6 Michael Hanselmann
      logging.warning(msg_linger)
648 a4ccecf6 Michael Hanselmann
      utils_wrapper.IgnoreProcessNotFound(os.kill, child.pid, signal.SIGKILL)
649 a4ccecf6 Michael Hanselmann
650 a4ccecf6 Michael Hanselmann
  out = out.getvalue()
651 a4ccecf6 Michael Hanselmann
  err = err.getvalue()
652 a4ccecf6 Michael Hanselmann
653 a4ccecf6 Michael Hanselmann
  status = child.wait()
654 a4ccecf6 Michael Hanselmann
  return out, err, status, timeout_action
655 a4ccecf6 Michael Hanselmann
656 a4ccecf6 Michael Hanselmann
657 7b0bf9cd Apollon Oikonomopoulos
def _RunCmdFile(cmd, env, via_shell, output, cwd, noclose_fds):
658 a4ccecf6 Michael Hanselmann
  """Run a command and save its output to a file.
659 a4ccecf6 Michael Hanselmann

660 a4ccecf6 Michael Hanselmann
  @type  cmd: string or list
661 a4ccecf6 Michael Hanselmann
  @param cmd: Command to run
662 a4ccecf6 Michael Hanselmann
  @type env: dict
663 a4ccecf6 Michael Hanselmann
  @param env: The environment to use
664 a4ccecf6 Michael Hanselmann
  @type via_shell: bool
665 a4ccecf6 Michael Hanselmann
  @param via_shell: if we should run via the shell
666 a4ccecf6 Michael Hanselmann
  @type output: str
667 a4ccecf6 Michael Hanselmann
  @param output: the filename in which to save the output
668 a4ccecf6 Michael Hanselmann
  @type cwd: string
669 a4ccecf6 Michael Hanselmann
  @param cwd: the working directory for the program
670 7b0bf9cd Apollon Oikonomopoulos
  @type noclose_fds: list
671 7b0bf9cd Apollon Oikonomopoulos
  @param noclose_fds: list of additional (fd >=3) file descriptors to leave
672 7b0bf9cd Apollon Oikonomopoulos
                      open for the child process
673 a4ccecf6 Michael Hanselmann
  @rtype: int
674 a4ccecf6 Michael Hanselmann
  @return: the exit status
675 a4ccecf6 Michael Hanselmann

676 a4ccecf6 Michael Hanselmann
  """
677 a4ccecf6 Michael Hanselmann
  fh = open(output, "a")
678 7b0bf9cd Apollon Oikonomopoulos
679 7b0bf9cd Apollon Oikonomopoulos
  if noclose_fds:
680 7b0bf9cd Apollon Oikonomopoulos
    preexec_fn = lambda: CloseFDs(noclose_fds + [fh.fileno()])
681 7b0bf9cd Apollon Oikonomopoulos
    close_fds = False
682 7b0bf9cd Apollon Oikonomopoulos
  else:
683 7b0bf9cd Apollon Oikonomopoulos
    preexec_fn = None
684 7b0bf9cd Apollon Oikonomopoulos
    close_fds = True
685 7b0bf9cd Apollon Oikonomopoulos
686 a4ccecf6 Michael Hanselmann
  try:
687 a4ccecf6 Michael Hanselmann
    child = subprocess.Popen(cmd, shell=via_shell,
688 a4ccecf6 Michael Hanselmann
                             stderr=subprocess.STDOUT,
689 a4ccecf6 Michael Hanselmann
                             stdout=fh,
690 a4ccecf6 Michael Hanselmann
                             stdin=subprocess.PIPE,
691 7b0bf9cd Apollon Oikonomopoulos
                             close_fds=close_fds, env=env,
692 7b0bf9cd Apollon Oikonomopoulos
                             cwd=cwd,
693 7b0bf9cd Apollon Oikonomopoulos
                             preexec_fn=preexec_fn)
694 a4ccecf6 Michael Hanselmann
695 a4ccecf6 Michael Hanselmann
    child.stdin.close()
696 a4ccecf6 Michael Hanselmann
    status = child.wait()
697 a4ccecf6 Michael Hanselmann
  finally:
698 a4ccecf6 Michael Hanselmann
    fh.close()
699 a4ccecf6 Michael Hanselmann
  return status
700 a4ccecf6 Michael Hanselmann
701 a4ccecf6 Michael Hanselmann
702 a4ccecf6 Michael Hanselmann
def RunParts(dir_name, env=None, reset_env=False):
703 a4ccecf6 Michael Hanselmann
  """Run Scripts or programs in a directory
704 a4ccecf6 Michael Hanselmann

705 a4ccecf6 Michael Hanselmann
  @type dir_name: string
706 a4ccecf6 Michael Hanselmann
  @param dir_name: absolute path to a directory
707 a4ccecf6 Michael Hanselmann
  @type env: dict
708 a4ccecf6 Michael Hanselmann
  @param env: The environment to use
709 a4ccecf6 Michael Hanselmann
  @type reset_env: boolean
710 a4ccecf6 Michael Hanselmann
  @param reset_env: whether to reset or keep the default os environment
711 a4ccecf6 Michael Hanselmann
  @rtype: list of tuples
712 a4ccecf6 Michael Hanselmann
  @return: list of (name, (one of RUNDIR_STATUS), RunResult)
713 a4ccecf6 Michael Hanselmann

714 a4ccecf6 Michael Hanselmann
  """
715 a4ccecf6 Michael Hanselmann
  rr = []
716 a4ccecf6 Michael Hanselmann
717 a4ccecf6 Michael Hanselmann
  try:
718 a4ccecf6 Michael Hanselmann
    dir_contents = utils_io.ListVisibleFiles(dir_name)
719 a4ccecf6 Michael Hanselmann
  except OSError, err:
720 a4ccecf6 Michael Hanselmann
    logging.warning("RunParts: skipping %s (cannot list: %s)", dir_name, err)
721 a4ccecf6 Michael Hanselmann
    return rr
722 a4ccecf6 Michael Hanselmann
723 a4ccecf6 Michael Hanselmann
  for relname in sorted(dir_contents):
724 a4ccecf6 Michael Hanselmann
    fname = utils_io.PathJoin(dir_name, relname)
725 10b86782 Michael Hanselmann
    if not (constants.EXT_PLUGIN_MASK.match(relname) is not None and
726 10b86782 Michael Hanselmann
            utils_wrapper.IsExecutable(fname)):
727 a4ccecf6 Michael Hanselmann
      rr.append((relname, constants.RUNPARTS_SKIP, None))
728 a4ccecf6 Michael Hanselmann
    else:
729 a4ccecf6 Michael Hanselmann
      try:
730 a4ccecf6 Michael Hanselmann
        result = RunCmd([fname], env=env, reset_env=reset_env)
731 b459a848 Andrea Spadaccini
      except Exception, err: # pylint: disable=W0703
732 a4ccecf6 Michael Hanselmann
        rr.append((relname, constants.RUNPARTS_ERR, str(err)))
733 a4ccecf6 Michael Hanselmann
      else:
734 a4ccecf6 Michael Hanselmann
        rr.append((relname, constants.RUNPARTS_RUN, result))
735 a4ccecf6 Michael Hanselmann
736 a4ccecf6 Michael Hanselmann
  return rr
737 a4ccecf6 Michael Hanselmann
738 a4ccecf6 Michael Hanselmann
739 a4ccecf6 Michael Hanselmann
def _GetProcStatusPath(pid):
740 a4ccecf6 Michael Hanselmann
  """Returns the path for a PID's proc status file.
741 a4ccecf6 Michael Hanselmann

742 a4ccecf6 Michael Hanselmann
  @type pid: int
743 a4ccecf6 Michael Hanselmann
  @param pid: Process ID
744 a4ccecf6 Michael Hanselmann
  @rtype: string
745 a4ccecf6 Michael Hanselmann

746 a4ccecf6 Michael Hanselmann
  """
747 a4ccecf6 Michael Hanselmann
  return "/proc/%d/status" % pid
748 a4ccecf6 Michael Hanselmann
749 a4ccecf6 Michael Hanselmann
750 a4ccecf6 Michael Hanselmann
def IsProcessAlive(pid):
751 a4ccecf6 Michael Hanselmann
  """Check if a given pid exists on the system.
752 a4ccecf6 Michael Hanselmann

753 a4ccecf6 Michael Hanselmann
  @note: zombie status is not handled, so zombie processes
754 a4ccecf6 Michael Hanselmann
      will be returned as alive
755 a4ccecf6 Michael Hanselmann
  @type pid: int
756 a4ccecf6 Michael Hanselmann
  @param pid: the process ID to check
757 a4ccecf6 Michael Hanselmann
  @rtype: boolean
758 a4ccecf6 Michael Hanselmann
  @return: True if the process exists
759 a4ccecf6 Michael Hanselmann

760 a4ccecf6 Michael Hanselmann
  """
761 a4ccecf6 Michael Hanselmann
  def _TryStat(name):
762 a4ccecf6 Michael Hanselmann
    try:
763 a4ccecf6 Michael Hanselmann
      os.stat(name)
764 a4ccecf6 Michael Hanselmann
      return True
765 a4ccecf6 Michael Hanselmann
    except EnvironmentError, err:
766 a4ccecf6 Michael Hanselmann
      if err.errno in (errno.ENOENT, errno.ENOTDIR):
767 a4ccecf6 Michael Hanselmann
        return False
768 a4ccecf6 Michael Hanselmann
      elif err.errno == errno.EINVAL:
769 a4ccecf6 Michael Hanselmann
        raise utils_retry.RetryAgain(err)
770 a4ccecf6 Michael Hanselmann
      raise
771 a4ccecf6 Michael Hanselmann
772 a4ccecf6 Michael Hanselmann
  assert isinstance(pid, int), "pid must be an integer"
773 a4ccecf6 Michael Hanselmann
  if pid <= 0:
774 a4ccecf6 Michael Hanselmann
    return False
775 a4ccecf6 Michael Hanselmann
776 a4ccecf6 Michael Hanselmann
  # /proc in a multiprocessor environment can have strange behaviors.
777 a4ccecf6 Michael Hanselmann
  # Retry the os.stat a few times until we get a good result.
778 a4ccecf6 Michael Hanselmann
  try:
779 a4ccecf6 Michael Hanselmann
    return utils_retry.Retry(_TryStat, (0.01, 1.5, 0.1), 0.5,
780 a4ccecf6 Michael Hanselmann
                             args=[_GetProcStatusPath(pid)])
781 a4ccecf6 Michael Hanselmann
  except utils_retry.RetryTimeout, err:
782 a4ccecf6 Michael Hanselmann
    err.RaiseInner()
783 a4ccecf6 Michael Hanselmann
784 a4ccecf6 Michael Hanselmann
785 306b855a Jose A. Lopes
def IsDaemonAlive(name):
786 306b855a Jose A. Lopes
  """Determines whether a daemon is alive
787 306b855a Jose A. Lopes

788 306b855a Jose A. Lopes
  @type name: string
789 306b855a Jose A. Lopes
  @param name: daemon name
790 306b855a Jose A. Lopes

791 306b855a Jose A. Lopes
  @rtype: boolean
792 306b855a Jose A. Lopes
  @return: True if daemon is running, False otherwise
793 306b855a Jose A. Lopes

794 306b855a Jose A. Lopes
  """
795 306b855a Jose A. Lopes
  return IsProcessAlive(utils_io.ReadPidFile(utils_io.DaemonPidFileName(name)))
796 306b855a Jose A. Lopes
797 306b855a Jose A. Lopes
798 a4ccecf6 Michael Hanselmann
def _ParseSigsetT(sigset):
799 a4ccecf6 Michael Hanselmann
  """Parse a rendered sigset_t value.
800 a4ccecf6 Michael Hanselmann

801 a4ccecf6 Michael Hanselmann
  This is the opposite of the Linux kernel's fs/proc/array.c:render_sigset_t
802 a4ccecf6 Michael Hanselmann
  function.
803 a4ccecf6 Michael Hanselmann

804 a4ccecf6 Michael Hanselmann
  @type sigset: string
805 a4ccecf6 Michael Hanselmann
  @param sigset: Rendered signal set from /proc/$pid/status
806 a4ccecf6 Michael Hanselmann
  @rtype: set
807 a4ccecf6 Michael Hanselmann
  @return: Set of all enabled signal numbers
808 a4ccecf6 Michael Hanselmann

809 a4ccecf6 Michael Hanselmann
  """
810 a4ccecf6 Michael Hanselmann
  result = set()
811 a4ccecf6 Michael Hanselmann
812 a4ccecf6 Michael Hanselmann
  signum = 0
813 a4ccecf6 Michael Hanselmann
  for ch in reversed(sigset):
814 a4ccecf6 Michael Hanselmann
    chv = int(ch, 16)
815 a4ccecf6 Michael Hanselmann
816 a4ccecf6 Michael Hanselmann
    # The following could be done in a loop, but it's easier to read and
817 a4ccecf6 Michael Hanselmann
    # understand in the unrolled form
818 a4ccecf6 Michael Hanselmann
    if chv & 1:
819 a4ccecf6 Michael Hanselmann
      result.add(signum + 1)
820 a4ccecf6 Michael Hanselmann
    if chv & 2:
821 a4ccecf6 Michael Hanselmann
      result.add(signum + 2)
822 a4ccecf6 Michael Hanselmann
    if chv & 4:
823 a4ccecf6 Michael Hanselmann
      result.add(signum + 3)
824 a4ccecf6 Michael Hanselmann
    if chv & 8:
825 a4ccecf6 Michael Hanselmann
      result.add(signum + 4)
826 a4ccecf6 Michael Hanselmann
827 a4ccecf6 Michael Hanselmann
    signum += 4
828 a4ccecf6 Michael Hanselmann
829 a4ccecf6 Michael Hanselmann
  return result
830 a4ccecf6 Michael Hanselmann
831 a4ccecf6 Michael Hanselmann
832 a4ccecf6 Michael Hanselmann
def _GetProcStatusField(pstatus, field):
833 a4ccecf6 Michael Hanselmann
  """Retrieves a field from the contents of a proc status file.
834 a4ccecf6 Michael Hanselmann

835 a4ccecf6 Michael Hanselmann
  @type pstatus: string
836 a4ccecf6 Michael Hanselmann
  @param pstatus: Contents of /proc/$pid/status
837 a4ccecf6 Michael Hanselmann
  @type field: string
838 a4ccecf6 Michael Hanselmann
  @param field: Name of field whose value should be returned
839 a4ccecf6 Michael Hanselmann
  @rtype: string
840 a4ccecf6 Michael Hanselmann

841 a4ccecf6 Michael Hanselmann
  """
842 a4ccecf6 Michael Hanselmann
  for line in pstatus.splitlines():
843 a4ccecf6 Michael Hanselmann
    parts = line.split(":", 1)
844 a4ccecf6 Michael Hanselmann
845 a4ccecf6 Michael Hanselmann
    if len(parts) < 2 or parts[0] != field:
846 a4ccecf6 Michael Hanselmann
      continue
847 a4ccecf6 Michael Hanselmann
848 a4ccecf6 Michael Hanselmann
    return parts[1].strip()
849 a4ccecf6 Michael Hanselmann
850 a4ccecf6 Michael Hanselmann
  return None
851 a4ccecf6 Michael Hanselmann
852 a4ccecf6 Michael Hanselmann
853 a4ccecf6 Michael Hanselmann
def IsProcessHandlingSignal(pid, signum, status_path=None):
854 a4ccecf6 Michael Hanselmann
  """Checks whether a process is handling a signal.
855 a4ccecf6 Michael Hanselmann

856 a4ccecf6 Michael Hanselmann
  @type pid: int
857 a4ccecf6 Michael Hanselmann
  @param pid: Process ID
858 a4ccecf6 Michael Hanselmann
  @type signum: int
859 a4ccecf6 Michael Hanselmann
  @param signum: Signal number
860 a4ccecf6 Michael Hanselmann
  @rtype: bool
861 a4ccecf6 Michael Hanselmann

862 a4ccecf6 Michael Hanselmann
  """
863 a4ccecf6 Michael Hanselmann
  if status_path is None:
864 a4ccecf6 Michael Hanselmann
    status_path = _GetProcStatusPath(pid)
865 a4ccecf6 Michael Hanselmann
866 a4ccecf6 Michael Hanselmann
  try:
867 a4ccecf6 Michael Hanselmann
    proc_status = utils_io.ReadFile(status_path)
868 a4ccecf6 Michael Hanselmann
  except EnvironmentError, err:
869 a4ccecf6 Michael Hanselmann
    # In at least one case, reading /proc/$pid/status failed with ESRCH.
870 a4ccecf6 Michael Hanselmann
    if err.errno in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL, errno.ESRCH):
871 a4ccecf6 Michael Hanselmann
      return False
872 a4ccecf6 Michael Hanselmann
    raise
873 a4ccecf6 Michael Hanselmann
874 a4ccecf6 Michael Hanselmann
  sigcgt = _GetProcStatusField(proc_status, "SigCgt")
875 a4ccecf6 Michael Hanselmann
  if sigcgt is None:
876 a4ccecf6 Michael Hanselmann
    raise RuntimeError("%s is missing 'SigCgt' field" % status_path)
877 a4ccecf6 Michael Hanselmann
878 a4ccecf6 Michael Hanselmann
  # Now check whether signal is handled
879 a4ccecf6 Michael Hanselmann
  return signum in _ParseSigsetT(sigcgt)
880 a4ccecf6 Michael Hanselmann
881 a4ccecf6 Michael Hanselmann
882 a4ccecf6 Michael Hanselmann
def Daemonize(logfile):
883 a4ccecf6 Michael Hanselmann
  """Daemonize the current process.
884 a4ccecf6 Michael Hanselmann

885 a4ccecf6 Michael Hanselmann
  This detaches the current process from the controlling terminal and
886 a4ccecf6 Michael Hanselmann
  runs it in the background as a daemon.
887 a4ccecf6 Michael Hanselmann

888 a4ccecf6 Michael Hanselmann
  @type logfile: str
889 a4ccecf6 Michael Hanselmann
  @param logfile: the logfile to which we should redirect stdout/stderr
890 110f49ef Michael Hanselmann
  @rtype: tuple; (int, callable)
891 110f49ef Michael Hanselmann
  @return: File descriptor of pipe(2) which must be closed to notify parent
892 110f49ef Michael Hanselmann
    process and a callable to reopen log files
893 a4ccecf6 Michael Hanselmann

894 a4ccecf6 Michael Hanselmann
  """
895 b459a848 Andrea Spadaccini
  # pylint: disable=W0212
896 a4ccecf6 Michael Hanselmann
  # yes, we really want os._exit
897 a4ccecf6 Michael Hanselmann
898 a4ccecf6 Michael Hanselmann
  # TODO: do another attempt to merge Daemonize and StartDaemon, or at
899 a4ccecf6 Michael Hanselmann
  # least abstract the pipe functionality between them
900 a4ccecf6 Michael Hanselmann
901 a4ccecf6 Michael Hanselmann
  # Create pipe for sending error messages
902 a4ccecf6 Michael Hanselmann
  (rpipe, wpipe) = os.pipe()
903 a4ccecf6 Michael Hanselmann
904 a4ccecf6 Michael Hanselmann
  # this might fail
905 a4ccecf6 Michael Hanselmann
  pid = os.fork()
906 a4ccecf6 Michael Hanselmann
  if (pid == 0):  # The first child.
907 a4ccecf6 Michael Hanselmann
    SetupDaemonEnv()
908 a4ccecf6 Michael Hanselmann
909 a4ccecf6 Michael Hanselmann
    # this might fail
910 a4ccecf6 Michael Hanselmann
    pid = os.fork() # Fork a second child.
911 a4ccecf6 Michael Hanselmann
    if (pid == 0):  # The second child.
912 a4ccecf6 Michael Hanselmann
      utils_wrapper.CloseFdNoError(rpipe)
913 a4ccecf6 Michael Hanselmann
    else:
914 a4ccecf6 Michael Hanselmann
      # exit() or _exit()?  See below.
915 a4ccecf6 Michael Hanselmann
      os._exit(0) # Exit parent (the first child) of the second child.
916 a4ccecf6 Michael Hanselmann
  else:
917 a4ccecf6 Michael Hanselmann
    utils_wrapper.CloseFdNoError(wpipe)
918 a4ccecf6 Michael Hanselmann
    # Wait for daemon to be started (or an error message to
919 a4ccecf6 Michael Hanselmann
    # arrive) and read up to 100 KB as an error message
920 a4ccecf6 Michael Hanselmann
    errormsg = utils_wrapper.RetryOnSignal(os.read, rpipe, 100 * 1024)
921 a4ccecf6 Michael Hanselmann
    if errormsg:
922 a4ccecf6 Michael Hanselmann
      sys.stderr.write("Error when starting daemon process: %r\n" % errormsg)
923 a4ccecf6 Michael Hanselmann
      rcode = 1
924 a4ccecf6 Michael Hanselmann
    else:
925 a4ccecf6 Michael Hanselmann
      rcode = 0
926 a4ccecf6 Michael Hanselmann
    os._exit(rcode) # Exit parent of the first child.
927 a4ccecf6 Michael Hanselmann
928 110f49ef Michael Hanselmann
  reopen_fn = compat.partial(SetupDaemonFDs, logfile, None)
929 110f49ef Michael Hanselmann
930 110f49ef Michael Hanselmann
  # Open logs for the first time
931 110f49ef Michael Hanselmann
  reopen_fn()
932 110f49ef Michael Hanselmann
933 110f49ef Michael Hanselmann
  return (wpipe, reopen_fn)
934 a4ccecf6 Michael Hanselmann
935 a4ccecf6 Michael Hanselmann
936 a4ccecf6 Michael Hanselmann
def KillProcess(pid, signal_=signal.SIGTERM, timeout=30,
937 a4ccecf6 Michael Hanselmann
                waitpid=False):
938 a4ccecf6 Michael Hanselmann
  """Kill a process given by its pid.
939 a4ccecf6 Michael Hanselmann

940 a4ccecf6 Michael Hanselmann
  @type pid: int
941 a4ccecf6 Michael Hanselmann
  @param pid: The PID to terminate.
942 a4ccecf6 Michael Hanselmann
  @type signal_: int
943 a4ccecf6 Michael Hanselmann
  @param signal_: The signal to send, by default SIGTERM
944 a4ccecf6 Michael Hanselmann
  @type timeout: int
945 a4ccecf6 Michael Hanselmann
  @param timeout: The timeout after which, if the process is still alive,
946 a4ccecf6 Michael Hanselmann
                  a SIGKILL will be sent. If not positive, no such checking
947 a4ccecf6 Michael Hanselmann
                  will be done
948 a4ccecf6 Michael Hanselmann
  @type waitpid: boolean
949 a4ccecf6 Michael Hanselmann
  @param waitpid: If true, we should waitpid on this process after
950 a4ccecf6 Michael Hanselmann
      sending signals, since it's our own child and otherwise it
951 a4ccecf6 Michael Hanselmann
      would remain as zombie
952 a4ccecf6 Michael Hanselmann

953 a4ccecf6 Michael Hanselmann
  """
954 a4ccecf6 Michael Hanselmann
  def _helper(pid, signal_, wait):
955 a4ccecf6 Michael Hanselmann
    """Simple helper to encapsulate the kill/waitpid sequence"""
956 a4ccecf6 Michael Hanselmann
    if utils_wrapper.IgnoreProcessNotFound(os.kill, pid, signal_) and wait:
957 a4ccecf6 Michael Hanselmann
      try:
958 a4ccecf6 Michael Hanselmann
        os.waitpid(pid, os.WNOHANG)
959 a4ccecf6 Michael Hanselmann
      except OSError:
960 a4ccecf6 Michael Hanselmann
        pass
961 a4ccecf6 Michael Hanselmann
962 a4ccecf6 Michael Hanselmann
  if pid <= 0:
963 a4ccecf6 Michael Hanselmann
    # kill with pid=0 == suicide
964 a4ccecf6 Michael Hanselmann
    raise errors.ProgrammerError("Invalid pid given '%s'" % pid)
965 a4ccecf6 Michael Hanselmann
966 a4ccecf6 Michael Hanselmann
  if not IsProcessAlive(pid):
967 a4ccecf6 Michael Hanselmann
    return
968 a4ccecf6 Michael Hanselmann
969 a4ccecf6 Michael Hanselmann
  _helper(pid, signal_, waitpid)
970 a4ccecf6 Michael Hanselmann
971 a4ccecf6 Michael Hanselmann
  if timeout <= 0:
972 a4ccecf6 Michael Hanselmann
    return
973 a4ccecf6 Michael Hanselmann
974 a4ccecf6 Michael Hanselmann
  def _CheckProcess():
975 a4ccecf6 Michael Hanselmann
    if not IsProcessAlive(pid):
976 a4ccecf6 Michael Hanselmann
      return
977 a4ccecf6 Michael Hanselmann
978 a4ccecf6 Michael Hanselmann
    try:
979 a4ccecf6 Michael Hanselmann
      (result_pid, _) = os.waitpid(pid, os.WNOHANG)
980 a4ccecf6 Michael Hanselmann
    except OSError:
981 a4ccecf6 Michael Hanselmann
      raise utils_retry.RetryAgain()
982 a4ccecf6 Michael Hanselmann
983 a4ccecf6 Michael Hanselmann
    if result_pid > 0:
984 a4ccecf6 Michael Hanselmann
      return
985 a4ccecf6 Michael Hanselmann
986 a4ccecf6 Michael Hanselmann
    raise utils_retry.RetryAgain()
987 a4ccecf6 Michael Hanselmann
988 a4ccecf6 Michael Hanselmann
  try:
989 a4ccecf6 Michael Hanselmann
    # Wait up to $timeout seconds
990 a4ccecf6 Michael Hanselmann
    utils_retry.Retry(_CheckProcess, (0.01, 1.5, 0.1), timeout)
991 a4ccecf6 Michael Hanselmann
  except utils_retry.RetryTimeout:
992 a4ccecf6 Michael Hanselmann
    pass
993 a4ccecf6 Michael Hanselmann
994 a4ccecf6 Michael Hanselmann
  if IsProcessAlive(pid):
995 a4ccecf6 Michael Hanselmann
    # Kill process if it's still alive
996 a4ccecf6 Michael Hanselmann
    _helper(pid, signal.SIGKILL, waitpid)
997 a4ccecf6 Michael Hanselmann
998 a4ccecf6 Michael Hanselmann
999 a4ccecf6 Michael Hanselmann
def RunInSeparateProcess(fn, *args):
1000 a4ccecf6 Michael Hanselmann
  """Runs a function in a separate process.
1001 a4ccecf6 Michael Hanselmann

1002 a4ccecf6 Michael Hanselmann
  Note: Only boolean return values are supported.
1003 a4ccecf6 Michael Hanselmann

1004 a4ccecf6 Michael Hanselmann
  @type fn: callable
1005 a4ccecf6 Michael Hanselmann
  @param fn: Function to be called
1006 a4ccecf6 Michael Hanselmann
  @rtype: bool
1007 a4ccecf6 Michael Hanselmann
  @return: Function's result
1008 a4ccecf6 Michael Hanselmann

1009 a4ccecf6 Michael Hanselmann
  """
1010 a4ccecf6 Michael Hanselmann
  pid = os.fork()
1011 a4ccecf6 Michael Hanselmann
  if pid == 0:
1012 a4ccecf6 Michael Hanselmann
    # Child process
1013 a4ccecf6 Michael Hanselmann
    try:
1014 a4ccecf6 Michael Hanselmann
      # In case the function uses temporary files
1015 a4ccecf6 Michael Hanselmann
      utils_wrapper.ResetTempfileModule()
1016 a4ccecf6 Michael Hanselmann
1017 a4ccecf6 Michael Hanselmann
      # Call function
1018 a4ccecf6 Michael Hanselmann
      result = int(bool(fn(*args)))
1019 a4ccecf6 Michael Hanselmann
      assert result in (0, 1)
1020 b459a848 Andrea Spadaccini
    except: # pylint: disable=W0702
1021 a4ccecf6 Michael Hanselmann
      logging.exception("Error while calling function in separate process")
1022 a4ccecf6 Michael Hanselmann
      # 0 and 1 are reserved for the return value
1023 a4ccecf6 Michael Hanselmann
      result = 33
1024 a4ccecf6 Michael Hanselmann
1025 b459a848 Andrea Spadaccini
    os._exit(result) # pylint: disable=W0212
1026 a4ccecf6 Michael Hanselmann
1027 a4ccecf6 Michael Hanselmann
  # Parent process
1028 a4ccecf6 Michael Hanselmann
1029 a4ccecf6 Michael Hanselmann
  # Avoid zombies and check exit code
1030 a4ccecf6 Michael Hanselmann
  (_, status) = os.waitpid(pid, 0)
1031 a4ccecf6 Michael Hanselmann
1032 a4ccecf6 Michael Hanselmann
  if os.WIFSIGNALED(status):
1033 a4ccecf6 Michael Hanselmann
    exitcode = None
1034 a4ccecf6 Michael Hanselmann
    signum = os.WTERMSIG(status)
1035 a4ccecf6 Michael Hanselmann
  else:
1036 a4ccecf6 Michael Hanselmann
    exitcode = os.WEXITSTATUS(status)
1037 a4ccecf6 Michael Hanselmann
    signum = None
1038 a4ccecf6 Michael Hanselmann
1039 a4ccecf6 Michael Hanselmann
  if not (exitcode in (0, 1) and signum is None):
1040 a4ccecf6 Michael Hanselmann
    raise errors.GenericError("Child program failed (code=%s, signal=%s)" %
1041 a4ccecf6 Michael Hanselmann
                              (exitcode, signum))
1042 a4ccecf6 Michael Hanselmann
1043 a4ccecf6 Michael Hanselmann
  return bool(exitcode)
1044 a4ccecf6 Michael Hanselmann
1045 a4ccecf6 Michael Hanselmann
1046 a4ccecf6 Michael Hanselmann
def CloseFDs(noclose_fds=None):
1047 a4ccecf6 Michael Hanselmann
  """Close file descriptors.
1048 a4ccecf6 Michael Hanselmann

1049 a4ccecf6 Michael Hanselmann
  This closes all file descriptors above 2 (i.e. except
1050 a4ccecf6 Michael Hanselmann
  stdin/out/err).
1051 a4ccecf6 Michael Hanselmann

1052 a4ccecf6 Michael Hanselmann
  @type noclose_fds: list or None
1053 a4ccecf6 Michael Hanselmann
  @param noclose_fds: if given, it denotes a list of file descriptor
1054 a4ccecf6 Michael Hanselmann
      that should not be closed
1055 a4ccecf6 Michael Hanselmann

1056 a4ccecf6 Michael Hanselmann
  """
1057 a4ccecf6 Michael Hanselmann
  # Default maximum for the number of available file descriptors.
1058 a4ccecf6 Michael Hanselmann
  if 'SC_OPEN_MAX' in os.sysconf_names:
1059 a4ccecf6 Michael Hanselmann
    try:
1060 a4ccecf6 Michael Hanselmann
      MAXFD = os.sysconf('SC_OPEN_MAX')
1061 a4ccecf6 Michael Hanselmann
      if MAXFD < 0:
1062 a4ccecf6 Michael Hanselmann
        MAXFD = 1024
1063 a4ccecf6 Michael Hanselmann
    except OSError:
1064 a4ccecf6 Michael Hanselmann
      MAXFD = 1024
1065 a4ccecf6 Michael Hanselmann
  else:
1066 a4ccecf6 Michael Hanselmann
    MAXFD = 1024
1067 a4ccecf6 Michael Hanselmann
1068 a4ccecf6 Michael Hanselmann
  maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
1069 a4ccecf6 Michael Hanselmann
  if (maxfd == resource.RLIM_INFINITY):
1070 a4ccecf6 Michael Hanselmann
    maxfd = MAXFD
1071 a4ccecf6 Michael Hanselmann
1072 a4ccecf6 Michael Hanselmann
  # Iterate through and close all file descriptors (except the standard ones)
1073 a4ccecf6 Michael Hanselmann
  for fd in range(3, maxfd):
1074 a4ccecf6 Michael Hanselmann
    if noclose_fds and fd in noclose_fds:
1075 a4ccecf6 Michael Hanselmann
      continue
1076 a4ccecf6 Michael Hanselmann
    utils_wrapper.CloseFdNoError(fd)