os::exec+x86_64 +linux

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,
	// Not all of these members are supported on all operating systems.
	// Only utime and stime are guaranteed to be available.
	rusage: struct {
		utime: time::instant,
		stime: time::instant,
		maxrss: u64,
		minflt: u64,
		majflt: u64,
		inblock: u64,
		oublock: u64,
		nvcsw: u64,
		nivcsw: u64,
	},
};

// Undocumented types:
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[link]

type closefd = void;

Used to close a file descriptor which does not have the CLOEXEC flag set.

type exit_status[link]

type exit_status = (exited | signaled);

The exit status of a process.

type exited[link]

type exited = int;

The exit status code of a process.

type nullfd[link]

type nullfd = void;

Represents a "null" file descriptor, e.g. /dev/null.

type process[link]

type process = unix::pid;

Stores information about a child process.

type signaled[link]

type signaled = signal::sig;

The signal number which caused a process to terminate.

type status[link]

type status = struct {
	status: int,
	// Not all of these members are supported on all operating systems.
	// Only utime and stime are guaranteed to be available.
	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[link]

Show undocumented member
type command = struct {
	platform: platform_cmd,
	argv: []str,
	env: []str,
	files: []((io::file | nullfd | closefd), io::file),
	dir: str,
};

type platform_cmd[link]

Show undocumented member
type platform_cmd = io::file;

Errors

type error[link]

type error = !(nocmd | ...errors::error | io::error | fs::error);

All errors that can be returned from os::exec.

type nocmd[link]

type nocmd = !void;

Returned when path resolution fails to find a command by its name.

Functions

fn addfile[link]

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[link]

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[link]

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[link]

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[link]

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[link]

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[link]

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[link]

fn exec(cmd: *command) never;

Executes a prepared command in the current address space, overwriting the running process with the new command.

fn exit[link]

fn exit(stat: *status) exit_status;

Returns the exit status of a completed process.

fn exitstr[link]

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[link]

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[link]

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[link]

fn kill(proc: process) (void | errors::error);

Terminates a process. On Linux, this sends unix::signal::sig::TERM to the process.

fn lookup[link]

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[link]

fn nullstd(cmd: *command) void;

Redirects all standard files (stdin, stdout, and stderr) to /dev/null or the platform-specific equivalent.

fn peek[link]

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[link]

fn peekany() ((process, status) | void | error);

Checks if any child process has completed, returning its process info and status if so.

fn pipe[link]

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:

let pipe = exec::pipe();
exec::addfile(&cmd, os::stdout_file, pipe.1);
let proc = exec::start(&cmd)!;
io::close(pipe.1)!;

let data = io::drain(pipe.0)!;
io::close(pipe.0)!;
exec::wait(&proc)!;

To write to the standard input of a process:

let pipe = exec::pipe();
exec::addfile(&cmd, os::stdin_file, pipe.0);
let proc = exec::start(&cmd)!;

io::writeall(data)!;
io::close(pipe.1)!;
io::close(pipe.0)!;
exec::wait(&proc)!;

fn self[link]

fn self() process;

Returns the currently running process.

fn setenv[link]

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[link]

fn setname(cmd: *command, name: str) void;

Sets the 0th value of argv for this command. It is uncommon to need this.

fn sig[link]

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[link]

fn start(cmd: *command) (process | error);

Starts a prepared command in a new process.

fn strerror[link]

fn strerror(err: error) const str;

Returns a human-readable message for the given error.

fn unsetenv[link]

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[link]

fn wait(proc: *process) (status | error);

Waits for a process to complete, then returns its status information.

fn waitall[link]

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[link]

fn waitany() ((process, status) | error);

Waits for the first child process to complete, then returns its process info and status