Module: POSIX::Spawn

### Home Classes Methods

### In Files

- lib/posix/spawn.rb
- lib/posix/spawn/child.rb
- lib/posix/spawn/version.rb

### Namespace

- CLASS POSIX::Spawn::Child
- CLASS POSIX::Spawn::MaximumOutputExceeded
- CLASS POSIX::Spawn::TimeoutExceeded

### Methods

- #`
- #fspawn
- #popen4
- #pspawn
- #spawn
- #system

### Files

- COPYING
- HACKING

### Class/Module Index

Quicksearch

- POSIX
- POSIX::Spawn
- POSIX::Spawn::Child
- POSIX::Spawn::MaximumOutputExceeded
- POSIX::Spawn::TimeoutExceeded
- IO

No matching classes.

# POSIX::Spawn

The POSIX::Spawn module implements a compatible subset of Ruby 1.9's Process::spawn and related methods using the IEEE Std 1003.1 posix_spawn(2) system interfaces where available, or a pure Ruby fork/exec based implementation when not.

In Ruby 1.9, a versatile new process spawning interface was added (Process::spawn) as the foundation for enhanced versions of existing process-related methods like Kernel#system, Kernel#`, and IO#popen. These methods are backward compatible with their Ruby 1.8 counterparts but support a large number of new options. The POSIX::Spawn module implements many of these methods with support for most of Ruby 1.9's features.

The argument signatures for all of these methods follow a new convention, making it possible to take advantage of Process::spawn features:

    spawn([env], command, [argv1, ...], [options])
    system([env], command, [argv1, ...], [options])
    popen([[env], command, [argv1, ...]], mode="r", [options])

The env, command, and options arguments are described below.

## Environment

If a hash is given in the first argument (env), the child process's environment becomes a merge of the parent's and any modifications specified in the hash. When a value in env is nil, the variable is unset in the child:

    # set FOO as BAR and unset BAZ.
    spawn({"FOO" => "BAR", "BAZ" => nil}, 'echo', 'hello world')

## Command

The command and optional argvN string arguments specify the command to execute and any program arguments. When only command is given and includes a space character, the command text is executed by the system shell interpreter, as if by:

    /bin/sh -c 'command'

When command does not include a space character, or one or more argvN arguments are given, the command is executed as if by execve(2) with each argument forming the new program's argv.

NOTE: Use of the shell variation is generally discouraged unless you indeed want to execute a shell program. Specifying an explicitly argv is typically more secure and less error prone in most cases.

## Options

When a hash is given in the last argument (options), it specifies a current directory and zero or more fd redirects for the child process.

The :chdir option specifies the current directory:

    spawn(command, :chdir => "/var/tmp")

The :in, :out, :err, a Fixnum, an IO object or an Array option specify fd redirection. For example, stderr can be merged into stdout as follows:

    spawn(command, :err => :out)
    spawn(command, 2 => 1)
    spawn(command, STDERR => :out)
    spawn(command, STDERR => STDOUT)

The key is a fd in the newly spawned child process (stderr in this case). The value is a fd in the parent process (stdout in this case).

You can also specify a filename for redirection instead of an fd:

    spawn(command, :in => "/dev/null")   # read mode
    spawn(command, :out => "/dev/null")  # write mode
    spawn(command, :err => "log")        # write mode
    spawn(command, 3 => "/dev/null")     # read mode

When redirecting to stdout or stderr, the files are opened in write mode; otherwise, read mode is used.

It's also possible to control the open flags and file permissions directly by passing an array value:

    spawn(command, :in=>["file"])       # read mode assumed
    spawn(command, :in=>["file", "r"])  # explicit read mode
    spawn(command, :out=>["log", "w"])  # explicit write mode, 0644 assumed
    spawn(command, :out=>["log", "w", 0600])
    spawn(command, :out=>["log", File::APPEND | File::CREAT, 0600])

The array is a [filename, open_mode, perms] tuple. open_mode can be a string or an integer. When open_mode is omitted or nil, File::RDONLY is assumed. The perms element should be an integer. When perms is omitted or nil, 0644 is assumed.

The :close It's possible to direct an fd be closed in the child process. This is important for implementing `popen`-style logic and other forms of IPC between processes using `IO.pipe`:

    rd, wr = IO.pipe
    pid = spawn('echo', 'hello world', rd => :close, :stdout => wr)
    wr.close
    output = rd.read
    Process.wait(pid)

## Spawn Implementation

The POSIX::Spawn#spawn method uses the best available implementation given the current platform and Ruby version. In order of preference, they are:

    1. The posix_spawn based C extension method (pspawn).
    2. Process::spawn when available (Ruby 1.9 only).
    3. A simple pure-Ruby fork/exec based spawn implementation compatible
       with Ruby >= 1.8.7.

### Constants

OFLAGS

  Mapping of string open modes to integer oflag versions.

VERSION

### Public Instance Methods

`(cmd) click to toggle source

Executes a command in a subshell using the system's shell interpreter and returns anything written to the new process's stdout. This method is compatible with Kernel#`.

