Add Sudo type (#221)

* Create `Sudo` type and `SudoKind` enum

* Fix build

* reformat

* Fix choco on windows

* Fix linux

* Fix linux more

* more fix stuff hehe hoho hahaha

* more fix stuff hehe hoho hahaha

Co-authored-by: Thomas Schönauer <37108907+DottoDev@users.noreply.github.com>
This commit is contained in:
Rebecca Turner
2022-11-25 17:19:32 -05:00
committed by GitHub
parent 526c4c9a58
commit b31778bdd8
10 changed files with 157 additions and 89 deletions

View File

@@ -1,16 +1,17 @@
#![allow(dead_code)] #![allow(dead_code)]
use crate::executor::RunType; use crate::executor::RunType;
use crate::git::Git; use crate::git::Git;
use crate::sudo::Sudo;
use crate::utils::require_option; use crate::utils::require_option;
use crate::{config::Config, executor::Executor}; use crate::{config::Config, executor::Executor};
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use directories::BaseDirs; use directories::BaseDirs;
use std::path::{Path, PathBuf}; use std::path::Path;
use std::sync::Mutex; use std::sync::Mutex;
pub struct ExecutionContext<'a> { pub struct ExecutionContext<'a> {
run_type: RunType, run_type: RunType,
sudo: &'a Option<PathBuf>, sudo: Option<Sudo>,
git: &'a Git, git: &'a Git,
config: &'a Config, config: &'a Config,
base_dirs: &'a BaseDirs, base_dirs: &'a BaseDirs,
@@ -23,7 +24,7 @@ pub struct ExecutionContext<'a> {
impl<'a> ExecutionContext<'a> { impl<'a> ExecutionContext<'a> {
pub fn new( pub fn new(
run_type: RunType, run_type: RunType,
sudo: &'a Option<PathBuf>, sudo: Option<Sudo>,
git: &'a Git, git: &'a Git,
config: &'a Config, config: &'a Config,
base_dirs: &'a BaseDirs, base_dirs: &'a BaseDirs,
@@ -40,18 +41,7 @@ impl<'a> ExecutionContext<'a> {
pub fn execute_elevated(&self, command: &Path, interactive: bool) -> Result<Executor> { pub fn execute_elevated(&self, command: &Path, interactive: bool) -> Result<Executor> {
let sudo = require_option(self.sudo.clone(), "Sudo is required for this operation".into())?; let sudo = require_option(self.sudo.clone(), "Sudo is required for this operation".into())?;
let mut cmd = self.run_type.execute(&sudo); Ok(sudo.execute_elevated(self, command, interactive))
if sudo.ends_with("sudo") {
cmd.arg("--preserve-env=DIFFPROG");
}
if interactive {
cmd.arg("-i");
}
cmd.arg(command);
Ok(cmd)
} }
pub fn run_type(&self) -> RunType { pub fn run_type(&self) -> RunType {
@@ -62,8 +52,8 @@ impl<'a> ExecutionContext<'a> {
self.git self.git
} }
pub fn sudo(&self) -> &Option<PathBuf> { pub fn sudo(&self) -> &Option<Sudo> {
self.sudo &self.sudo
} }
pub fn config(&self) -> &Config { pub fn config(&self) -> &Config {

View File

@@ -83,10 +83,10 @@ fn run() -> Result<()> {
let git = git::Git::new(); let git = git::Git::new();
let mut git_repos = git::Repositories::new(&git); let mut git_repos = git::Repositories::new(&git);
let sudo = sudo::path(); let sudo = sudo::Sudo::detect();
let run_type = executor::RunType::new(config.dry_run()); let run_type = executor::RunType::new(config.dry_run());
let ctx = execution_context::ExecutionContext::new(run_type, &sudo, &git, &config, &base_dirs); let ctx = execution_context::ExecutionContext::new(run_type, sudo, &git, &config, &base_dirs);
let mut runner = runner::Runner::new(&ctx); let mut runner = runner::Runner::new(&ctx);
@@ -121,7 +121,9 @@ fn run() -> Result<()> {
} }
if config.pre_sudo() { if config.pre_sudo() {
sudo::elevate(&ctx, sudo.as_ref())?; if let Some(sudo) = ctx.sudo() {
sudo.elevate(&ctx)?;
}
} }
let powershell = powershell::Powershell::new(); let powershell = powershell::Powershell::new();
@@ -202,17 +204,17 @@ fn run() -> Result<()> {
#[cfg(target_os = "dragonfly")] #[cfg(target_os = "dragonfly")]
runner.execute(Step::Pkg, "DragonFly BSD Packages", || { runner.execute(Step::Pkg, "DragonFly BSD Packages", || {
dragonfly::upgrade_packages(sudo.as_ref(), run_type) dragonfly::upgrade_packages(ctx.sudo().as_ref(), run_type)
})?; })?;
#[cfg(target_os = "freebsd")] #[cfg(target_os = "freebsd")]
runner.execute(Step::Pkg, "FreeBSD Packages", || { runner.execute(Step::Pkg, "FreeBSD Packages", || {
freebsd::upgrade_packages(&ctx, sudo.as_ref(), run_type) freebsd::upgrade_packages(&ctx, ctx.sudo().as_ref(), run_type)
})?; })?;
#[cfg(target_os = "openbsd")] #[cfg(target_os = "openbsd")]
runner.execute(Step::Pkg, "OpenBSD Packages", || { runner.execute(Step::Pkg, "OpenBSD Packages", || {
openbsd::upgrade_packages(sudo.as_ref(), run_type) openbsd::upgrade_packages(ctx.sudo().as_ref(), run_type)
})?; })?;
#[cfg(target_os = "android")] #[cfg(target_os = "android")]
@@ -383,7 +385,7 @@ fn run() -> Result<()> {
runner.execute(Step::DebGet, "deb-get", || linux::run_deb_get(&ctx))?; runner.execute(Step::DebGet, "deb-get", || linux::run_deb_get(&ctx))?;
runner.execute(Step::Toolbx, "toolbx", || toolbx::run_toolbx(&ctx))?; runner.execute(Step::Toolbx, "toolbx", || toolbx::run_toolbx(&ctx))?;
runner.execute(Step::Flatpak, "Flatpak", || linux::flatpak_update(&ctx))?; runner.execute(Step::Flatpak, "Flatpak", || linux::flatpak_update(&ctx))?;
runner.execute(Step::Snap, "snap", || linux::run_snap(sudo.as_ref(), run_type))?; runner.execute(Step::Snap, "snap", || linux::run_snap(ctx.sudo().as_ref(), run_type))?;
runner.execute(Step::Pacstall, "pacstall", || linux::run_pacstall(&ctx))?; runner.execute(Step::Pacstall, "pacstall", || linux::run_pacstall(&ctx))?;
runner.execute(Step::Pacdef, "pacdef", || linux::run_pacdef(&ctx))?; runner.execute(Step::Pacdef, "pacdef", || linux::run_pacdef(&ctx))?;
runner.execute(Step::Protonup, "protonup", || linux::run_protonup_update(&ctx))?; runner.execute(Step::Protonup, "protonup", || linux::run_protonup_update(&ctx))?;
@@ -403,11 +405,11 @@ fn run() -> Result<()> {
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
{ {
runner.execute(Step::System, "pihole", || { runner.execute(Step::System, "pihole", || {
linux::run_pihole_update(sudo.as_ref(), run_type) linux::run_pihole_update(ctx.sudo().as_ref(), run_type)
})?; })?;
runner.execute(Step::Firmware, "Firmware upgrades", || linux::run_fwupdmgr(&ctx))?; runner.execute(Step::Firmware, "Firmware upgrades", || linux::run_fwupdmgr(&ctx))?;
runner.execute(Step::Restarts, "Restarts", || { runner.execute(Step::Restarts, "Restarts", || {
linux::run_needrestart(sudo.as_ref(), run_type) linux::run_needrestart(ctx.sudo().as_ref(), run_type)
})?; })?;
} }
@@ -420,12 +422,12 @@ fn run() -> Result<()> {
#[cfg(target_os = "freebsd")] #[cfg(target_os = "freebsd")]
runner.execute(Step::System, "FreeBSD Upgrade", || { runner.execute(Step::System, "FreeBSD Upgrade", || {
freebsd::upgrade_freebsd(sudo.as_ref(), run_type) freebsd::upgrade_freebsd(ctx.sudo().as_ref(), run_type)
})?; })?;
#[cfg(target_os = "openbsd")] #[cfg(target_os = "openbsd")]
runner.execute(Step::System, "OpenBSD Upgrade", || { runner.execute(Step::System, "OpenBSD Upgrade", || {
openbsd::upgrade_openbsd(sudo.as_ref(), run_type) openbsd::upgrade_openbsd(ctx.sudo().as_ref(), run_type)
})?; })?;
#[cfg(windows)] #[cfg(windows)]
@@ -457,10 +459,10 @@ fn run() -> Result<()> {
} }
#[cfg(target_os = "freebsd")] #[cfg(target_os = "freebsd")]
freebsd::audit_packages(&sudo).ok(); freebsd::audit_packages(ctx.sudo().as_ref()).ok();
#[cfg(target_os = "dragonfly")] #[cfg(target_os = "dragonfly")]
dragonfly::audit_packages(&sudo).ok(); dragonfly::audit_packages(ctx.sudo().as_ref()).ok();
} }
let mut post_command_failed = false; let mut post_command_failed = false;

View File

@@ -202,7 +202,6 @@ pub fn run_juliaup(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
} }
run_type.execute(&juliaup).arg("update").status_checked() run_type.execute(&juliaup).arg("update").status_checked()
} }
pub fn run_choosenim(ctx: &ExecutionContext) -> Result<()> { pub fn run_choosenim(ctx: &ExecutionContext) -> Result<()> {

View File

@@ -4,7 +4,6 @@ use std::os::unix::fs::MetadataExt;
use std::path::PathBuf; use std::path::PathBuf;
use std::process::Command; use std::process::Command;
use crate::sudo;
use crate::utils::require_option; use crate::utils::require_option;
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
@@ -13,9 +12,7 @@ use semver::Version;
use tracing::debug; use tracing::debug;
use crate::command::CommandExt; use crate::command::CommandExt;
use crate::executor::RunType;
use crate::terminal::print_separator; use crate::terminal::print_separator;
use crate::utils::sudo;
use crate::utils::{require, PathExt}; use crate::utils::{require, PathExt};
use crate::{error::SkipStep, execution_context::ExecutionContext}; use crate::{error::SkipStep, execution_context::ExecutionContext};
@@ -91,14 +88,17 @@ impl NPM {
Version::parse(&version_str?).map_err(|err| err.into()) Version::parse(&version_str?).map_err(|err| err.into())
} }
fn upgrade(&self, run_type: RunType, use_sudo: bool) -> Result<()> { fn upgrade(&self, ctx: &ExecutionContext, use_sudo: bool) -> Result<()> {
let args = ["update", self.global_location_arg()]; let args = ["update", self.global_location_arg()];
if use_sudo { if use_sudo {
let sudo_option = sudo::path(); let sudo = require_option(ctx.sudo().clone(), String::from("sudo is not installed"))?;
let sudo = require_option(sudo_option, String::from("sudo is not installed"))?; ctx.run_type()
run_type.execute(sudo).arg(&self.command).args(args).status_checked()?; .execute(sudo)
.arg(&self.command)
.args(args)
.status_checked()?;
} else { } else {
run_type.execute(&self.command).args(args).status_checked()?; ctx.run_type().execute(&self.command).args(args).status_checked()?;
} }
Ok(()) Ok(())
@@ -151,17 +151,18 @@ impl Yarn {
.map(|s| PathBuf::from(s.stdout.trim())) .map(|s| PathBuf::from(s.stdout.trim()))
} }
fn upgrade(&self, run_type: RunType, use_sudo: bool) -> Result<()> { fn upgrade(&self, ctx: &ExecutionContext, use_sudo: bool) -> Result<()> {
let args = ["global", "upgrade"]; let args = ["global", "upgrade"];
if use_sudo { if use_sudo {
run_type let sudo = require_option(ctx.sudo().clone(), String::from("sudo is not installed"))?;
.execute("sudo") ctx.run_type()
.execute(sudo)
.arg(self.yarn.as_ref().unwrap_or(&self.command)) .arg(self.yarn.as_ref().unwrap_or(&self.command))
.args(args) .args(args)
.status_checked()?; .status_checked()?;
} else { } else {
run_type.execute(&self.command).args(args).status_checked()?; ctx.run_type().execute(&self.command).args(args).status_checked()?;
} }
Ok(()) Ok(())
@@ -216,12 +217,12 @@ pub fn run_npm_upgrade(ctx: &ExecutionContext) -> Result<()> {
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
{ {
npm.upgrade(ctx.run_type(), should_use_sudo(&npm, ctx)?) npm.upgrade(ctx, should_use_sudo(&npm, ctx)?)
} }
#[cfg(not(target_os = "linux"))] #[cfg(not(target_os = "linux"))]
{ {
npm.upgrade(ctx.run_type(), false) npm.upgrade(ctx, false)
} }
} }
@@ -232,12 +233,12 @@ pub fn run_pnpm_upgrade(ctx: &ExecutionContext) -> Result<()> {
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
{ {
pnpm.upgrade(ctx.run_type(), should_use_sudo(&pnpm, ctx)?) pnpm.upgrade(ctx, should_use_sudo(&pnpm, ctx)?)
} }
#[cfg(not(target_os = "linux"))] #[cfg(not(target_os = "linux"))]
{ {
pnpm.upgrade(ctx.run_type(), false) pnpm.upgrade(ctx, false)
} }
} }
@@ -253,12 +254,12 @@ pub fn run_yarn_upgrade(ctx: &ExecutionContext) -> Result<()> {
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
{ {
yarn.upgrade(ctx.run_type(), should_use_sudo_yarn(&yarn, ctx)?) yarn.upgrade(ctx, should_use_sudo_yarn(&yarn, ctx)?)
} }
#[cfg(not(target_os = "linux"))] #[cfg(not(target_os = "linux"))]
{ {
yarn.upgrade(ctx.run_type(), false) yarn.upgrade(ctx, false)
} }
} }

View File

@@ -10,6 +10,7 @@ use walkdir::WalkDir;
use crate::command::CommandExt; use crate::command::CommandExt;
use crate::error::TopgradeError; use crate::error::TopgradeError;
use crate::execution_context::ExecutionContext; use crate::execution_context::ExecutionContext;
use crate::sudo::Sudo;
use crate::utils::which; use crate::utils::which;
use crate::{config, Step}; use crate::{config, Step};
@@ -110,7 +111,7 @@ impl Trizen {
} }
pub struct Pacman { pub struct Pacman {
sudo: PathBuf, sudo: Sudo,
executable: PathBuf, executable: PathBuf,
} }
@@ -229,7 +230,7 @@ impl ArchPackageManager for Pamac {
pub struct Aura { pub struct Aura {
executable: PathBuf, executable: PathBuf,
sudo: PathBuf, sudo: Sudo,
} }
impl Aura { impl Aura {

View File

@@ -1,12 +1,13 @@
use crate::command::CommandExt; use crate::command::CommandExt;
use crate::executor::RunType; use crate::executor::RunType;
use crate::sudo::Sudo;
use crate::terminal::print_separator; use crate::terminal::print_separator;
use crate::utils::require_option; use crate::utils::require_option;
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use std::path::PathBuf; use std::path::PathBuf;
use std::process::Command; use std::process::Command;
pub fn upgrade_packages(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> { pub fn upgrade_packages(sudo: Option<&Sudo>, run_type: RunType) -> Result<()> {
let sudo = require_option(sudo, String::from("No sudo detected"))?; let sudo = require_option(sudo, String::from("No sudo detected"))?;
print_separator("DragonFly BSD Packages"); print_separator("DragonFly BSD Packages");
run_type run_type
@@ -15,7 +16,7 @@ pub fn upgrade_packages(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()>
.status_checked() .status_checked()
} }
pub fn audit_packages(sudo: &Option<PathBuf>) -> Result<()> { pub fn audit_packages(sudo: Option<&Sudo>) -> Result<()> {
if let Some(sudo) = sudo { if let Some(sudo) = sudo {
println!(); println!();
Command::new(sudo) Command::new(sudo)

View File

@@ -1,14 +1,14 @@
use crate::command::CommandExt; use crate::command::CommandExt;
use crate::execution_context::ExecutionContext; use crate::execution_context::ExecutionContext;
use crate::executor::RunType; use crate::executor::RunType;
use crate::sudo::Sudo;
use crate::terminal::print_separator; use crate::terminal::print_separator;
use crate::utils::require_option; use crate::utils::require_option;
use crate::Step; use crate::Step;
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use std::path::PathBuf;
use std::process::Command; use std::process::Command;
pub fn upgrade_freebsd(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> { pub fn upgrade_freebsd(sudo: Option<&Sudo>, run_type: RunType) -> Result<()> {
let sudo = require_option(sudo, String::from("No sudo detected"))?; let sudo = require_option(sudo, String::from("No sudo detected"))?;
print_separator("FreeBSD Update"); print_separator("FreeBSD Update");
run_type run_type
@@ -17,7 +17,7 @@ pub fn upgrade_freebsd(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()>
.status_checked() .status_checked()
} }
pub fn upgrade_packages(ctx: &ExecutionContext, sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> { pub fn upgrade_packages(ctx: &ExecutionContext, sudo: Option<&Sudo>, run_type: RunType) -> Result<()> {
let sudo = require_option(sudo, String::from("No sudo detected"))?; let sudo = require_option(sudo, String::from("No sudo detected"))?;
print_separator("FreeBSD Packages"); print_separator("FreeBSD Packages");
@@ -30,7 +30,7 @@ pub fn upgrade_packages(ctx: &ExecutionContext, sudo: Option<&PathBuf>, run_type
command.status_checked() command.status_checked()
} }
pub fn audit_packages(sudo: &Option<PathBuf>) -> Result<()> { pub fn audit_packages(sudo: Option<&Sudo>) -> Result<()> {
if let Some(sudo) = sudo { if let Some(sudo) = sudo {
println!(); println!();
Command::new(sudo) Command::new(sudo)

View File

@@ -10,6 +10,7 @@ use crate::error::{SkipStep, TopgradeError};
use crate::execution_context::ExecutionContext; use crate::execution_context::ExecutionContext;
use crate::executor::RunType; use crate::executor::RunType;
use crate::steps::os::archlinux; use crate::steps::os::archlinux;
use crate::sudo::Sudo;
use crate::terminal::{print_separator, print_warning}; use crate::terminal::{print_separator, print_warning};
use crate::utils::{require, require_option, which, PathExt}; use crate::utils::{require, require_option, which, PathExt};
use crate::Step; use crate::Step;
@@ -498,7 +499,7 @@ fn upgrade_neon(ctx: &ExecutionContext) -> Result<()> {
Ok(()) Ok(())
} }
pub fn run_needrestart(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> { pub fn run_needrestart(sudo: Option<&Sudo>, run_type: RunType) -> Result<()> {
let sudo = require_option(sudo, String::from("sudo is not installed"))?; let sudo = require_option(sudo, String::from("sudo is not installed"))?;
let needrestart = require("needrestart")?; let needrestart = require("needrestart")?;
let distribution = Distribution::detect()?; let distribution = Distribution::detect()?;
@@ -603,7 +604,7 @@ pub fn flatpak_update(ctx: &ExecutionContext) -> Result<()> {
Ok(()) Ok(())
} }
pub fn run_snap(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> { pub fn run_snap(sudo: Option<&Sudo>, run_type: RunType) -> Result<()> {
let sudo = require_option(sudo, String::from("sudo is not installed"))?; let sudo = require_option(sudo, String::from("sudo is not installed"))?;
let snap = require("snap")?; let snap = require("snap")?;
@@ -615,7 +616,7 @@ pub fn run_snap(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
run_type.execute(sudo).arg(snap).arg("refresh").status_checked() run_type.execute(sudo).arg(snap).arg("refresh").status_checked()
} }
pub fn run_pihole_update(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> { pub fn run_pihole_update(sudo: Option<&Sudo>, run_type: RunType) -> Result<()> {
let sudo = require_option(sudo, String::from("sudo is not installed"))?; let sudo = require_option(sudo, String::from("sudo is not installed"))?;
let pihole = require("pihole")?; let pihole = require("pihole")?;
Path::new("/opt/pihole/update.sh").require()?; Path::new("/opt/pihole/update.sh").require()?;

View File

@@ -19,17 +19,16 @@ pub fn run_chocolatey(ctx: &ExecutionContext) -> Result<()> {
print_separator("Chocolatey"); print_separator("Chocolatey");
let mut cmd = &choco; let mut command = match ctx.sudo() {
let mut args = vec!["upgrade", "all"]; Some(sudo) => {
let mut command = ctx.run_type().execute(sudo);
if let Some(sudo) = ctx.sudo() { command.arg(choco);
cmd = sudo; command
args.insert(0, "choco");
} }
None => ctx.run_type().execute(choco),
};
let mut command = ctx.run_type().execute(cmd); command.args(["upgrade", "all"]);
command.args(&args);
if yes { if yes {
command.arg("--yes"); command.arg("--yes");

View File

@@ -1,3 +1,5 @@
use std::ffi::OsStr;
use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use color_eyre::eyre::Context; use color_eyre::eyre::Context;
@@ -5,30 +7,102 @@ use color_eyre::eyre::Result;
use crate::command::CommandExt; use crate::command::CommandExt;
use crate::execution_context::ExecutionContext; use crate::execution_context::ExecutionContext;
use crate::executor::Executor;
use crate::terminal::print_separator; use crate::terminal::print_separator;
use crate::utils::which; use crate::utils::which;
/// Get the path of the `sudo` utility. #[derive(Clone, Debug)]
/// pub struct Sudo {
/// Detects `doas`, `sudo`, `gsudo`, or `pkexec`. /// The path to the `sudo` binary.
pub fn path() -> Option<PathBuf> { path: PathBuf,
which("doas") /// The type of program being used as `sudo`.
.or_else(|| which("sudo")) kind: SudoKind,
.or_else(|| which("gsudo"))
.or_else(|| which("pkexec"))
} }
/// Elevate permissions with `sudo`. impl Sudo {
pub fn elevate(ctx: &ExecutionContext, sudo: Option<&PathBuf>) -> Result<()> { /// Get the `sudo` binary for this platform.
if let Some(sudo) = sudo { pub fn detect() -> Option<Self> {
print_separator("Sudo"); which("doas")
ctx.run_type() .map(|p| (p, SudoKind::Doas))
.execute(sudo) .or_else(|| which("sudo").map(|p| (p, SudoKind::Sudo)))
// TODO: Does this work with `doas`, `pkexec`, `gsudo`, GNU `sudo`...? .or_else(|| which("gsudo").map(|p| (p, SudoKind::Gsudo)))
.arg("-v") .or_else(|| which("pkexec").map(|p| (p, SudoKind::Pkexec)))
.status_checked() .map(|(path, kind)| Self { path, kind })
.wrap_err("Failed to elevate permissions")?;
} }
Ok(()) /// Elevate permissions with `sudo`.
///
/// This helps prevent blocking `sudo` prompts from stopping the run in the middle of a
/// step.
///
/// See: https://github.com/topgrade-rs/topgrade/issues/205
pub fn elevate(&self, ctx: &ExecutionContext) -> Result<()> {
print_separator("Sudo");
let mut cmd = ctx.run_type().execute(self);
match self.kind {
SudoKind::Doas => {
// `doas` doesn't have anything like `sudo -v` to cache credentials,
// so we just execute a dummy `echo` command so we have something
// unobtrusive to run.
// See: https://man.openbsd.org/doas
cmd.arg("echo");
}
SudoKind::Sudo => {
// From `man sudo` on macOS:
// -v, --validate
// Update the user's cached credentials, authenticating the user
// if necessary. For the sudoers plugin, this extends the sudo
// timeout for another 5 minutes by default, but does not run a
// command. Not all security policies support cached credentials.
cmd.arg("-v");
}
SudoKind::Gsudo => {
// Shows current user, cache and console status.
// See: https://gerardog.github.io/gsudo/docs/usage
cmd.arg("status");
}
SudoKind::Pkexec => {
// I don't think this does anything; `pkexec` usually asks for
// authentication every time, although it can be configured
// differently.
//
// See the note for `doas` above.
//
// See: https://linux.die.net/man/1/pkexec
cmd.arg("echo");
}
}
cmd.status_checked().wrap_err("Failed to elevate permissions")
}
/// Execute a command with `sudo`.
pub fn execute_elevated(&self, ctx: &ExecutionContext, command: &Path, interactive: bool) -> Executor {
let mut cmd = ctx.run_type().execute(self);
if let SudoKind::Sudo = self.kind {
cmd.arg("--preserve-env=DIFFPROG");
}
if interactive {
cmd.arg("-i");
}
cmd.arg(command);
cmd
}
}
#[derive(Clone, Copy, Debug)]
enum SudoKind {
Doas,
Sudo,
Gsudo,
Pkexec,
}
impl AsRef<OsStr> for Sudo {
fn as_ref(&self) -> &OsStr {
self.path.as_ref()
}
} }