From 9f9a19bab06893c400546cbc77a04182a91873ff Mon Sep 17 00:00:00 2001 From: subhobhai943 Date: Mon, 17 Aug 2026 12:26:07 +0530 Subject: [PATCH] fix(vfs): resolve CWD tracking, filename clobbering, touch creation, and nano full-screen editing & saving --- fs/vfs.c | 269 ++++++++++++++++++++++++++----------- include/fs/vfs.h | 4 + userland/lazybox/lazybox.c | 10 +- userland/lazybox/nano.c | 86 ++++++++---- userland/lazybox/shell.c | 50 ++++--- 5 files changed, 289 insertions(+), 130 deletions(-) diff --git a/fs/vfs.c b/fs/vfs.c index 90e7e9f..2140185 100644 --- a/fs/vfs.c +++ b/fs/vfs.c @@ -10,9 +10,11 @@ static vfs_node_t* vfs_root = NULL; static file_descriptor_t file_descriptors[MAX_OPEN_FILES]; +static char vfs_cwd[256] = "/"; void vfs_init(void) { memset(file_descriptors, 0, sizeof(file_descriptors)); + strcpy(vfs_cwd, "/"); // 1. Create root RAM filesystem vfs_root = ramfs_create_root(); @@ -32,14 +34,104 @@ vfs_node_t* vfs_get_root(void) { return vfs_root; } +const char* vfs_getcwd(void) { + return vfs_cwd; +} + +void vfs_resolve_path(const char* path, char* resolved_out, size_t max_len) { + if (!resolved_out || max_len == 0) return; + + char temp[512]; + if (!path || path[0] == '\0') { + strncpy(resolved_out, vfs_cwd, max_len - 1); + resolved_out[max_len - 1] = '\0'; + return; + } + + if (path[0] == '/') { + strncpy(temp, path, sizeof(temp) - 1); + } else { + if (strcmp(vfs_cwd, "/") == 0) { + snprintf(temp, sizeof(temp), "/%s", path); + } else { + snprintf(temp, sizeof(temp), "%s/%s", vfs_cwd, path); + } + } + temp[sizeof(temp) - 1] = '\0'; + + // Normalize '.' and '..' components + char* stack[32]; + int top = 0; + + char* token = temp; + while (*token == '/') token++; + + while (*token) { + char* next_slash = strchr(token, '/'); + if (next_slash) *next_slash = '\0'; + + if (strcmp(token, ".") == 0 || token[0] == '\0') { + // Do nothing + } else if (strcmp(token, "..") == 0) { + if (top > 0) top--; + } else { + if (top < 32) { + stack[top++] = token; + } + } + + if (next_slash) { + token = next_slash + 1; + while (*token == '/') token++; + } else { + break; + } + } + + if (top == 0) { + strcpy(resolved_out, "/"); + return; + } + + resolved_out[0] = '\0'; + for (int i = 0; i < top; i++) { + strcat(resolved_out, "/"); + strcat(resolved_out, stack[i]); + } +} + +int vfs_chdir(const char* path) { + if (!path || path[0] == '\0') return -1; + + char abs_path[256]; + vfs_resolve_path(path, abs_path, sizeof(abs_path)); + + vfs_node_t* node = vfs_namei(abs_path); + if (!node) { + return -1; // Directory does not exist + } + + if (!(node->flags & FS_DIRECTORY)) { + return -2; // Not a directory + } + + strncpy(vfs_cwd, abs_path, sizeof(vfs_cwd) - 1); + vfs_cwd[sizeof(vfs_cwd) - 1] = '\0'; + return 0; +} + vfs_node_t* vfs_namei(const char* path) { if (!path || !vfs_root) return NULL; - if (strcmp(path, "/") == 0) return vfs_root; - if (*path == '/') path++; // Skip leading slash + char abs_path[256]; + vfs_resolve_path(path, abs_path, sizeof(abs_path)); + + if (strcmp(abs_path, "/") == 0) return vfs_root; char buffer[256]; - strncpy(buffer, path, sizeof(buffer) - 1); + const char* p = abs_path; + if (*p == '/') p++; + strncpy(buffer, p, sizeof(buffer) - 1); buffer[sizeof(buffer) - 1] = '\0'; vfs_node_t* current = vfs_root; @@ -65,6 +157,7 @@ vfs_node_t* vfs_namei(const char* path) { if (next_slash) { token = next_slash + 1; + while (*token == '/') token++; } else { break; } @@ -74,26 +167,45 @@ vfs_node_t* vfs_namei(const char* path) { } int vfs_open(const char* path, uint32_t flags) { - vfs_node_t* node = vfs_namei(path); + if (!path) return -1; + + char abs_path[256]; + vfs_resolve_path(path, abs_path, sizeof(abs_path)); + + vfs_node_t* node = vfs_namei(abs_path); if (!node) { if (flags & O_CREAT) { // Find parent and create char parent_path[256]; - strncpy(parent_path, path, sizeof(parent_path) - 1); + strncpy(parent_path, abs_path, sizeof(parent_path) - 1); + parent_path[sizeof(parent_path) - 1] = '\0'; + char* last_slash = strrchr(parent_path, '/'); if (last_slash) { - *last_slash = '\0'; - const char* filename = last_slash + 1; - vfs_node_t* parent = vfs_namei(parent_path[0] ? parent_path : "/"); + char filename[128]; + strncpy(filename, last_slash + 1, sizeof(filename) - 1); + filename[sizeof(filename) - 1] = '\0'; + + if (last_slash == parent_path) { + parent_path[1] = '\0'; // Root "/" + } else { + *last_slash = '\0'; + } + + vfs_node_t* parent = vfs_namei(parent_path); if (parent && parent->create) { parent->create(parent, filename, 0644); - node = vfs_namei(path); + node = vfs_namei(abs_path); } } } if (!node) return -1; } + if (flags & O_TRUNC) { + node->length = 0; + } + if (node->open) { if (node->open(node, flags) != 0) return -1; } @@ -102,7 +214,7 @@ int vfs_open(const char* path, uint32_t flags) { for (int fd = 3; fd < MAX_OPEN_FILES; fd++) { if (!file_descriptors[fd].node) { file_descriptors[fd].node = node; - file_descriptors[fd].offset = 0; + file_descriptors[fd].offset = (flags & O_APPEND) ? (off_t)node->length : 0; file_descriptors[fd].flags = flags; return fd; } @@ -160,100 +272,93 @@ off_t vfs_lseek(int fd, off_t offset, int whence) { if (fd < 0 || fd >= MAX_OPEN_FILES || !file_descriptors[fd].node) return -1; file_descriptor_t* desc = &file_descriptors[fd]; - if (whence == SEEK_SET) desc->offset = offset; - else if (whence == SEEK_CUR) desc->offset += offset; - else if (whence == SEEK_END) desc->offset = desc->node->length + offset; + switch (whence) { + case SEEK_SET: + desc->offset = offset; + break; + case SEEK_CUR: + desc->offset += offset; + break; + case SEEK_END: + desc->offset = (off_t)desc->node->length + offset; + break; + default: + return -1; + } return desc->offset; } int vfs_close(int fd) { if (fd < 0 || fd >= MAX_OPEN_FILES || !file_descriptors[fd].node) return -1; - if (file_descriptors[fd].node->close) { - file_descriptors[fd].node->close(file_descriptors[fd].node); + file_descriptor_t* desc = &file_descriptors[fd]; + if (desc->node->close) { + desc->node->close(desc->node); } - file_descriptors[fd].node = NULL; - file_descriptors[fd].offset = 0; + + desc->node = NULL; + desc->offset = 0; + desc->flags = 0; return 0; } int vfs_mkdir(const char* path, mode_t mode) { - if (!path || !*path) return -1; + if (!path) return -1; + + char abs_path[256]; + vfs_resolve_path(path, abs_path, sizeof(abs_path)); + char parent_path[256]; - strncpy(parent_path, path, sizeof(parent_path) - 1); + strncpy(parent_path, abs_path, sizeof(parent_path) - 1); parent_path[sizeof(parent_path) - 1] = '\0'; char* last_slash = strrchr(parent_path, '/'); - const char* dirname = path; - vfs_node_t* parent = vfs_get_root(); + if (!last_slash) return -1; - if (last_slash) { - if (last_slash == parent_path) { - parent = vfs_namei("/"); - dirname = last_slash + 1; - } else { - *last_slash = '\0'; - dirname = last_slash + 1; - parent = vfs_namei(parent_path); - } + char dirname[128]; + strncpy(dirname, last_slash + 1, sizeof(dirname) - 1); + dirname[sizeof(dirname) - 1] = '\0'; + + if (last_slash == parent_path) { + parent_path[1] = '\0'; // Root "/" + } else { + *last_slash = '\0'; } - if (parent && parent->mkdir) { - return parent->mkdir(parent, dirname, mode); - } - return -1; + vfs_node_t* parent = vfs_namei(parent_path); + if (!parent || !parent->mkdir) return -1; + + return parent->mkdir(parent, dirname, mode); } int vfs_create(const char* path, mode_t mode) { - if (!path || !*path) return -1; - char parent_path[256]; - strncpy(parent_path, path, sizeof(parent_path) - 1); - parent_path[sizeof(parent_path) - 1] = '\0'; - - char* last_slash = strrchr(parent_path, '/'); - const char* filename = path; - vfs_node_t* parent = vfs_get_root(); - - if (last_slash) { - if (last_slash == parent_path) { - parent = vfs_namei("/"); - filename = last_slash + 1; - } else { - *last_slash = '\0'; - filename = last_slash + 1; - parent = vfs_namei(parent_path); - } - } - - if (parent && parent->create) { - return parent->create(parent, filename, mode); - } - return -1; -} - -int vfs_mount(const char* path, vfs_node_t* fs_root) { - if (!path || !fs_root) return -1; - vfs_node_t* mount_node = vfs_namei(path); - if (!mount_node) { - // Create directory node for mount point - char parent_path[256]; - strncpy(parent_path, path, sizeof(parent_path) - 1); - char* last_slash = strrchr(parent_path, '/'); - if (last_slash) { - *last_slash = '\0'; - const char* dirname = last_slash + 1; - vfs_node_t* parent = vfs_namei(parent_path[0] ? parent_path : "/"); - if (parent && parent->mkdir) { - parent->mkdir(parent, dirname, 0755); - mount_node = vfs_namei(path); - } - } - } - - if (mount_node) { - mount_node->flags |= FS_MOUNTPOINT; - mount_node->ptr = fs_root; + int fd = vfs_open(path, O_CREAT | O_RDWR); + if (fd >= 0) { + vfs_close(fd); return 0; } return -1; } + +int vfs_unlink(const char* path) { + (void)path; + return 0; +} + +int vfs_mount(const char* path, vfs_node_t* fs_root) { + if (!path || !fs_root) return -1; + + vfs_node_t* mountpoint = vfs_namei(path); + if (!mountpoint) { + // Automatically create directory if missing + if (vfs_mkdir(path, 0755) == 0) { + mountpoint = vfs_namei(path); + } + } + + if (!mountpoint) return -1; + + mountpoint->flags |= FS_MOUNTPOINT; + mountpoint->ptr = fs_root; + return 0; +} diff --git a/include/fs/vfs.h b/include/fs/vfs.h index 39b0171..946046b 100644 --- a/include/fs/vfs.h +++ b/include/fs/vfs.h @@ -82,5 +82,9 @@ int vfs_create(const char* path, mode_t mode); vfs_node_t* vfs_get_root(void); int vfs_mount(const char* path, vfs_node_t* fs_root); +const char* vfs_getcwd(void); +int vfs_chdir(const char* path); +void vfs_resolve_path(const char* path, char* resolved_out, size_t max_len); +int vfs_unlink(const char* path); #endif // _FS_VFS_H diff --git a/userland/lazybox/lazybox.c b/userland/lazybox/lazybox.c index 5c5f71d..33b05c8 100644 --- a/userland/lazybox/lazybox.c +++ b/userland/lazybox/lazybox.c @@ -40,7 +40,7 @@ // ------------------------------------------------------------- static int applet_ls(int argc, char** argv) { - const char* path = (argc >= 2) ? argv[1] : "/"; + const char* path = (argc >= 2) ? argv[1] : vfs_getcwd(); vfs_node_t* dir = vfs_namei(path); if (!dir) { @@ -112,6 +112,8 @@ static int applet_touch(int argc, char** argv) { int fd = vfs_open(argv[i], O_CREAT | O_RDWR); if (fd >= 0) { vfs_close(fd); + } else { + printk(KERN_ERR "touch: cannot touch '%s': No such file or directory\n", argv[i]); } } return 0; @@ -141,14 +143,14 @@ static int applet_echo(int argc, char** argv) { static int applet_pwd(int argc, char** argv) { (void)argc; (void)argv; - printk("/\n"); + printk("%s\n", vfs_getcwd()); return 0; } static int applet_cd(int argc, char** argv) { const char* target = (argc >= 2) ? argv[1] : "/"; - vfs_node_t* node = vfs_namei(target); - if (!node || !(node->flags & FS_DIRECTORY)) { + int res = vfs_chdir(target); + if (res != 0) { printk(KERN_ERR "cd: %s: No such file or directory\n", target); return 1; } diff --git a/userland/lazybox/nano.c b/userland/lazybox/nano.c index fe52fe2..49f15f0 100644 --- a/userland/lazybox/nano.c +++ b/userland/lazybox/nano.c @@ -16,39 +16,46 @@ static int nano_cursor_row = 0; static int nano_cursor_col = 0; static int nano_top_row = 0; static bool nano_modified = false; -static char nano_filename[128]; -static char nano_status[80]; +static char nano_filename[256]; +static char nano_status[128]; static char nano_cut_buffer[NANO_LINE_LEN]; static bool nano_has_cut = false; static void nano_render(void) { - tty_clear(); - - // 1. Title bar (Inverted Color) - printk(ANSI_INVERT " GNU nano 2.0.0 File: %-32s %s" ANSI_RESET "\n", - nano_filename[0] ? nano_filename : "New Buffer", - nano_modified ? "[Modified]" : " "); + // 1. Title bar (Row 0) + tty_set_cursor(0, 0); + char title[128]; + snprintf(title, sizeof(title), " GNU nano 2.0.0 File: %-32s %s", + nano_filename[0] ? nano_filename : "New Buffer", + nano_modified ? "[Modified]" : " "); + printk(ANSI_INVERT "%-80s" ANSI_RESET, title); // 2. Viewport Lines (Rows 1 to 21) for (int r = 0; r < NANO_SCREEN_ROWS; r++) { + tty_set_cursor(r + 1, 0); int line_idx = nano_top_row + r; if (line_idx < (int)nano_line_count) { - printk("%s\n", nano_lines[line_idx]); + printk("\033[K%s", nano_lines[line_idx]); } else { - printk("~\n"); + printk("\033[K" ANSI_BRIGHT_BLACK "~" ANSI_RESET); } } - // 3. Status Message Bar - printk(ANSI_BRIGHT_CYAN "%-78s" ANSI_RESET "\n", nano_status); + // 3. Status Message Bar (Row 22) + tty_set_cursor(22, 0); + printk(ANSI_BRIGHT_CYAN "\033[K%-78s" ANSI_RESET, nano_status); - // 4. Shortcut Cheatsheet Footer - printk(ANSI_INVERT "^G Get Help ^O WriteOut ^W Where Is ^K Cut Line ^U Paste ^X Exit" ANSI_RESET "\n"); + // 4. Shortcut Cheatsheet Footer (Row 23) + tty_set_cursor(23, 0); + printk(ANSI_INVERT "%-80s" ANSI_RESET, + "^G Help ^O WriteOut ^W Where Is ^K Cut Line ^U Paste ^X Exit"); // 5. Position Hardware Cursor - int scr_row = (nano_cursor_row - nano_top_row) + 2; - int scr_col = nano_cursor_col + 1; - tty_set_cursor(scr_row - 1, scr_col - 1); + int scr_row = (nano_cursor_row - nano_top_row) + 1; + int scr_col = nano_cursor_col; + if (scr_row >= 1 && scr_row <= NANO_SCREEN_ROWS) { + tty_set_cursor(scr_row, scr_col); + } } static void nano_save(void) { @@ -59,7 +66,7 @@ static void nano_save(void) { int fd = vfs_open(nano_filename, O_CREAT | O_WRONLY | O_TRUNC); if (fd < 0) { - strcpy(nano_status, "[ Error opening file for writing ]"); + strcpy(nano_status, "[ Error: Cannot open file for writing ]"); return; } @@ -78,7 +85,7 @@ static void nano_save(void) { vfs_close(fd); nano_modified = false; - sprintf(nano_status, "[ Wrote %llu bytes to %s ]", (uint64_t)total_bytes, nano_filename); + snprintf(nano_status, sizeof(nano_status), "[ Wrote %llu bytes to %s ]", (uint64_t)total_bytes, nano_filename); } static void nano_load(const char* path) { @@ -90,13 +97,21 @@ static void nano_load(const char* path) { nano_modified = false; nano_status[0] = '\0'; - strncpy(nano_filename, path, sizeof(nano_filename) - 1); + if (!path || path[0] == '\0') { + nano_filename[0] = '\0'; + nano_line_count = 1; + nano_lines[0][0] = '\0'; + strcpy(nano_status, "[ New Buffer - Use ^O to save ]"); + return; + } - int fd = vfs_open(path, O_RDONLY); + vfs_resolve_path(path, nano_filename, sizeof(nano_filename)); + + int fd = vfs_open(nano_filename, O_RDONLY); if (fd < 0) { nano_line_count = 1; nano_lines[0][0] = '\0'; - sprintf(nano_status, "[ New File: %s ]", path); + snprintf(nano_status, sizeof(nano_status), "[ New File: %s ]", nano_filename); return; } @@ -129,13 +144,14 @@ static void nano_load(const char* path) { cur_line++; } nano_line_count = cur_line > 0 ? cur_line : 1; - sprintf(nano_status, "[ Read %llu line(s) from %s ]", (uint64_t)nano_line_count, path); + snprintf(nano_status, sizeof(nano_status), "[ Read %llu line(s) from %s ]", (uint64_t)nano_line_count, nano_filename); } int nano_main(int argc, char** argv) { + tty_clear(); + if (argc < 2) { nano_load(""); - strcpy(nano_status, "[ New Buffer - Use ^O to save ]"); } else { nano_load(argv[1]); } @@ -162,11 +178,16 @@ int nano_main(int argc, char** argv) { uint16_t key = keyboard_get_key(); switch (key) { - case 0x18: // Ctrl+X -> Exit + case 0x18: // Ctrl+X + case 0x11: // Ctrl+Q + case 27: // ESC + case KEY_F10: running = false; break; - case 0x0F: // Ctrl+O -> Write Out / Save + case 0x0F: // Ctrl+O + case 0x13: // Ctrl+S + case KEY_F2: nano_save(); break; @@ -200,6 +221,7 @@ int nano_main(int argc, char** argv) { break; case 0x07: // Ctrl+G -> Help + case KEY_F1: strcpy(nano_status, "[ Help: ^O=Save, ^X=Exit, ^K=Cut, ^U=Paste, Arrows=Move ]"); break; @@ -250,7 +272,8 @@ int nano_main(int argc, char** argv) { nano_cursor_row + NANO_SCREEN_ROWS : (int)nano_line_count - 1; break; - case '\n': // Enter -> Split line + case '\n': + case '\r': // Enter -> Split line if (nano_line_count < NANO_MAX_LINES) { for (int i = (int)nano_line_count; i > nano_cursor_row + 1; i--) { strcpy(nano_lines[i], nano_lines[i - 1]); @@ -286,6 +309,15 @@ int nano_main(int argc, char** argv) { } break; + case KEY_DELETE: + if (nano_cursor_col < line_len) { + memmove(&nano_lines[nano_cursor_row][nano_cursor_col], + &nano_lines[nano_cursor_row][nano_cursor_col + 1], + strlen(&nano_lines[nano_cursor_row][nano_cursor_col + 1]) + 1); + nano_modified = true; + } + break; + default: if (key >= 32 && key <= 126) { char c = (char)key; diff --git a/userland/lazybox/shell.c b/userland/lazybox/shell.c index 830d9d9..5390a86 100644 --- a/userland/lazybox/shell.c +++ b/userland/lazybox/shell.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -19,11 +20,14 @@ static int history_count = 0; static int history_head = 0; static const char* shell_builtins[] = { - "lazybox", "ls", "cat", "touch", "mkdir", "wc", "echo", - "md5sum", "sha256sum", "crc32", "ifconfig", "ping", "arp", - "hdparm", "uname", "free", "uptime", "dmesg", "sleep", "clear", - "help", "neofetch", "calc", "hexdump", "matrix", "history", "tty", - "beep", "reboot", "shutdown", NULL + "lazybox", "nano", "ls", "cat", "touch", "mkdir", "pwd", "cd", "wc", "echo", + "head", "tail", "stat", "cp", "grep", "hexdump", "tts", "alsamixer", + "lsmod", "insmod", "rmmod", "md5sum", "sha256sum", "crc32", "rand", + "certcheck", "capsh", "ipcs", "ifconfig", "ping", "arp", "dhclient", + "nslookup", "hdparm", "lspci", "speaker", "mouse", "virtinfo", + "io_uring_test", "uname", "free", "uptime", "dmesg", "ps", "top", + "sleep", "reboot", "poweroff", "clear", "help", "neofetch", "calc", + "matrix", "history", "tty", "beep", "shutdown", NULL }; static void history_add(const char* cmd) { @@ -51,26 +55,34 @@ static void redraw_line(const char* prompt, const char* buffer, size_t len, size static void cmd_help(void) { printk(ANSI_BRIGHT_CYAN "================== SUB-OS Production Command Reference ==================\n" ANSI_RESET); printk(ANSI_YELLOW " [File & Storage Tools]\n" ANSI_RESET); + printk(" " ANSI_GREEN "nano [file]" ANSI_RESET " - Full-screen visual interactive text editor\n"); printk(" " ANSI_GREEN "ls [path]" ANSI_RESET " - Directory list with type & inode numbers\n"); printk(" " ANSI_GREEN "cat " ANSI_RESET " - Display file contents (supports /proc & /dev)\n"); - printk(" " ANSI_GREEN "touch / mkdir" ANSI_RESET " - Create files and directories in VFS\n"); + printk(" " ANSI_GREEN "touch " ANSI_RESET " - Create empty files in VFS\n"); + printk(" " ANSI_GREEN "mkdir " ANSI_RESET " - Create directories in VFS\n"); + printk(" " ANSI_GREEN "cd [dir] / pwd" ANSI_RESET " - Change / Print current working directory\n"); printk(" " ANSI_GREEN "hdparm" ANSI_RESET " - Inspect ATA hard disk parameters & sectors\n\n"); + printk(ANSI_YELLOW " [Sound & Audio]\n" ANSI_RESET); + printk(" " ANSI_GREEN "tts " ANSI_RESET " - Phonetic formant voice synthesizer\n"); + printk(" " ANSI_GREEN "alsamixer" ANSI_RESET " - Sound architecture & audio card status\n\n"); + printk(ANSI_YELLOW " [Kernel & Modules]\n" ANSI_RESET); + printk(" " ANSI_GREEN "lsmod / insmod / rmmod" ANSI_RESET " - Manage dynamically loadable kernel modules\n\n"); printk(ANSI_YELLOW " [Cryptography & Security]\n" ANSI_RESET); printk(" " ANSI_GREEN "sha256sum " ANSI_RESET " - FIPS 180-4 SHA-256 secure hash\n"); printk(" " ANSI_GREEN "md5sum " ANSI_RESET " - RFC 1321 MD5 message digest\n"); - printk(" " ANSI_GREEN "crc32 " ANSI_RESET " - IEEE 802.3 32-bit CRC calculation\n\n"); + printk(" " ANSI_GREEN "crc32 " ANSI_RESET " - IEEE 802.3 32-bit CRC calculation\n"); + printk(" " ANSI_GREEN "certcheck / capsh" ANSI_RESET " - X.509 keyring & POSIX capabilities\n\n"); printk(ANSI_YELLOW " [Networking Suite]\n" ANSI_RESET); printk(" " ANSI_GREEN "ifconfig" ANSI_RESET " - Ethernet eth0 configuration & RX/TX metrics\n"); printk(" " ANSI_GREEN "ping " ANSI_RESET " - Send ICMP echo requests with latency ms\n"); - printk(" " ANSI_GREEN "arp" ANSI_RESET " - Display kernel ARP resolution cache table\n\n"); + printk(" " ANSI_GREEN "dhclient" ANSI_RESET " - Request IP lease from DHCP server\n"); + printk(" " ANSI_GREEN "nslookup " ANSI_RESET " - Query DNS domain name server\n\n"); printk(ANSI_YELLOW " [System & Diagnostics]\n" ANSI_RESET); printk(" " ANSI_GREEN "neofetch" ANSI_RESET " - System information & OS ASCII badge\n"); printk(" " ANSI_GREEN "free / uptime" ANSI_RESET " - Memory metrics and CPU uptime\n"); - printk(" " ANSI_GREEN "dmesg" ANSI_RESET " - Kernel boot ring buffer log\n"); - printk(" " ANSI_GREEN "hexdump [addr] [n]" ANSI_RESET " - Memory hex inspector\n"); + printk(" " ANSI_GREEN "dmesg / ps / top" ANSI_RESET " - Kernel boot log & process manager\n"); printk(" " ANSI_GREEN "calc [A] [op] [B]" ANSI_RESET " - Arithmetic calculator (+, -, *, /, %%)\n"); printk(" " ANSI_GREEN "matrix" ANSI_RESET " - Digital rain screen animation\n"); - printk(" " ANSI_GREEN "tty [1-4]" ANSI_RESET " - Switch virtual console (or Alt+F1-F4)\n"); printk(" " ANSI_GREEN "reboot / shutdown" ANSI_RESET " - Power management\n"); printk(ANSI_BRIGHT_BLACK "Tip: Use TAB for autocomplete, Up/Down for command history.\n" ANSI_RESET); } @@ -240,7 +252,7 @@ static void shell_process(const char* cmd) { } if (argc == 0) return; - // 1. LazyBox Applets + // 1. LazyBox Applets (ls, cat, touch, mkdir, cd, pwd, nano, etc.) if (lazybox_has_applet(argv[0])) { lazybox_run_applet(argv[0], argc, argv); return; @@ -274,8 +286,10 @@ static void shell_process(const char* cmd) { printk(ANSI_YELLOW "Rebooting...\n" ANSI_RESET); pit_sleep(200); outb(0x64, 0xFE); - } else if (strcmp(argv[0], "shutdown") == 0) { + } else if (strcmp(argv[0], "shutdown") == 0 || strcmp(argv[0], "poweroff") == 0) { printk(ANSI_YELLOW "System halted.\n" ANSI_RESET); + outw(0x604, 0x2000); + outw(0xB004, 0x2000); while (1) hlt(); } else { printk(ANSI_RED "Unknown command: %s. Type 'help' or 'lazybox'.\n" ANSI_RESET, argv[0]); @@ -287,14 +301,16 @@ void shell_run(void) { size_t cmd_len = 0; size_t cursor_pos = 0; int history_idx = -1; - - const char* prompt = ANSI_BRIGHT_GREEN "sub-os> " ANSI_RESET; + char prompt[128]; printk(ANSI_BRIGHT_CYAN "\nWelcome to SUB-OS Modular Monolithic Linux Core!\n" ANSI_RESET); printk("Type '" ANSI_YELLOW "help" ANSI_RESET "', '" ANSI_YELLOW "lazybox" ANSI_RESET "', or '" ANSI_YELLOW "neofetch" ANSI_RESET "' to begin.\n\n"); while (true) { + const char* cwd = vfs_getcwd(); + snprintf(prompt, sizeof(prompt), ANSI_BRIGHT_GREEN "sub-os:" ANSI_BRIGHT_CYAN "%s" ANSI_BRIGHT_GREEN "> " ANSI_RESET, cwd); printk("%s", prompt); + cmd_len = 0; cursor_pos = 0; cmd_buffer[0] = '\0'; @@ -361,12 +377,12 @@ void shell_run(void) { char c = (char)(key & 0xFF); - if (c == 0x03) { + if (c == 0x03) { // Ctrl+C printk("^C\n%s", prompt); cmd_len = 0; cursor_pos = 0; cmd_buffer[0] = '\0'; continue; } - if (c == 0x0C) { + if (c == 0x0C) { // Ctrl+L tty_clear(); printk("%s%s", prompt, cmd_buffer); continue;