os::exec +linux +x86_64

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;
type exit_status;
type exited;
type nullfd;
type process;
type signal;
type signaled;
type status;

// Undocumented types:
type command;
type platform_cmd;

Errors

type error;
type nocmd;

Functions

fn addfile(*command, io::file, (io::file | nullfd | closefd)) void;
fn check(*status) (void | !exit_status);
fn clearenv(*command) void;
fn closestd(*command) void;
fn cmd(str, str...) (command | error);
fn exec(*command) void;
fn exit(*status) exit_status;
fn exitstr(exit_status) const str;
fn finish(*command) void;
fn fork() (process | void | error);
fn kill(process, signal...) (void | errors::error);
fn nullstd(*command) void;
fn peek(*process) (status | void | error);
fn peekany() ((process, status) | void | error);
fn pipe() (io::file, io::file);
fn self() process;
fn setenv(*command, str, str) (void | errors::invalid);
fn setname(*command, str) void;
fn start(*command) (error | process);
fn strerror(error) const str;
fn unsetenv(*command, str) (void | errors::invalid);
fn wait(*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 = int;

Stores information about a child process.

type signal[link]

type signal = enum {
	SIGHUP = rt::SIGHUP,
	SIGINT = rt::SIGINT,
	SIGQUIT = rt::SIGQUIT,
	SIGILL = rt::SIGILL,
	SIGTRAP = rt::SIGTRAP,
	SIGABRT = rt::SIGABRT,
	SIGBUS = rt::SIGBUS,
	SIGFPE = rt::SIGFPE,
	SIGKILL = rt::SIGKILL,
	SIGUSR1 = rt::SIGUSR1,
	SIGSEGV = rt::SIGSEGV,
	SIGUSR2 = rt::SIGUSR2,
	SIGPIPE = rt::SIGPIPE,
	SIGALRM = rt::SIGALRM,
	SIGTERM = rt::SIGTERM,
	SIGSTKFLT = rt::SIGSTKFLT,
	SIGCHLD = rt::SIGCHLD,
	SIGCONT = rt::SIGCONT,
	SIGSTOP = rt::SIGSTOP,
	SIGTSTP = rt::SIGTSTP,
	SIGTTIN = rt::SIGTTIN,
	SIGTTOU = rt::SIGTTOU,
	SIGURG = rt::SIGURG,
	SIGXCPU = rt::SIGXCPU,
	SIGXFSZ = rt::SIGXFSZ,
	SIGVTALRM = rt::SIGVTALRM,
	SIGPROF = rt::SIGPROF,
	SIGWINCH = rt::SIGWINCH,
	SIGIO = rt::SIGIO,
	SIGPOLL = rt::SIGPOLL,
	SIGPWR = rt::SIGPWR,
	SIGSYS = rt::SIGSYS,

};

An enumeration of all known signals. Only a subset of these are defined by POSIX, consult the specification for details:

https://pubs.opengroup.org/onlinepubs/009695399/basedefs/signal.h.html

type signaled[link]

type signaled = int;

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 { // TODO: utime, stime
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),
};

type platform_cmd[link]

Show undocumented member
type platform_cmd = io::file;

Errors

type error[link]

type error = !(nocmd | ...errors::error | io::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, os::stdout_file);
exec::addfile(&cmd, os::stdout_file, os::stderr);

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 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::status(status) == 0);

By default, the new command will inherit the current process's environment.

fn exec[link]

@noreturn fn exec(cmd: *command) void;

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.

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, sig: signal...) (void | errors::error);

Sends a signal to a child process. If no variadic arguments are provided, the program is terminated in a platform-specific manner. You may provide exactly one variadic argument, the signal you wish to send, but this is only supported on Unix-like systems.

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);

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

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' must be a valid environment variable name per POSIX definition 3.235. This includes underscores and alphanumeric ASCII characters, and cannot begin with a number.

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

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

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' must be a valid environment variable name per POSIX definition 3.235. This includes underscores and alphanumeric ASCII characters, and cannot begin with a number.

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