From 912bd4a20e1a1b018cafb4e4774945ab4a74b56e Mon Sep 17 00:00:00 2001 From: Lluciocc <114759545+Lluciocc@users.noreply.github.com> Date: Mon, 11 May 2026 20:28:16 +0200 Subject: [PATCH] pr: Add ps && hexdump (#26) * Adding hexdump and ps.c * Add hexdump and ps command descriptions to help * Update with missing ; --- src/userland/cli/help.c | 2 + src/userland/cli/hexdump.c | 111 ++++++++++++++ src/userland/cli/ps.c | 299 +++++++++++++++++++++++++++++++++++++ 3 files changed, 412 insertions(+) create mode 100644 src/userland/cli/hexdump.c create mode 100644 src/userland/cli/ps.c diff --git a/src/userland/cli/help.c b/src/userland/cli/help.c index d5f7903..20ff62a 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"); 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