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) diff --git a/src/userland/cli/help.c b/src/userland/cli/help.c index 20ff62a..8f651e3 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("time - Measure command execution time\n"); printf("\nHint: Use Ctrl+C to force quit any running application.\n"); return 0; } diff --git a/src/userland/cli/time.c b/src/userland/cli/time.c new file mode 100644 index 0000000..96776a1 --- /dev/null +++ b/src/userland/cli/time.c @@ -0,0 +1,141 @@ +// 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 "stdlib.h" +#include "syscall.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: time [args...]\n"); + printf("\n"); + printf("Examples:\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). +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; +}