Viewing: posix_stubs.c
📄 posix_stubs.c (Read Only) ⬅ To go back
/*
 * posix_stubs.c — POSIX syscall wrappers for AdrOS/newlib (i686)
 *
 * These functions provide the POSIX API layer on top of AdrOS kernel syscalls.
 * Each function issues an AdrOS syscall via INT 0x80.
 *
 * AdrOS syscall convention (i386):
 *   EAX = syscall number
 *   EBX = arg1, ECX = arg2, EDX = arg3, ESI = arg4, EDI = arg5
 *   Return value in EAX (negative = -errno)
 */

#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <termios.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <pwd.h>
#include <sys/ioctl.h>
#include <dirent.h>
#include <stdint.h>
#include <stdarg.h>
#include <stdlib.h>
#include <fcntl.h>
#include <regex.h>
#include <fnmatch.h>
#include <time.h>

/* ---- AdrOS syscall numbers (must match include/syscall.h) ---- */
#define SYS_WAITPID     7
#define SYS_DUP         12
#define SYS_DUP2        13
#define SYS_PIPE        14
#define SYS_GETPPID     17
#define SYS_POLL        18
#define SYS_SELECT      20
#define SYS_IOCTL       21
#define SYS_SETSID      22
#define SYS_SETPGID     23
#define SYS_GETPGRP     24
#define SYS_SIGACTION   25
#define SYS_SIGPROCMASK 26
#define SYS_GETDENTS    30
#define SYS_FCNTL       31
#define SYS_CHDIR       32
#define SYS_GETCWD      33
#define SYS_NANOSLEEP   42
#define SYS_CHMOD       50
#define SYS_CHOWN       51
#define SYS_GETUID      52
#define SYS_GETGID      53
#define SYS_ACCESS      74
#define SYS_UMASK       75
#define SYS_SETUID      76
#define SYS_SETGID      77
#define SYS_ALARM       83
#define SYS_GETEUID     88
#define SYS_GETEGID     89
#define SYS_SETEUID     90
#define SYS_SETEGID     91

/* ---- Raw syscall helpers ---- */

static inline int _sc0(int nr) {
    int ret;
    __asm__ volatile("int $0x80" : "=a"(ret) : "a"(nr) : "memory");
    return ret;
}

static inline int _sc1(int nr, int a1) {
    int ret;
    __asm__ volatile("int $0x80" : "=a"(ret) : "a"(nr), "b"(a1) : "memory");
    return ret;
}

static inline int _sc2(int nr, int a1, int a2) {
    int ret;
    __asm__ volatile("int $0x80" : "=a"(ret) : "a"(nr), "b"(a1), "c"(a2) : "memory");
    return ret;
}

static inline int _sc3(int nr, int a1, int a2, int a3) {
    int ret;
    __asm__ volatile("int $0x80" : "=a"(ret) : "a"(nr), "b"(a1), "c"(a2), "d"(a3) : "memory");
    return ret;
}

static inline int _sc4(int nr, int a1, int a2, int a3, int a4) {
    int ret;
    __asm__ volatile("int $0x80" : "=a"(ret)
        : "a"(nr), "b"(a1), "c"(a2), "d"(a3), "S"(a4) : "memory");
    return ret;
}

static inline int _sc5(int nr, int a1, int a2, int a3, int a4, int a5) {
    int ret;
    __asm__ volatile("int $0x80" : "=a"(ret)
        : "a"(nr), "b"(a1), "c"(a2), "d"(a3), "S"(a4), "D"(a5) : "memory");
    return ret;
}

/* Convert negative syscall return to errno + return -1 */
static inline int _check(int r) {
    if (r < 0) { errno = -r; return -1; }
    return r;
}

/* ---- TTY ioctl numbers (must match kernel tty.c) ---- */
#define TTY_TCGETS    0x5401
#define TTY_TCSETS    0x5402
#define TTY_TCSETSW   0x5403
#define TTY_TCSETSF   0x5404
#define TTY_TIOCGPGRP 0x540F
#define TTY_TIOCSPGRP 0x5410
#define TTY_TIOCGWINSZ 0x5413

