unshare/
std_api.rs

1// This file was derived from rust's own libstd/process.rs with the following
2// copyright:
3//
4// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
5// file at the top-level directory of this distribution and at
6// http://rust-lang.org/COPYRIGHT.
7//
8use std::ffi::OsStr;
9use std::default::Default;
10use std::collections::HashMap;
11use std::collections::HashSet;
12use std::env;
13use std::path::Path;
14
15use libc::{uid_t, gid_t};
16use crate::ffi_util::ToCString;
17use crate::{Command, Stdio, Fd};
18
19
20impl Command {
21    /// Constructs a new `Command` for launching the program at
22    /// path `program`, with the following default configuration:
23    ///
24    /// * No arguments to the program
25    /// * Inherit the current process's environment
26    /// * Inherit the current process's working directory
27    /// * Inherit stdin/stdout/stderr for `spawn` or `status`, but create pipes for `output`
28    ///
29    /// Builder methods are provided to change these defaults and
30    /// otherwise configure the process.
31    pub fn new<S: AsRef<OsStr>>(program: S) -> Command {
32        Command {
33            filename: program.to_cstring(),
34            args: vec![program.to_cstring()],
35            environ: None,
36            config: Default::default(),
37            chroot_dir: None,
38            pivot_root: None,
39            fds: vec![
40                (0, Fd::inherit()),
41                (1, Fd::inherit()),
42                (2, Fd::inherit()),
43                ].into_iter().collect(),
44            close_fds: Vec::new(),
45            id_map_commands: None,
46            pid_env_vars: HashSet::new(),
47            keep_caps: None,
48            before_unfreeze: None,
49            pre_exec: None,
50        }
51    }
52
53    /// Add an argument to pass to the program.
54    pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Command {
55        self.args.push(arg.to_cstring());
56        self
57    }
58
59    /// Add multiple arguments to pass to the program.
60    pub fn args<S: AsRef<OsStr>>(&mut self, args: &[S]) -> &mut Command {
61        self.args.extend(args.iter().map(ToCString::to_cstring));
62        self
63    }
64
65    // TODO(tailhook) It's only public for our run module any better way?
66    // TODO(tailhook) make it private
67    #[doc(hidden)]
68    pub fn init_env_map(&mut self) {
69        if self.environ.is_none() {
70            self.environ = Some(env::vars_os().collect());
71        }
72    }
73
74    /// Inserts or updates an environment variable mapping.
75    pub fn env<K, V>(&mut self, key: K, val: V) -> &mut Command
76        where K: AsRef<OsStr>, V: AsRef<OsStr>
77    {
78        self.init_env_map();
79        self.environ.as_mut().unwrap().insert(
80            key.as_ref().to_os_string(),
81            val.as_ref().to_os_string());
82        self.pid_env_vars.remove(key.as_ref());
83        self
84    }
85
86    /// Inserts or updates multiple environment variable mappings.
87    pub fn envs<I, K, V>(&mut self, vars: I)-> &mut Command
88        where I: IntoIterator<Item=(K, V)>, K: AsRef<OsStr>, V: AsRef<OsStr>
89    {
90        for (ref key, ref val) in vars {
91            self.init_env_map();
92            self.environ.as_mut().unwrap().insert(
93                key.as_ref().to_os_string(),
94                val.as_ref().to_os_string());
95            self.pid_env_vars.remove(key.as_ref());
96        }
97        self
98    }
99    
100    /// Removes an environment variable mapping.
101    pub fn env_remove<K: AsRef<OsStr>>(&mut self, key: K) -> &mut Command {
102        self.init_env_map();
103        self.environ.as_mut().unwrap().remove(key.as_ref());
104        self.pid_env_vars.remove(key.as_ref());
105        self
106    }
107
108    /// Clears the entire environment map for the child process.
109    pub fn env_clear(&mut self) -> &mut Command {
110        self.environ = Some(HashMap::new());
111        self.pid_env_vars = HashSet::new();
112        self
113    }
114
115    /// Sets the working directory for the child process.
116    ///
117    /// Note: in case of `chroot` or `pivot_root` the working directory is
118    /// always set to something inside the new root. Algorithm is following:
119    ///
120    /// 1. If path is set to absolute path, current dir is this path *inside*
121    ///    the chroot
122    /// 2. Check if chroot dir is prefix of `env::current_dir()`. If it is
123    ///    set current directory to the suffix. Otherwise set current directory
124    ///    to the new root dir.
125    /// 3. If `current_dir` is specified (and relative) set working directory
126    ///    to the value (i.e. relative to the dir set in #2)
127    ///
128    /// The `pivot_root` is treated just the same as `chroot`. I.e. we will
129    /// not try to set working directory inside the `old_root`, unless path
130    /// inside is set explicitly by this method.
131    ///
132    /// At the end of the day, the ``cmd.current_dir(env::current_dir())`` is
133    /// not no-op if using chroot/pivot_root.
134    pub fn current_dir<P: AsRef<Path>>(&mut self, dir: P) -> &mut Command
135    {
136        self.config.work_dir = Some(dir.as_ref().to_cstring());
137        self
138    }
139
140    /// Configuration for the child process's stdin handle (file descriptor 0).
141    pub fn stdin(&mut self, cfg: Stdio) -> &mut Command {
142        self.fds.insert(0, cfg.to_fd(false));
143        self
144    }
145
146    /// Configuration for the child process's stdout handle (file descriptor 1).
147    pub fn stdout(&mut self, cfg: Stdio) -> &mut Command {
148        self.fds.insert(1, cfg.to_fd(true));
149        self
150    }
151
152    /// Configuration for the child process's stderr handle (file descriptor 2).
153    pub fn stderr(&mut self, cfg: Stdio) -> &mut Command {
154        self.fds.insert(2, cfg.to_fd(true));
155        self
156    }
157
158    /// Set user id of the new process. Note that it works only for root
159    /// process or if you also set up user namespace
160    pub fn uid(&mut self, id: uid_t) -> &mut Command {
161        self.config.uid = Some(id);
162        self
163    }
164
165    /// Set primary group id of the new process. Note that it works only for
166    /// root process or if you also set up user namespace
167    pub fn gid(&mut self, id: gid_t) -> &mut Command {
168        self.config.gid = Some(id);
169        self
170    }
171
172    /// Set supplementary group ids. Note that it works only for root process
173    /// or if you also set up user namespace
174    pub fn groups(&mut self, ids: Vec<gid_t>) -> &mut Command {
175        self.config.supplementary_gids = Some(ids);
176        self
177    }
178}
179