aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/action.rs6
-rw-r--r--src/config.rs26
-rw-r--r--src/util.rs21
3 files changed, 44 insertions, 9 deletions
diff --git a/src/action.rs b/src/action.rs
index 1aeefb6..58effbe 100644
--- a/src/action.rs
+++ b/src/action.rs
@@ -1,5 +1,5 @@
use crate::config::{self, ConfigCommand, TEMP_CONFIG_PATH, create_config};
-use crate::util::{dir_size, get_editor, is_root, open_in_editor, yn_prompt};
+use crate::util::{dir_size, get_editor, open_in_editor, yn_prompt};
use git2::Repository;
use std::fs;
use std::path::{Path, PathBuf};
@@ -76,7 +76,7 @@ impl Action {
}
fn add(url: &str) -> Result<(), String> {
- if !is_root() {
+ if !nix::unistd::geteuid().is_root() {
return Err("add must be run as root".to_string());
}
@@ -138,7 +138,7 @@ fn autoremove() {
}
fn remove(packages: Vec<String>) -> Result<(), String> {
- if !is_root() {
+ if !nix::unistd::geteuid().is_root() {
return Err("remove must be run as root".to_string());
}
diff --git a/src/config.rs b/src/config.rs
index 7c6cf2b..4976af3 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -1,8 +1,11 @@
use serde::Deserialize;
use std::fs;
+use std::os::unix::process::CommandExt;
use std::path::{Path, PathBuf};
use std::process::Command;
+use crate::util::get_invoking_user_env;
+
pub const TEMP_CONFIG_PATH: &str = "/var/lib/forge/.tmp";
pub enum ConfigCommand {
@@ -66,6 +69,9 @@ pub fn run_config_command(
command: ConfigCommand,
) -> Result<(), String> {
let config = Config::new(config_path).ok_or("config not found".to_string())?;
+
+ let is_build = matches!(command, ConfigCommand::Build);
+
let cmd = match command {
ConfigCommand::Build => config.build,
ConfigCommand::Install => config.install,
@@ -77,9 +83,23 @@ pub fn run_config_command(
let cmd_base = parts.next().ok_or("empty command".to_string())?;
let args: Vec<&str> = parts.collect();
- let status = Command::new(cmd_base)
- .args(&args)
- .current_dir(repo_path)
+ let mut command = Command::new(cmd_base);
+ command.args(&args).current_dir(repo_path);
+
+ if is_build {
+ if let Some((uid, gid, home, path)) = get_invoking_user_env() {
+ command.env("HOME", home).env("PATH", path);
+ unsafe {
+ command.pre_exec(move || {
+ nix::unistd::setgid(nix::unistd::Gid::from_raw(gid))?;
+ nix::unistd::setuid(nix::unistd::Uid::from_raw(uid))?;
+ Ok(())
+ });
+ }
+ }
+ }
+
+ let status = command
.status()
.map_err(|e| format!("failed to execute command: {}", e))?;
diff --git a/src/util.rs b/src/util.rs
index 90aacb6..e79124d 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -1,4 +1,3 @@
-use libc;
use std::env;
use std::fs;
use std::io;
@@ -28,8 +27,24 @@ pub fn get_editor() -> String {
.unwrap_or_else(|_| "nano".to_string())
}
-pub fn is_root() -> bool {
- unsafe { libc::geteuid() == 0 }
+pub fn get_invoking_user_env() -> Option<(u32, u32, String, String)> {
+ let username = std::env::var("SUDO_USER").ok()?;
+ if username.is_empty() {
+ return None;
+ }
+
+ let user = nix::unistd::User::from_name(&username).ok()??;
+ let uid = user.uid.as_raw();
+ let gid = user.gid.as_raw();
+ let home = user.dir.to_string_lossy().to_string();
+
+ // Reconstruct a sane PATH for the user including common tool locations
+ let path = format!(
+ "{home}/.cargo/bin:{home}/.local/bin:/usr/local/bin:/usr/bin:/bin",
+ home = home
+ );
+
+ Some((uid, gid, home, path))
}
pub fn open_in_editor(editor: &str, file: &str) -> Result<(), String> {