/* ================================================================
 * File descriptor operations
 * ================================================================ */

int dup(int fd) {
    return _check(_sc1(SYS_DUP, fd));
}

int dup2(int oldfd, int newfd) {
    return _check(_sc2(SYS_DUP2, oldfd, newfd));
}

int fcntl(int fd, int cmd, ...) {
    va_list ap;
    va_start(ap, cmd);
    int arg = va_arg(ap, int);
    va_end(ap);
    return _check(_sc3(SYS_FCNTL, fd, cmd, arg));
}

int pipe(int fds[2]) {
    return _check(_sc1(SYS_PIPE, (int)fds));
}

/* ================================================================
 * File operations
 * ================================================================ */

int chown(const char *path, uid_t owner, gid_t group) {
    return _check(_sc3(SYS_CHOWN, (int)path, (int)owner, (int)group));
}

int chmod(const char *path, mode_t mode) {
    return _check(_sc2(SYS_CHMOD, (int)path, (int)mode));
}

int lstat(const char *path, struct stat *st) {
    /* AdrOS has no separate lstat syscall yet — fall back to stat */
    return stat(path, st);
}

int access(const char *path, int mode) {
    return _check(_sc2(SYS_ACCESS, (int)path, mode));
}

int chdir(const char *path) {
    return _check(_sc1(SYS_CHDIR, (int)path));
}

char *getcwd(char *buf, size_t size) {
    int r = _sc2(SYS_GETCWD, (int)buf, (int)size);
    if (r < 0) { errno = -r; return 0; }
    return buf;
}

int fchmod(int fd, mode_t mode) {
    /* No fchmod syscall yet — return ENOSYS */
    (void)fd; (void)mode;
    errno = ENOSYS;
    return -1;
}

/* ================================================================
 * Process/signal operations
 * ================================================================ */

pid_t waitpid(pid_t pid, int *status, int options) {
    return (pid_t)_check(_sc3(SYS_WAITPID, (int)pid, (int)status, options));
}

int setpgid(pid_t pid, pid_t pgid) {
    return _check(_sc2(SYS_SETPGID, (int)pid, (int)pgid));
}

pid_t setsid(void) {
    return (pid_t)_check(_sc0(SYS_SETSID));
}

pid_t getpgrp(void) {
    return (pid_t)_sc0(SYS_GETPGRP);
}

int killpg(int pgrp, int sig) {
    return kill(-pgrp, sig);
}

pid_t getppid(void) {
    return (pid_t)_sc0(SYS_GETPPID);
}

uid_t getuid(void) { return (uid_t)_sc0(SYS_GETUID); }
uid_t geteuid(void) { return (uid_t)_sc0(SYS_GETEUID); }
gid_t getgid(void) { return (gid_t)_sc0(SYS_GETGID); }
gid_t getegid(void) { return (gid_t)_sc0(SYS_GETEGID); }

int setuid(uid_t uid) { return _check(_sc1(SYS_SETUID, (int)uid)); }
int setgid(gid_t gid) { return _check(_sc1(SYS_SETGID, (int)gid)); }

int setreuid(uid_t ruid, uid_t euid) {
    /* AdrOS has setuid/seteuid but no setreuid — approximate */
    if (ruid != (uid_t)-1) { int r = _check(_sc1(SYS_SETUID, (int)ruid)); if (r < 0) return r; }
    if (euid != (uid_t)-1) { int r = _check(_sc1(SYS_SETEUID, (int)euid)); if (r < 0) return r; }
    return 0;
}

int setregid(gid_t rgid, gid_t egid) {
    if (rgid != (gid_t)-1) { int r = _check(_sc1(SYS_SETGID, (int)rgid)); if (r < 0) return r; }
    if (egid != (gid_t)-1) { int r = _check(_sc1(SYS_SETEGID, (int)egid)); if (r < 0) return r; }
    return 0;
}

mode_t umask(mode_t mask) {
    return (mode_t)_sc1(SYS_UMASK, (int)mask);
}

