aboutsummaryrefslogtreecommitdiffstats
path: root/src/run/mod.rs
diff options
context:
space:
mode:
authorJonas Maier <>2026-03-05 19:58:18 +0100
committerJonas Maier <>2026-03-05 19:58:18 +0100
commit88e257128546f2f7aa549cdd62fd15f706ae5135 (patch)
tree44aab5b6c2bf4ae079f223bb132aaa2cd56652be /src/run/mod.rs
parente79adb55ac3b94bbdd40d8b6e2ed35ab32a5fd9d (diff)
downloadpish-88e257128546f2f7aa549cdd62fd15f706ae5135.tar.gz
better error messages
Diffstat (limited to 'src/run/mod.rs')
-rw-r--r--src/run/mod.rs91
1 files changed, 35 insertions, 56 deletions
diff --git a/src/run/mod.rs b/src/run/mod.rs
index 6484e30..e97c377 100644
--- a/src/run/mod.rs
+++ b/src/run/mod.rs
@@ -1,6 +1,4 @@
use std::collections::HashMap;
-use std::fs;
-use std::os::unix::fs::PermissionsExt;
use std::path::PathBuf;
use crate::parse::Ast;
@@ -42,14 +40,7 @@ pub fn run(se: &mut Session, cmd: Vec<u8>) {
(None, None)
};
- let Some(dc) = se.dispatch.get(&cmd.cmd[..]) else {
- println!(
- "unknown command {}",
- String::from_utf8_lossy(cmd.cmd.as_slice())
- );
- spawn_error = true;
- break;
- };
+ let dc = se.dispatch.get(&cmd.cmd[..]);
match dc {
CommandKind::Path(path) => {
@@ -66,10 +57,30 @@ pub fn run(se: &mut Session, cmd: Vec<u8>) {
command.stdout(Stdio::from(w));
}
- let Ok(child) = command.spawn() else {
- println!("failed to spawn {path:?}");
- spawn_error = true;
- break;
+ let child = match command.spawn() {
+ Ok(c) => c,
+ Err(e) => {
+ let cmd = path.to_string_lossy();
+ let msg = match e.kind() {
+ io::ErrorKind::NotFound => format!("{cmd} not found"),
+ io::ErrorKind::PermissionDenied => format!("{cmd} is not executable"),
+ io::ErrorKind::FileTooLarge => format!("{cmd} is too massive"),
+ io::ErrorKind::ResourceBusy | io::ErrorKind::ExecutableFileBusy => {
+ format!("{cmd} is busy")
+ }
+ io::ErrorKind::TooManyLinks => format!("{cmd} could not be resolved"),
+ io::ErrorKind::InvalidFilename => {
+ format!("{cmd} is not a valid file name")
+ }
+ io::ErrorKind::ArgumentListTooLong => format!("too many arguments"),
+ io::ErrorKind::Interrupted => format!("got interrupted"),
+ io::ErrorKind::Unsupported => format!("{cmd} is not supported"),
+ e => format!("I am surprised you can get this error here: {e:?}"),
+ };
+ println!("pish: {msg}");
+ spawn_error = true;
+ break;
+ }
};
children.push(child);
@@ -88,9 +99,8 @@ pub fn run(se: &mut Session, cmd: Vec<u8>) {
None => Box::new(io::stdout()),
};
- let handle = std::thread::spawn(move || {
- builtin.io(&cmd.args, &mut input, &mut output)
- });
+ let handle =
+ std::thread::spawn(move || builtin.io(&cmd.args, &mut input, &mut output));
threads.push(handle);
}
@@ -107,7 +117,7 @@ pub fn run(se: &mut Session, cmd: Vec<u8>) {
println!("failed to kill child - {e:?}");
}
}
- status_string = "ERR".into();
+ status_string = "".into();
} else {
let mut code = 0;
for jh in threads {
@@ -178,40 +188,6 @@ impl CommandDispatch {
pub fn new() -> Self {
let mut map = HashMap::new();
- // all the commands from PATH
- let path = std::env::var_os("PATH").unwrap();
- for p in path.as_bytes().split(|x| *x == b':').rev() {
- let p = PathBuf::from(OsStr::from_bytes(p));
- let Ok(entries) = fs::read_dir(p) else {
- continue;
- };
-
- for entry in entries {
- let Ok(entry) = entry else { continue };
- let Ok(meta) = entry.metadata() else {
- continue;
- };
-
- if !meta.is_file() {
- continue;
- }
-
- let perms = meta.permissions();
- let mode = perms.mode();
-
- // Check if any execute bit is set (owner/group/other)
- if mode & 0o111 == 0 {
- continue;
- }
-
- // insert into our command map, mind the .rev() on the iterator above s.t. correct precedence is had
- map.insert(
- entry.file_name().as_bytes().to_vec(),
- CommandKind::Path(entry.path()),
- );
- }
- }
-
// builtins
for &b in BUILTINS {
map.insert(b.name().as_bytes().to_vec(), CommandKind::Builtin(b));
@@ -220,11 +196,14 @@ impl CommandDispatch {
Self { map }
}
- fn get(&self, cmd: &bstr) -> Option<CommandKind> {
- if cmd.starts_with(b"/") || cmd.starts_with(b"./") {
- Some(CommandKind::Path(PathBuf::from(OsStr::from_bytes(cmd))))
+ fn get(&self, cmd: &bstr) -> CommandKind {
+ let path_cmd = CommandKind::Path(PathBuf::from(OsStr::from_bytes(cmd)));
+ if cmd.contains(&b'/') {
+ path_cmd
+ } else if let Some(cmd) = self.map.get(cmd) {
+ cmd.clone()
} else {
- self.map.get(cmd).cloned()
+ path_cmd
}
}
}