diff options
| -rw-r--r-- | shell/src/lib.rs | 46 |
1 files changed, 45 insertions, 1 deletions
diff --git a/shell/src/lib.rs b/shell/src/lib.rs index 6de056c..e500337 100644 --- a/shell/src/lib.rs +++ b/shell/src/lib.rs | |||
| @@ -1253,9 +1253,53 @@ fn build_exports() -> rsapi::Exports { | |||
| 1253 | /// Run `cmd` as an external PE32+ binary from /bin/cli/. Returns false | 1253 | /// Run `cmd` as an external PE32+ binary from /bin/cli/. Returns false |
| 1254 | /// when no external binary resolved (the caller falls back to built-ins). | 1254 | /// when no external binary resolved (the caller falls back to built-ins). |
| 1255 | fn exec_external(p: &Parsed) -> bool { | 1255 | fn exec_external(p: &Parsed) -> bool { |
| 1256 | let Some(h) = rsnix::exec::resolve("cli", &p.cmd) else { | 1256 | // Try CLI first (blocking), then GUI (fire-and-forget). |
| 1257 | let cli_h = rsnix::exec::resolve("cli", &p.cmd); | ||
| 1258 | let gui_h = if cli_h.is_none() { rsnix::exec::resolve("gui", &p.cmd) } else { None }; | ||
| 1259 | |||
| 1260 | if let Some(h) = cli_h { | ||
| 1261 | exec_cli(p, h) | ||
| 1262 | } else if let Some(h) = gui_h { | ||
| 1263 | exec_gui(p, h) | ||
| 1264 | } else { | ||
| 1257 | return false; | 1265 | return false; |
| 1266 | } | ||
| 1267 | } | ||
| 1268 | |||
| 1269 | fn exec_gui(p: &Parsed, h: usize) -> bool { | ||
| 1270 | // Fire-and-forget: spawn the GUI binary, return immediately. | ||
| 1271 | let bytes = match rsnix::exec::read_file(h) { | ||
| 1272 | Ok(b) => b, | ||
| 1273 | Err(_) => { | ||
| 1274 | term_err(&alloc::format!("{}: read failed", p.cmd)); | ||
| 1275 | return true; | ||
| 1276 | } | ||
| 1277 | }; | ||
| 1278 | let image = match rsnix::load::load_image(&bytes) { | ||
| 1279 | Ok(img) => img, | ||
| 1280 | Err(e) => { | ||
| 1281 | term_err(&alloc::format!("{}: cannot load ({:?})", p.cmd, e)); | ||
| 1282 | return true; | ||
| 1283 | } | ||
| 1258 | }; | 1284 | }; |
| 1285 | let mut argv: Vec<String> = Vec::with_capacity(p.args.len() + 1); | ||
| 1286 | argv.push(p.cmd.clone()); | ||
| 1287 | argv.extend(p.args.iter().cloned()); | ||
| 1288 | let name = alloc::format!("{}", p.cmd); | ||
| 1289 | let exports = Box::leak(Box::new(build_exports())); | ||
| 1290 | match rsnix::exec::spawn(image, exports, &argv, &name) { | ||
| 1291 | Ok(_id) => { | ||
| 1292 | // Fire-and-forget: do NOT wait for completion. | ||
| 1293 | // The binary runs its own event loop; when it exits, | ||
| 1294 | // the task is cleaned up by the scheduler. | ||
| 1295 | term_println(&alloc::format!("{}: started", p.cmd)); | ||
| 1296 | } | ||
| 1297 | Err(_) => term_err(&alloc::format!("{}: cannot start", p.cmd)), | ||
| 1298 | } | ||
| 1299 | true | ||
| 1300 | } | ||
| 1301 | |||
| 1302 | fn exec_cli(p: &Parsed, h: usize) -> bool { | ||
| 1259 | let bytes = match rsnix::exec::read_file(h) { | 1303 | let bytes = match rsnix::exec::read_file(h) { |
| 1260 | Ok(b) => b, | 1304 | Ok(b) => b, |
| 1261 | Err(_) => { | 1305 | Err(_) => { |
