From ba281ea3f32a01f07928a0189a889a16cf4a889e Mon Sep 17 00:00:00 2001 From: Lluciocc <114759545+Lluciocc@users.noreply.github.com> Date: Mon, 11 May 2026 19:32:26 +0200 Subject: [PATCH 1/9] Adding hexdump and ps.c --- src/userland/cli/hexdump.c | 111 ++++++++++++++ src/userland/cli/ps.c | 299 +++++++++++++++++++++++++++++++++++++ 2 files changed, 410 insertions(+) create mode 100644 src/userland/cli/hexdump.c create mode 100644 src/userland/cli/ps.c diff --git a/src/userland/cli/hexdump.c b/src/userland/cli/hexdump.c new file mode 100644 index 0000000..f722d63 --- /dev/null +++ b/src/userland/cli/hexdump.c @@ -0,0 +1,111 @@ +// Copyright (c) 2023-2026 Chris (boreddevnl) +// This software is released under the GNU General Public License v3.0. See LICENSE file for details. +// This header needs to maintain in any file it is present in, as per the GPL license terms. +// BOREDOS_APP_DESC: Display file contents in hexadecimal. + +#include "syscall.h" +#include "stdlib.h" +#include "string.h" +#include "stdio.h" + +#define BYTES_PER_LINE 16 + +static int sc_strcmp(const char *a, const char *b) { + while (*a && *a == *b) { + a++; + b++; + } + + return (unsigned char)*a - (unsigned char)*b; +} + +static void print_usage(void) { + printf("Usage: hexdump \n"); + printf("\n"); + printf("Display file contents in hexadecimal.\n"); +} + +static void print_hex_byte(unsigned char b) { + const char *hex = "0123456789ABCDEF"; + + putchar(hex[(b >> 4) & 0xF]); + putchar(hex[b & 0xF]); +} + +static void print_hex32(unsigned int v) { + const char *hex = "0123456789ABCDEF"; + + for (int i = 7; i >= 0; i--) { + putchar(hex[(v >> (i * 4)) & 0xF]); + } +} + +int main(int argc, char **argv) { + int fd; + int offset = 0; + + unsigned char buf[BYTES_PER_LINE]; + + if (argc < 2) { + print_usage(); + return 1; + } + + if (sc_strcmp(argv[1], "-h") == 0 || + sc_strcmp(argv[1], "--help") == 0) { + print_usage(); + return 0; + } + + fd = sys_open(argv[1], "r"); + + if (fd < 0) { + printf("hexdump: cannot open '%s'\n", argv[1]); + return 1; + } + + while (1) { + int bytes = sys_read(fd, buf, BYTES_PER_LINE); + + if (bytes <= 0) + break; + + // Offset + print_hex32(offset); + printf(" "); + + // Hex bytes + for (int i = 0; i < BYTES_PER_LINE; i++) { + if (i < bytes) { + print_hex_byte(buf[i]); + } else { + printf(" "); + } + + printf(" "); + + if (i == 7) + printf(" "); + } + + printf(" |"); + + // ASCII preview + for (int i = 0; i < bytes; i++) { + unsigned char c = buf[i]; + + if (c >= 32 && c <= 126) + putchar(c); + else + putchar('.'); + } + + printf("|\n"); + + offset += bytes; + } + + sys_close(fd); + + return 0; +} \ No newline at end of file diff --git a/src/userland/cli/ps.c b/src/userland/cli/ps.c new file mode 100644 index 0000000..f34554d --- /dev/null +++ b/src/userland/cli/ps.c @@ -0,0 +1,299 @@ +// Copyright (c) 2023-2026 Chris (boreddevnl) +// This software is released under the GNU General Public License v3.0. See LICENSE file for details. +// This header needs to maintain in any file it is present in, as per the GPL license terms. +// BOREDOS_APP_DESC: List running processes. + +#include "../libc/syscall.h" +#include "../libc/stdlib.h" +#include "../libc/string.h" +#include "../libc/stdio.h" + +#define MAX_PROC_ENTRIES 64 + +static int sc_strcmp(const char *a, const char *b) { + while (*a && *a == *b) { + a++; + b++; + } + return (unsigned char)*a - (unsigned char)*b; +} + +static int is_numeric(const char *s) { + int i = 0; + + if (!s || !s[0]) + return 0; + + while (s[i]) { + if (s[i] < '0' || s[i] > '9') + return 0; + i++; + } + + return 1; +} + +static void print_spaces(int count) { + for (int i = 0; i < count; i++) + printf(" "); +} + +static void print_padded(const char *s, int width) { + int len; + + if (!s) + s = ""; + + printf("%s", s); + + len = (int)strlen(s); + + if (len < width) + print_spaces(width - len); + else + printf(" "); +} + +static int find_value(const char *buf, const char *key) { + char *p = (char*)buf; + int key_len = strlen(key); + + while (*p) { + if (memcmp(p, key, key_len) == 0 && p[key_len] == ':') { + p += key_len + 1; + + while (*p == ' ' || *p == '\t') + p++; + + return atoi(p); + } + + while (*p && *p != '\n') + p++; + + if (*p == '\n') + p++; + } + + return 0; +} + +static void find_string(const char *buf, + const char *key, + char *out, + int max_len) { + char *p = (char*)buf; + int key_len = strlen(key); + + out[0] = 0; + + while (*p) { + if (memcmp(p, key, key_len) == 0 && p[key_len] == ':') { + int i = 0; + + p += key_len + 1; + + while (*p == ' ' || *p == '\t') + p++; + + while (*p && + *p != '\n' && + *p != '\r' && + i < max_len - 1) { + out[i++] = *p++; + } + + out[i] = 0; + return; + } + + while (*p && *p != '\n') + p++; + + if (*p == '\n') + p++; + } +} + +static int read_file_to_buf(const char *path, + char *buf, + int max_len) { + int fd; + int bytes; + + fd = sys_open(path, "r"); + + if (fd < 0) + return -1; + + bytes = sys_read(fd, buf, max_len - 1); + + sys_close(fd); + + if (bytes < 0) + return -1; + + buf[bytes] = 0; + + return bytes; +} + +static void format_mem(int kb, char *out) { + char tmp[32]; + + if (kb < 1024) { + itoa(kb, tmp); + + strcpy(out, tmp); + strcat(out, " KB"); + } else { + int mb = kb / 1024; + int frac = ((kb % 1024) * 10) / 1024; + + itoa(mb, tmp); + + strcpy(out, tmp); + strcat(out, "."); + + itoa(frac, tmp); + strcat(out, tmp); + strcat(out, " MiB"); + } +} + +static void print_usage(void) { + printf("Usage: ps [options]\n"); + printf("\n"); + printf("Options:\n"); + printf(" -a Show all processes\n"); + printf(" -i Include idle tasks\n"); + printf(" -m Show memory usage\n"); + printf(" -t Show scheduler ticks\n"); + printf(" -p PID Show only one process\n"); + printf(" -h Show this help\n"); +} + +static void print_header(int show_mem, + int show_ticks, + int show_idle) { + print_padded("PID", 8); + print_padded("NAME", 22); + + if (show_mem) + print_padded("MEMORY", 14); + + if (show_ticks) + print_padded("TICKS", 12); + + if (show_idle) + print_padded("IDLE", 8); + + printf("\n"); +} + +int main(int argc, char **argv) { + int show_mem = 0; + int show_ticks = 0; + int include_idle = 0; + int show_idle_col = 0; + int filter_pid = -1; + + FAT32_FileInfo entries[MAX_PROC_ENTRIES]; + + for (int i = 1; i < argc; i++) { + if (sc_strcmp(argv[i], "-m") == 0) { + show_mem = 1; + } else if (sc_strcmp(argv[i], "-t") == 0) { + show_ticks = 1; + } else if (sc_strcmp(argv[i], "-a") == 0) { + include_idle = 1; + show_idle_col = 1; + } else if (sc_strcmp(argv[i], "-i") == 0) { + include_idle = 1; + show_idle_col = 1; + } else if (sc_strcmp(argv[i], "-p") == 0 && i + 1 < argc) { + filter_pid = atoi(argv[++i]); + } else if (sc_strcmp(argv[i], "-h") == 0) { + print_usage(); + return 0; + } else { + print_usage(); + return 1; + } + } + + int count = sys_list("/proc", entries, MAX_PROC_ENTRIES); + + if (count < 0) { + printf("ps: failed to read /proc\n"); + return 1; + } + + print_header(show_mem, show_ticks, show_idle_col); + + for (int i = 0; i < count; i++) { + char path[96]; + char buf[512]; + char name[64]; + char mem_str[32]; + char tmp[32]; + + int pid; + int memory_kb; + int ticks; + int idle; + + if (!entries[i].is_directory) + continue; + + if (!is_numeric(entries[i].name)) + continue; + + pid = atoi(entries[i].name); + + if (filter_pid >= 0 && pid != filter_pid) + continue; + + strcpy(path, "/proc/"); + strcat(path, entries[i].name); + strcat(path, "/status"); + + if (read_file_to_buf(path, buf, sizeof(buf)) <= 0) + continue; + + find_string(buf, "Name", name, sizeof(name)); + + memory_kb = find_value(buf, "Memory"); + ticks = find_value(buf, "Ticks"); + idle = find_value(buf, "Idle"); + + if (idle && !include_idle) + continue; + + itoa(pid, tmp); + print_padded(tmp, 8); + + if (!name[0]) + strcpy(name, "Unknown"); + + print_padded(name, 22); + + if (show_mem) { + format_mem(memory_kb, mem_str); + print_padded(mem_str, 14); + } + + if (show_ticks) { + itoa(ticks, tmp); + print_padded(tmp, 12); + } + + if (show_idle_col) { + print_padded(idle ? "yes" : "no", 8); + } + + printf("\n"); + } + + return 0; +} \ No newline at end of file From f94384e572f0f83e63a1ae291d24f55f51394a45 Mon Sep 17 00:00:00 2001 From: Lluciocc <114759545+Lluciocc@users.noreply.github.com> Date: Mon, 11 May 2026 19:36:27 +0200 Subject: [PATCH 2/9] Add hexdump and ps command descriptions to help --- src/userland/cli/help.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/userland/cli/help.c b/src/userland/cli/help.c index d5f7903..490a1eb 100644 --- a/src/userland/cli/help.c +++ b/src/userland/cli/help.c @@ -25,6 +25,8 @@ int main(int argc, char **argv) { printf("date - Print current date and time\n"); printf("uptime - Print system uptime\n"); printf("meminfo - Print memory information\n"); + printf("hexdump - Display file contents in hexadecimal.\n"); + printf("ps [options] - List running processes\n") printf("lsblk - List block devices and partitions\n"); printf("cowsay [msg] - Fun cow says something\n"); printf("beep - Make a beep sound\n"); From fe1ba182d95676423beef510d129ed655f84b82b Mon Sep 17 00:00:00 2001 From: Lluciocc <114759545+Lluciocc@users.noreply.github.com> Date: Mon, 11 May 2026 20:25:35 +0200 Subject: [PATCH 3/9] Update with missing ; --- src/userland/cli/help.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/userland/cli/help.c b/src/userland/cli/help.c index 490a1eb..20ff62a 100644 --- a/src/userland/cli/help.c +++ b/src/userland/cli/help.c @@ -26,7 +26,7 @@ int main(int argc, char **argv) { printf("uptime - Print system uptime\n"); printf("meminfo - Print memory information\n"); printf("hexdump - Display file contents in hexadecimal.\n"); - printf("ps [options] - List running processes\n") + printf("ps [options] - List running processes\n"); printf("lsblk - List block devices and partitions\n"); printf("cowsay [msg] - Fun cow says something\n"); printf("beep - Make a beep sound\n"); From 70ab1837c2cd3db216c3f5ffb3d02ecf054743cc Mon Sep 17 00:00:00 2001 From: Lluciocc <114759545+Lluciocc@users.noreply.github.com> Date: Tue, 12 May 2026 09:04:27 +0200 Subject: [PATCH 4/9] Add ptime --- src/userland/cli/ptime.c | 140 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 src/userland/cli/ptime.c diff --git a/src/userland/cli/ptime.c b/src/userland/cli/ptime.c new file mode 100644 index 0000000..10a411e --- /dev/null +++ b/src/userland/cli/ptime.c @@ -0,0 +1,140 @@ +// Copyright (c) 2023-2026 Chris (boreddevnl) +// This software is released under the GNU General Public License v3.0. See LICENSE file for details. +// This header needs to maintain in any file it is present in, as per the GPL license terms. + +#include "../libc/stdlib.h" + +#define CMDLINE_MAX 512 + +static int sc_strcmp(const char *a, const char *b) { + while (*a && *a == *b) { + a++; + b++; + } + + return (unsigned char)*a - (unsigned char)*b; +} + +static int has_slash(const char *s) { + while (s && *s) { + if (*s == '/') + return 1; + s++; + } + + return 0; +} + +static int ends_with_elf(const char *s) { + int len; + + if (!s) + return 0; + + len = strlen(s); + + if (len < 4) + return 0; + + return sc_strcmp(s + len - 4, ".elf") == 0; +} + +static void print_usage(void) { + printf("Usage: ptime [args...]\n"); + printf("\n"); + printf("Examples:\n"); + printf(" ptime ls\n"); + printf(" ptime hexdump file.txt\n"); + printf(" ptime /bin/hexdump.elf file.txt\n"); +} + +// Read the system uptime in milliseconds by reading /proc/uptime and parsing the first number (seconds). +static unsigned long long read_uptime_ms(void) { + char buf[64]; + int fd; + int bytes; + int seconds; + + fd = sys_open("/proc/uptime", "r"); + + if (fd < 0) + return 0; + + bytes = sys_read(fd, buf, sizeof(buf) - 1); + + sys_close(fd); + + if (bytes <= 0) + return 0; + + buf[bytes] = 0; + + seconds = atoi(buf); + + return (unsigned long long)seconds * 1000ULL; +} + +// Build the command line for execution +// If the first argument contains a slash, use it as is. Otherwise, prepend "/bin/" and append ".elf" if it doesn't already end with ".elf". +static void build_command_line(int argc, char **argv, char *out) { + int i; + + out[0] = 0; + + if (has_slash(argv[1])) { + strcat(out, argv[1]); + } else { + strcat(out, "/bin/"); + strcat(out, argv[1]); + + if (!ends_with_elf(argv[1])) { + strcat(out, ".elf"); + } + } + + for (i = 2; i < argc; i++) { + strcat(out, " "); + strcat(out, argv[i]); + } +} + +int main(int argc, char **argv) { + char cmdline[CMDLINE_MAX]; + + unsigned long long start; + unsigned long long end; + unsigned long long elapsed; + + int ret; + + if (argc < 2) { + print_usage(); + return 1; + } + + if (sc_strcmp(argv[1], "-h") == 0 || + sc_strcmp(argv[1], "--help") == 0) { + print_usage(); + return 0; + } + + build_command_line(argc, argv, cmdline); + + start = read_uptime_ms(); + + ret = system(cmdline); + + end = read_uptime_ms(); + + if (end >= start) + elapsed = end - start; + else + elapsed = 0; + + printf("\n"); + printf("Command: %s\n", cmdline); + printf("Exit code: %d\n", ret); + printf("Elapsed: %llu ms\n", elapsed); + + return ret; +} From 11593b1b2384ae1199dc1fbe743ddc5499d3ba7d Mon Sep 17 00:00:00 2001 From: Lluciocc <114759545+Lluciocc@users.noreply.github.com> Date: Tue, 12 May 2026 09:06:05 +0200 Subject: [PATCH 5/9] Add ptime command help message --- src/userland/cli/help.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/userland/cli/help.c b/src/userland/cli/help.c index 20ff62a..83ee46b 100644 --- a/src/userland/cli/help.c +++ b/src/userland/cli/help.c @@ -38,6 +38,7 @@ int main(int argc, char **argv) { printf("clear - Clear the screen\n"); printf("exit - Exit the terminal\n"); printf("net - Network tools\n"); + printf("ptime - Measure command execution time\n"); printf("\nHint: Use Ctrl+C to force quit any running application.\n"); return 0; } From 0075493fbaa5e22f92a6bbb88a74ed5a09527c40 Mon Sep 17 00:00:00 2001 From: Lluciocc <114759545+Lluciocc@users.noreply.github.com> Date: Tue, 12 May 2026 18:31:25 +0200 Subject: [PATCH 6/9] Rename object files in Makefile to include 'libc_' prefix --- src/userland/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/userland/Makefile b/src/userland/Makefile index 5b80484..a0d6906 100644 --- a/src/userland/Makefile +++ b/src/userland/Makefile @@ -20,7 +20,7 @@ $(if $(filter doom,$1),$(APP_METADATA_SOURCE_DOOM),$(if $(filter lua,$1),$(APP_M endef LIBC_SOURCES = $(wildcard libc/*.c) -LIBC_OBJS = $(patsubst libc/%.c, $(BIN_DIR)/%.o, $(LIBC_SOURCES)) $(BIN_DIR)/crt0.o $(BIN_DIR)/libwidget.o $(BIN_DIR)/stb_image.o +LIBC_OBJS = $(patsubst libc/%.c, $(BIN_DIR)/libc_%.o, $(LIBC_SOURCES)) $(BIN_DIR)/crt0.o $(BIN_DIR)/libwidget.o $(BIN_DIR)/stb_image.o VPATH = cli gui sys games libc net cli/third_party vpath %.c cli gui sys games libc net cli/third_party @@ -46,7 +46,7 @@ $(BIN_DIR): $(BIN_DIR)/crt0.o: crt0.asm $(AS) -f elf64 $< -o $@ -$(BIN_DIR)/%.o: libc/%.c | $(BIN_DIR) +$(BIN_DIR)/libc_%.o: libc/%.c | $(BIN_DIR) $(CC) $(CFLAGS) -c $< -o $@ $(BIN_DIR)/libwidget.o: ../wm/libwidget.c | $(BIN_DIR) From c275da6145d4d8e1a7e7ee8742663115c9dc0230 Mon Sep 17 00:00:00 2001 From: Lluciocc <114759545+Lluciocc@users.noreply.github.com> Date: Tue, 12 May 2026 18:32:36 +0200 Subject: [PATCH 7/9] Rename ptime to time --- src/userland/cli/{ptime.c => time.c} | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) rename src/userland/cli/{ptime.c => time.c} (94%) diff --git a/src/userland/cli/ptime.c b/src/userland/cli/time.c similarity index 94% rename from src/userland/cli/ptime.c rename to src/userland/cli/time.c index 10a411e..9a8ffaa 100644 --- a/src/userland/cli/ptime.c +++ b/src/userland/cli/time.c @@ -40,12 +40,12 @@ static int ends_with_elf(const char *s) { } static void print_usage(void) { - printf("Usage: ptime [args...]\n"); + printf("Usage: time [args...]\n"); printf("\n"); printf("Examples:\n"); - printf(" ptime ls\n"); - printf(" ptime hexdump file.txt\n"); - printf(" ptime /bin/hexdump.elf file.txt\n"); + printf(" time ls\n"); + printf(" time hexdump file.txt\n"); + printf(" time /bin/hexdump.elf file.txt\n"); } // Read the system uptime in milliseconds by reading /proc/uptime and parsing the first number (seconds). From 078ad437a5d38939e26633a09334b3ac273ad00b Mon Sep 17 00:00:00 2001 From: Lluciocc <114759545+Lluciocc@users.noreply.github.com> Date: Tue, 12 May 2026 18:33:08 +0200 Subject: [PATCH 8/9] Rename 'ptime' command to 'time' in help text --- src/userland/cli/help.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/userland/cli/help.c b/src/userland/cli/help.c index 83ee46b..8f651e3 100644 --- a/src/userland/cli/help.c +++ b/src/userland/cli/help.c @@ -38,7 +38,7 @@ int main(int argc, char **argv) { printf("clear - Clear the screen\n"); printf("exit - Exit the terminal\n"); printf("net - Network tools\n"); - printf("ptime - Measure command execution time\n"); + printf("time - Measure command execution time\n"); printf("\nHint: Use Ctrl+C to force quit any running application.\n"); return 0; } From 2580700ff928e2bceb68c88848530dae882c66d1 Mon Sep 17 00:00:00 2001 From: Lluciocc <114759545+Lluciocc@users.noreply.github.com> Date: Tue, 12 May 2026 18:40:27 +0200 Subject: [PATCH 9/9] Update time.c --- src/userland/cli/time.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/userland/cli/time.c b/src/userland/cli/time.c index 9a8ffaa..96776a1 100644 --- a/src/userland/cli/time.c +++ b/src/userland/cli/time.c @@ -2,7 +2,8 @@ // This software is released under the GNU General Public License v3.0. See LICENSE file for details. // This header needs to maintain in any file it is present in, as per the GPL license terms. -#include "../libc/stdlib.h" +#include "stdlib.h" +#include "syscall.h" #define CMDLINE_MAX 512