diff --git a/kernel/src/Api/Filesystem.hpp b/kernel/src/Api/Filesystem.hpp index 2236334..67f236b 100644 --- a/kernel/src/Api/Filesystem.hpp +++ b/kernel/src/Api/Filesystem.hpp @@ -12,10 +12,13 @@ #include #include #include +#include "Path.hpp" namespace Montauk { static int Sys_Open(const char* path) { - return Fs::Vfs::VfsOpen(path); + char resolved[256]; + if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return -1; + return Fs::Vfs::VfsOpen(resolved); } static int Sys_Read(int handle, uint8_t* buffer, uint64_t offset, uint64_t size) { @@ -31,11 +34,14 @@ namespace Montauk { } static int Sys_ReadDir(const char* path, const char** outNames, int maxEntries) { + char resolved[256]; + if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return -1; + // Get entries from VFS into a kernel-local array const char* kernelNames[256]; int max = maxEntries; if (max > 256) max = 256; - int count = Fs::Vfs::VfsReadDir(path, kernelNames, max); + int count = Fs::Vfs::VfsReadDir(resolved, kernelNames, max); if (count <= 0) return count; // Allocate a user-accessible page for string data via process heap @@ -70,22 +76,32 @@ namespace Montauk { } static int Sys_FCreate(const char* path) { - return Fs::Vfs::VfsCreate(path); + char resolved[256]; + if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return -1; + return Fs::Vfs::VfsCreate(resolved); } static int Sys_FDelete(const char* path) { - return Fs::Vfs::VfsDelete(path); + char resolved[256]; + if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return -1; + return Fs::Vfs::VfsDelete(resolved); } static int Sys_FMkdir(const char* path) { - return Fs::Vfs::VfsMkdir(path); + char resolved[256]; + if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return -1; + return Fs::Vfs::VfsMkdir(resolved); } static int Sys_FRename(const char* oldPath, const char* newPath) { - return Fs::Vfs::VfsRename(oldPath, newPath); + char resolvedOld[256]; + char resolvedNew[256]; + if (!ResolveProcessPath(oldPath, resolvedOld, sizeof(resolvedOld))) return -1; + if (!ResolveProcessPath(newPath, resolvedNew, sizeof(resolvedNew))) return -1; + return Fs::Vfs::VfsRename(resolvedOld, resolvedNew); } static int Sys_DriveList(int* outDrives, int maxEntries) { return Fs::Vfs::VfsDriveList(outDrives, maxEntries); } -}; \ No newline at end of file +}; diff --git a/kernel/src/Api/IoRedir.hpp b/kernel/src/Api/IoRedir.hpp index 46810b2..5bd08b7 100644 --- a/kernel/src/Api/IoRedir.hpp +++ b/kernel/src/Api/IoRedir.hpp @@ -11,11 +11,15 @@ #include "Syscall.hpp" #include "Common.hpp" +#include "Path.hpp" namespace Montauk { static int Sys_SpawnRedir(const char* path, const char* args) { - int childPid = Sched::Spawn(path, args); + char resolved[256]; + if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return -1; + + int childPid = Sched::Spawn(resolved, args); if (childPid < 0) return -1; auto* child = Sched::GetProcessByPid(childPid); diff --git a/kernel/src/Api/Path.hpp b/kernel/src/Api/Path.hpp new file mode 100644 index 0000000..eedbed7 --- /dev/null +++ b/kernel/src/Api/Path.hpp @@ -0,0 +1,143 @@ +/* + * Path.hpp + * Per-process working-directory path resolution helpers + * Copyright (c) 2026 Daniel Hammer +*/ + +#pragma once +#include +#include +#include + +namespace Montauk { + + static int ParseDrivePrefix(const char* path, int* outPrefixLen = nullptr) { + if (path == nullptr || path[0] < '0' || path[0] > '9') return -1; + + int drive = 0; + int i = 0; + while (path[i] >= '0' && path[i] <= '9') { + drive = drive * 10 + (path[i] - '0'); + i++; + } + + if (path[i] != ':') return -1; + if (outPrefixLen) *outPrefixLen = i + 1; + return drive; + } + + static int WriteDriveRoot(char* out, int outMax, int drive) { + if (out == nullptr || outMax < 4 || drive < 0) return -1; + + char digits[12]; + int digitCount = 0; + do { + digits[digitCount++] = (char)('0' + (drive % 10)); + drive /= 10; + } while (drive > 0 && digitCount < (int)sizeof(digits)); + + if (digitCount + 2 >= outMax) return -1; + + int len = 0; + for (int i = digitCount - 1; i >= 0; i--) out[len++] = digits[i]; + out[len++] = ':'; + out[len++] = '/'; + out[len] = '\0'; + return len; + } + + static bool AppendPathSegment(char* out, int outMax, int& len, int rootLen, + int* segmentBases, int& segmentCount, + const char* segment, int segmentLen) { + if (segmentLen <= 0) return true; + if (segmentLen == 1 && segment[0] == '.') return true; + + if (segmentLen == 2 && segment[0] == '.' && segment[1] == '.') { + if (segmentCount > 0) { + len = segmentBases[--segmentCount]; + out[len] = '\0'; + } + return true; + } + + if (segmentCount >= 64) return false; + + int baseLen = len; + if (len > rootLen) { + if (len >= outMax - 1) return false; + out[len++] = '/'; + } + + if (len + segmentLen >= outMax) return false; + memcpy(out + len, segment, (std::size_t)segmentLen); + len += segmentLen; + out[len] = '\0'; + segmentBases[segmentCount++] = baseLen; + return true; + } + + static bool NormalizePathInto(char* out, int outMax, int& len, int rootLen, + int* segmentBases, int& segmentCount, + const char* path) { + const char* segmentStart = path; + for (const char* p = path;; ++p) { + if (*p == '/' || *p == '\0') { + if (!AppendPathSegment(out, outMax, len, rootLen, segmentBases, + segmentCount, segmentStart, (int)(p - segmentStart))) { + return false; + } + if (*p == '\0') break; + segmentStart = p + 1; + } + } + return true; + } + + static bool ResolvePathAgainst(const char* cwd, const char* path, char* out, int outMax) { + if (cwd == nullptr || path == nullptr || out == nullptr || outMax < 4 || path[0] == '\0') return false; + + int drive = -1; + int inputPrefixLen = 0; + const char* remainder = path; + bool useCwdBase = false; + + drive = ParseDrivePrefix(path, &inputPrefixLen); + if (drive >= 0) { + remainder = path + inputPrefixLen; + if (*remainder == '/') remainder++; + } else if (path[0] == '/') { + drive = ParseDrivePrefix(cwd); + if (drive < 0) return false; + remainder = path + 1; + } else { + drive = ParseDrivePrefix(cwd); + if (drive < 0) return false; + useCwdBase = true; + } + + int segmentBases[64]; + int segmentCount = 0; + int len = WriteDriveRoot(out, outMax, drive); + if (len < 0) return false; + int rootLen = len; + + if (useCwdBase) { + int cwdPrefixLen = 0; + if (ParseDrivePrefix(cwd, &cwdPrefixLen) < 0) return false; + + const char* cwdRemainder = cwd + cwdPrefixLen; + if (*cwdRemainder == '/') cwdRemainder++; + if (!NormalizePathInto(out, outMax, len, rootLen, segmentBases, segmentCount, cwdRemainder)) { + return false; + } + } + + return NormalizePathInto(out, outMax, len, rootLen, segmentBases, segmentCount, remainder); + } + + static bool ResolveProcessPath(const char* path, char* out, int outMax) { + auto* proc = Sched::GetCurrentProcessPtr(); + const char* cwd = (proc && proc->cwd[0]) ? proc->cwd : "0:/"; + return ResolvePathAgainst(cwd, path, out, outMax); + } +} diff --git a/kernel/src/Api/Process.hpp b/kernel/src/Api/Process.hpp index 198e857..d1b59fa 100644 --- a/kernel/src/Api/Process.hpp +++ b/kernel/src/Api/Process.hpp @@ -11,9 +11,11 @@ #include #include #include +#include #include "Syscall.hpp" #include "WinServer.hpp" +#include "Path.hpp" namespace Montauk { static void Sys_Exit(int exitCode) { @@ -38,8 +40,11 @@ namespace Montauk { } static int Sys_Spawn(const char* path, const char* args) { + char resolved[256]; + if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return -1; + auto* parent = Sched::GetCurrentProcessPtr(); - int childPid = Sched::Spawn(path, args); + int childPid = Sched::Spawn(resolved, args); if (childPid < 0) return childPid; // Inherit I/O redirection: if the parent is redirected, the child @@ -120,4 +125,46 @@ namespace Montauk { buf[i] = '\0'; return i; } -}; \ No newline at end of file + + static int Sys_GetCwd(char* buf, uint64_t maxLen) { + auto* proc = Sched::GetCurrentProcessPtr(); + if (proc == nullptr || buf == nullptr || maxLen == 0) return -1; + + const char* cwd = proc->cwd[0] ? proc->cwd : "0:/"; + int i = 0; + for (; i < (int)maxLen - 1 && cwd[i]; i++) buf[i] = cwd[i]; + buf[i] = '\0'; + return i; + } + + static int Sys_Chdir(const char* path) { + auto* proc = Sched::GetCurrentProcessPtr(); + if (proc == nullptr || path == nullptr) return -1; + + char resolved[256]; + if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return -1; + + bool isDriveRoot = false; + { + int prefixLen = 0; + if (ParseDrivePrefix(resolved, &prefixLen) >= 0 && + resolved[prefixLen] == '/' && resolved[prefixLen + 1] == '\0') { + isDriveRoot = true; + } + } + + if (isDriveRoot) { + const char* entries[1]; + if (Fs::Vfs::VfsReadDir(resolved, entries, 1) < 0) return -1; + } else { + int handle = Fs::Vfs::VfsOpen(resolved); + if (handle < 0) return -1; + Fs::Vfs::VfsClose(handle); + } + + int i = 0; + for (; i < 255 && resolved[i]; i++) proc->cwd[i] = resolved[i]; + proc->cwd[i] = '\0'; + return 0; + } +}; diff --git a/kernel/src/Api/Syscall.cpp b/kernel/src/Api/Syscall.cpp index 333b0ca..283fd2f 100644 --- a/kernel/src/Api/Syscall.cpp +++ b/kernel/src/Api/Syscall.cpp @@ -347,6 +347,12 @@ namespace Montauk { case SYS_GETUSER: if (!ValidUserPtr(frame->arg1)) return -1; return Sys_GetUser((char*)frame->arg1, frame->arg2); + case SYS_GETCWD: + if (!ValidUserPtr(frame->arg1)) return -1; + return Sys_GetCwd((char*)frame->arg1, frame->arg2); + case SYS_CHDIR: + if (!ValidUserPtr(frame->arg1)) return -1; + return Sys_Chdir((const char*)frame->arg1); default: return -1; } diff --git a/kernel/src/Api/Syscall.hpp b/kernel/src/Api/Syscall.hpp index ad19b04..dd5f71f 100644 --- a/kernel/src/Api/Syscall.hpp +++ b/kernel/src/Api/Syscall.hpp @@ -184,6 +184,8 @@ namespace Montauk { /* Filesystem.hpp */ static constexpr uint64_t SYS_FRENAME = 94; + static constexpr uint64_t SYS_GETCWD = 95; + static constexpr uint64_t SYS_CHDIR = 96; static constexpr int SOCK_TCP = 1; static constexpr int SOCK_UDP = 2; diff --git a/kernel/src/Sched/Scheduler.cpp b/kernel/src/Sched/Scheduler.cpp index efdb766..a8e14b7 100644 --- a/kernel/src/Sched/Scheduler.cpp +++ b/kernel/src/Sched/Scheduler.cpp @@ -91,6 +91,7 @@ namespace Sched { processTable[i].heapNext = 0; processTable[i].args[0] = '\0'; processTable[i].user[0] = '\0'; + processTable[i].cwd[0] = '\0'; processTable[i].runningOnCpu = -1; processTable[i].killPending = false; processTable[i].waitingForPid = -1; @@ -301,6 +302,23 @@ namespace Sched { } } + { + auto* cpu = Smp::GetCurrentCpuData(); + int parentSlot = cpu->currentSlot; + if (parentSlot >= 0 && processTable[parentSlot].cwd[0]) { + int i = 0; + for (; i < 255 && processTable[parentSlot].cwd[i]; i++) { + proc.cwd[i] = processTable[parentSlot].cwd[i]; + } + proc.cwd[i] = '\0'; + } else { + proc.cwd[0] = '0'; + proc.cwd[1] = ':'; + proc.cwd[2] = '/'; + proc.cwd[3] = '\0'; + } + } + proc.redirected = false; proc.parentPid = -1; proc.outBuf = nullptr; diff --git a/kernel/src/Sched/Scheduler.hpp b/kernel/src/Sched/Scheduler.hpp index bf81c55..93ac46a 100644 --- a/kernel/src/Sched/Scheduler.hpp +++ b/kernel/src/Sched/Scheduler.hpp @@ -44,6 +44,7 @@ namespace Sched { uint64_t heapNext; // Simple bump allocator for user heap char args[256]; // Command-line arguments (set by parent via Spawn) char user[32]; // Owner user name (inherited from parent on spawn) + char cwd[256]; // Absolute current working directory int runningOnCpu; // CPU index running this process (-1 if not running) bool killPending = false; // Set by Sys_Kill when target is running on another CPU diff --git a/programs/include/Api/Syscall.hpp b/programs/include/Api/Syscall.hpp index 64eb5ae..f7e02c2 100644 --- a/programs/include/Api/Syscall.hpp +++ b/programs/include/Api/Syscall.hpp @@ -123,6 +123,9 @@ namespace Montauk { // User management static constexpr uint64_t SYS_SETUSER = 92; static constexpr uint64_t SYS_GETUSER = 93; + static constexpr uint64_t SYS_FRENAME = 94; + static constexpr uint64_t SYS_GETCWD = 95; + static constexpr uint64_t SYS_CHDIR = 96; // Audio control commands (for SYS_AUDIOCTL) static constexpr int AUDIO_CTL_SET_VOLUME = 0; diff --git a/programs/include/libc/montauk.h b/programs/include/libc/montauk.h index b194d70..2653efd 100644 --- a/programs/include/libc/montauk.h +++ b/programs/include/libc/montauk.h @@ -97,6 +97,8 @@ extern "C" { #define MTK_SYS_AUDIOCTL 83 #define MTK_SYS_SETTZ 90 #define MTK_SYS_GETTZ 91 +#define MTK_SYS_GETCWD 95 +#define MTK_SYS_CHDIR 96 #define MTK_SOCK_TCP 1 #define MTK_SOCK_UDP 2 @@ -318,6 +320,14 @@ static inline int mtk_getargs(char *buf, unsigned long max_len) { return (int)_mtk_syscall2(MTK_SYS_GETARGS, (long)buf, (long)max_len); } +static inline int mtk_chdir(const char *path) { + return (int)_mtk_syscall1(MTK_SYS_CHDIR, (long)path); +} + +static inline int mtk_getcwd(char *buf, unsigned long max_len) { + return (int)_mtk_syscall2(MTK_SYS_GETCWD, (long)buf, (long)max_len); +} + /* ==================================================================== Console I/O ==================================================================== */ diff --git a/programs/include/libc/unistd.h b/programs/include/libc/unistd.h index 4912e83..96910af 100644 --- a/programs/include/libc/unistd.h +++ b/programs/include/libc/unistd.h @@ -13,6 +13,8 @@ int read(int fd, void *buf, size_t count); int write(int fd, const void *buf, size_t count); int close(int fd); long lseek(int fd, long offset, int whence); +int chdir(const char *path); +char *getcwd(char *buf, size_t size); unsigned int sleep(unsigned int seconds); diff --git a/programs/include/montauk/syscall.h b/programs/include/montauk/syscall.h index 11c08aa..2ba9c9e 100644 --- a/programs/include/montauk/syscall.h +++ b/programs/include/montauk/syscall.h @@ -120,6 +120,12 @@ namespace montauk { inline int spawn(const char* path, const char* args = nullptr) { return (int)syscall2(Montauk::SYS_SPAWN, (uint64_t)path, (uint64_t)args); } + inline int chdir(const char* path) { + return (int)syscall1(Montauk::SYS_CHDIR, (uint64_t)path); + } + inline int getcwd(char* buf, uint64_t maxLen) { + return (int)syscall2(Montauk::SYS_GETCWD, (uint64_t)buf, maxLen); + } // Console inline void print(const char* text) { syscall1(Montauk::SYS_PRINT, (uint64_t)text); } diff --git a/programs/lib/libc/libc.c b/programs/lib/libc/libc.c index 842df44..789e0ce 100644 --- a/programs/lib/libc/libc.c +++ b/programs/lib/libc/libc.c @@ -13,6 +13,7 @@ #include #include #include +#include #include /* ======================================================================== @@ -96,6 +97,8 @@ static inline long _zos_syscall4(long nr, long a1, long a2, long a3, long a4) { #define SYS_FDELETE 77 #define SYS_FMKDIR 78 #define SYS_FRENAME 94 +#define SYS_GETCWD 95 +#define SYS_CHDIR 96 /* ======================================================================== errno @@ -1395,6 +1398,30 @@ long lseek(int fd, long offset, int whence) { return (long)newpos; } +int chdir(const char *path) { + if (path == NULL) { + errno = EINVAL; + return -1; + } + if ((int)_zos_syscall1(SYS_CHDIR, (long)path) < 0) { + errno = ENOENT; + return -1; + } + return 0; +} + +char *getcwd(char *buf, size_t size) { + if (buf == NULL || size == 0) { + errno = EINVAL; + return NULL; + } + if ((int)_zos_syscall2(SYS_GETCWD, (long)buf, (long)size) < 0) { + errno = ERANGE; + return NULL; + } + return buf; +} + /* ======================================================================== sys/stat.h functions ======================================================================== */ diff --git a/programs/lib/libc/obj/libc.o b/programs/lib/libc/obj/libc.o index 7c0b06b..81d83ec 100644 Binary files a/programs/lib/libc/obj/libc.o and b/programs/lib/libc/obj/libc.o differ diff --git a/programs/src/rm/main.cpp b/programs/src/rm/main.cpp index 0f05156..238ad9e 100644 --- a/programs/src/rm/main.cpp +++ b/programs/src/rm/main.cpp @@ -11,22 +11,16 @@ extern "C" void _start() { char args[256]; montauk::getargs((char *)&args, 256); - if (*args) { - const char* arg = montauk::skip_spaces((const char *)&args); - - if (*arg != '\0') { - int fd = montauk::open(arg); - if (fd < 0) { - montauk::print("file not found\n"); - } else { - montauk::close(fd); - montauk::fdelete(arg); - } - } - } else { + const char* path = montauk::skip_spaces((const char *)&args); + if (*path == '\0') { montauk::print("usage: rm [file]\n"); montauk::exit(-1); } + if (montauk::fdelete(path) < 0) { + montauk::print("rm: failed to remove file\n"); + montauk::exit(-1); + } + montauk::exit(0); -} \ No newline at end of file +} diff --git a/programs/src/shell/builtins.cpp b/programs/src/shell/builtins.cpp index 56328d6..d4bacc2 100644 --- a/programs/src/shell/builtins.cpp +++ b/programs/src/shell/builtins.cpp @@ -6,6 +6,21 @@ #include "shell.h" +static void print_ls_entry(const char* entry) { + int len = slen(entry); + bool hadTrailingSlash = len > 0 && entry[len - 1] == '/'; + + while (len > 0 && entry[len - 1] == '/') len--; + + int base = 0; + for (int i = 0; i < len; i++) { + if (entry[i] == '/') base = i + 1; + } + + for (int i = base; i < len; i++) montauk::putchar(entry[i]); + if (hadTrailingSlash) montauk::putchar('/'); +} + // ---- help ---- void cmd_help() { @@ -67,28 +82,9 @@ void cmd_help() { void cmd_ls(const char* arg) { arg = skip_spaces(arg); - char dir[128]; - int drive = current_drive; - if (*arg) { - if (has_drive_prefix(arg)) { - drive = parse_drive_prefix(arg); - int plen = drive_prefix_len(arg); - scopy(dir, arg + plen + 1, sizeof(dir)); - } else if (arg[0] == '/') { - scopy(dir, arg + 1, sizeof(dir)); - } else if (cwd[0]) { - scopy(dir, cwd, sizeof(dir)); - scat(dir, "/", sizeof(dir)); - scat(dir, arg, sizeof(dir)); - } else { - scopy(dir, arg, sizeof(dir)); - } - } else { - scopy(dir, cwd, sizeof(dir)); - } - char path[128]; - build_drive_path(drive, dir, path, sizeof(path)); + if (*arg) scopy(path, arg, sizeof(path)); + else scopy(path, ".", sizeof(path)); const char* entries[64]; int count = montauk::readdir(path, entries, 64); @@ -97,16 +93,9 @@ void cmd_ls(const char* arg) { return; } - int prefixLen = 0; - if (dir[0]) prefixLen = slen(dir) + 1; - for (int i = 0; i < count; i++) { montauk::print(" "); - if (prefixLen > 0 && starts_with(entries[i], dir)) { - montauk::print(entries[i] + prefixLen); - } else { - montauk::print(entries[i]); - } + print_ls_entry(entries[i]); montauk::putchar('\n'); } } @@ -116,141 +105,30 @@ void cmd_ls(const char* arg) { bool switch_drive(int drive) { char path[8]; build_drive_path(drive, "", path, sizeof(path)); - const char* entries[1]; - if (montauk::readdir(path, entries, 1) < 0) return false; - current_drive = drive; - cwd[0] = '\0'; + if (montauk::chdir(path) < 0) return false; + sync_cwd(); return true; } int cmd_cd(const char* arg) { arg = skip_spaces(arg); - // cd with no argument -> go to home directory (or root if no session) - if (*arg == '\0') { - if (session_home[0] && has_drive_prefix(session_home)) { - int drive = parse_drive_prefix(session_home); - int plen = drive_prefix_len(session_home); - const char* rel = session_home + plen; - if (*rel == '/') rel++; - current_drive = drive; - if (*rel) scopy(cwd, rel, sizeof(cwd)); - else cwd[0] = '\0'; - } else { - cwd[0] = '\0'; - } - return 0; - } - - // cd / -> go to root - if (streq(arg, "/")) { - cwd[0] = '\0'; - return 0; - } - - // Strip trailing slashes from argument - static char argBuf[128]; - int aLen = 0; - while (arg[aLen] && aLen < 127) { argBuf[aLen] = arg[aLen]; aLen++; } - argBuf[aLen] = '\0'; - while (aLen > 0 && argBuf[aLen - 1] == '/') argBuf[--aLen] = '\0'; - arg = argBuf; - - if (*arg == '\0') { - cwd[0] = '\0'; - return 0; - } - - // cd .. -> go up one level - if (streq(arg, "..")) { - int len = slen(cwd); - int last = -1; - for (int i = 0; i < len; i++) { - if (cwd[i] == '/') last = i; - } - if (last >= 0) { - cwd[last] = '\0'; - } else { - cwd[0] = '\0'; - } - return 0; - } - - // cd /path -> absolute path from root - if (arg[0] == '/') { - arg++; - if (*arg == '\0') { cwd[0] = '\0'; return 0; } - char path[128]; - build_dir_path(arg, path, sizeof(path)); - const char* entries[1]; - if (montauk::readdir(path, entries, 1) < 0) { - montauk::print("cd: no such directory: "); - montauk::print(arg); - montauk::putchar('\n'); - return 1; - } - scopy(cwd, arg, sizeof(cwd)); - return 0; - } - - // cd N:/ or cd N:/path -> switch drive - if (has_drive_prefix(arg)) { - int drive = parse_drive_prefix(arg); - int plen = drive_prefix_len(arg); - const char* rel = arg + plen; - if (*rel == '/') rel++; - - char rootPath[8]; - build_drive_path(drive, "", rootPath, sizeof(rootPath)); - const char* rootEntries[1]; - if (montauk::readdir(rootPath, rootEntries, 1) < 0) { - montauk::print("cd: no such drive: "); - montauk::print(arg); - montauk::putchar('\n'); - return 1; - } - - if (*rel != '\0') { - char path[128]; - build_drive_path(drive, rel, path, sizeof(path)); - const char* entries[1]; - if (montauk::readdir(path, entries, 1) < 0) { - montauk::print("cd: no such directory: "); - montauk::print(arg); - montauk::putchar('\n'); - return 1; - } - current_drive = drive; - scopy(cwd, rel, sizeof(cwd)); - } else { - current_drive = drive; - cwd[0] = '\0'; - } - return 0; - } - - // Relative path char target[128]; - if (cwd[0]) { - scopy(target, cwd, sizeof(target)); - scat(target, "/", sizeof(target)); - scat(target, arg, sizeof(target)); + if (*arg == '\0') { + if (session_home[0]) scopy(target, session_home, sizeof(target)); + else scopy(target, "/", sizeof(target)); } else { scopy(target, arg, sizeof(target)); } - char path[128]; - build_dir_path(target, path, sizeof(path)); - const char* entries[1]; - int count = montauk::readdir(path, entries, 1); - if (count < 0) { + if (montauk::chdir(target) < 0) { montauk::print("cd: no such directory: "); - montauk::print(arg); + montauk::print(target); montauk::putchar('\n'); return 1; } - scopy(cwd, target, sizeof(cwd)); + sync_cwd(); return 0; } diff --git a/programs/src/shell/exec.cpp b/programs/src/shell/exec.cpp index bfe7ed1..491f11d 100644 --- a/programs/src/shell/exec.cpp +++ b/programs/src/shell/exec.cpp @@ -36,81 +36,29 @@ static void build_cwd_path(const char* name, char* out, int outMax) { scat(out, name, outMax); } -// ---- Resolve arguments: expand relative file paths against CWD ---- - -static void resolve_args(const char* args, char* out, int outMax) { - if (!args || !args[0]) { out[0] = '\0'; return; } - - int o = 0; - const char* p = args; - - while (*p && o < outMax - 1) { - while (*p == ' ' && o < outMax - 1) { out[o++] = *p++; } - if (!*p) break; - - const char* tokStart = p; - int tokLen = 0; - while (p[tokLen] && p[tokLen] != ' ') tokLen++; - - bool resolve = (cwd[0] || current_drive != 0) && !has_drive_prefix(tokStart) && tokStart[0] != '-'; - - if (resolve) { - char candidate[256]; - int r = 0; - if (current_drive >= 10) candidate[r++] = '0' + current_drive / 10; - candidate[r++] = '0' + current_drive % 10; - candidate[r++] = ':'; candidate[r++] = '/'; - int j = 0; - while (cwd[j] && r < 255) candidate[r++] = cwd[j++]; - if (cwd[0] && r < 255) candidate[r++] = '/'; - - // Strip leading "./" from token - int skip = 0; - if (tokLen >= 2 && tokStart[0] == '.' && tokStart[1] == '/') skip = 2; - - for (int k = skip; k < tokLen && r < 255; k++) candidate[r++] = tokStart[k]; - candidate[r] = '\0'; - - int h = montauk::open(candidate); - if (h >= 0) { - montauk::close(h); - for (int k = 0; k < r && o < outMax - 1; k++) out[o++] = candidate[k]; - } else { - bool looksLikeFile = false; - for (int k = 0; k < tokLen; k++) { - if (tokStart[k] == '.') { looksLikeFile = true; break; } - } - if (looksLikeFile) { - for (int k = 0; k < r && o < outMax - 1; k++) out[o++] = candidate[k]; - } else { - for (int k = 0; k < tokLen && o < outMax - 1; k++) out[o++] = tokStart[k]; - } - } - } else { - for (int k = 0; k < tokLen && o < outMax - 1; k++) out[o++] = tokStart[k]; - } - - p = tokStart + tokLen; - } - out[o] = '\0'; -} - // ---- Search and execute an external command ---- int exec_external(const char* cmd, const char* args) { char path[256]; - - char resolvedArgs[512]; - resolve_args(args, resolvedArgs, sizeof(resolvedArgs)); - const char* finalArgs = resolvedArgs[0] ? resolvedArgs : nullptr; + 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. If cmd has a drive prefix (absolute path), try it directly - if (has_drive_prefix(cmd)) { + // 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; diff --git a/programs/src/shell/main.cpp b/programs/src/shell/main.cpp index d0729c1..913207d 100644 --- a/programs/src/shell/main.cpp +++ b/programs/src/shell/main.cpp @@ -14,6 +14,28 @@ int last_exit = 0; char session_user[32] = ""; char session_home[64] = ""; +void sync_cwd() { + char abs[128]; + if (montauk::getcwd(abs, sizeof(abs)) < 0) { + current_drive = 0; + cwd[0] = '\0'; + return; + } + + int drive = parse_drive_prefix(abs); + if (drive < 0) { + current_drive = 0; + cwd[0] = '\0'; + return; + } + + current_drive = drive; + int plen = drive_prefix_len(abs); + const char* rel = abs + plen; + if (*rel == '/') rel++; + scopy(cwd, rel, sizeof(cwd)); +} + // ---- Session info (read once at startup) ---- void read_session() { @@ -165,6 +187,7 @@ static int process_command(const char* line) { if (streq(cmd, "false")) { return 1; } if (streq(cmd, "pwd")) { + sync_cwd(); char path[128]; build_dir_path(cwd, path, sizeof(path)); montauk::print(path); @@ -202,6 +225,7 @@ static int process_command(const char* line) { montauk::print(session_home); montauk::putchar('\n'); } + sync_cwd(); char path[128]; build_dir_path(cwd, path, sizeof(path)); montauk::print("PWD="); @@ -331,6 +355,7 @@ static constexpr uint8_t SC_RIGHT = 0x4D; // ---- Entry point ---- extern "C" void _start() { + sync_cwd(); read_session(); montauk::print("\n"); diff --git a/programs/src/shell/shell.h b/programs/src/shell/shell.h index a79ebc3..52c139a 100644 --- a/programs/src/shell/shell.h +++ b/programs/src/shell/shell.h @@ -113,6 +113,7 @@ const char* var_user_value(int idx); // ---- Session (main.cpp) ---- void read_session(); +void sync_cwd(); // ---- Builtins (builtins.cpp) ---- diff --git a/programs/src/shell/vars.cpp b/programs/src/shell/vars.cpp index 47ff5f7..a2d634d 100644 --- a/programs/src/shell/vars.cpp +++ b/programs/src/shell/vars.cpp @@ -61,6 +61,7 @@ const char* var_get(const char* name) { if (streq(name, "USER")) return session_user[0] ? session_user : nullptr; if (streq(name, "HOME")) return session_home[0] ? session_home : nullptr; if (streq(name, "PWD")) { + sync_cwd(); build_dir_path(cwd, synth, sizeof(synth)); return synth; } diff --git a/programs/src/tcc/montauk_compat.h b/programs/src/tcc/montauk_compat.h index 97d63ca..f1e7c25 100644 --- a/programs/src/tcc/montauk_compat.h +++ b/programs/src/tcc/montauk_compat.h @@ -72,19 +72,8 @@ static inline int gettimeofday(struct timeval *tv, struct timezone *tz) { return 0; } -/* ==================================================================== - getcwd stub (for debug info) - ==================================================================== */ - -static inline char *getcwd(char *buf, size_t size) { - if (buf && size > 4) { - buf[0] = '0'; - buf[1] = ':'; - buf[2] = '/'; - buf[3] = '\0'; - } - return buf; -} +/* getcwd is provided by libc now */ +char *getcwd(char *buf, size_t size); /* ==================================================================== POSIX file access stubs diff --git a/programs/src/touch/main.cpp b/programs/src/touch/main.cpp index 3362d77..3ef83f4 100644 --- a/programs/src/touch/main.cpp +++ b/programs/src/touch/main.cpp @@ -11,21 +11,24 @@ extern "C" void _start() { char args[256]; montauk::getargs((char *)&args, 256); - if (*args) { - const char* arg = montauk::skip_spaces((const char *)&args); - int fd = montauk::open(arg); - montauk::close(fd); - - if (fd >= 0) { /* file already exists */ - montauk::exit(0); - } else { - int fd = montauk::fcreate(arg); - montauk::close(fd); - - montauk::exit(0); - } - } else { + const char* path = montauk::skip_spaces((const char *)&args); + if (*path == '\0') { montauk::print("usage: touch [filename]\n"); montauk::exit(-1); } -} \ No newline at end of file + + int fd = montauk::open(path); + if (fd >= 0) { + montauk::close(fd); + montauk::exit(0); + } + + fd = montauk::fcreate(path); + if (fd < 0) { + montauk::print("touch: failed to create file\n"); + montauk::exit(-1); + } + + montauk::close(fd); + montauk::exit(0); +}