proot/main.rs
1//! PRoot reimplemented in Rust.
2//!
3//! The program runs a command inside a guest root filesystem without any
4//! privilege. Path-taking syscalls are routed through seccomp user
5//! notification and answered by a small pool of supervisor threads; only the
6//! syscalls that must change the tracee's own state in place (`execve`,
7//! `chdir`, unix socket `bind`/`connect`) take a ptrace stop. Everything else
8//! runs untraced at native speed. Where ptrace is filtered out, those few
9//! syscalls are served through notifications too, with in-place rewrites
10//! (`syscall::direct`).
11//!
12//! The binary behaves like bubblewrap when invoked through a name ending in
13//! `bwrap`, busybox style, so a symlink is enough to make it a drop-in.
14
15mod abi;
16mod access;
17mod cli;
18mod config;
19mod exec;
20mod fs;
21mod guest_stub;
22mod launch;
23mod procs;
24mod seccomp;
25mod state;
26mod sys;
27mod syscall;
28mod tracee;
29mod tracer;
30
31use std::ffi::OsString;
32use std::os::unix::ffi::OsStrExt;
33
34/// Program entry point.
35///
36/// Dispatches on the basename of `argv[0]`: a name ending in `bwrap` selects
37/// the bubblewrap-compatible front end, anything else the PRoot front end.
38/// Exits with the traced command's exit status, or 1 on internal error.
39fn main() {
40 let mut args: Vec<OsString> = std::env::args_os().collect();
41 let argv0 = args.remove(0);
42 let base = std::path::Path::new(&argv0)
43 .file_name()
44 .map(|f| f.as_bytes().to_vec())
45 .unwrap_or_default();
46 let parsed = if base.ends_with(b"bwrap") {
47 cli::bwrap::parse(args, &cli::host::Local)
48 } else {
49 cli::parse(args, &cli::host::Local)
50 };
51 let config = match parsed {
52 Ok(c) => c,
53 Err(cli::CliError::Exit { code, text }) => {
54 print!("{text}");
55 std::process::exit(code)
56 }
57 Err(cli::CliError::Usage(msg)) => {
58 eprintln!("proot: {msg}");
59 std::process::exit(125);
60 }
61 };
62 match launch::run(config) {
63 Ok(code) => std::process::exit(code),
64 Err(e) => {
65 eprintln!("proot: {e}");
66 std::process::exit(1);
67 }
68 }
69}