refactor(sudo): add SudoExecuteOpts builder functions and preserve_env enum
This commit is contained in:
@@ -127,15 +127,7 @@ pub fn run_rubygems(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
} else {
|
} else {
|
||||||
let sudo = ctx.require_sudo()?;
|
let sudo = ctx.require_sudo()?;
|
||||||
if !Path::new("/usr/lib/ruby/vendor_ruby/rubygems/defaults/operating_system.rb").exists() {
|
if !Path::new("/usr/lib/ruby/vendor_ruby/rubygems/defaults/operating_system.rb").exists() {
|
||||||
sudo.execute_opts(
|
sudo.execute_opts(ctx, &gem, SudoExecuteOpts::new().preserve_env().set_home())?
|
||||||
ctx,
|
|
||||||
&gem,
|
|
||||||
SudoExecuteOpts {
|
|
||||||
preserve_env: Some(&[]),
|
|
||||||
set_home: true,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
)?
|
|
||||||
.args(["update", "--system"])
|
.args(["update", "--system"])
|
||||||
.status_checked()?;
|
.status_checked()?;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -993,14 +993,7 @@ pub fn run_config_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
print_separator(t!("Configuration update"));
|
print_separator(t!("Configuration update"));
|
||||||
sudo.execute_opts(
|
sudo.execute_opts(ctx, &pacdiff, SudoExecuteOpts::new().preserve_env_list(&["DIFFPROG"]))?
|
||||||
ctx,
|
|
||||||
&pacdiff,
|
|
||||||
SudoExecuteOpts {
|
|
||||||
preserve_env: Some(&["DIFFPROG"]),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
)?
|
|
||||||
.status_checked()?;
|
.status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -330,15 +330,7 @@ pub fn run_brew_formula(ctx: &ExecutionContext, variant: BrewVariant) -> Result<
|
|||||||
print_separator(format!("{} ({})", variant.step_title(), sudo_as_user));
|
print_separator(format!("{} ({})", variant.step_title(), sudo_as_user));
|
||||||
|
|
||||||
let sudo = ctx.require_sudo()?;
|
let sudo = ctx.require_sudo()?;
|
||||||
sudo.execute_opts(
|
sudo.execute_opts(ctx, &binary_name, SudoExecuteOpts::new().set_home().user(&user.name))?
|
||||||
ctx,
|
|
||||||
&binary_name,
|
|
||||||
SudoExecuteOpts {
|
|
||||||
set_home: true,
|
|
||||||
user: Some(&user.name),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
)?
|
|
||||||
.current_dir("/tmp") // brew needs a writable current directory
|
.current_dir("/tmp") // brew needs a writable current directory
|
||||||
.arg("update")
|
.arg("update")
|
||||||
.status_checked()?;
|
.status_checked()?;
|
||||||
@@ -557,14 +549,7 @@ pub fn run_nix_self_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
let nix_args = nix_args();
|
let nix_args = nix_args();
|
||||||
if multi_user {
|
if multi_user {
|
||||||
let sudo = ctx.require_sudo()?;
|
let sudo = ctx.require_sudo()?;
|
||||||
sudo.execute_opts(
|
sudo.execute_opts(ctx, &nix, SudoExecuteOpts::new().interactive())?
|
||||||
ctx,
|
|
||||||
&nix,
|
|
||||||
SudoExecuteOpts {
|
|
||||||
interactive: true,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
)?
|
|
||||||
.args(nix_args)
|
.args(nix_args)
|
||||||
.arg("upgrade-nix")
|
.arg("upgrade-nix")
|
||||||
.status_checked()
|
.status_checked()
|
||||||
|
|||||||
86
src/sudo.rs
86
src/sudo.rs
@@ -23,20 +23,72 @@ pub struct Sudo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
/// Generic sudo options, translated into flags to pass to `sudo`. Depending on the sudo kind, OS
|
pub enum SudoPreserveEnv<'a> {
|
||||||
/// and system config, some options might be specified by default or unsupported.
|
/// Preserve all environment variables.
|
||||||
|
All,
|
||||||
|
/// Preserve only the specified environment variables.
|
||||||
|
Some(&'a [&'a str]),
|
||||||
|
/// Preserve no environment variables.
|
||||||
|
#[default]
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generic sudo options, translated into flags to pass to `sudo`.
|
||||||
|
/// NOTE: Depending on the sudo kind, OS and system config, some options might be specified by
|
||||||
|
/// default or unsupported.
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct SudoExecuteOpts<'a> {
|
pub struct SudoExecuteOpts<'a> {
|
||||||
/// Run the command "interactively", i.e. inside a login shell.
|
/// Run the command "interactively", i.e. inside a login shell.
|
||||||
pub interactive: bool,
|
pub interactive: bool,
|
||||||
/// Preserve environment variables across the sudo call. If an empty list is given, preserves
|
/// Preserve environment variables across the sudo call.
|
||||||
/// all existing environment variables.
|
pub preserve_env: SudoPreserveEnv<'a>,
|
||||||
pub preserve_env: Option<&'a [&'a str]>,
|
|
||||||
/// Set the HOME environment variable to the target user's home directory.
|
/// Set the HOME environment variable to the target user's home directory.
|
||||||
pub set_home: bool,
|
pub set_home: bool,
|
||||||
/// Run the command as a user other than the root user.
|
/// Run the command as a user other than the root user.
|
||||||
pub user: Option<&'a str>,
|
pub user: Option<&'a str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> SudoExecuteOpts<'a> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run the command "interactively", i.e. inside a login shell.
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn interactive(mut self) -> Self {
|
||||||
|
self.interactive = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Preserve all environment variables across the sudo call.
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn preserve_env(mut self) -> Self {
|
||||||
|
self.preserve_env = SudoPreserveEnv::All;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Preserve only the specified environment variables across the sudo call.
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn preserve_env_list(mut self, vars: &'a [&'a str]) -> Self {
|
||||||
|
self.preserve_env = SudoPreserveEnv::Some(vars);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the HOME environment variable to the target user's home directory.
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn set_home(mut self) -> Self {
|
||||||
|
self.set_home = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run the command as a user other than the root user.
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn user(mut self, user: &'a str) -> Self {
|
||||||
|
self.user = Some(user);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
const DETECT_ORDER: [SudoKind; 5] = [
|
const DETECT_ORDER: [SudoKind; 5] = [
|
||||||
SudoKind::Doas,
|
SudoKind::Doas,
|
||||||
@@ -143,7 +195,7 @@ impl Sudo {
|
|||||||
|
|
||||||
/// Execute a command with `sudo`.
|
/// Execute a command with `sudo`.
|
||||||
pub fn execute<S: AsRef<OsStr>>(&self, ctx: &ExecutionContext, command: S) -> Result<Executor> {
|
pub fn execute<S: AsRef<OsStr>>(&self, ctx: &ExecutionContext, command: S) -> Result<Executor> {
|
||||||
self.execute_opts(ctx, command, SudoExecuteOpts::default())
|
self.execute_opts(ctx, command, SudoExecuteOpts::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute a command with `sudo`, with custom options.
|
/// Execute a command with `sudo`, with custom options.
|
||||||
@@ -182,9 +234,8 @@ impl Sudo {
|
|||||||
cmd.arg("-d");
|
cmd.arg("-d");
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(preserve_env) = opts.preserve_env {
|
match opts.preserve_env {
|
||||||
if preserve_env.is_empty() {
|
SudoPreserveEnv::All => match self.kind {
|
||||||
match self.kind {
|
|
||||||
SudoKind::Sudo => {
|
SudoKind::Sudo => {
|
||||||
cmd.arg("-E");
|
cmd.arg("-E");
|
||||||
}
|
}
|
||||||
@@ -198,30 +249,29 @@ impl Sudo {
|
|||||||
}
|
}
|
||||||
.into());
|
.into());
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
} else {
|
SudoPreserveEnv::Some(vars) => match self.kind {
|
||||||
match self.kind {
|
|
||||||
SudoKind::Sudo if cfg!(not(target_os = "windows")) => {
|
SudoKind::Sudo if cfg!(not(target_os = "windows")) => {
|
||||||
cmd.arg(format!("--preserve_env={}", preserve_env.join(",")));
|
cmd.arg(format!("--preserve_env={}", vars.join(",")));
|
||||||
}
|
}
|
||||||
SudoKind::Run0 => {
|
SudoKind::Run0 => {
|
||||||
for env in preserve_env {
|
for env in vars {
|
||||||
cmd.arg(format!("--setenv={}", env));
|
cmd.arg(format!("--setenv={}", env));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SudoKind::Please => {
|
SudoKind::Please => {
|
||||||
cmd.arg("-a");
|
cmd.arg("-a");
|
||||||
cmd.arg(preserve_env.join(","));
|
cmd.arg(vars.join(","));
|
||||||
}
|
}
|
||||||
SudoKind::Doas | SudoKind::Sudo | SudoKind::Gsudo | SudoKind::Pkexec => {
|
SudoKind::Doas | SudoKind::Sudo | SudoKind::Gsudo | SudoKind::Pkexec => {
|
||||||
return Err(UnsupportedSudo {
|
return Err(UnsupportedSudo {
|
||||||
sudo_kind: self.kind,
|
sudo_kind: self.kind,
|
||||||
option: "preserve_env list",
|
option: "preserve_env_list",
|
||||||
}
|
}
|
||||||
.into());
|
.into());
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
SudoPreserveEnv::None => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.set_home {
|
if opts.set_home {
|
||||||
|
|||||||
Reference in New Issue
Block a user