Returns the String output of the command.

    # File lib/posix/spawn.rb, line 268
    def `(cmd)
      r, w = IO.pipe
      pid = spawn(['/bin/sh', '/bin/sh'], '-c', cmd, :out => w, r => :close)

      if pid > 0
        w.close
        out = r.read
        ::Process.waitpid(pid)
        out
      else
        ''
      end
    ensure
      [r, w].each{ |io| io.close rescue nil }
    end

fspawn(*args) click to toggle source

Spawn a child process with a variety of options using a pure Ruby fork + exec. Supports the standard spawn interface as described in the POSIX::Spawn module documentation.

    # File lib/posix/spawn.rb, line 193
    def fspawn(*args)
      env, argv, options = extract_process_spawn_arguments(*args)
      valid_options = [:chdir, :unsetenv_others, :pgroup]

      if badopt = options.find{ |key,val| !fd?(key) && !valid_options.include?(key) }
        raise ArgumentError, "Invalid option: #{badopt[0].inspect}"
      elsif !argv.is_a?(Array) || !argv[0].is_a?(Array) || argv[0].size != 2
        raise ArgumentError, "Invalid command name"
      end

      fork do
        begin
          # handle FD => {FD, :close, [file,mode,perms]} options
          options.each do |key, val|
            if fd?(key)
              key = fd_to_io(key)

              if fd?(val)
                val = fd_to_io(val)
                key.reopen(val)
              elsif val == :close
                if key.respond_to?(:close_on_exec=)
                  key.close_on_exec = true
                else
                  key.close
                end
              elsif val.is_a?(Array)
                file, mode_string, perms = *val
                key.reopen(File.open(file, mode_string, perms))
              end
            end
          end

          # setup child environment
          ENV.replace({}) if options[:unsetenv_others] == true
          env.each { |k, v| ENV[k] = v }

          # { :chdir => '/' } in options means change into that dir
          ::Dir.chdir(options[:chdir]) if options[:chdir]

          # { :pgroup => pgid } options
          pgroup = options[:pgroup]
          pgroup = 0 if pgroup == true
          Process::setpgid(0, pgroup) if pgroup

          # do the deed
          ::Kernel::exec(*argv)
        ensure
          exit!(127)
        end
      end
    end

popen4(*argv) click to toggle source

Spawn a child process with all standard IO streams piped in and out of the spawning process. Supports the standard spawn interface as described in the POSIX::Spawn module documentation.

Returns a [pid, stdin, stderr, stdout] tuple, where pid is the new process's pid, stdin is a writeable IO object, and stdout / stderr are readable IO objects. The caller should take care to close all IO objects when finished and the child process's status must be collected by a call to Process::waitpid or equivalent.

    # File lib/posix/spawn.rb, line 293
    def popen4(*argv)
      # create some pipes (see pipe(2) manual -- the ruby docs suck)
      ird, iwr = IO.pipe
      ord, owr = IO.pipe
      erd, ewr = IO.pipe

      # spawn the child process with either end of pipes hooked together
      opts =
        ((argv.pop if argv[-1].is_a?(Hash)) || {}).merge(
          # redirect fds        # close other sides
          :in  => ird,          iwr  => :close,
          :out => owr,          ord  => :close,
          :err => ewr,          erd  => :close
        )
      pid = spawn(*(argv + [opts]))

      [pid, iwr, ord, erd]
    ensure
      # we're in the parent, close child-side fds
      [ird, owr, ewr].each { |fd| fd.close }
    end

pspawn(*args) click to toggle source

Spawn a child process with a variety of options using the posix_spawn(2) systems interfaces. Supports the standard spawn interface as described in the POSIX::Spawn module documentation.

Raises NotImplementedError when the posix_spawn_ext module could not be loaded due to lack of platform support.

    # File lib/posix/spawn.rb, line 174
    def pspawn(*args)
      env, argv, options = extract_process_spawn_arguments(*args)
      raise NotImplementedError unless respond_to?(:_pspawn)

      if defined? JRUBY_VERSION
        # On the JVM, changes made to the environment are not propagated down
        # to C via get/setenv, so we have to fake it here.
        unless options[:unsetenv_others] == true
          env = ENV.merge(env)
          options[:unsetenv_others] = true
        end
      end

      _pspawn(env, argv, options)
    end

spawn(*args) click to toggle source

Spawn a child process with a variety of options using the best available implementation for the current platform and Ruby version.

spawn(, command, [argv1, ...], [options])

env - Optional hash specifying the new process's environment. command - A string command name, or shell program, used to determine the

    program to execute.

argvN - Zero or more string program arguments (argv). options - Optional hash of operations to perform before executing the

    new child process.

Returns the integer pid of the newly spawned process.

Raises any number of Errno | exceptions on failure.

    # File lib/posix/spawn.rb, line 158
    def spawn(*args)
      if respond_to?(:_pspawn)
        pspawn(*args)
      elsif ::Process.respond_to?(:spawn)
        ::Process::spawn(*args)
      else
        fspawn(*args)
      end
    end

system(*args) click to toggle source

Executes a command and waits for it to complete. The command's exit status is available as $?. Supports the standard spawn interface as described in the POSIX::Spawn module documentation.

This method is compatible with Kernel#system.

Returns true if the command returns a zero exit status, or false for non-zero exit.

    # File lib/posix/spawn.rb, line 254
    def system(*args)
      pid = spawn(*args)
      return false if pid <= 0
      ::Process.waitpid(pid)
      $?.exitstatus == 0
    rescue Errno::ENOENT
      false
    end

[Validate]

Generated with the Darkfish Rdoc Generator 2.