aboutsummaryrefslogtreecommitdiffstats
path: root/process.c
diff options
context:
space:
mode:
authorBurdette Lamar <BurdetteLamar@Yahoo.com>2023-08-31 13:02:09 -0500
committerGitHub <noreply@github.com>2023-08-31 14:02:09 -0400
commit84fa8ae84eeb20a35ff2040dbf107c6d9babfdec (patch)
tree9f5e2af0d5e0c7e4faa207ce19e6ef9b910672ea /process.c
parent8470acc1ec6c06c62d857d5a01f6f9438f27fa10 (diff)
downloadruby-84fa8ae84eeb20a35ff2040dbf107c6d9babfdec.tar.gz
[DOC] RDoc for #spawn (#8342)
Diffstat (limited to 'process.c')
-rw-r--r--process.c327
1 files changed, 88 insertions, 239 deletions
diff --git a/process.c b/process.c
index 0161ddb455..47db4fa626 100644
--- a/process.c
+++ b/process.c
@@ -4872,271 +4872,120 @@ rb_f_system(int argc, VALUE *argv, VALUE _)
/*
* call-seq:
- * spawn([env,] command... [,options]) -> pid
- * Process.spawn([env,] command... [,options]) -> pid
- *
- * spawn executes specified command and return its pid.
- *
- * pid = spawn("tar xf ruby-2.0.0-p195.tar.bz2")
- * Process.wait pid
- *
- * pid = spawn(RbConfig.ruby, "-eputs'Hello, world!'")
- * Process.wait pid
- *
- * This method is similar to Kernel#system but it doesn't wait for the command
- * to finish.
- *
- * The parent process should
- * use Process.wait to collect
- * the termination status of its child or
- * use Process.detach to register
- * disinterest in their status;
- * otherwise, the operating system may accumulate zombie processes.
- *
- * spawn has bunch of options to specify process attributes:
- *
- * env: hash
- * name => val : set the environment variable
- * name => nil : unset the environment variable
- *
- * the keys and the values except for +nil+ must be strings.
- * command...:
- * commandline : command line string which is passed to the standard shell
- * cmdname, arg1, ... : command name and one or more arguments (This form does not use the shell. See below for caveats.)
- * [cmdname, argv0], arg1, ... : command name, argv[0] and zero or more arguments (no shell)
- * options: hash
- * clearing environment variables:
- * :unsetenv_others => true : clear environment variables except specified by env
- * :unsetenv_others => false : don't clear (default)
- * process group:
- * :pgroup => true or 0 : make a new process group
- * :pgroup => pgid : join the specified process group
- * :pgroup => nil : don't change the process group (default)
- * create new process group: Windows only
- * :new_pgroup => true : the new process is the root process of a new process group
- * :new_pgroup => false : don't create a new process group (default)
- * resource limit: resourcename is core, cpu, data, etc. See Process.setrlimit.
- * :rlimit_resourcename => limit
- * :rlimit_resourcename => [cur_limit, max_limit]
- * umask:
- * :umask => int
- * redirection:
- * key:
- * FD : single file descriptor in child process
- * [FD, FD, ...] : multiple file descriptor in child process
- * value:
- * FD : redirect to the file descriptor in parent process
- * string : redirect to file with open(string, "r" or "w")
- * [string] : redirect to file with open(string, File::RDONLY)
- * [string, open_mode] : redirect to file with open(string, open_mode, 0644)
- * [string, open_mode, perm] : redirect to file with open(string, open_mode, perm)
- * [:child, FD] : redirect to the redirected file descriptor
- * :close : close the file descriptor in child process
- * FD is one of follows
- * :in : the file descriptor 0 which is the standard input
- * :out : the file descriptor 1 which is the standard output
- * :err : the file descriptor 2 which is the standard error
- * integer : the file descriptor of specified the integer
- * io : the file descriptor specified as io.fileno
- * file descriptor inheritance: close non-redirected non-standard fds (3, 4, 5, ...) or not
- * :close_others => false : inherit
- * current directory:
- * :chdir => str
- *
- * The <code>cmdname, arg1, ...</code> form does not use the shell.
- * However, on different OSes, different things are provided as
- * built-in commands. An example of this is +'echo'+, which is a
- * built-in on Windows, but is a normal program on Linux and Mac OS X.
- * This means that <code>Process.spawn 'echo', '%Path%'</code> will
- * display the contents of the <tt>%Path%</tt> environment variable
- * on Windows, but <code>Process.spawn 'echo', '$PATH'</code> prints
- * the literal <tt>$PATH</tt>.
- *
- * If a hash is given as +env+, the environment is
- * updated by +env+ before <code>exec(2)</code> in the child process.
- * If a pair in +env+ has nil as the value, the variable is deleted.
- *
- * # set FOO as BAR and unset BAZ.
- * pid = spawn({"FOO"=>"BAR", "BAZ"=>nil}, command)
- *
- * If a hash is given as +options+,
- * it specifies
- * process group,
- * create new process group,
- * resource limit,
- * current directory,
- * umask and
- * redirects for the child process.
- * Also, it can be specified to clear environment variables.
- *
- * The <code>:unsetenv_others</code> key in +options+ specifies
- * to clear environment variables, other than specified by +env+.
- *
- * pid = spawn(command, :unsetenv_others=>true) # no environment variable
- * pid = spawn({"FOO"=>"BAR"}, command, :unsetenv_others=>true) # FOO only
- *
- * The <code>:pgroup</code> key in +options+ specifies a process group.
- * The corresponding value should be true, zero, a positive integer, or nil.
- * true and zero cause the process to be a process leader of a new process group.
- * A non-zero positive integer causes the process to join the provided process group.
- * The default value, nil, causes the process to remain in the same process group.
- *
- * pid = spawn(command, :pgroup=>true) # process leader
- * pid = spawn(command, :pgroup=>10) # belongs to the process group 10
- *
- * The <code>:new_pgroup</code> key in +options+ specifies to pass
- * +CREATE_NEW_PROCESS_GROUP+ flag to <code>CreateProcessW()</code> that is
- * Windows API. This option is only for Windows.
- * true means the new process is the root process of the new process group.
- * The new process has CTRL+C disabled. This flag is necessary for
- * <code>Process.kill(:SIGINT, pid)</code> on the subprocess.
- * :new_pgroup is false by default.
- *
- * pid = spawn(command, :new_pgroup=>true) # new process group
- * pid = spawn(command, :new_pgroup=>false) # same process group
- *
- * The <code>:rlimit_</code><em>foo</em> key specifies a resource limit.
- * <em>foo</em> should be one of resource types such as <code>core</code>.
- * The corresponding value should be an integer or an array which have one or
- * two integers: same as cur_limit and max_limit arguments for
- * Process.setrlimit.
- *
- * cur, max = Process.getrlimit(:CORE)
- * pid = spawn(command, :rlimit_core=>[0,max]) # disable core temporary.
- * pid = spawn(command, :rlimit_core=>max) # enable core dump
- * pid = spawn(command, :rlimit_core=>0) # never dump core.
- *
- * The <code>:umask</code> key in +options+ specifies the umask.
- *
- * pid = spawn(command, :umask=>077)
- *
- * The :in, :out, :err, an integer, an IO and an array key specifies a redirection.
- * The redirection maps a file descriptor in the child process.
- *
- * For example, stderr can be merged into stdout as follows:
- *
- * pid = spawn(command, :err=>:out)
- * pid = spawn(command, 2=>1)
- * pid = spawn(command, STDERR=>:out)
- * pid = spawn(command, STDERR=>STDOUT)
- *
- * The hash keys specifies a file descriptor in the child process
- * started by #spawn.
- * :err, 2 and STDERR specifies the standard error stream (stderr).
- *
- * The hash values specifies a file descriptor in the parent process
- * which invokes #spawn.
- * :out, 1 and STDOUT specifies the standard output stream (stdout).
- *
- * In the above example,
- * the standard output in the child process is not specified.
- * So it is inherited from the parent process.
- *
- * The standard input stream (stdin) can be specified by :in, 0 and STDIN.
- *
- * A filename can be specified as a hash value.
- *
- * pid = spawn(command, :in=>File::NULL) # read mode
- * pid = spawn(command, :out=>File::NULL) # write mode
- * pid = spawn(command, :err=>"log") # write mode
- * pid = spawn(command, [:out, :err]=>File::NULL) # write mode
- * pid = spawn(command, 3=>File::NULL) # read mode
+ * spawn([env, ] command_line, options = {}) -> pid
+ * spawn([env, ] exe_path, *args, options = {}) -> pid
*
- * For stdout and stderr (and combination of them),
- * it is opened in write mode.
- * Otherwise read mode is used.
+ * Creates a new child process by doing one of the following
+ * in that process:
+ *
+ * - Passing string +command_line+ to the shell.
+ * - Invoking the executable at +exe_path+.
+ *
+ * This method has potential security vulnerabilities if called with untrusted input;
+ * see {Command Injection}[rdoc-ref:command_injection.rdoc].
+ *
+ * Returns the process ID (pid) of the new process,
+ * without waiting for it to complete.
+ *
+ * To avoid zombie processes, the parent process should call either:
+ *
+ * - Process.wait, to collect the termination statuses of its children.
+ * - Process.detach, to register disinterest in their status.
+ *
+ * The new process is created using the
+ * {exec system call}[https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/execve.html];
+ * it may inherit some of its environment from the calling program
+ * (possibly including open file descriptors).
+ *
+ * Argument +env+, if given, is a hash that affects +ENV+ for the new process;
+ * see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
+ *
+ * Argument +options+ is a hash of options for the new process;
+ * see {Execution Options}[rdoc-ref:Process@Execution+Options].
+ *
+ * The first required argument is one of the following:
+ *
+ * - +command_line+ if it is a string,
+ * and if it begins with a shell reserved word or special built-in,
+ * or if it contains one or more metacharacters.
+ * - +exe_path+ otherwise.
*
- * For specifying flags and permission of file creation explicitly,
- * an array is used instead.
+ * <b>Argument +command_line+</b>
+ *
+ * \String argument +command_line+ is a command line to be passed to a shell;
+ * it must begin with a shell reserved word, begin with a special built-in,
+ * or contain meta characters:
+ *
+ * spawn('echo') # => 798847
+ * Process.wait # => 798847
+ * spawn('if true; then echo "Foo"; fi') # => 798848
+ * Process.wait # => 798848
+ * spawn('date > /tmp/date.tmp') # => 798879
+ * Process.wait # => 798849
+ * spawn('date > /nop/date.tmp') # => 798882 # Issues error message.
+ * Process.wait # => 798882
*
- * pid = spawn(command, :in=>["file"]) # read mode is assumed
- * pid = spawn(command, :in=>["file", "r"])
- * pid = spawn(command, :out=>["log", "w"]) # 0644 assumed
- * pid = spawn(command, :out=>["log", "w", 0600])
- * pid = spawn(command, :out=>["log", File::WRONLY|File::EXCL|File::CREAT, 0600])
+ * The command line may also contain arguments and options for the command:
*
- * The array specifies a filename, flags and permission.
- * The flags can be a string or an integer.
- * If the flags is omitted or nil, File::RDONLY is assumed.
- * The permission should be an integer.
- * If the permission is omitted or nil, 0644 is assumed.
+ * spawn('echo "Foo"') # => 799031
+ * Process.wait # => 799031
*
- * If an array of IOs and integers are specified as a hash key,
- * all the elements are redirected.
+ * Output:
*
- * # stdout and stderr is redirected to log file.
- * # The file "log" is opened just once.
- * pid = spawn(command, [:out, :err]=>["log", "w"])
+ * Foo
*
- * Another way to merge multiple file descriptors is [:child, fd].
- * \[:child, fd] means the file descriptor in the child process.
- * This is different from fd.
- * For example, :err=>:out means redirecting child stderr to parent stdout.
- * But :err=>[:child, :out] means redirecting child stderr to child stdout.
- * They differ if stdout is redirected in the child process as follows.
+ * On a Unix-like system, the shell is <tt>/bin/sh</tt>;
+ * otherwise the shell is determined by environment variable
+ * <tt>ENV['RUBYSHELL']</tt>, if defined, or <tt>ENV['COMSPEC']</tt> otherwise.
*
- * # stdout and stderr is redirected to log file.
- * # The file "log" is opened just once.
- * pid = spawn(command, :out=>["log", "w"], :err=>[:child, :out])
+ * Except for the +COMSPEC+ case,
+ * the entire string +command_line+ is passed as an argument
+ * to {shell option -c}[https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/utilities/sh.html].
*
- * \[:child, :out] can be used to merge stderr into stdout in IO.popen.
- * In this case, IO.popen redirects stdout to a pipe in the child process
- * and [:child, :out] refers the redirected stdout.
+ * The shell performs normal shell expansion on the command line:
*
- * io = IO.popen(["sh", "-c", "echo out; echo err >&2", :err=>[:child, :out]])
- * p io.read #=> "out\nerr\n"
+ * spawn('echo C*') # => 799139
+ * Process.wait # => 799139
*
- * The <code>:chdir</code> key in +options+ specifies the current directory.
+ * Output:
*
- * pid = spawn(command, :chdir=>"/var/tmp")
+ * CONTRIBUTING.md COPYING COPYING.ja
*
- * spawn closes all non-standard unspecified descriptors by default.
- * The "standard" descriptors are 0, 1 and 2.
- * This behavior is specified by :close_others option.
- * :close_others doesn't affect the standard descriptors which are
- * closed only if :close is specified explicitly.
+ * Raises an exception if the new process could not execute.
*
- * pid = spawn(command, :close_others=>true) # close 3,4,5,... (default)
- * pid = spawn(command, :close_others=>false) # don't close 3,4,5,...
+ * <b>Argument +exe_path+</b>
*
- * :close_others is false by default for spawn and IO.popen.
+ * Argument +exe_path+ is one of the following:
*
- * Note that fds which close-on-exec flag is already set are closed
- * regardless of :close_others option.
+ * - The string path to an executable to be called.
+ * - A 2-element array containing the path to an executable
+ * and the string to be used as the name of the executing process.
*
- * So IO.pipe and spawn can be used as IO.popen.
+ * Example:
*
- * # similar to r = IO.popen(command)
- * r, w = IO.pipe
- * pid = spawn(command, :out=>w) # r, w is closed in the child process.
- * w.close
+ * spawn('/usr/bin/date') # => 799198 # Path to date on Unix-style system.
+ * Process.wait # => 799198
*
- * :close is specified as a hash value to close a fd individually.
+ * Output:
*
- * f = open(foo)
- * system(command, f=>:close) # don't inherit f.
+ * Thu Aug 31 10:06:48 AM CDT 2023
*
- * If a file descriptor need to be inherited,
- * io=>io can be used.
+ * Ruby invokes the executable directly, with no shell and no shell expansion.
*
- * # valgrind has --log-fd option for log destination.
- * # log_w=>log_w indicates log_w.fileno inherits to child process.
- * log_r, log_w = IO.pipe
- * pid = spawn("valgrind", "--log-fd=#{log_w.fileno}", "echo", "a", log_w=>log_w)
- * log_w.close
- * p log_r.read
+ * If one or more +args+ is given, each is an argument or option
+ * to be passed to the executable:
*
- * It is also possible to exchange file descriptors.
+ * spawn('echo', 'C*') # => 799392
+ * Process.wait # => 799392
+ * spawn('echo', 'hello', 'world') # => 799393
+ * Process.wait # => 799393
*
- * pid = spawn(command, :out=>:err, :err=>:out)
+ * Output:
*
- * The hash keys specify file descriptors in the child process.
- * The hash values specifies file descriptors in the parent process.
- * So the above specifies exchanging stdout and stderr.
- * Internally, +spawn+ uses an extra file descriptor to resolve such cyclic
- * file descriptor mapping.
+ * C*
+ * hello world
*
- * See Kernel.exec for the standard shell.
+ * Raises an exception if the new process could not execute.
*/
static VALUE