]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
feat: Phase 2 — getrusage syscall, FIONREAD ioctl, libgen.h, misc ulibc
authorTulio A M Mendes <[email protected]>
Sat, 14 Mar 2026 07:54:46 +0000 (04:54 -0300)
committerTulio A M Mendes <[email protected]>
Sat, 14 Mar 2026 07:54:46 +0000 (04:54 -0300)
Kernel:
- Add SYSCALL_GETRUSAGE (137) returning process utime/stime as struct rusage
- Add FIONREAD (0x541B) ioctl to TTY (returns canon_buf available bytes)
- Add FIONREAD (0x541B) ioctl to pipe (returns pipe buffer count)

ulibc:
- sys/resource.h: Add RUSAGE_SELF/CHILDREN, struct rusage, getrusage()
- resource.c: Add getrusage() syscall wrapper
- libgen.h + libgen.c: basename() and dirname() implementations
- misc.c: gethostname() (returns 'adros'), ttyname(), pipe2() wrapper
- syscall.h: Add SYS_GETRUSAGE (137)

Tests: 101/101 smoke, 64/64 host utils, cppcheck clean

include/syscall.h
src/kernel/syscall.c
src/kernel/tty.c
user/ulibc/include/libgen.h [new file with mode: 0644]
user/ulibc/include/sys/resource.h
user/ulibc/include/syscall.h
user/ulibc/src/libgen.c [new file with mode: 0644]
user/ulibc/src/misc.c [new file with mode: 0644]
user/ulibc/src/resource.c

index 2ddca80cea794d2d8f6ed767698fd4d8795514bd..2b998d65e1096cccfc640b0317c7cb0066eb92e2 100644 (file)
@@ -167,6 +167,7 @@ enum {
     SYSCALL_GETPEERNAME  = 134,
     SYSCALL_GETSOCKNAME  = 135,
     SYSCALL_UNAME        = 136,
+    SYSCALL_GETRUSAGE    = 137,
 };
 
 #endif
index 98e606659e2377a51cb94542799849b8a7400d58..64b40bb6410f2a6f4978ca592e99c24a6aceeb5a 100644 (file)
@@ -1644,16 +1644,30 @@ static int pipe_poll(fs_node_t* n, int events) {
     return revents;
 }
 
+static int pipe_ioctl(fs_node_t* n, uint32_t cmd, void* user_arg) {
+    struct pipe_node* pn = (struct pipe_node*)n;
+    if (!pn || !pn->ps) return -EBADF;
+    if (cmd == 0x541B /* FIONREAD */) {
+        if (!user_arg || user_range_ok(user_arg, sizeof(int)) == 0) return -EFAULT;
+        int avail = (int)pn->ps->count;
+        if (copy_to_user(user_arg, &avail, sizeof(avail)) < 0) return -EFAULT;
+        return 0;
+    }
+    return -ENOTTY;
+}
+
 static const struct file_operations pipe_read_fops = {
     .read  = pipe_read,
     .close = pipe_close,
     .poll  = pipe_poll,
+    .ioctl = pipe_ioctl,
 };
 
 static const struct file_operations pipe_write_fops = {
     .write = pipe_write,
     .close = pipe_close,
     .poll  = pipe_poll,
+    .ioctl = pipe_ioctl,
 };
 
 static int pipe_node_create(struct pipe_state* ps, int is_read_end, fs_node_t** out_node) {
@@ -4866,6 +4880,33 @@ static void socket_syscall_dispatch(struct registers* regs, uint32_t syscall_no)
         return;
     }
 
