Revision d5d76ab2 lib/utils/process.py

b/lib/utils/process.py
142 142

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

  
148 148
  The command should not read from its standard input, as it will be
......
170 170
  @type noclose_fds: list
171 171
  @param noclose_fds: list of additional (fd >=3) file descriptors to leave
172 172
                      open for the child process
173
  @type input_fd: C{file}-like object or numeric file descriptor
174
  @param input_fd: File descriptor for process' standard input
173 175
  @param _postfork_fn: Callback run after fork but before timeout (unittest)
174 176
  @rtype: L{RunResult}
175 177
  @return: RunResult instance
......
183 185
    raise errors.ProgrammerError("Parameters 'output' and 'interactive' can"
184 186
                                 " not be provided at the same time")
185 187

  
188
  if not (output is None or input_fd is None):
189
    # The current logic in "_RunCmdFile", which is used when output is defined,
190
    # does not support input files (not hard to implement, though)
191
    raise errors.ProgrammerError("Parameters 'output' and 'input_fd' can"
192
                                 " not be used at the same time")
193

  
186 194
  if isinstance(cmd, basestring):
187 195
    strcmd = cmd
188 196
    shell = True
......
202 210
    if output is None:
203 211
      out, err, status, timeout_action = _RunCmdPipe(cmd, cmd_env, shell, cwd,
204 212
                                                     interactive, timeout,
205
                                                     noclose_fds,
213
                                                     noclose_fds, input_fd,
206 214
                                                     _postfork_fn=_postfork_fn)
207 215
    else:
208 216
      assert _postfork_fn is None, \
209 217
          "_postfork_fn not supported if output provided"
218
      assert input_fd is None
210 219
      timeout_action = _TIMEOUT_NONE
211 220
      status = _RunCmdFile(cmd, cmd_env, shell, output, cwd, noclose_fds)
212 221
      out = err = ""
......
481 490

  
482 491

  
483 492
def _RunCmdPipe(cmd, env, via_shell, cwd, interactive, timeout, noclose_fds,
493
                input_fd,
484 494
                _linger_timeout=constants.CHILD_LINGER_TIMEOUT,
485 495
                _postfork_fn=None):
486 496
  """Run a command and return its output.
......
500 510
  @type noclose_fds: list
501 511
  @param noclose_fds: list of additional (fd >=3) file descriptors to leave
502 512
                      open for the child process
513
  @type input_fd: C{file}-like object or numeric file descriptor
514
  @param input_fd: File descriptor for process' standard input
503 515
  @param _postfork_fn: Function run after fork but before timeout (unittest)
504 516
  @rtype: tuple
505 517
  @return: (out, err, status)
......
507 519
  """
508 520
  poller = select.poll()
509 521

  
510
  stderr = subprocess.PIPE
511
  stdout = subprocess.PIPE
512
  stdin = subprocess.PIPE
513

  
514 522
  if interactive:
515
    stderr = stdout = stdin = None
523
    stderr = None
524
    stdout = None
525
  else:
526
    stderr = subprocess.PIPE
527
    stdout = subprocess.PIPE
528

  
529
  if input_fd:
530
    stdin = input_fd
531
  elif interactive:
532
    stdin = None
533
  else:
534
    stdin = subprocess.PIPE
516 535

  
517 536
  if noclose_fds:
518 537
    preexec_fn = lambda: CloseFDs(noclose_fds)
......
549 568

  
550 569
  timeout_action = _TIMEOUT_NONE
551 570

  
571
  # subprocess: "If the stdin argument is PIPE, this attribute is a file object
572
  # that provides input to the child process. Otherwise, it is None."
573
  assert (stdin == subprocess.PIPE) ^ (child.stdin is None), \
574
    "subprocess' stdin did not behave as documented"
575

  
552 576
  if not interactive:
553
    child.stdin.close()
577
    if child.stdin is not None:
578
      child.stdin.close()
554 579
    poller.register(child.stdout, select.POLLIN)
555 580
    poller.register(child.stderr, select.POLLIN)
556 581
    fdmap = {

Also available in: Unified diff