NOTE: the name flspawn
is provisional and may be changed in the
future.
All examples in this file assume the module has been loaded as follows:
local spawn = require 'flspawn'
The simplest usage is:
pid,err,errno = spawn("prog","arg","arg")
or
flag,status_or_err,code = spawn.wait("prog","arg","arg")
or
pipe,err,errno = spawn.read_from("prog","arg","arg")
or
pipe,err,errno = spawn.write_to("prog","arg","arg")
This creates a subprocess which will execute prog
(searched for in
the caller's PATH
) with the specified args. No shell is executed
unless prog
itself is a shell or a shell script. No interpretation
is performed on the arguments, which must be strings (or numbers which
will be converted to strings by Lua). argv[0]
is set to prog
.
For spawn()
, the pid
of the new subprocess is returned if a
subprocess could be started; otherwise a false value is returned along
with an error message string and an error code. The subprocess
executes concurrently and is not waited for.
For spawn.wait()
, if the subprocess could not be started then an
error is returned as for spawn()
, otherwise the call waits for the
subprocess to complete, and then returns the same three results as
os.execute()
: a success flag (true if the subprocess exited with a
success code), a string "exit"
or "signal"
, and an exit code.
While waiting for the subprocess, the signals SIGINT
, SIGQUIT
and
SIGCHLD
are blocked (but unlike system()
, no signals are ignored -
see below for how to do that).
For spawn.read_from()
and spawn.write_to()
, the result is
equivalent to that of io.popen()
. For spawn.read_from()
, the
invoked subprocess will have /dev/null
as its stdin; for
spawn.write_to()
, the subprocess stdout is unchanged from the
parent.
This function differs from other comparable "spawn" or "exec" functions in critical respects:
-
File descriptors 0,1,2 are passed to the subprocess unchanged, but no other open files are passed to it regardless of any file descriptor flags.
-
All signals are reset to defaults and unblocked in the subprocess.
General usage is as follows:
pid,err_or_pipe,errno =
spawn {
exec = bool,
wait = bool,
verbose = label,
program = "prog", -- required
args = {...},
environ = {...},
files = {
[n] = action, ...
},
directory = "dir",
directory_before = "dir",
chroot = "dir",
chroot_before = "dir",
search_path = path,
signals = {
ignore = {...},
block = {...},
preserve = {...},
ignore_waiting = {...},
block_waiting = {...}
},
resources = {
name = limit, ...
},
reset_ids = bool,
new_session = bool,
process_group = pgrp,
foreground_tty = ttyfd,
clean_environ = bool,
jail_before = jid,
jail_after = jid
}
All arguments except program
are optional.
-
exec
(boolean) If set to true means that the call will not start a subprocess, but will replace the current process. All other actions are performed identically. In the event of an error after preliminary processing of parameters, the current process will be terminated by_exit(127)
. This option enables theverbose
option by default, since error reporting is otherwise impossible. Default is false. -
wait
(boolean) If set to true, then if the subprocess could be started, wait for it to complete and then return result status values in the same form asos.execute
in place of the subprocess pid. If the subprocess could not be started then the error is returned normally.If invoked as
spawn.wait {...}
, thenwait
is defaulted to true, otherwise false. -
verbose
(boolean or string) If set to true or a string, errors in preparing the subprocess will be reported to wherever the subprocessstderr
descriptor points at the time (which will be either thestderr
of the invoking process, or the destination specified infiles
for descriptor 2 of the subprocess). If a string is given, it is used as a prefix. If explicitly set to false, nothing is written to stderr even in theexec
case.Note that a pipe created by
spawn.output_pipe
will be closed if the subprocess is not started, so is not a suitable destination for verbose errors. -
program
(string) specifies the executable file to run. Ifsearch_path
is unset or false, thenprogram
is an absolute path or is relative to the current directory. Ifsearch_path
is set andprogram
is not absolute, it is searched for in the applicable path.Note that all file and directory actions, including all jail and chroot operations, are performed before the program is searched for, so any specified paths must be resolvable within the final root and current directories.
-
args
(sequence of string or number values) specifies the arguments to the program.argv[0]
defaults toprogram
but may be overridden by an[0] =
entry inargs
.An
__index
metavalue (but not__pairs
or__ipairs
) is respected. -
environ
(table with string keys and string or number values) specifies environment variables to add to the environment of the spawned program. Note that settingPATH
here never affects the path used to findprogram
(seesearch_path
).A
__pairs
metamethod is respected (but not__index
). -
clean_environ
(boolean) if true, the subprocess starts with an empty environment, with only the entries specified byenviron
added. -
files
(table with non-negative integer keys, not necessarily a sequence) specifies the desired assignment of file descriptors in the spawned program. All file descriptors above 2 which are not explicitly assigned here will be closed in the subprocess. The value specified for a descriptor must be one of:-
spawn.close
(leaves the descriptor closed; default for fds above 2) -
spawn.null
(open the descriptor on/dev/null
) -
spawn.inherit
(inherit the corresponding descriptor from the invoking process; default for stdin, stdout and stderr) -
spawn.input_pipe
(create a pipe for the spawned program to read from; the invoker's end of the pipe is returned as the second result) -
spawn.output_pipe
(create a pipe for the spawned program to write to; the invoker's end is returned as the second result) -
spawn.inherit_from(n)
(inherit from the specified descriptor of the invoking process) -
spawn.copy_from(n)
(copy whatever descriptor n is set to in the subprocess after allopen
actions were performed) -
spawn.open(filename,flags[,mode])
(open the specified file in the subprocess;flags
can be "r", "r+", etc., or numeric)
File actions are performed in this order: inheritance and pipes first, then all other actions except copies, and copies last. Dependencies between inherit operations are properly handled (for example, it's safe to exchange two descriptors).
A
__pairs
metamethod is respected (but not__index
). -
-
search_path
(string or boolean) if set to true or a string, specifies thatprogram
is searched for in the specified path; true uses the caller'sPATH
environment variable (not affected by theenviron
parameter), or a string can be used to specify an explicit list of directories with colon separators as normal. -
jail_before
(integer) specifies the jail id of a jail to attach to before processing any other directory or file actions -
chroot_before
(string) specifies a directory to change to after processingjail_before
but before all other directory and file actions -
directory_before
(string) specifies a directory to change to before processing file actions, but afterjail_before
andchroot_before
-
jail_after
(integer) specifies a jail to attach to after processing file actions, but beforechroot
anddirectory
-
chroot
(string) specifies a directory to chroot to after processing all file actions and jails, but beforedirectory
-
directory
(string) specifies a directory to change to after processing all file actions, jails, and chroots -
signals
(table) specifies signal dispositions for the subprocess. By default, all signals are reset to default and unblocked. Each of the elementsignore
,block
, andpreserve
may specify a list (in the form of a sequence of numbers orSIGxxx
strings) of signals to ignore, block, or preserve the blocked/ignored state, respectively. (If a signal is listed under bothignore
andpreserve
, thenignore
takes precedence.) Signals caught in the current process are reset to default unless listed inignore
.signals
can also be set to a string"preserve"
to preserve all signals from the invoking process.If
wait
is enabled, thenignore_waiting
specifies a list of signals to ignore while waiting for the subprocess, andblock_waiting
specifies a list of signals to block while waiting. The default forblock_waiting
is to blockSIGINT
,SIGQUIT
, andSIGCHLD
; no signals are ignored by default.Respects
__index
but not__pairs
on both the signals table and its elements. -
resources
(table) specifies resource limits to be set withsetrlimit
in the subprocess. The keys of theresources
table are resource names or numbers; the names may be either lowercase versions of theRLIMIT_*
constants (without theRLIMIT_
prefix), or the names recognized inlogin.conf
. The values may be strings, which are processed with optional suffixes as inlogin.conf
, or integers, or tables with optional elementscur
andmax
(orrlim_cur
andrlim_max
) to set soft and hard limits independently. (String or integer values set both the soft and hard limit together.)Respects
__index
but not__pairs
on both the resources table and any table elements. -
reset_ids
(boolean) If true, the effective GID and UID are reset to the real GID and UID before processing any files, directories, or jails. -
new_session
(boolean) If true, a new session is created for the subprocess before any file or directory actions. -
process_group
(integer or boolean) If set, the subprocess is moved to the specified process group. A value oftrue
uses the subprocess's own pid as the process group (thus guaranteeing a new process group). -
foreground_tty
(integer or boolean) If set, the subprocess' process group (after processingprocess_group
) is set as the foreground process group of the specified descriptor, which must be a tty device either inherited or opened as a file action.true
uses descriptor 0 as the tty.
If no input_pipe
or output_pipe
actions were specified, then the
return value is just the subprocess id on success, or a false value
followed by the error text and error code on failure.
If an input_pipe
or output_pipe
action was specified (it is an
error to specify more than one pipe action), then on success, a second
result is returned with a Lua filehandle opened on the invoker's side
of the pipe. This filehandle, like one returned by io.popen
, will
wait for the subprocess to terminate when the handle is closed.
(If you want any more complex plumbing than this, you can open your own pipes using the posix module and pass the appropriate descriptors.)
As a convenience, the module also provides:
flag, status, code = spawn.waitpid(pid)
with the obvious meaning;
envtab = spawn.environ()
which returns a (newly generated each time) table containing a copy of the current environment of the process; and
fdtab = spawn.open_fds()
which returns a table containing the list of currently open fds as a sequence.