unsigned alarm(unsigned seconds) {
    return (unsigned)_sc1(SYS_ALARM, (int)seconds);
}

unsigned sleep(unsigned seconds) {
    struct timespec ts = { .tv_sec = seconds, .tv_nsec = 0 };
    struct timespec rem = { 0, 0 };
    int r = _sc2(SYS_NANOSLEEP, (int)&ts, (int)&rem);
    if (r < 0) return (unsigned)rem.tv_sec;
    return 0;
}

/* ================================================================
 * Signal operations
 * ================================================================ */

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact) {
    return _check(_sc3(SYS_SIGACTION, signum, (int)act, (int)oldact));
}

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset) {
    return _check(_sc3(SYS_SIGPROCMASK, how, (int)set, (int)oldset));
}

/* ================================================================
 * Terminal operations
 * ================================================================ */

int tcgetattr(int fd, struct termios *t) {
    return _check(_sc3(SYS_IOCTL, fd, TTY_TCGETS, (int)t));
}

int tcsetattr(int fd, int optional_actions, const struct termios *t) {
    int cmd;
    switch (optional_actions) {
    case TCSADRAIN: cmd = TTY_TCSETSW; break;
    case TCSAFLUSH: cmd = TTY_TCSETSF; break;
    default:        cmd = TTY_TCSETS;   break;
    }
    return _check(_sc3(SYS_IOCTL, fd, cmd, (int)t));
}

pid_t tcgetpgrp(int fd) {
    pid_t pgrp = 0;
    int r = _sc3(SYS_IOCTL, fd, TTY_TIOCGPGRP, (int)&pgrp);
    if (r < 0) { errno = -r; return (pid_t)-1; }
    return pgrp;
}

int tcsetpgrp(int fd, pid_t pgrp) {
    return _check(_sc3(SYS_IOCTL, fd, TTY_TIOCSPGRP, (int)&pgrp));
}

int tcdrain(int fd) { (void)fd; return 0; }
int tcflow(int fd, int action) { (void)fd; (void)action; return 0; }
int tcflush(int fd, int queue_selector) { (void)fd; (void)queue_selector; return 0; }
int tcsendbreak(int fd, int duration) { (void)fd; (void)duration; return 0; }

speed_t cfgetispeed(const struct termios *t) { (void)t; return B9600; }
speed_t cfgetospeed(const struct termios *t) { (void)t; return B9600; }
int cfsetispeed(struct termios *t, speed_t speed) { (void)t; (void)speed; return 0; }
int cfsetospeed(struct termios *t, speed_t speed) { (void)t; (void)speed; return 0; }

char *ttyname(int fd) {
    /* Minimal: check if fd is a tty, return generic name */
    int r = _sc3(SYS_IOCTL, fd, TTY_TIOCGPGRP, 0);
    if (r < 0) { errno = ENOTTY; return 0; }
    return "/dev/tty";
}

int ioctl(int fd, unsigned long request, ...) {
    va_list ap;
    va_start(ap, request);
    void *arg = va_arg(ap, void *);
    va_end(ap);
    return _check(_sc3(SYS_IOCTL, fd, (int)request, (int)arg));
}

/* ================================================================
 * I/O multiplexing
 * ================================================================ */

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
           struct timeval *timeout) {
    return _check(_sc5(SYS_SELECT, nfds, (int)readfds, (int)writefds,
                       (int)exceptfds, (int)timeout));
}

int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
            const struct timespec *timeout, const sigset_t *sigmask) {
    /* Approximate pselect with select (ignore sigmask) */
    struct timeval tv, *tvp = 0;
    (void)sigmask;
    if (timeout) {
        tv.tv_sec  = timeout->tv_sec;
        tv.tv_usec = timeout->tv_nsec / 1000;
        tvp = &tv;
    }
    return select(nfds, readfds, writefds, exceptfds, tvp);
}

/* ================================================================
 * Directory operations (wrap getdents syscall)
 * ================================================================ */

/* AdrOS getdents returns fixed-size entries: { uint32_t ino; char name[256]; } */
#define ADROS_DIRENT_SIZE 260

