aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar BanceDev 2026-02-26 17:34:49 -0500
committerGravatar BanceDev 2026-02-26 17:34:49 -0500
commit44388f8de44ba13f740a5fc7e0f838c961fad084 (patch)
treeca0e92573e6e4e52ee2c22475ec5dcbe6dd8f60b
parentproper config command handling (diff)
begin permissions shift for build commands
-rw-r--r--Cargo.lock24
-rw-r--r--Cargo.toml2
-rw-r--r--TODO2
-rw-r--r--src/action.rs6
-rw-r--r--src/config.rs26
-rw-r--r--src/util.rs21
6 files changed, 68 insertions, 13 deletions
diff --git a/Cargo.lock b/Cargo.lock
index a7a747b..82d1028 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -27,6 +27,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
+name = "cfg_aliases"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
+
+[[package]]
name = "displaydoc"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -54,7 +60,7 @@ name = "forge"
version = "0.1.0"
dependencies = [
"git2",
- "libc",
+ "nix",
"serde",
"toml",
]
@@ -225,9 +231,9 @@ dependencies = [
[[package]]
name = "libc"
-version = "0.2.182"
+version = "0.2.180"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112"
+checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
[[package]]
name = "libgit2-sys"
@@ -282,6 +288,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
[[package]]
+name = "nix"
+version = "0.31.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "225e7cfe711e0ba79a68baeddb2982723e4235247aefce1482f2f16c27865b66"
+dependencies = [
+ "bitflags",
+ "cfg-if",
+ "cfg_aliases",
+ "libc",
+]
+
+[[package]]
name = "openssl-probe"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 88af1b2..848c4cf 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -5,6 +5,6 @@ edition = "2024"
[dependencies]
git2 = "0.20.4"
-libc = "0.2.182"
+nix = { version = "0.31.1", features = ["user"] }
serde = { version = "1.0.228", features = ["derive"] }
toml = "1.0.3"
diff --git a/TODO b/TODO
index b1df5d3..5052c6e 100644
--- a/TODO
+++ b/TODO
@@ -1,3 +1,5 @@
+Make a forge user and make it own relevant paths
+
Add config command to set forge's values like the editor
Implement update
Implement upgrade
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> {