136 lines
3.8 KiB
C++
136 lines
3.8 KiB
C++
/*
|
|
* exec.cpp
|
|
* External command search and execution
|
|
* Copyright (c) 2025-2026 Daniel Hammer
|
|
*/
|
|
|
|
#include "shell.h"
|
|
|
|
// ---- Check if a file exists ----
|
|
|
|
static bool file_exists(const char* path) {
|
|
int h = montauk::open(path);
|
|
if (h < 0) return false;
|
|
montauk::close(h);
|
|
return true;
|
|
}
|
|
|
|
// ---- Try to spawn an ELF at the given path ----
|
|
|
|
static void print_exit_code(int code) {
|
|
if (code == 0) return;
|
|
char buf[16];
|
|
int n = 0;
|
|
if (code >= 256) {
|
|
montauk::print("[terminated by signal ");
|
|
code -= 256;
|
|
} else {
|
|
montauk::print("[exit code ");
|
|
}
|
|
if (code == 0) buf[n++] = '0';
|
|
while (code > 0 && n < 15) {
|
|
buf[n++] = (char)('0' + code % 10);
|
|
code /= 10;
|
|
}
|
|
while (n > 0) {
|
|
char c[2] = { buf[--n], 0 };
|
|
montauk::print(c);
|
|
}
|
|
montauk::print("]\n");
|
|
}
|
|
|
|
static bool try_exec(const char* path, const char* args) {
|
|
if (!file_exists(path)) return false;
|
|
|
|
int pid = montauk::caps::launch(path, {.args = args});
|
|
if (pid < 0) return false;
|
|
print_exit_code(montauk::waitpid(pid));
|
|
return true;
|
|
}
|
|
|
|
// ---- Build an absolute path from CWD + relative name ----
|
|
|
|
static void build_cwd_path(const char* name, char* out, int outMax) {
|
|
build_drive_path(current_drive, "", out, outMax);
|
|
if (cwd[0]) {
|
|
scat(out, cwd, outMax);
|
|
scat(out, "/", outMax);
|
|
}
|
|
scat(out, name, outMax);
|
|
}
|
|
|
|
// ---- Search and execute an external command ----
|
|
|
|
int exec_external(const char* cmd, const char* args) {
|
|
char path[256];
|
|
const char* finalArgs = (args && args[0]) ? args : nullptr;
|
|
|
|
// Strip leading "./" from command name
|
|
const char* name = cmd;
|
|
if (name[0] == '.' && name[1] == '/') name += 2;
|
|
|
|
// 0. Direct paths are resolved by the kernel against the process CWD.
|
|
bool hasSlash = false;
|
|
for (int i = 0; cmd[i]; i++) {
|
|
if (cmd[i] == '/') {
|
|
hasSlash = true;
|
|
break;
|
|
}
|
|
}
|
|
if (has_drive_prefix(cmd) || cmd[0] == '/' || cmd[0] == '.' || hasSlash) {
|
|
if (try_exec(cmd, finalArgs)) return 0;
|
|
scopy(path, cmd, sizeof(path));
|
|
scat(path, ".elf", sizeof(path));
|
|
if (try_exec(path, finalArgs)) return 0;
|
|
montauk::print(cmd);
|
|
montauk::print(": not found\n");
|
|
return 127;
|
|
}
|
|
|
|
// 1. Try as-is in CWD (exact name, e.g., "a.out" or "hello.elf")
|
|
build_cwd_path(name, path, sizeof(path));
|
|
if (try_exec(path, finalArgs)) return 0;
|
|
|
|
// 2. Try with .elf extension in CWD
|
|
build_cwd_path(name, path, sizeof(path));
|
|
scat(path, ".elf", sizeof(path));
|
|
if (try_exec(path, finalArgs)) return 0;
|
|
|
|
// 3. Try 0:/os/<cmd>.elf
|
|
scopy(path, "0:/os/", sizeof(path));
|
|
scat(path, name, sizeof(path));
|
|
scat(path, ".elf", sizeof(path));
|
|
if (try_exec(path, finalArgs)) return 0;
|
|
|
|
// 4. Try 0:/os/<cmd> (no extension)
|
|
scopy(path, "0:/os/", sizeof(path));
|
|
scat(path, name, sizeof(path));
|
|
if (try_exec(path, finalArgs)) return 0;
|
|
|
|
// 5. Try 0:/sdk/bin/<cmd>.elf (Montauk SDK: as, ld, ar, ...)
|
|
scopy(path, "0:/sdk/bin/", sizeof(path));
|
|
scat(path, name, sizeof(path));
|
|
scat(path, ".elf", sizeof(path));
|
|
if (try_exec(path, finalArgs)) return 0;
|
|
|
|
// 6. Try 0:/games/<cmd>.elf
|
|
scopy(path, "0:/games/", sizeof(path));
|
|
scat(path, name, sizeof(path));
|
|
scat(path, ".elf", sizeof(path));
|
|
if (try_exec(path, finalArgs)) return 0;
|
|
|
|
// 7. If on a non-zero drive, also try drive root
|
|
if (current_drive != 0) {
|
|
build_drive_path(current_drive, name, path, sizeof(path));
|
|
if (try_exec(path, finalArgs)) return 0;
|
|
|
|
build_drive_path(current_drive, name, path, sizeof(path));
|
|
scat(path, ".elf", sizeof(path));
|
|
if (try_exec(path, finalArgs)) return 0;
|
|
}
|
|
|
|
montauk::print(cmd);
|
|
montauk::print(": command not found\n");
|
|
return 127;
|
|
}
|