DIR *opendir(const char *name) {
    int fd = open(name, 0 /* O_RDONLY */, 0);
    if (fd < 0) return 0;
    DIR *d = (DIR *)malloc(sizeof(DIR));
    if (!d) { close(fd); errno = ENOMEM; return 0; }
    d->dd_fd = fd;
    d->dd_loc = 0;
    d->dd_size = 0;
    d->dd_buf = (char *)malloc(4096);
    if (!d->dd_buf) { close(fd); free(d); errno = ENOMEM; return 0; }
    return d;
}

static struct dirent _de_ret;

struct dirent *readdir(DIR *d) {
    if (!d) return 0;
    /* Refill buffer if exhausted */
    if (d->dd_loc >= d->dd_size) {
        int n = _check(_sc3(SYS_GETDENTS, d->dd_fd, (int)d->dd_buf, 4096));
        if (n <= 0) return 0;
        d->dd_size = n;
        d->dd_loc = 0;
    }
    if (d->dd_loc + ADROS_DIRENT_SIZE > d->dd_size) return 0;
    char *ent = d->dd_buf + d->dd_loc;
    uint32_t ino;
    memcpy(&ino, ent, 4);
    _de_ret.d_ino = (ino_t)ino;
    strncpy(_de_ret.d_name, ent + 4, MAXNAMLEN);
    _de_ret.d_name[MAXNAMLEN] = '\0';
    d->dd_loc += ADROS_DIRENT_SIZE;
    return &_de_ret;
}

int closedir(DIR *d) {
    if (!d) return -1;
    int r = close(d->dd_fd);
    free(d->dd_buf);
    free(d);
    return r;
}

void rewinddir(DIR *d) {
    if (!d) return;
    lseek(d->dd_fd, 0, 0);
    d->dd_loc = 0;
    d->dd_size = 0;
}

/* ================================================================
 * Misc
 * ================================================================ */

int gethostname(char *name, size_t len) {
    if (name && len > 5) { strcpy(name, "adros"); return 0; }
    errno = ENAMETOOLONG; return -1;
}

int mkfifo(const char *path, mode_t mode) {
    (void)path; (void)mode;
    errno = ENOSYS;
    return -1;
}

/* pwd stubs — return hardcoded root user */
static struct passwd _pw = {"root", "", 0, 0, "", "/", "/bin/sh"};
struct passwd *getpwuid(uid_t uid) { (void)uid; return &_pw; }
struct passwd *getpwnam(const char *name) { (void)name; return &_pw; }

/* Group stubs */
struct group { char *gr_name; char *gr_passwd; gid_t gr_gid; char **gr_mem; };
static struct group _gr = {"root", "", 0, 0};
struct group *getgrent(void) { return &_gr; }
void setgrent(void) {}
void endgrent(void) {}

/* ================================================================
 * Regex stubs (kept as stubs — real regex in Phase 3)
 * ================================================================ */

int regcomp(regex_t *preg, const char *pattern, int cflags) {
    (void)preg; (void)pattern; (void)cflags;
    return -1;
}
int regexec(const regex_t *preg, const char *string, size_t nmatch,
            regmatch_t pmatch[], int eflags) {
    (void)preg; (void)string; (void)nmatch; (void)pmatch; (void)eflags;
    return -1;
}
void regfree(regex_t *preg) { (void)preg; }
size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size) {
    (void)errcode; (void)preg;
    if (errbuf && errbuf_size > 0) errbuf[0] = '\0';
    return 0;
}

/* fnmatch — basic wildcard matching (* and ? support) */
int fnmatch(const char *pattern, const char *string, int flags) {
    (void)flags;
    const char *p = pattern, *s = string;
    const char *star_p = 0, *star_s = 0;
    while (*s) {
        if (*p == '*') {
            star_p = ++p;
            star_s = s;
            continue;
        }
        if (*p == '?' || *p == *s) { p++; s++; continue; }
        if (star_p) { p = star_p; s = ++star_s; continue; }
        return 1; /* FNM_NOMATCH */
    }
    while (*p == '*') p++;
    return *p ? 1 : 0;
}