runas/
lib.rs

1//! This library implements basic support for running a command in an elevated context.
2//!
3//! In particular this runs a command through "sudo" or other platform equivalents.
4//!
5//! ## Basic Usage
6//!
7//! The library provides a single struct called `Command` which largely follows the
8//! API of `std::process::Command`.  However it does not support capturing output or
9//! gives any guarantees for the working directory or environment.  This is because
10//! the platform APIs do not have support for that either in some cases.
11//!
12//! In particular the working directory is always the system32 folder on windows and
13//! the environment variables are always the ones of the initial system session on
14//! OS X if the GUI mode is used.
15//!
16//! ```rust,no_run
17//! use runas::Command;
18//!
19//! let status = Command::new("rm")
20//!     .arg("/usr/local/my-app")
21//!     .status()
22//!     .unwrap();
23//! ```
24//!
25//! ## Platform Support
26//!
27//! The following platforms are supported:
28//!
29//! * Windows: always GUI mode
30//! * OS X: GUI and CLI mode
31//! * Linux: CLI mode
32use std::ffi::{OsStr, OsString};
33use std::io;
34use std::process::ExitStatus;
35
36#[cfg(target_os = "macos")]
37mod impl_darwin;
38#[cfg(unix)]
39mod impl_unix;
40#[cfg(windows)]
41mod impl_windows;
42
43/// A process builder for elevated execution
44pub struct Command {
45    command: OsString,
46    args: Vec<OsString>,
47    force_prompt: bool,
48    hide: bool,
49    gui: bool,
50}
51
52/// The `Command` type acts as a process builder for spawning programs that run in
53/// an elevated context.
54///
55/// Example:
56///
57/// ```rust,no_run
58/// use runas::Command;
59/// let status = Command::new("cmd").status();
60/// ```
61impl Command {
62    /// Creates a new command type for a given program.
63    ///
64    /// The default configuration is to spawn without arguments, to be visible and
65    /// to not be launched from a GUI context.
66    pub fn new<S: AsRef<OsStr>>(program: S) -> Command {
67        Command {
68            command: program.as_ref().to_os_string(),
69            args: vec![],
70            hide: false,
71            gui: false,
72            force_prompt: true,
73        }
74    }
75
76    /// Add an argument to pass to the program.
77    pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Command {
78        self.args.push(arg.as_ref().to_os_string());
79        self
80    }
81
82    /// Add multiple arguments to pass to the program.
83
84    pub fn args<S: AsRef<OsStr>>(&mut self, args: &[S]) -> &mut Command {
85        for arg in args {
86            self.arg(arg);
87        }
88        self
89    }
90
91    /// Controls the visibility of the program on supported platforms.  The default is
92    /// to launch the program visible.
93    pub fn show(&mut self, val: bool) -> &mut Command {
94        self.hide = !val;
95        self
96    }
97
98    /// Controls the GUI context.  The default behavior is to assume that the program is
99    /// launched from a command line (not using a GUI).  This primarily controls how the
100    /// elevation prompt is rendered.  On some platforms like Windows the elevation prompt
101    /// is always a GUI element.
102    ///
103    /// If the preferred mode is not available it falls back to the other automatically.
104    pub fn gui(&mut self, val: bool) -> &mut Command {
105        self.gui = val;
106        self
107    }
108
109    /// Can disable the prompt forcing for supported platforms.  Mostly this allows sudo
110    /// on unix platforms to not prompt for a password.
111    pub fn force_prompt(&mut self, val: bool) -> &mut Command {
112        self.force_prompt = val;
113        self
114    }
115
116    /// Executes a command as a child process, waiting for it to finish and
117    /// collecting its exit status.
118    pub fn status(&mut self) -> io::Result<ExitStatus> {
119        #[cfg(all(unix, target_os = "macos"))]
120        use crate::impl_darwin::runas_impl;
121        #[cfg(all(unix, not(target_os = "macos")))]
122        use impl_unix::runas_impl;
123        #[cfg(windows)]
124        use impl_windows::runas_impl;
125        runas_impl(self)
126    }
127}