mirror of
https://github.com/subhobhai943/SUB-OS.git
synced 2026-10-26 09:02:46 +00:00
Initial commit: SUB-OS 64-Bit Production Monolithic Operating System with LazyBox userland suite
This commit is contained in:
commit
cd9c786d14
88 files changed
+7132
No files matched your search
@@ -0,0 +1,456 @@
|
||||
#include <userland/lazybox.h>
|
||||
#include <fs/vfs.h>
|
||||
#include <net/net.h>
|
||||
#include <drivers/e1000.h>
|
||||
#include <drivers/ata.h>
|
||||
#include <drivers/tty.h>
|
||||
#include <crypto/crypto.h>
|
||||
#include <mm/pmm.h>
|
||||
#include <mm/kmalloc.h>
|
||||
#include <arch/x86_64/pit.h>
|
||||
#include <arch/x86_64/cpuid.h>
|
||||
#include <kernel/printk.h>
|
||||
#include <lib/string.h>
|
||||
#include <lib/printf.h>
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// Core Utilities
|
||||
// -------------------------------------------------------------
|
||||
|
||||
static int applet_ls(int argc, char** argv) {
|
||||
const char* path = (argc >= 2) ? argv[1] : "/";
|
||||
vfs_node_t* dir = vfs_namei(path);
|
||||
|
||||
if (!dir) {
|
||||
printk(KERN_ERR "ls: cannot access '%s': No such file or directory\n", path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(dir->flags & FS_DIRECTORY)) {
|
||||
printk(KERN_INFO "%s\n", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
printk(ANSI_BRIGHT_CYAN "Type Size (B) Inode Name\n" ANSI_RESET);
|
||||
printk("-----------------------------------------\n");
|
||||
|
||||
uint32_t idx = 0;
|
||||
struct vfs_dirent* ent;
|
||||
while ((ent = dir->readdir(dir, idx++)) != NULL) {
|
||||
const char* color = ANSI_WHITE;
|
||||
const char* type_str = "FILE ";
|
||||
if (ent->type & FS_DIRECTORY) {
|
||||
color = ANSI_BRIGHT_BLUE;
|
||||
type_str = "DIR ";
|
||||
} else if (ent->type & FS_CHARDEVICE) {
|
||||
color = ANSI_BRIGHT_YELLOW;
|
||||
type_str = "CHR ";
|
||||
}
|
||||
|
||||
vfs_node_t* child = dir->finddir ? dir->finddir(dir, ent->name) : NULL;
|
||||
size_t sz = child ? child->length : 0;
|
||||
|
||||
printk("%s %8llu %6llu %s%s" ANSI_RESET "\n",
|
||||
type_str, sz, ent->inode, color, ent->name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int applet_cat(int argc, char** argv) {
|
||||
if (argc < 2) {
|
||||
printk(KERN_INFO "Usage: cat <file>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
int fd = vfs_open(argv[i], O_RDONLY);
|
||||
if (fd < 0) {
|
||||
printk(KERN_ERR "cat: %s: No such file or directory\n", argv[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
char buf[512];
|
||||
ssize_t bytes;
|
||||
while ((bytes = vfs_read(fd, buf, sizeof(buf) - 1)) > 0) {
|
||||
buf[bytes] = '\0';
|
||||
printk("%s", buf);
|
||||
}
|
||||
vfs_close(fd);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int applet_touch(int argc, char** argv) {
|
||||
if (argc < 2) {
|
||||
printk(KERN_INFO "Usage: touch <file...>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
int fd = vfs_open(argv[i], O_CREAT | O_RDWR);
|
||||
if (fd >= 0) {
|
||||
vfs_close(fd);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int applet_mkdir(int argc, char** argv) {
|
||||
if (argc < 2) {
|
||||
printk(KERN_INFO "Usage: mkdir <directory>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (vfs_mkdir(argv[i], 0755) != 0) {
|
||||
printk(KERN_ERR "mkdir: cannot create directory '%s'\n", argv[i]);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int applet_echo(int argc, char** argv) {
|
||||
for (int i = 1; i < argc; i++) {
|
||||
printk("%s%s", argv[i], (i == argc - 1) ? "" : " ");
|
||||
}
|
||||
printk("\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int applet_wc(int argc, char** argv) {
|
||||
if (argc < 2) {
|
||||
printk(KERN_INFO "Usage: wc <file>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int fd = vfs_open(argv[1], O_RDONLY);
|
||||
if (fd < 0) {
|
||||
printk(KERN_ERR "wc: %s: No such file\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lines = 0, words = 0, bytes = 0;
|
||||
bool in_word = false;
|
||||
char buf[256];
|
||||
ssize_t n;
|
||||
|
||||
while ((n = vfs_read(fd, buf, sizeof(buf))) > 0) {
|
||||
bytes += (int)n;
|
||||
for (ssize_t i = 0; i < n; i++) {
|
||||
if (buf[i] == '\n') lines++;
|
||||
if (buf[i] == ' ' || buf[i] == '\t' || buf[i] == '\n' || buf[i] == '\r') {
|
||||
in_word = false;
|
||||
} else if (!in_word) {
|
||||
in_word = true;
|
||||
words++;
|
||||
}
|
||||
}
|
||||
}
|
||||
vfs_close(fd);
|
||||
|
||||
printk(KERN_INFO "%4d %4d %4d %s\n", lines, words, bytes, argv[1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// Cryptographic Hash Utilities
|
||||
// -------------------------------------------------------------
|
||||
|
||||
static int applet_md5sum(int argc, char** argv) {
|
||||
if (argc < 2) {
|
||||
printk(KERN_INFO "Usage: md5sum <file|text>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int fd = vfs_open(argv[1], O_RDONLY);
|
||||
if (fd >= 0) {
|
||||
md5_ctx_t ctx;
|
||||
md5_init(&ctx);
|
||||
char buf[512];
|
||||
ssize_t n;
|
||||
while ((n = vfs_read(fd, buf, sizeof(buf))) > 0) {
|
||||
md5_update(&ctx, buf, (size_t)n);
|
||||
}
|
||||
vfs_close(fd);
|
||||
|
||||
uint8_t hash[16];
|
||||
md5_final(hash, &ctx);
|
||||
for (int i = 0; i < 16; i++) printk("%02x", hash[i]);
|
||||
printk(" %s\n", argv[1]);
|
||||
} else {
|
||||
// String mode
|
||||
char out[33];
|
||||
md5_string(argv[1], out);
|
||||
printk("%s \"%s\"\n", out, argv[1]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int applet_sha256sum(int argc, char** argv) {
|
||||
if (argc < 2) {
|
||||
printk(KERN_INFO "Usage: sha256sum <file|text>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int fd = vfs_open(argv[1], O_RDONLY);
|
||||
if (fd >= 0) {
|
||||
sha256_ctx_t ctx;
|
||||
sha256_init(&ctx);
|
||||
char buf[512];
|
||||
ssize_t n;
|
||||
while ((n = vfs_read(fd, buf, sizeof(buf))) > 0) {
|
||||
sha256_update(&ctx, buf, (size_t)n);
|
||||
}
|
||||
vfs_close(fd);
|
||||
|
||||
uint8_t hash[32];
|
||||
sha256_final(hash, &ctx);
|
||||
for (int i = 0; i < 32; i++) printk("%02x", hash[i]);
|
||||
printk(" %s\n", argv[1]);
|
||||
} else {
|
||||
char out[65];
|
||||
sha256_string(argv[1], out);
|
||||
printk("%s \"%s\"\n", out, argv[1]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int applet_crc32(int argc, char** argv) {
|
||||
if (argc < 2) {
|
||||
printk(KERN_INFO "Usage: crc32 <text>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t val = crc32(0, argv[1], strlen(argv[1]));
|
||||
printk("0x%08X \"%s\"\n", val, argv[1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// Network Utilities
|
||||
// -------------------------------------------------------------
|
||||
|
||||
static int applet_ifconfig(int argc, char** argv) {
|
||||
(void)argc; (void)argv;
|
||||
net_if_t* net_if = net_get_primary_if();
|
||||
|
||||
char ip_s[16], gw_s[16], mask_s[16], mac_s[18];
|
||||
ip_to_str(net_if->ip, ip_s);
|
||||
ip_to_str(net_if->gateway, gw_s);
|
||||
ip_to_str(net_if->subnet, mask_s);
|
||||
mac_to_str(net_if->mac, mac_s);
|
||||
|
||||
printk(ANSI_BRIGHT_GREEN "%s: " ANSI_RESET "flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500\n", net_if->name);
|
||||
printk(" inet " ANSI_BRIGHT_YELLOW "%s" ANSI_RESET " netmask %s broadcast %s\n", ip_s, mask_s, gw_s);
|
||||
printk(" ether " ANSI_BRIGHT_CYAN "%s" ANSI_RESET " txqueuelen 1000 (Ethernet)\n", mac_s);
|
||||
printk(" RX packets %llu bytes %llu\n", e1000_get_rx_packets(), e1000_get_rx_bytes());
|
||||
printk(" TX packets %llu bytes %llu\n", e1000_get_tx_packets(), e1000_get_tx_bytes());
|
||||
printk(" Link Status: %s\n", e1000_is_link_up() ? ANSI_GREEN "UP" ANSI_RESET : ANSI_RED "DOWN" ANSI_RESET);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int applet_ping(int argc, char** argv) {
|
||||
if (argc < 2) {
|
||||
printk(KERN_INFO "Usage: ping <ip-address> [count]\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t target_ip = ip_parse(argv[1]);
|
||||
if (target_ip == 0) {
|
||||
printk(KERN_ERR "Invalid IP address: %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t count = 4;
|
||||
if (argc >= 3) {
|
||||
int val = atoi(argv[2]);
|
||||
if (val > 0) count = (uint32_t)val;
|
||||
}
|
||||
|
||||
net_ping(target_ip, count, 1000);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int applet_arp(int argc, char** argv) {
|
||||
(void)argc; (void)argv;
|
||||
int count = 0;
|
||||
arp_entry_t* tbl = net_get_arp_table(&count);
|
||||
|
||||
printk(ANSI_BRIGHT_CYAN "Address HWtype HWaddress Flags Iface\n" ANSI_RESET);
|
||||
char ip_s[16], mac_s[18];
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (tbl[i].valid) {
|
||||
ip_to_str(tbl[i].ip, ip_s);
|
||||
mac_to_str(tbl[i].mac, mac_s);
|
||||
printk("%-16s ether %-18s C eth0\n", ip_s, mac_s);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// System & Hardware Utilities
|
||||
// -------------------------------------------------------------
|
||||
|
||||
static int applet_uname(int argc, char** argv) {
|
||||
bool all = (argc >= 2 && strcmp(argv[1], "-a") == 0);
|
||||
if (all) {
|
||||
printk("SUB-OS sub-node 0.2.0-lts #1 SMP PREEMPT Sun Aug 16 2026 x86_64 GNU/LazyBox\n");
|
||||
} else {
|
||||
printk("SUB-OS\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int applet_free(int argc, char** argv) {
|
||||
(void)argc; (void)argv;
|
||||
uint64_t total_kb = (pmm_get_total_pages() * 4096) / 1024;
|
||||
uint64_t used_kb = (pmm_get_used_pages() * 4096) / 1024;
|
||||
uint64_t free_kb = (pmm_get_free_pages() * 4096) / 1024;
|
||||
|
||||
size_t heap_used = heap_get_used_bytes();
|
||||
size_t heap_free = heap_get_free_bytes();
|
||||
|
||||
printk(ANSI_BRIGHT_CYAN " total used free shared buff/cache available\n" ANSI_RESET);
|
||||
printk("Mem: %12llu%12llu%12llu 0%12llu%12llu\n",
|
||||
total_kb, used_kb, free_kb, (heap_used / 1024), free_kb);
|
||||
printk("Heap: %12llu%12llu%12llu\n",
|
||||
(heap_used + heap_free) / 1024, heap_used / 1024, heap_free / 1024);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int applet_uptime(int argc, char** argv) {
|
||||
(void)argc; (void)argv;
|
||||
uint64_t ticks = pit_get_ticks();
|
||||
uint64_t secs = ticks / 100;
|
||||
uint64_t mins = secs / 60;
|
||||
uint64_t hours = mins / 60;
|
||||
secs %= 60;
|
||||
mins %= 60;
|
||||
|
||||
printk("up %02llu:%02llu:%02llu, 1 user, load average: 0.00, 0.01, 0.00\n", hours, mins, secs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int applet_dmesg(int argc, char** argv) {
|
||||
(void)argc; (void)argv;
|
||||
dmesg_dump();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int applet_hdparm(int argc, char** argv) {
|
||||
(void)argc; (void)argv;
|
||||
const ata_device_t* dev = ata_get_primary_master();
|
||||
if (!dev || !dev->present) {
|
||||
printk(KERN_ERR "No ATA Hard Disk Drive detected.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printk(ANSI_BRIGHT_CYAN "/dev/sda (ATA Primary Master):\n" ANSI_RESET);
|
||||
printk(" Model Number: %s\n", dev->model);
|
||||
printk(" Capacity: %llu MB (%u sectors)\n",
|
||||
((uint64_t)dev->sector_count * 512) / (1024 * 1024), dev->sector_count);
|
||||
printk(" Sector Size: 512 bytes logical/physical\n");
|
||||
printk(" Addressing: 28-bit LBA Mode\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int applet_clear(int argc, char** argv) {
|
||||
(void)argc; (void)argv;
|
||||
tty_clear();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int applet_sleep(int argc, char** argv) {
|
||||
if (argc < 2) {
|
||||
printk(KERN_INFO "Usage: sleep <seconds>\n");
|
||||
return 1;
|
||||
}
|
||||
int secs = atoi(argv[1]);
|
||||
if (secs > 0) {
|
||||
pit_sleep((uint32_t)secs * 1000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int applet_lazybox(int argc, char** argv);
|
||||
|
||||
// Applet Dispatch Table
|
||||
static const lazybox_applet_t applets[] = {
|
||||
{"lazybox", applet_lazybox, "lazybox [applet]", "Multi-call utility manager", "Core"},
|
||||
{"ls", applet_ls, "ls [path]", "List directory contents", "Filesystem"},
|
||||
{"cat", applet_cat, "cat <file...>", "Concatenate files to stdout","Filesystem"},
|
||||
{"touch", applet_touch, "touch <file...>", "Create empty files", "Filesystem"},
|
||||
{"mkdir", applet_mkdir, "mkdir <dir>", "Create directory", "Filesystem"},
|
||||
{"wc", applet_wc, "wc <file>", "Count lines, words, bytes", "Filesystem"},
|
||||
{"echo", applet_echo, "echo [text...]", "Display text to stdout", "Core"},
|
||||
{"md5sum", applet_md5sum, "md5sum <file|text>", "Compute MD5 hash", "Crypto"},
|
||||
{"sha256sum", applet_sha256sum, "sha256sum <file|text>", "Compute SHA-256 hash", "Crypto"},
|
||||
{"crc32", applet_crc32, "crc32 <text>", "Calculate CRC32 checksum", "Crypto"},
|
||||
{"ifconfig", applet_ifconfig, "ifconfig", "Display network interface", "Network"},
|
||||
{"ping", applet_ping, "ping <ip> [count]", "ICMP Echo ping utility", "Network"},
|
||||
{"arp", applet_arp, "arp", "View ARP cache table", "Network"},
|
||||
{"hdparm", applet_hdparm, "hdparm", "Inspect ATA hard disk", "Storage"},
|
||||
{"uname", applet_uname, "uname [-a]", "Print system architecture", "System"},
|
||||
{"free", applet_free, "free", "Display RAM and Heap usage", "System"},
|
||||
{"uptime", applet_uptime, "uptime", "System running duration", "System"},
|
||||
{"dmesg", applet_dmesg, "dmesg", "Dump kernel boot ringbuffer","System"},
|
||||
{"sleep", applet_sleep, "sleep <seconds>", "Delay execution", "System"},
|
||||
{"clear", applet_clear, "clear", "Clear console screen", "Terminal"},
|
||||
{NULL, NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
static int applet_lazybox(int argc, char** argv) {
|
||||
if (argc >= 2) {
|
||||
return lazybox_run_applet(argv[1], argc - 1, &argv[1]);
|
||||
}
|
||||
|
||||
printk(ANSI_BRIGHT_CYAN "LazyBox v%s (2026-08-16) Linux-Compatible Multi-Call Suite\n" ANSI_RESET, LAZYBOX_VERSION);
|
||||
printk("Usage: lazybox [function] [arguments]...\n\n");
|
||||
printk(ANSI_YELLOW "Defined Applet Categories:\n" ANSI_RESET);
|
||||
|
||||
const char* cats[] = {"Filesystem", "Crypto", "Network", "Storage", "System", "Terminal", "Core", NULL};
|
||||
for (int c = 0; cats[c] != NULL; c++) {
|
||||
printk(ANSI_BRIGHT_GREEN " [%s]\n " ANSI_RESET, cats[c]);
|
||||
for (int i = 0; applets[i].name != NULL; i++) {
|
||||
if (strcmp(applets[i].category, cats[c]) == 0) {
|
||||
printk(" %-12s", applets[i].name);
|
||||
}
|
||||
}
|
||||
printk("\n");
|
||||
}
|
||||
printk("\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void lazybox_init(void) {
|
||||
// Initialized
|
||||
}
|
||||
|
||||
bool lazybox_has_applet(const char* name) {
|
||||
if (!name) return false;
|
||||
for (int i = 0; applets[i].name != NULL; i++) {
|
||||
if (strcmp(applets[i].name, name) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int lazybox_run_applet(const char* name, int argc, char** argv) {
|
||||
if (!name) return -1;
|
||||
for (int i = 0; applets[i].name != NULL; i++) {
|
||||
if (strcmp(applets[i].name, name) == 0) {
|
||||
return applets[i].func(argc, argv);
|
||||
}
|
||||
}
|
||||
printk(KERN_ERR "lazybox: %s: applet not found\n", name);
|
||||
return 127;
|
||||
}
|
||||
|
||||
const lazybox_applet_t* lazybox_get_applets(int* count_out) {
|
||||
int count = 0;
|
||||
while (applets[count].name != NULL) count++;
|
||||
if (count_out) *count_out = count;
|
||||
return applets;
|
||||
}
|
||||
@@ -0,0 +1,429 @@
|
||||
#include <userland/shell.h>
|
||||
#include <userland/lazybox.h>
|
||||
#include <drivers/tty.h>
|
||||
#include <drivers/keyboard.h>
|
||||
#include <drivers/speaker.h>
|
||||
#include <arch/x86_64/pit.h>
|
||||
#include <arch/x86_64/cpuid.h>
|
||||
#include <arch/x86_64/io.h>
|
||||
#include <mm/pmm.h>
|
||||
#include <mm/kmalloc.h>
|
||||
#include <kernel/printk.h>
|
||||
#include <lib/string.h>
|
||||
#include <lib/printf.h>
|
||||
|
||||
#define HISTORY_SIZE 16
|
||||
|
||||
static char history[HISTORY_SIZE][MAX_COMMAND_LENGTH];
|
||||
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
|
||||
};
|
||||
|
||||
static void history_add(const char* cmd) {
|
||||
if (!cmd || cmd[0] == '\0') return;
|
||||
if (history_count > 0) {
|
||||
int last_idx = (history_head - 1 + HISTORY_SIZE) % HISTORY_SIZE;
|
||||
if (strcmp(history[last_idx], cmd) == 0) return;
|
||||
}
|
||||
strncpy(history[history_head], cmd, MAX_COMMAND_LENGTH - 1);
|
||||
history[history_head][MAX_COMMAND_LENGTH - 1] = '\0';
|
||||
history_head = (history_head + 1) % HISTORY_SIZE;
|
||||
if (history_count < HISTORY_SIZE) history_count++;
|
||||
}
|
||||
|
||||
static void redraw_line(const char* prompt, const char* buffer, size_t len, size_t cursor_pos) {
|
||||
printk("\r\033[K%s%s", prompt, buffer);
|
||||
if (cursor_pos < len) {
|
||||
size_t diff = len - cursor_pos;
|
||||
for (size_t i = 0; i < diff; i++) {
|
||||
printk("\033[D");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 "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 "hdparm" ANSI_RESET " - Inspect ATA hard disk parameters & sectors\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_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_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 "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);
|
||||
}
|
||||
|
||||
static void cmd_neofetch(void) {
|
||||
uint64_t total = pmm_get_total_pages();
|
||||
uint64_t used = pmm_get_used_pages();
|
||||
uint64_t free = pmm_get_free_pages();
|
||||
uint64_t total_mb = (total * 4096) / (1024 * 1024);
|
||||
uint64_t used_mb = (used * 4096) / (1024 * 1024);
|
||||
|
||||
uint64_t ticks = pit_get_ticks();
|
||||
uint64_t secs = ticks / 100;
|
||||
uint64_t mins = secs / 60;
|
||||
uint64_t hours = mins / 60;
|
||||
secs %= 60;
|
||||
mins %= 60;
|
||||
|
||||
const cpu_info_t* cpu = cpuid_get_info();
|
||||
|
||||
printk("\n");
|
||||
printk(ANSI_BRIGHT_CYAN " _____ _ _ ____ " ANSI_BRIGHT_GREEN "OS: " ANSI_RESET "SUB-OS v0.2.0-lts (Modular Monolithic)\n");
|
||||
printk(ANSI_BRIGHT_CYAN " / ____| | | | _ \\ " ANSI_BRIGHT_GREEN "Arch: " ANSI_RESET "x86_64 (64-Bit Long Mode)\n");
|
||||
printk(ANSI_BRIGHT_CYAN " | (___ | | | | |_) | " ANSI_BRIGHT_GREEN "Kernel: " ANSI_RESET "Modular Drivers + VFS + Crypto + Net\n");
|
||||
printk(ANSI_BRIGHT_CYAN " \\___ \\| | | | _ < " ANSI_BRIGHT_GREEN "CPU: " ANSI_RESET "%s (%s)\n", cpu->model, cpu->vendor);
|
||||
printk(ANSI_BRIGHT_CYAN " ____) | |__| | |_) | " ANSI_BRIGHT_GREEN "Memory: " ANSI_RESET "%llu MB / %llu MB (Free: %llu MB)\n", used_mb, total_mb, (free * 4096) / (1024 * 1024));
|
||||
printk(ANSI_BRIGHT_CYAN " |_____/ \\____/|____/ " ANSI_BRIGHT_GREEN "Heap: " ANSI_RESET "%llu KB used / %llu KB total\n", heap_get_used_bytes() / 1024, (heap_get_used_bytes() + heap_get_free_bytes()) / 1024);
|
||||
printk(ANSI_BRIGHT_CYAN " " ANSI_BRIGHT_GREEN "Uptime: " ANSI_RESET "%02llu:%02llu:%02llu\n", hours, mins, secs);
|
||||
printk(ANSI_BRIGHT_CYAN " " ANSI_BRIGHT_GREEN "TTY: " ANSI_RESET "tty%d (Alt+F1-F4 to switch)\n", tty_get_current() + 1);
|
||||
printk(" \n");
|
||||
printk(ANSI_BLACK "\xdb\xdb" ANSI_RED "\xdb\xdb" ANSI_GREEN "\xdb\xdb" ANSI_YELLOW "\xdb\xdb" ANSI_BLUE "\xdb\xdb" ANSI_MAGENTA "\xdb\xdb" ANSI_CYAN "\xdb\xdb" ANSI_WHITE "\xdb\xdb" ANSI_RESET "\n\n");
|
||||
}
|
||||
|
||||
static void cmd_calc(const char* args) {
|
||||
while (*args == ' ') args++;
|
||||
int64_t a = 0, b = 0;
|
||||
char op = 0;
|
||||
|
||||
bool neg_a = false;
|
||||
if (*args == '-') { neg_a = true; args++; }
|
||||
while (*args >= '0' && *args <= '9') { a = a * 10 + (*args - '0'); args++; }
|
||||
if (neg_a) a = -a;
|
||||
|
||||
while (*args == ' ') args++;
|
||||
if (*args) op = *args++;
|
||||
|
||||
while (*args == ' ') args++;
|
||||
bool neg_b = false;
|
||||
if (*args == '-') { neg_b = true; args++; }
|
||||
while (*args >= '0' && *args <= '9') { b = b * 10 + (*args - '0'); args++; }
|
||||
if (neg_b) b = -b;
|
||||
|
||||
int64_t res = 0;
|
||||
if (op == '+') res = a + b;
|
||||
else if (op == '-') res = a - b;
|
||||
else if (op == '*') res = a * b;
|
||||
else if (op == '/') {
|
||||
if (b == 0) { printk(ANSI_RED "Division by zero\n" ANSI_RESET); return; }
|
||||
res = a / b;
|
||||
} else if (op == '%') {
|
||||
if (b == 0) { printk(ANSI_RED "Modulo by zero\n" ANSI_RESET); return; }
|
||||
res = a % b;
|
||||
} else {
|
||||
printk("Usage: calc 15 + 27\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printk("%lld %c %lld = " ANSI_BRIGHT_GREEN "%lld\n" ANSI_RESET, a, op, b, res);
|
||||
}
|
||||
|
||||
static void cmd_hexdump(const char* args) {
|
||||
uint64_t addr = 0x100000;
|
||||
uint64_t len = 64;
|
||||
|
||||
while (*args == ' ') args++;
|
||||
if (*args) {
|
||||
if (args[0] == '0' && (args[1] == 'x' || args[1] == 'X')) args += 2;
|
||||
addr = 0;
|
||||
while ((*args >= '0' && *args <= '9') || (*args >= 'a' && *args <= 'f') || (*args >= 'A' && *args <= 'F')) {
|
||||
addr <<= 4;
|
||||
if (*args >= '0' && *args <= '9') addr |= (*args - '0');
|
||||
else if (*args >= 'a' && *args <= 'f') addr |= (*args - 'a' + 10);
|
||||
else if (*args >= 'A' && *args <= 'F') addr |= (*args - 'A' + 10);
|
||||
args++;
|
||||
}
|
||||
while (*args == ' ') args++;
|
||||
if (*args >= '0' && *args <= '9') {
|
||||
len = 0;
|
||||
while (*args >= '0' && *args <= '9') {
|
||||
len = len * 10 + (*args - '0');
|
||||
args++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (len > 512) len = 512;
|
||||
|
||||
uint8_t* ptr = (uint8_t*)addr;
|
||||
printk("Hexdump of 0x%lx (%llu bytes):\n", addr, len);
|
||||
for (uint64_t i = 0; i < len; i += 16) {
|
||||
printk(ANSI_BRIGHT_BLACK "%016lx: " ANSI_RESET, addr + i);
|
||||
for (uint64_t j = 0; j < 16; j++) {
|
||||
if (i + j < len) printk("%02x ", ptr[i + j]);
|
||||
else printk(" ");
|
||||
if (j == 7) printk(" ");
|
||||
}
|
||||
printk(" |");
|
||||
for (uint64_t j = 0; j < 16; j++) {
|
||||
if (i + j < len) {
|
||||
uint8_t b = ptr[i + j];
|
||||
printk("%c", (b >= 32 && b <= 126) ? (char)b : '.');
|
||||
}
|
||||
}
|
||||
printk("|\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void cmd_matrix(void) {
|
||||
tty_clear();
|
||||
printk(ANSI_BRIGHT_GREEN "Press any key to exit Matrix mode...\n" ANSI_RESET);
|
||||
pit_sleep(600);
|
||||
tty_clear();
|
||||
|
||||
int drops[TTY_WIDTH];
|
||||
for (int i = 0; i < TTY_WIDTH; i++) drops[i] = -(i % 25);
|
||||
const char charset[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!@#$%^&*";
|
||||
int charset_len = sizeof(charset) - 1;
|
||||
uint32_t rand_seed = (uint32_t)pit_get_ticks();
|
||||
|
||||
while (!keyboard_has_key()) {
|
||||
for (int x = 0; x < TTY_WIDTH; x += 2) {
|
||||
rand_seed = rand_seed * 1103515245 + 12345;
|
||||
int y = drops[x];
|
||||
if (y >= 0 && y < TTY_HEIGHT) {
|
||||
tty_set_cursor(y, x);
|
||||
printk("\033[92m%c\033[0m", charset[rand_seed % charset_len]);
|
||||
}
|
||||
if (y - 8 >= 0 && y - 8 < TTY_HEIGHT) {
|
||||
tty_set_cursor(y - 8, x);
|
||||
printk(" ");
|
||||
}
|
||||
drops[x]++;
|
||||
if (drops[x] - 8 >= TTY_HEIGHT) drops[x] = 0;
|
||||
}
|
||||
pit_sleep(40);
|
||||
}
|
||||
keyboard_get_key();
|
||||
tty_clear();
|
||||
}
|
||||
|
||||
static void shell_process(const char* cmd) {
|
||||
while (*cmd == ' ') cmd++;
|
||||
if (*cmd == '\0') return;
|
||||
|
||||
char cmd_copy[MAX_COMMAND_LENGTH];
|
||||
strncpy(cmd_copy, cmd, sizeof(cmd_copy) - 1);
|
||||
cmd_copy[sizeof(cmd_copy) - 1] = '\0';
|
||||
|
||||
char* argv[16];
|
||||
int argc = 0;
|
||||
char* token = cmd_copy;
|
||||
|
||||
while (*token) {
|
||||
while (*token == ' ') *token++ = '\0';
|
||||
if (*token == '\0') break;
|
||||
if (argc < 16) argv[argc++] = token;
|
||||
while (*token && *token != ' ') token++;
|
||||
}
|
||||
if (argc == 0) return;
|
||||
|
||||
// 1. LazyBox Applets
|
||||
if (lazybox_has_applet(argv[0])) {
|
||||
lazybox_run_applet(argv[0], argc, argv);
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Builtins
|
||||
if (strcmp(argv[0], "help") == 0) {
|
||||
cmd_help();
|
||||
} else if (strcmp(argv[0], "neofetch") == 0 || strcmp(argv[0], "version") == 0) {
|
||||
cmd_neofetch();
|
||||
} else if (strcmp(argv[0], "calc") == 0) {
|
||||
cmd_calc(cmd + 4);
|
||||
} else if (strcmp(argv[0], "hexdump") == 0) {
|
||||
cmd_hexdump(cmd + 7);
|
||||
} else if (strcmp(argv[0], "matrix") == 0) {
|
||||
cmd_matrix();
|
||||
} else if (strcmp(argv[0], "beep") == 0) {
|
||||
speaker_beep(587, 100);
|
||||
} else if (strcmp(argv[0], "tty") == 0) {
|
||||
if (argc >= 2 && argv[1][0] >= '1' && argv[1][0] <= '4') {
|
||||
tty_switch(argv[1][0] - '1');
|
||||
} else {
|
||||
printk("Active TTY: tty%d (Switch with 'tty 1-4' or Alt+F1-F4)\n", tty_get_current() + 1);
|
||||
}
|
||||
} else if (strcmp(argv[0], "history") == 0) {
|
||||
for (int i = 0; i < history_count; i++) {
|
||||
int idx = (history_head - history_count + i + HISTORY_SIZE) % HISTORY_SIZE;
|
||||
printk(" %2d: %s\n", i + 1, history[idx]);
|
||||
}
|
||||
} else if (strcmp(argv[0], "reboot") == 0) {
|
||||
printk(ANSI_YELLOW "Rebooting...\n" ANSI_RESET);
|
||||
pit_sleep(200);
|
||||
outb(0x64, 0xFE);
|
||||
} else if (strcmp(argv[0], "shutdown") == 0) {
|
||||
printk(ANSI_YELLOW "System halted.\n" ANSI_RESET);
|
||||
while (1) hlt();
|
||||
} else {
|
||||
printk(ANSI_RED "Unknown command: %s. Type 'help' or 'lazybox'.\n" ANSI_RESET, argv[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void shell_run(void) {
|
||||
char cmd_buffer[MAX_COMMAND_LENGTH];
|
||||
size_t cmd_len = 0;
|
||||
size_t cursor_pos = 0;
|
||||
int history_idx = -1;
|
||||
|
||||
const char* prompt = ANSI_BRIGHT_GREEN "sub-os> " ANSI_RESET;
|
||||
|
||||
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) {
|
||||
printk("%s", prompt);
|
||||
cmd_len = 0;
|
||||
cursor_pos = 0;
|
||||
cmd_buffer[0] = '\0';
|
||||
history_idx = -1;
|
||||
|
||||
while (true) {
|
||||
uint16_t key = keyboard_get_key();
|
||||
|
||||
if (key & KEY_SPECIAL_FLAG) {
|
||||
switch (key) {
|
||||
case KEY_LEFT:
|
||||
if (cursor_pos > 0) { cursor_pos--; printk("\033[D"); }
|
||||
break;
|
||||
case KEY_RIGHT:
|
||||
if (cursor_pos < cmd_len) { cursor_pos++; printk("\033[C"); }
|
||||
break;
|
||||
case KEY_HOME:
|
||||
while (cursor_pos > 0) { cursor_pos--; printk("\033[D"); }
|
||||
break;
|
||||
case KEY_END:
|
||||
while (cursor_pos < cmd_len) { cursor_pos++; printk("\033[C"); }
|
||||
break;
|
||||
case KEY_DELETE:
|
||||
if (cursor_pos < cmd_len) {
|
||||
for (size_t i = cursor_pos; i < cmd_len - 1; i++) cmd_buffer[i] = cmd_buffer[i + 1];
|
||||
cmd_len--;
|
||||
cmd_buffer[cmd_len] = '\0';
|
||||
redraw_line(prompt, cmd_buffer, cmd_len, cursor_pos);
|
||||
}
|
||||
break;
|
||||
case KEY_UP:
|
||||
if (history_count > 0) {
|
||||
if (history_idx == -1) history_idx = history_count - 1;
|
||||
else if (history_idx > 0) history_idx--;
|
||||
int actual = (history_head - history_count + history_idx + HISTORY_SIZE) % HISTORY_SIZE;
|
||||
strncpy(cmd_buffer, history[actual], MAX_COMMAND_LENGTH - 1);
|
||||
cmd_buffer[MAX_COMMAND_LENGTH - 1] = '\0';
|
||||
cmd_len = strlen(cmd_buffer);
|
||||
cursor_pos = cmd_len;
|
||||
redraw_line(prompt, cmd_buffer, cmd_len, cursor_pos);
|
||||
}
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
if (history_idx != -1) {
|
||||
if (history_idx < history_count - 1) {
|
||||
history_idx++;
|
||||
int actual = (history_head - history_count + history_idx + HISTORY_SIZE) % HISTORY_SIZE;
|
||||
strncpy(cmd_buffer, history[actual], MAX_COMMAND_LENGTH - 1);
|
||||
cmd_buffer[MAX_COMMAND_LENGTH - 1] = '\0';
|
||||
cmd_len = strlen(cmd_buffer);
|
||||
cursor_pos = cmd_len;
|
||||
} else {
|
||||
history_idx = -1;
|
||||
cmd_buffer[0] = '\0';
|
||||
cmd_len = 0;
|
||||
cursor_pos = 0;
|
||||
}
|
||||
redraw_line(prompt, cmd_buffer, cmd_len, cursor_pos);
|
||||
}
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
char c = (char)(key & 0xFF);
|
||||
|
||||
if (c == 0x03) {
|
||||
printk("^C\n%s", prompt);
|
||||
cmd_len = 0; cursor_pos = 0; cmd_buffer[0] = '\0';
|
||||
continue;
|
||||
}
|
||||
if (c == 0x0C) {
|
||||
tty_clear();
|
||||
printk("%s%s", prompt, cmd_buffer);
|
||||
continue;
|
||||
}
|
||||
if (c == '\b') {
|
||||
if (cursor_pos > 0) {
|
||||
for (size_t i = cursor_pos - 1; i < cmd_len - 1; i++) cmd_buffer[i] = cmd_buffer[i + 1];
|
||||
cmd_len--;
|
||||
cursor_pos--;
|
||||
cmd_buffer[cmd_len] = '\0';
|
||||
redraw_line(prompt, cmd_buffer, cmd_len, cursor_pos);
|
||||
}
|
||||
} else if (c == '\t') {
|
||||
if (cmd_len > 0) {
|
||||
int matches = 0;
|
||||
const char* last = NULL;
|
||||
for (int i = 0; shell_builtins[i] != NULL; i++) {
|
||||
if (strncmp(shell_builtins[i], cmd_buffer, cmd_len) == 0) {
|
||||
matches++;
|
||||
last = shell_builtins[i];
|
||||
}
|
||||
}
|
||||
if (matches == 1 && last) {
|
||||
strncpy(cmd_buffer, last, MAX_COMMAND_LENGTH - 1);
|
||||
cmd_len = strlen(cmd_buffer);
|
||||
cursor_pos = cmd_len;
|
||||
redraw_line(prompt, cmd_buffer, cmd_len, cursor_pos);
|
||||
} else if (matches > 1) {
|
||||
printk("\n");
|
||||
for (int i = 0; shell_builtins[i] != NULL; i++) {
|
||||
if (strncmp(shell_builtins[i], cmd_buffer, cmd_len) == 0) {
|
||||
printk(" %s", shell_builtins[i]);
|
||||
}
|
||||
}
|
||||
printk("\n");
|
||||
redraw_line(prompt, cmd_buffer, cmd_len, cursor_pos);
|
||||
}
|
||||
}
|
||||
} else if (c == '\n' || c == '\r') {
|
||||
printk("\n");
|
||||
cmd_buffer[cmd_len] = '\0';
|
||||
break;
|
||||
} else if ((unsigned char)c >= 32 && (unsigned char)c <= 126) {
|
||||
if (cmd_len < MAX_COMMAND_LENGTH - 1) {
|
||||
for (size_t i = cmd_len; i > cursor_pos; i--) cmd_buffer[i] = cmd_buffer[i - 1];
|
||||
cmd_buffer[cursor_pos] = c;
|
||||
cmd_len++;
|
||||
cursor_pos++;
|
||||
cmd_buffer[cmd_len] = '\0';
|
||||
redraw_line(prompt, cmd_buffer, cmd_len, cursor_pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd_len > 0) {
|
||||
history_add(cmd_buffer);
|
||||
shell_process(cmd_buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user