]> 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 47236c28849370bafcd01ca08998ab30c503cf63..6570cd1f19f887d4f4b55c0490fcfa3b730ca181 100644 (file)
@@ -176,6 +176,7 @@ enum {
     SYSCALL_GETPEERNAME  = 134,
     SYSCALL_GETSOCKNAME  = 135,
     SYSCALL_UNAME        = 136,
+    SYSCALL_GETRUSAGE    = 137,
 };
 
 #endif
index f68019772db2e6d0f5224ac41b6e7c6389c9a871..f7bfcbb61aec313a87f33ea8040c08f77bbf8e86 100644 (file)
@@ -1653,16 +1653,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) {
@@ -4875,6 +4889,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 139d09964b6d2b581aae3dfd58ae57bcce914d94..074ba08fc161b37a44d82a3f66bd5dbfd8dc7edd 100644 (file)
@@ -244,6 +244,7 @@ enum {
     TTY_TIOCSPGRP = 0x5410,
     TTY_TIOCGWINSZ = 0x5413,
     TTY_TIOCSWINSZ = 0x5414,
+    TTY_FIONREAD = 0x541B,
 };
 
 int tty_ioctl(uint32_t cmd, void* user_arg) {
@@ -320,6 +321,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..1d41bd9
--- /dev/null
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2018, Tulio A M Mendes <[email protected]>
+ * All rights reserved.
+ * See LICENSE for details.
+ *
+ * Source: https://github.com/tadryanom/AdrOS
+ */
+
+#ifndef ULIBC_LIBGEN_H
+#define ULIBC_LIBGEN_H
+
+char* basename(char* path);
+char* dirname(char* path);
+
+#endif
index 7dfc7ab4f57b18a6d4166ef77b027da7197f451e..c85c4581dd06f7f58bf097de4e221e6af5f3d037 100644 (file)
@@ -11,6 +11,7 @@
 #define ULIBC_SYS_RESOURCE_H
 
 #include <stdint.h>
+#include <sys/time.h>
 
 #define RLIMIT_CPU      0
 #define RLIMIT_FSIZE    1
@@ -32,4 +33,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 cc79ec233c028e3aab86bfe3768364aaddcc4b37..c02ff6b09f3f4435997042f7a27286c4d7e9b0d3 100644 (file)
@@ -100,6 +100,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..b2b8f5c
--- /dev/null
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2018, Tulio A M Mendes <[email protected]>
+ * All rights reserved.
+ * See LICENSE for details.
+ *
+ * Source: https://github.com/tadryanom/AdrOS
+ */
+
+#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..7041b52
--- /dev/null
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2018, Tulio A M Mendes <[email protected]>
+ * All rights reserved.
+ * See LICENSE for details.
+ *
+ * Source: https://github.com/tadryanom/AdrOS
+ */
+
+#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 81c355e9af2306f892b48f00f5d49f181fc5c0a8..e9659ca3ed62bc46d06d4c8fa035f76019bf743a 100644 (file)
@@ -18,3 +18,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));
+}