fix(vfs): resolve CWD tracking, filename clobbering, touch creation, and nano full-screen editing & saving

This commit is contained in:
subhobhai943 committed 2026-08-17 12:26:07 +05:30
1 parent d680335f05
commit 9f9a19bab0
5 files changed
+282 -123

No files matched your search

+182 -77
View File
@@ -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) {
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';
const char* filename = last_slash + 1;
vfs_node_t* parent = vfs_namei(parent_path[0] ? parent_path : "/");
}
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;
char dirname[128];
strncpy(dirname, last_slash + 1, sizeof(dirname) - 1);
dirname[sizeof(dirname) - 1] = '\0';
if (last_slash) {
if (last_slash == parent_path) {
parent = vfs_namei("/");
dirname = last_slash + 1;
parent_path[1] = '\0'; // Root "/"
} else {
*last_slash = '\0';
dirname = last_slash + 1;
parent = vfs_namei(parent_path);
}
}
if (parent && parent->mkdir) {
vfs_node_t* parent = vfs_namei(parent_path);
if (!parent || !parent->mkdir) return -1;
return parent->mkdir(parent, dirname, mode);
}
return -1;
}
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;
}
+4
View File
@@ -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
+6 -4
View File
@@ -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;
}
+57 -25
View File
@@ -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",
// 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;
+33 -17
View File
@@ -1,5 +1,6 @@
#include <userland/shell.h>
#include <userland/lazybox.h>
#include <fs/vfs.h>
#include <drivers/tty.h>
#include <drivers/keyboard.h>
#include <drivers/speaker.h>
@@ -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 <file>" 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 <file>" ANSI_RESET " - Create empty files in VFS\n");
printk(" " ANSI_GREEN "mkdir <dir>" 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 <text>" 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 <file>" ANSI_RESET " - FIPS 180-4 SHA-256 secure hash\n");
printk(" " ANSI_GREEN "md5sum <file>" ANSI_RESET " - RFC 1321 MD5 message digest\n");
printk(" " ANSI_GREEN "crc32 <text>" ANSI_RESET " - IEEE 802.3 32-bit CRC calculation\n\n");
printk(" " ANSI_GREEN "crc32 <text>" 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 <ip>" 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 <host>" 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;