+    if (syscall_no == SYSCALL_GETRUSAGE) {
+        int who = (int)sc_arg0(regs);
+        void* user_buf = (void*)sc_arg1(regs);
+        if (!user_buf || user_range_ok(user_buf, 64) == 0) {
+            sc_ret(regs) = (uint32_t)-EFAULT; return;
+        }
+        /* struct rusage: we fill ru_utime and ru_stime (2 x struct timeval = 16 bytes)
+         * then zero the rest (total 64 bytes to be safe) */
+        struct {
+            uint32_t ru_utime_sec;  uint32_t ru_utime_usec;
+            uint32_t ru_stime_sec;  uint32_t ru_stime_usec;
+            uint32_t padding[12]; /* remaining fields zero */
+        } ru;
+        memset(&ru, 0, sizeof(ru));
+        (void)who; /* RUSAGE_SELF=0, RUSAGE_CHILDREN=-1 — we only report self */
+        uint32_t hz = 100; /* tick rate */
+        ru.ru_utime_sec  = current_process->utime / hz;
+        ru.ru_utime_usec = (current_process->utime % hz) * (1000000 / hz);
+        ru.ru_stime_sec  = current_process->stime / hz;
+        ru.ru_stime_usec = (current_process->stime % hz) * (1000000 / hz);
+        if (copy_to_user(user_buf, &ru, sizeof(ru)) < 0) {
+            sc_ret(regs) = (uint32_t)-EFAULT; return;
+        }
+        sc_ret(regs) = 0;
+        return;
+    }
+
     if (syscall_no == SYSCALL_UNAME) {
         /* struct utsname: 5 fields of 65 bytes each = 325 bytes */
         void* user_buf = (void*)sc_arg0(regs);
index e9e9fc63a93f0d354003a6bd901d509cd9b449c3..91e281c73d1401c553a19a9221a960a4d671e8c4 100644 (file)
@@ -235,6 +235,7 @@ enum {
     TTY_TIOCSPGRP = 0x5410,
     TTY_TIOCGWINSZ = 0x5413,
     TTY_TIOCSWINSZ = 0x5414,
+    TTY_FIONREAD = 0x541B,
 };
 
 int tty_ioctl(uint32_t cmd, void* user_arg) {
@@ -311,6 +312,15 @@ int tty_ioctl(uint32_t cmd, void* user_arg) {
         return 0;
     }
 
+    if (cmd == TTY_FIONREAD) {
+        if (user_range_ok(user_arg, sizeof(int)) == 0) return -EFAULT;
+        uintptr_t flags = spin_lock_irqsave(&tty_lock);
+        int avail = (int)((canon_head - canon_tail) & (TTY_CANON_BUF - 1));
+        spin_unlock_irqrestore(&tty_lock, flags);
+        if (copy_to_user(user_arg, &avail, sizeof(avail)) < 0) return -EFAULT;
+        return 0;
+    }
+
     return -EINVAL;
 }
 
diff --git a/user/ulibc/include/libgen.h b/user/ulibc/include/libgen.h
new file mode 100644 (file)
index 0000000..f666f9e
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef ULIBC_LIBGEN_H
+#define ULIBC_LIBGEN_H
+
+char* basename(char* path);
+char* dirname(char* path);
+
+#endif
index 071211b02b26bf3ed9d3cb5cdc693d29799fcc8d..f4b9793f83d22c3901cbc869f4e5a953a8f16387 100644 (file)
@@ -2,6 +2,7 @@
 #define ULIBC_SYS_RESOURCE_H
 
 #include <stdint.h>
+#include <sys/time.h>
 
 #define RLIMIT_CPU      0
 #define RLIMIT_FSIZE    1
@@ -23,4 +24,28 @@ struct rlimit {
 int getrlimit(int resource, struct rlimit *rlim);
 int setrlimit(int resource, const struct rlimit *rlim);
 
+#define RUSAGE_SELF     0
+#define RUSAGE_CHILDREN (-1)
+
+struct rusage {
+    struct timeval ru_utime;
+    struct timeval ru_stime;
+    long ru_maxrss;
+    long ru_ixrss;
+    long ru_idrss;
+    long ru_isrss;
+    long ru_minflt;
+    long ru_majflt;
+    long ru_nswap;
+    long ru_inblock;
+    long ru_oublock;
+    long ru_msgsnd;
+    long ru_msgrcv;
+    long ru_nsignals;
+    long ru_nvcsw;
+    long ru_nivcsw;
+};
+
+int getrusage(int who, struct rusage *usage);
+
 #endif
index e47d199c9885741e66a71be95f3640ef94e7eced..5c517ebcdc50e3965e684279edb23aea44ae46bd 100644 (file)
@@ -91,6 +91,7 @@ enum {
     SYS_GETPEERNAME = 134,
     SYS_GETSOCKNAME = 135,
     SYS_UNAME = 136,
+    SYS_GETRUSAGE = 137,
 };
 
 /* Raw syscall wrappers — up to 5 args via INT 0x80 */
diff --git a/user/ulibc/src/libgen.c b/user/ulibc/src/libgen.c
new file mode 100644 (file)
index 0000000..0c63a47
--- /dev/null
@@ -0,0 +1,24 @@
+#include "libgen.h"
+#include "string.h"
+
+char* basename(char* path) {
+    if (!path || !*path) return ".";
+    size_t len = strlen(path);
+    /* Remove trailing slashes */
+    while (len > 1 && path[len - 1] == '/') path[--len] = '\0';
+    char* p = strrchr(path, '/');
+    return p ? p + 1 : path;
+}
+
+char* dirname(char* path) {
+    static char dot[] = ".";
+    if (!path || !*path) return dot;
+    size_t len = strlen(path);
+    /* Remove trailing slashes */
+    while (len > 1 && path[len - 1] == '/') path[--len] = '\0';
+    char* p = strrchr(path, '/');
+    if (!p) return dot;
+    if (p == path) { path[1] = '\0'; return path; }
+    *p = '\0';
+    return path;
+}
diff --git a/user/ulibc/src/misc.c b/user/ulibc/src/misc.c
new file mode 100644 (file)
index 0000000..0f70fe2
--- /dev/null
@@ -0,0 +1,26 @@
+#include "unistd.h"
+#include "string.h"
+#include "syscall.h"
+#include "errno.h"
+
+int gethostname(char* name, size_t len) {
+    if (!name || len == 0) { errno = EINVAL; return -1; }
+    const char* hostname = "adros";
+    size_t hlen = strlen(hostname);
+    if (hlen + 1 > len) { errno = ENAMETOOLONG; return -1; }
+    memcpy(name, hostname, hlen + 1);
+    return 0;
+}
+
+static char ttyname_buf[32];
+
+char* ttyname(int fd) {
+    if (!isatty(fd)) return (char*)0;
+    strcpy(ttyname_buf, "/dev/tty");
+    return ttyname_buf;
+}
+
+int pipe2(int fds[2], int flags) {
+    int r = _syscall2(SYS_PIPE2, (int)fds, flags);
+    return __syscall_ret(r);
+}
index 0236b00d9c55b996d6778a3889ebb039fabb32d9..1dd6aba87d8e00d85be2416e429de7cb9792b27f 100644 (file)
@@ -9,3 +9,7 @@ int getrlimit(int resource, struct rlimit *rlim) {
 int setrlimit(int resource, const struct rlimit *rlim) {
     return __syscall_ret(_syscall2(SYS_SETRLIMIT, resource, (int)rlim));
 }
+
+int getrusage(int who, struct rusage *usage) {
+    return __syscall_ret(_syscall2(SYS_GETRUSAGE, who, (int)usage));
+}