Struct unshare::Command [] [src]

pub struct Command { /* fields omitted */ }

Main class for running processes. Works in the spirit of builder pattern.

Methods

impl Command
[src]

Constructs a new Command for launching the program at path program, with the following default configuration:

  • No arguments to the program
  • Inherit the current process's environment
  • Inherit the current process's working directory
  • Inherit stdin/stdout/stderr for spawn or status, but create pipes for output

Builder methods are provided to change these defaults and otherwise configure the process.

Add an argument to pass to the program.

Add multiple arguments to pass to the program.

Inserts or updates an environment variable mapping.

Removes an environment variable mapping.

Clears the entire environment map for the child process.

Sets the working directory for the child process.

Note: in case of chroot or pivot_root the working directory is always set to something inside the new root. Algorithm is following:

  1. If path is set to absolute path, current dir is this path inside the chroot
  2. Check if chroot dir is prefix of env::current_dir(). If it is set current directory to the suffix. Otherwise set current directory to the new root dir.
  3. If current_dir is specified (and relative) set working directory to the value (i.e. relative to the dir set in #2)

The pivot_root is treated just the same as chroot. I.e. we will not try to set working directory inside the old_root, unless path inside is set explicitly by this method.

At the end of the day, the cmd.current_dir(env::current_dir()) is not no-op if using chroot/pivot_root.

Configuration for the child process's stdin handle (file descriptor 0).

Configuration for the child process's stdout handle (file descriptor 1).

Configuration for the child process's stderr handle (file descriptor 2).

Set user id of the new process. Note that it works only for root process or if you also set up user namespace

Set primary group id of the new process. Note that it works only for root process or if you also set up user namespace

Set supplementary group ids. Note that it works only for root process or if you also set up user namespace

impl Command
[src]

Allow child process to daemonize. By default we run equivalent of set_parent_death_signal(SIGKILL). See the set_parent_death_signal for better explanation.

Set a signal that is sent to a process when it's parent is dead. This is by default set to SIGKILL. And you should keep it that way unless you know what you are doing.

Particularly you should consider the following choices:

  1. Instead of setting PDEATHSIG to some other signal, send signal yourself and wait until child gracefully finishes.

  2. Instead of daemonizing use systemd/upstart/whatever system init script to run your service

Another issue with this option is that it works only with immediate child. To better control all descendant processes you may need the following:

  1. The prctl(PR_SET_CHILD_SUBREAPER..) in parent which allows to "catch" descendant processes.

  2. The pid namespaces

The former is out of scope of this library. The latter works by cmd.unshare(Namespace::Pid), but you may need to setup mount points and other important things (which are out of scope too).

To reset this behavior use allow_daemonize().

Set chroot dir. Only absolute path is supported

This method has a non-standard security feature: even if current_dir is unspecified we set it to the directory inside the new root dir. see more details in the description of Command::current_dir.

Note that if both chroot dir and pivot_root specified. The chroot dir is applied after pivot root. If chroot dir is relative it's relative to either suffix of the current directory with stripped off pivot dir or the pivot dir itself (if old workdir is not prefixed by pivot dir)

Panics

If directory is not absolute

Moves the root of the file system to the directory put_old and makes new_root the new root file system. Also it's optionally unmount new_root mount point after moving root (but it must exist anyway).

The documentation says that put_old must be underneath the new_root. Currently we have a restriction that both must be absolute and new_root be prefix of put_old, but we may lift it later.

Warning if you don't unshare the mount namespace you will get moved filesystem root for all processes running in that namespace including parent (currently running) process itself. If you don't run equivalent to mount --make-private for the old root filesystem and set unmount to true, you may get unmounted filesystem for running processes too.

See man 2 pivot for further details

Note that if both chroot dir and pivot_root specified. The chroot dir is applied after pivot root.

Panics

Panics if either path is not absolute or new_root is not a prefix of put_old.

Unshare given namespaces

Note: each namespace have some consequences on how new process will work, some of them are described in the Namespace type documentation.

Reassociate child process with a namespace specified by a file descriptor

file argument is an open file referring to a namespace

'ns' is a namespace type

See man 2 setns for further details

Note: using unshare and setns for the same namespace is meaningless.

Sets user id and group id mappings for new process

This automatically enables User namespace. You should also set uid and gid with respective methods for the new process.

Note there are basically two ways to enable id maps:

  1. Write them directly
  2. Invoke a newuidmap, newgidmap commands

First option works either if current process is root or if resulting map only contains current user in the mapping.

The library will not try to guess the behavior. By default it will write directly. You need to call the set_id_map_commands when you want non-default behavior.

See man 7 user_namespaces for more info

Set path to command-line utilities for writing uid/gid maps

The utilities provided my obey same interface as newuidmap and newgidmap from shadow (or sometimes uidmap) package. To get it working you usually need to setup /etc/subuid and /etc/subgid files.

See man 1 newuidmap, man 1 newgidmap for details

This method is no-op unless set_id_maps is called.

Keep signal mask intact after executing child, keeps also ignored signals

By default signal mask is empty and all signals are reset to the SIG_DFL value right before execve() syscall.

This is only useful if started process is aware of the issue and sets sigmasks to some reasonable value. When used wisely it may avoid some race conditions when signal is sent after child is cloned but before child have been able to establish it's state.

Set the argument zero for the process

By default argument zero is same as path to the program to run. You may set it to a short name of the command or to something else to pretend there is a symlink to a program (for example to run gzip as gunzip).

Makes child process a group leader

If child process is being launched as a foreground job, the child process group needs to be put into the foreground on the controlling terminal using tcsetpgrp. To request status information from stopped child process you should call waitpid with WUNTRACED flag. And then check status with WIFSTOPPED macro. After giving child process group access to the controlling terminal you should send the SIGCONT signal to the child process group.

impl Command
[src]

Configuration for any other file descriptor (panics for fds < 3) use stdin/stdout/stderr for them

Rust creates file descriptors with CLOEXEC flag by default, so no descriptors are inherited except ones specifically configured here (and stdio which is inherited by default)

Pass Raw file descriptor to the application

This method assumes that file descriptor is owned by an application and application is smart enough to keep it until process is started.

This is useful to avoid dup()ing of file descriptors that need to be hold by process supervisor.

Close a range of file descriptors as soon as process forks

Subsequent calls to this method add additional range. Use reset_fds to remove all the ranges.

File descriptors that never closed are:

  • the stdio file descriptors
  • descriptors configured using file_descriptor/file_descriptor_raw methods
  • internal file descriptors used for parent child notification by unshare crate itself (they are guaranteed to have CLOEXEC)

You should avoid this method if possilble and rely on CLOEXEC to do the work. But sometimes it's inevitable:

  1. If you need to ensure closing descriptors for security reasons
  2. If you have some bad library out of your control which doesn't set CLOEXEC on owned the file descriptors

Ranges obey the following rules:

  • Range like ..12 is transformed into 3..12
  • Range with undefined upper bound 3.. is capped at current ulimit for file descriptors at the moment of calling the method
  • The full range .. is an alias to 3..
  • Multiple overlapping ranges are closed multiple times which is both harmless and useless

Panics

Panics when can't get rlimit for range without upper bound. Should never happen in practice.

Panics when lower range of fd is < 3 (stdio file descriptors)

Reset file descriptor including stdio to the initial state

Initial state is inherit all the stdio and do nothing to other fds.

impl Command
[src]

Run the command and return exit status

Spawn the command and return a handle that can be waited for

Trait Implementations

impl Debug for Command
[src]

Formats the value using the given formatter.