Revision 7b0bf9cd lib/utils/process.py

b/lib/utils/process.py
141 141

  
142 142

  
143 143
def RunCmd(cmd, env=None, output=None, cwd="/", reset_env=False,
144
           interactive=False, timeout=None):
144
           interactive=False, timeout=None, noclose_fds=None):
145 145
  """Execute a (shell) command.
146 146

  
147 147
  The command should not read from its standard input, as it will be
......
166 166
  @type timeout: int
167 167
  @param timeout: If not None, timeout in seconds until child process gets
168 168
                  killed
169
  @type noclose_fds: list
170
  @param noclose_fds: list of additional (fd >=3) file descriptors to leave
171
                      open for the child process
169 172
  @rtype: L{RunResult}
170 173
  @return: RunResult instance
171 174
  @raise errors.ProgrammerError: if we call this when forks are disabled
......
196 199
  try:
197 200
    if output is None:
198 201
      out, err, status, timeout_action = _RunCmdPipe(cmd, cmd_env, shell, cwd,
199
                                                     interactive, timeout)
202
                                                     interactive, timeout,
203
                                                     noclose_fds)
200 204
    else:
201 205
      timeout_action = _TIMEOUT_NONE
202
      status = _RunCmdFile(cmd, cmd_env, shell, output, cwd)
206
      status = _RunCmdFile(cmd, cmd_env, shell, output, cwd, noclose_fds)
203 207
      out = err = ""
204 208
  except OSError, err:
205 209
    if err.errno == errno.ENOENT:
......
463 467
    pass
464 468

  
465 469

  
466
def _RunCmdPipe(cmd, env, via_shell, cwd, interactive, timeout,
470
def _RunCmdPipe(cmd, env, via_shell, cwd, interactive, timeout, noclose_fds,
467 471
                _linger_timeout=constants.CHILD_LINGER_TIMEOUT):
468 472
  """Run a command and return its output.
469 473

  
......
479 483
  @param interactive: Run command interactive (without piping)
480 484
  @type timeout: int
481 485
  @param timeout: Timeout after the programm gets terminated
486
  @type noclose_fds: list
487
  @param noclose_fds: list of additional (fd >=3) file descriptors to leave
488
                      open for the child process
482 489
  @rtype: tuple
483 490
  @return: (out, err, status)
484 491

  
......
492 499
  if interactive:
493 500
    stderr = stdout = stdin = None
494 501

  
502
  if noclose_fds:
503
    preexec_fn = lambda: CloseFDs(noclose_fds)
504
    close_fds = False
505
  else:
506
    preexec_fn = None
507
    close_fds = True
508

  
495 509
  child = subprocess.Popen(cmd, shell=via_shell,
496 510
                           stderr=stderr,
497 511
                           stdout=stdout,
498 512
                           stdin=stdin,
499
                           close_fds=True, env=env,
500
                           cwd=cwd)
513
                           close_fds=close_fds, env=env,
514
                           cwd=cwd,
515
                           preexec_fn=preexec_fn)
501 516

  
502 517
  out = StringIO()
503 518
  err = StringIO()
......
592 607
  return out, err, status, timeout_action
593 608

  
594 609

  
595
def _RunCmdFile(cmd, env, via_shell, output, cwd):
610
def _RunCmdFile(cmd, env, via_shell, output, cwd, noclose_fds):
596 611
  """Run a command and save its output to a file.
597 612

  
598 613
  @type  cmd: string or list
......
605 620
  @param output: the filename in which to save the output
606 621
  @type cwd: string
607 622
  @param cwd: the working directory for the program
623
  @type noclose_fds: list
624
  @param noclose_fds: list of additional (fd >=3) file descriptors to leave
625
                      open for the child process
608 626
  @rtype: int
609 627
  @return: the exit status
610 628

  
611 629
  """
612 630
  fh = open(output, "a")
631

  
632
  if noclose_fds:
633
    preexec_fn = lambda: CloseFDs(noclose_fds + [fh.fileno()])
634
    close_fds = False
635
  else:
636
    preexec_fn = None
637
    close_fds = True
638

  
613 639
  try:
614 640
    child = subprocess.Popen(cmd, shell=via_shell,
615 641
                             stderr=subprocess.STDOUT,
616 642
                             stdout=fh,
617 643
                             stdin=subprocess.PIPE,
618
                             close_fds=True, env=env,
619
                             cwd=cwd)
644
                             close_fds=close_fds, env=env,
645
                             cwd=cwd,
646
                             preexec_fn=preexec_fn)
620 647

  
621 648
    child.stdin.close()
622 649
    status = child.wait()

Also available in: Unified diff