diff --git a/src/core/man_entries.h b/src/core/man_entries.h index 8ef4dfd..d578763 100644 --- a/src/core/man_entries.h +++ b/src/core/man_entries.h @@ -56,6 +56,7 @@ void create_man_entries(void) { write_man_file("cc", "CC - C Compiler\n\nUsage: cc \n\nThe BoredOS C Compiler. Compiles C source files into executables. (execute these with ./>file<)"); write_man_file("crash", "CRASH - Trigger kernel exception\n\nUsage: crash\n\nIntentionally triggers a null pointer dereference to test handlers."); write_man_file("sysfetch", "SYSFETCH - Show OS information\n\nUsage: sysfetch\n\nDisplays system information in a neofetch-like layout. Configurable via /Library/conf/sysfetch.cfg."); + write_man_file("uname", "UNAME - Print system information\n\nUsage: uname [-amnoprsv]\n\nOptions:\n -a Print all information\n -s Kernel name\n -n Node name\n -r Kernel release\n -v Kernel build date and time\n -m Machine hardware name\n -p Processor type\n -o Operating system name"); write_man_file("meminfo", "MEMINFO - Memory usage stats\n\nUsage: meminfo\n\nDisplays current physical and virtual memory allocation statistics."); write_man_file("pci_list", "PCI_LIST - Scan PCI bus\n\nUsage: pci_list\n\nScans the PCI bus and lists all detected hardware devices."); write_man_file("reboot", "REBOOT - Restart system\n\nUsage: reboot\n\nRestarts the computer immediately."); diff --git a/src/userland/cli/uname.c b/src/userland/cli/uname.c new file mode 100644 index 0000000..d2aaf65 --- /dev/null +++ b/src/userland/cli/uname.c @@ -0,0 +1,236 @@ +// 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 +#include +#include + +static void str_copy(char *dst, const char *src, int max_len) { + int i = 0; + if (!dst || max_len <= 0) return; + if (!src) { dst[0] = 0; return; } + while (i < max_len - 1 && src[i]) { + dst[i] = src[i]; + i++; + } + dst[i] = 0; +} + +static bool starts_with(const char *s, const char *prefix) { + if (!s || !prefix) return false; + while (*prefix) { + if (*s != *prefix) return false; + s++; prefix++; + } + return true; +} + +static void trim_end(char *s) { + int len; + if (!s) return; + len = (int)strlen(s); + while (len > 0) { + char c = s[len - 1]; + if (c == '\n' || c == '\r' || c == ' ' || c == '\t') { + s[len - 1] = 0; + len--; + } else { + break; + } + } +} + +static const char *trim_start(const char *s) { + if (!s) return ""; + while (*s == ' ' || *s == '\t') s++; + return s; +} + +static void copy_range(char *dst, const char *start, int len, int max_len) { + int i; + if (!dst || max_len <= 0) return; + if (!start || len <= 0) { dst[0] = 0; return; } + if (len > max_len - 1) len = max_len - 1; + for (i = 0; i < len; i++) dst[i] = start[i]; + dst[len] = 0; + trim_end(dst); +} + +static void copy_line(const char *start, char *out, int out_len) { + int i = 0; + if (!start || !out || out_len <= 0) return; + while (start[i] && start[i] != '\n' && start[i] != '\r' && i < out_len - 1) { + out[i] = start[i]; + i++; + } + out[i] = 0; + trim_end(out); +} + +static int read_file_to_buf(const char *path, char *buf, int max_len) { + int fd; + int bytes; + if (!buf || max_len <= 0) return -1; + 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 parse_version_info(const char *vbuf, + char *os_name, int os_name_len, + char *kernel_name, int kernel_name_len, + char *kernel_ver, int kernel_ver_len, + char *build_str, int build_str_len) { + char line1[256] = {0}; + char line2[256] = {0}; + char line3[256] = {0}; + const char *l2; + const char *l3; + const char *end; + + if (!vbuf || !vbuf[0]) return; + + copy_line(vbuf, line1, sizeof(line1)); + l2 = strchr(vbuf, '\n'); + if (l2) { + l2++; + copy_line(l2, line2, sizeof(line2)); + l3 = strchr(l2, '\n'); + if (l3) { + l3++; + copy_line(l3, line3, sizeof(line3)); + } + } + + if (line1[0]) { + end = strstr(line1, " ["); + if (!end) end = strstr(line1, " Version"); + if (!end) end = line1 + (int)strlen(line1); + copy_range(os_name, line1, (int)(end - line1), os_name_len); + } + + if (line2[0]) { + const char *p = line2; + if (starts_with(p, "Kernel:")) { + p += 7; + if (*p == ' ') p++; + } + p = trim_start(p); + if (*p) { + const char *t = p; + while (*t && *t != ' ') t++; + copy_range(kernel_name, p, (int)(t - p), kernel_name_len); + while (*t == ' ') t++; + if (*t) copy_range(kernel_ver, t, (int)strlen(t), kernel_ver_len); + } + } + + if (line3[0]) { + const char *p = line3; + if (starts_with(p, "Build:")) { + p += 6; + if (*p == ' ') p++; + } + p = trim_start(p); + if (*p) copy_range(build_str, p, (int)strlen(p), build_str_len); + } +} + +static void parse_cpu_model(const char *buf, char *out, int out_len) { + const char *p; + const char *colon; + const char *end; + if (!buf || !out || out_len <= 0) return; + p = strstr(buf, "model name"); + if (!p) return; + colon = strchr(p, ':'); + if (!colon) return; + colon++; + colon = trim_start(colon); + end = colon; + while (*end && *end != '\n' && *end != '\r') end++; + copy_range(out, colon, (int)(end - colon), out_len); +} + +static void print_usage(void) { + printf("Usage: uname [-amnoprsv]\n"); +} + +static void print_field(const char *value, bool *first) { + if (!value || !value[0]) value = "Unknown"; + if (!*first) printf(" "); + printf("%s", value); + *first = false; +} + +int main(int argc, char **argv) { + bool want_s = false; + bool want_n = false; + bool want_r = false; + bool want_v = false; + bool want_m = false; + bool want_p = false; + bool want_o = false; + bool any_flags = false; + + for (int i = 1; i < argc; i++) { + const char *arg = argv[i]; + if (!arg || arg[0] != '-' || arg[1] == 0) { + print_usage(); + return 1; + } + for (int j = 1; arg[j]; j++) { + char c = arg[j]; + if (c == 'a') { + want_s = want_n = want_r = want_v = want_m = want_p = want_o = true; + any_flags = true; + } else if (c == 's') { want_s = true; any_flags = true; } + else if (c == 'n') { want_n = true; any_flags = true; } + else if (c == 'r') { want_r = true; any_flags = true; } + else if (c == 'v') { want_v = true; any_flags = true; } + else if (c == 'm') { want_m = true; any_flags = true; } + else if (c == 'p') { want_p = true; any_flags = true; } + else if (c == 'o') { want_o = true; any_flags = true; } + else { print_usage(); return 1; } + } + } + + if (!any_flags) want_s = true; + + char vbuf[1024] = {0}; + char cpubuf[2048] = {0}; + char os_name[64] = "Unknown"; + char kernel_name[64] = "Unknown"; + char kernel_ver[64] = "Unknown"; + char build_str[64] = "Unknown"; + char processor[128] = {0}; + + if (read_file_to_buf("/proc/version", vbuf, sizeof(vbuf)) > 0) { + parse_version_info(vbuf, os_name, sizeof(os_name), kernel_name, sizeof(kernel_name), + kernel_ver, sizeof(kernel_ver), build_str, sizeof(build_str)); + } + + if (read_file_to_buf("/proc/cpuinfo", cpubuf, sizeof(cpubuf)) > 0) { + parse_cpu_model(cpubuf, processor, sizeof(processor)); + } + + const char *nodename = "boredos"; + const char *machine = "x86_64"; + if (!processor[0]) str_copy(processor, machine, sizeof(processor)); + + bool first = true; + if (want_s) print_field(kernel_name, &first); + if (want_n) print_field(nodename, &first); + if (want_r) print_field(kernel_ver, &first); + if (want_v) print_field(build_str, &first); + if (want_m) print_field(machine, &first); + if (want_p) print_field(processor, &first); + if (want_o) print_field(os_name, &first); + printf("\n"); + + return 0; +}