os::exec
os::exec handles the execution of arbitrary commands. A programmer who needs to spawn an external command will usually utilize cmd to obtain a command instance (possibly using functions like setenv to customize it), then start to execute it and obtain a process (or, exec to replace the current process with it), then wait or peek to check in on its status.
Index
Types
type closefd = void;
type exit_status = (exited | signaled);
type exited = int;
type nullfd = void;
type process = unix::pid;
type signaled = signal::sig;
type status = struct {
status: int,
rusage: struct {
utime: time::instant,
stime: time::instant,
maxrss: u64,
minflt: u64,
majflt: u64,
inblock: u64,
oublock: u64,
nvcsw: u64,
nivcsw: u64,
},
};
type command = struct {
platform: platform_cmd,
argv: []str,
env: []str,
files: []((io::file | nullfd | closefd), io::file),
dir: str,
};
type platform_cmd = io::file;
Errors
type error = !(nocmd | ...errors::error | io::error | fs::error);
type nocmd = !void;
Functions
fn addfile(cmd: *command, child: io::file, source: (io::file | nullfd | closefd)) void;
fn chdir(cmd: *command, dir: str) void;
fn check(stat: *status) (void | !exit_status);
fn clearenv(cmd: *command) void;
fn closestd(cmd: *command) void;
fn cmd(name: str, args: str...) (command | error);
fn cmdfile(file: io::file, name: str, args: str...) command;
fn exec(cmd: *command) never;
fn exit(stat: *status) exit_status;
fn exitstr(status: exit_status) const str;
fn finish(cmd: *command) void;
fn fork() (process | void | error);
fn kill(proc: process) (void | errors::error);
fn lookup(name: str) (str | void);
fn nullstd(cmd: *command) void;
fn peek(proc: *process) (status | void | error);
fn peekany() ((process, status) | void | error);
fn pipe() (io::file, io::file);
fn self() process;
fn setenv(cmd: *command, key: str, value: str) (void | errors::invalid);
fn setname(cmd: *command, name: str) void;
fn sig(proc: process, sig: signal::sig) (void | errors::error);
fn start(cmd: *command) (process | error);
fn strerror(err: error) const str;
fn unsetenv(cmd: *command, key: str) (void | errors::invalid);
fn wait(proc: *process) (status | error);
fn waitall() (uint | error | !(process, exit_status));
fn waitany() ((process, status) | error);
Types
type closefd
type closefd = void;
Used to close a file descriptor which does not have the CLOEXEC flag set.
type exit_status
type exit_status = (exited | signaled);
The exit status of a process.
type exited
type exited = int;
The exit status code of a process.
type nullfd
type nullfd = void;
Represents a "null" file descriptor, e.g. /dev/null.
type process
type process = unix::pid;
Stores information about a child process.
type signaled
type signaled = signal::sig;
The signal number which caused a process to terminate.
type status
type status = struct {
status: int,
rusage: struct {
utime: time::instant,
stime: time::instant,
maxrss: u64,
minflt: u64,
majflt: u64,
inblock: u64,
oublock: u64,
nvcsw: u64,
nivcsw: u64,
},
};
Stores information about an exited process.
type command
Show undocumented member
type command = struct {
platform: platform_cmd,
argv: []str,
env: []str,
files: []((io::file | nullfd | closefd), io::file),
dir: str,
};
Show undocumented member
type platform_cmd = io::file;
Errors
type error
type error = !(nocmd | ...errors::error | io::error | fs::error);
All errors that can be returned from os::exec.
type nocmd
type nocmd = !void;
Returned when path resolution fails to find a command by its name.
Functions
fn addfile
fn addfile(cmd: *command, child: io::file, source: (io::file | nullfd | closefd)) void;
Configures a file in the child process's file table, such that the file described by the 'source' parameter is mapped onto file descriptor slot 'child' in the child process via dup(2).
This operation is performed atomically, such that the following code swaps stdout and stderr:
exec::addfile(&cmd, os::stderr_file, os::stdout_file);
exec::addfile(&cmd, os::stdout_file, os::stderr_file);
Pass nullfd in the 'source' argument to map the child's file descriptor to /dev/null or the appropriate platform-specific equivalent.
Pass closefd in the 'source' argument to close a file descriptor which was not opened with the CLOEXEC flag. Note that Hare opens all files with CLOEXEC by default, so this is not usually necessary.
To write to a process's stdin, capture its stdout, or pipe two programs together, see the pipe function.
fn chdir
fn chdir(cmd: *command, dir: str) void;
Configures the child process's working directory. This does not affect the process environment. The path is borrowed from the input, and must outlive the command.
fn check
fn check(stat: *status) (void | !exit_status);
Checks the exit status of a completed process, returning void if successful, or its status code as an error type if not.
fn clearenv
fn clearenv(cmd: *command) void;
Empties the environment variables for the command. By default, the command inherits the environment of the parent process.
fn closestd
fn closestd(cmd: *command) void;
Closes all standard files (stdin, stdout, and stderr) in the child process. Many programs do not work well under these conditions; you may want nullstd instead.
fn cmd
fn cmd(name: str, args: str...) (command | error);
Prepares a command based on its name and a list of arguments. The argument list should not start with the command name; it will be added for you. The argument list is borrowed from the strings you pass into this command.
If 'name' does not contain a '/', the $PATH will be consulted to find the correct executable. If path resolution fails, nocmd is returned.
let cmd = exec::cmd("echo", "hello world")!;
let proc = exec::start(&cmd)!;
let status = exec::wait(&proc)!;
assert(exec::check(&status) is void);
By default, the new command will inherit the current process's environment.
fn cmdfile
fn cmdfile(file: io::file, name: str, args: str...) command;
Same as cmd except that executable file is determined by io::file. This function is not portable.
fn exec
fn exec(cmd: *command) never;
Executes a prepared command in the current address space, overwriting the running process with the new command.
fn exit
fn exit(stat: *status) exit_status;
Returns the exit status of a completed process.
fn exitstr
fn exitstr(status: exit_status) const str;
Returns a human friendly string describing the exit status. The string is statically allocated; use strings::dup to extend its lifetime.
fn finish
fn finish(cmd: *command) void;
Frees state associated with a command. You only need to call this if you do not execute the command with exec or start; in those cases the state is cleaned up for you.
fn fork
fn fork() (process | void | error);
Forks the current process, returning the process of the child (to the parent) and void (to the child), or an error.
fn kill
fn kill(proc: process) (void | errors::error);
Terminates a process. On Linux, this sends unix::signal::sig::TERM to the process.
fn lookup
fn lookup(name: str) (str | void);
Looks up an executable by name in the system PATH. The return value is statically allocated.
The use of this function is lightly discouraged if cmd is suitable; otherwise you may have a TOCTOU issue.
fn nullstd
fn nullstd(cmd: *command) void;
Redirects all standard files (stdin, stdout, and stderr) to /dev/null or the platform-specific equivalent.
fn peek
fn peek(proc: *process) (status | void | error);
Checks for process completion, returning its status information on completion, or void if it is still running.
fn peekany
fn peekany() ((process, status) | void | error);
Checks if any child process has completed, returning its process info and status if so.
fn pipe
fn pipe() (io::file, io::file);
Creates an anonymous pipe for use with addfile. Any data written to the second file may be read from the first file. The caller should close one or both of the file descriptors after they have transferred them to another process, and after they have finished using them themselves, if applicable.
This function will abort the process if the system is unable to allocate the resources for a pipe. If you need to handle this error gracefully, you may call unix::pipe yourself, but this may reduce the portability of your software.
To capture the standard output of a process:
const (read, write) = exec::pipe();
exec::addfile(&cmd, os::stdout_file, write);
let proc = exec::start(&cmd)!;
io::close(write)!;
let data = io::drain(read)!;
io::close(read)!;
exec::wait(&proc)!;
To write to the standard input of a process:
const (read, write) = exec::pipe();
exec::addfile(&cmd, os::stdin_file, read);
let proc = exec::start(&cmd)!;
io::close(read)!;
io::writeall(write, data)!;
io::close(write)!;
exec::wait(&proc)!;
fn self
fn self() process;
Returns the currently running process.
fn setenv
fn setenv(cmd: *command, key: str, value: str) (void | errors::invalid);
Adds or sets a variable in the command environment. This does not affect the current process environment. The key may not contain '=' or '\0'.
fn setname
fn setname(cmd: *command, name: str) void;
Sets the 0th value of argv for this command. It is uncommon to need this.
fn sig
fn sig(proc: process, sig: signal::sig) (void | errors::error);
Sends a signal to a child process. This function is only supported on Unix-like systems.
fn start
fn start(cmd: *command) (process | error);
Starts a prepared command in a new process.
fn strerror
fn strerror(err: error) const str;
Returns a human-readable message for the given error.
fn unsetenv
fn unsetenv(cmd: *command, key: str) (void | errors::invalid);
Removes a variable in the command environment. This does not affect the current process environment. The key may not contain '=' or '\0'.
fn wait
fn wait(proc: *process) (status | error);
Waits for a process to complete, then returns its status information.
fn waitall
fn waitall() (uint | error | !(process, exit_status));
Waits for all children to terminate succesfully. If a child process exits with a nonzero status, returns its process info and exit status immediately, not waiting for the remaining children.
fn waitany
fn waitany() ((process, status) | error);
Waits for the first child process to complete, then returns its process info and status