Viewing: posix_compat.c
📄 posix_compat.c (Read Only) ⬅ To go back
/*
 * posix_compat.c — POSIX compatibility stubs for AdrOS cross-toolchain.
 * Provides missing functions needed by Busybox and other ported software.
 * These are thin stubs or minimal implementations.
 */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

/* ---- poll ---- */
#include <poll.h>
#include <sys/select.h>

int poll(struct pollfd *fds, nfds_t nfds, int timeout)
{
    /* Emulate poll() via select() */
    fd_set rfds, wfds, efds;
    int maxfd = -1;
    FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds);
    for (nfds_t i = 0; i < nfds; i++) {
        fds[i].revents = 0;
        if (fds[i].fd < 0) continue;
        if (fds[i].fd > maxfd) maxfd = fds[i].fd;
        if (fds[i].events & POLLIN)  FD_SET(fds[i].fd, &rfds);
        if (fds[i].events & POLLOUT) FD_SET(fds[i].fd, &wfds);
        FD_SET(fds[i].fd, &efds);
    }
    struct timeval tv, *tvp = NULL;
    if (timeout >= 0) {
        tv.tv_sec = timeout / 1000;
        tv.tv_usec = (timeout % 1000) * 1000;
        tvp = &tv;
    }
    int ret = select(maxfd + 1, &rfds, &wfds, &efds, tvp);
    if (ret < 0) return ret;
    int count = 0;
    for (nfds_t i = 0; i < nfds; i++) {
        if (fds[i].fd < 0) continue;
        if (FD_ISSET(fds[i].fd, &rfds))  fds[i].revents |= POLLIN;
        if (FD_ISSET(fds[i].fd, &wfds))  fds[i].revents |= POLLOUT;
        if (FD_ISSET(fds[i].fd, &efds))  fds[i].revents |= POLLERR;
        if (fds[i].revents) count++;
    }
    return count;
}

/* ---- popen / pclose ---- */
FILE *popen(const char *command, const char *type)
{
    (void)command; (void)type;
    errno = ENOSYS;
    return NULL;
}

int pclose(FILE *stream)
{
    (void)stream;
    errno = ENOSYS;
    return -1;
}

/* ---- getline / getdelim ---- */
ssize_t getdelim(char **lineptr, size_t *n, int delim, FILE *stream)
{
    if (!lineptr || !n || !stream) { errno = EINVAL; return -1; }
    if (!*lineptr || *n == 0) {
        *n = 128;
        *lineptr = malloc(*n);
        if (!*lineptr) { errno = ENOMEM; return -1; }
    }
    size_t pos = 0;
    int c;
    while ((c = fgetc(stream)) != EOF) {
        if (pos + 2 > *n) {
            size_t newn = *n * 2;
            char *tmp = realloc(*lineptr, newn);
            if (!tmp) { errno = ENOMEM; return -1; }
            *lineptr = tmp;
            *n = newn;
        }
        (*lineptr)[pos++] = (char)c;
        if (c == delim) break;
    }
    if (pos == 0 && c == EOF) return -1;
    (*lineptr)[pos] = '\0';
    return (ssize_t)pos;
}

ssize_t getline(char **lineptr, size_t *n, FILE *stream)
{
    return getdelim(lineptr, n, '\n', stream);
}

/* ---- dirname / basename (libgen) ---- */
char *dirname(char *path)
{
    static char dot[] = ".";
    if (!path || !*path) return dot;
    char *last = strrchr(path, '/');
    if (!last) return dot;
    if (last == path) { path[1] = '\0'; return path; }
    *last = '\0';
    return path;
}

char *basename(char *path)
{
    static char dot[] = ".";
    if (!path || !*path) return dot;
    char *p = strrchr(path, '/');
    return p ? p + 1 : path;
}

/* ---- symlink / lchown / utimes ---- */
int symlink(const char *target, const char *linkpath)
{
    (void)target; (void)linkpath;
    errno = ENOSYS;
    return -1;
}

int lchown(const char *pathname, uid_t owner, gid_t group)
{
    (void)pathname; (void)owner; (void)group;
    errno = ENOSYS;
    return -1;
}

struct timeval;
int utimes(const char *filename, const struct timeval times[2])
{
    (void)filename; (void)times;
    return 0; /* silently succeed */
}

/* ---- getgroups ---- */
int getgroups(int size, gid_t list[])
{
    if (size == 0) return 1;
    if (size >= 1) { list[0] = getgid(); return 1; }
    errno = EINVAL;
    return -1;
}

/* ---- setpriority / getpriority ---- */
int setpriority(int which, int who, int prio)
{
    (void)which; (void)who; (void)prio;
    return 0;
}

int getpriority(int which, int who)
{
    (void)which; (void)who;
    return 0;
}

/* ---- getrlimit / setrlimit ---- */
#include <sys/resource.h>

int getrlimit(int resource, struct rlimit *rlim)
{
    (void)resource;
    if (!rlim) { errno = EFAULT; return -1; }
    rlim->rlim_cur = RLIM_INFINITY;
    rlim->rlim_max = RLIM_INFINITY;
    return 0;
}

int setrlimit(int resource, const struct rlimit *rlim)
{
    (void)resource; (void)rlim;
    return 0;
}

/* ---- mount table stubs ---- */
#include <mntent.h>

FILE *setmntent(const char *filename, const char *type)
{
    return fopen(filename, type);
}

struct mntent *getmntent(FILE *fp)
{
    (void)fp;
    return NULL;
}

int endmntent(FILE *fp)
{
    if (fp) fclose(fp);
    return 1;
}

/* getmntent_r */
struct mntent *getmntent_r(FILE *fp, struct mntent *mntbuf,
                           char *buf, int buflen)
{
    (void)fp; (void)mntbuf; (void)buf; (void)buflen;
    return NULL;
}

/* ---- mount / umount2 ---- */
int mount(const char *source, const char *target, const char *fstype,
          unsigned long flags, const void *data)
{
    (void)source; (void)target; (void)fstype; (void)flags; (void)data;
    errno = ENOSYS;
    return -1;
}

int umount2(const char *target, int flags)
{
    (void)target; (void)flags;
    errno = ENOSYS;
    return -1;
}

/* ---- DNS stubs ---- */
#include <netdb.h>
int h_errno;

const char *hstrerror(int err)
{
    switch (err) {
    case HOST_NOT_FOUND: return "Host not found";
    case TRY_AGAIN:      return "Try again";
    case NO_RECOVERY:    return "Non-recoverable error";
    case NO_DATA:        return "No data";
    default:             return "Unknown DNS error";
    }
}

int getaddrinfo(const char *node, const char *service,
                const struct addrinfo *hints, struct addrinfo **res)
{
    (void)node; (void)service; (void)hints; (void)res;
    return -1; /* EAI_FAIL */
}

void freeaddrinfo(struct addrinfo *res)
{
    (void)res;
}

const char *gai_strerror(int errcode)
{
    (void)errcode;
    return "getaddrinfo not implemented";
}

int getnameinfo(const void *sa, unsigned int salen,
                char *host, unsigned int hostlen,
                char *serv, unsigned int servlen, int flags)
{
    (void)sa; (void)salen; (void)host; (void)hostlen;
    (void)serv; (void)servlen; (void)flags;
    return -1;
}

/* ---- mknod ---- */
int mknod(const char *pathname, mode_t mode, dev_t dev)
{
    (void)pathname; (void)mode; (void)dev;
    errno = ENOSYS;
    return -1;
}

/* ---- execvp ---- */
int execvp(const char *file, char *const argv[])
{
    /* Simple execvp: try PATH lookup */
    if (strchr(file, '/')) return execve(file, argv, environ);
    const char *path = getenv("PATH");
    if (!path) path = "/bin:/usr/bin";
    char buf[256];
    while (*path) {
        const char *end = strchr(path, ':');
        size_t len = end ? (size_t)(end - path) : strlen(path);
        if (len + 1 + strlen(file) + 1 <= sizeof(buf)) {
            memcpy(buf, path, len);
            buf[len] = '/';
            strcpy(buf + len + 1, file);
            execve(buf, argv, environ);
            if (errno != ENOENT) return -1;
        }
        path += len;
        if (*path == ':') path++;
    }
    errno = ENOENT;
    return -1;
}

/* ---- sysinfo ---- */
#include <sys/sysinfo.h>

int sysinfo(struct sysinfo *info)
{
    if (!info) { errno = EFAULT; return -1; }
    memset(info, 0, sizeof(*info));
    info->uptime = 0;
    info->totalram = 16 * 1024 * 1024; /* 16 MB default */
    info->freeram = 8 * 1024 * 1024;
    info->mem_unit = 1;
    info->procs = 1;
    return 0;
}

/* ---- getrusage ---- */
int getrusage(int who, struct rusage *usage)
{
    (void)who;
    if (!usage) { errno = EFAULT; return -1; }
    memset(usage, 0, sizeof(*usage));
    return 0;
}

/* ---- signal ---- */
#include <signal.h>

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler)
{
    struct sigaction sa, old;
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = handler;
    sa.sa_flags = SA_RESTART;
    if (sigaction(signum, &sa, &old) < 0) return SIG_ERR;
    return old.sa_handler;
}

int sigsuspend(const sigset_t *mask)
{
    (void)mask;
    errno = EINTR;
    return -1;
}

/* ---- uname ---- */
#include <sys/utsname.h>

static int _adros_syscall1(int nr, void *arg)
{
    int ret;
    __asm__ volatile("int $0x80" : "=a"(ret) : "a"(nr), "b"(arg));
    return ret;
}

int uname(struct utsname *buf)
{
    if (!buf) { errno = EFAULT; return -1; }
    int r = _adros_syscall1(136, buf);
    if (r < 0) { errno = -r; return -1; }
    return 0;
}

/* ---- vfork ---- */
pid_t vfork(void)
{
    return fork(); /* emulate vfork as fork */
}

/* ---- mmap / munmap ---- */
#include <sys/mman.h>

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
{
    (void)addr; (void)prot; (void)flags; (void)fd; (void)offset;
    if (flags & MAP_ANONYMOUS) {
        void *p = malloc(length);
        if (!p) { errno = ENOMEM; return MAP_FAILED; }
        memset(p, 0, length);
        return p;
    }
    errno = ENOSYS;
    return MAP_FAILED;
}

int munmap(void *addr, size_t length)
{
    (void)length;
    free(addr);
    return 0;
}

/* ---- rmdir ---- */
int rmdir(const char *pathname)
{
    /* Use unlink syscall with directory flag, or just unlink */
    int r;
    __asm__ volatile("int $0x80" : "=a"(r) : "a"(40), "b"(pathname));
    if (r < 0) { errno = -r; return -1; }
    return 0;
}

/* ---- ftruncate ---- */
int ftruncate(int fd, off_t length)
{
    (void)fd; (void)length;
    return 0; /* silently succeed */
}

/* ---- chroot ---- */
int chroot(const char *path)
{
    (void)path;
    errno = ENOSYS;
    return -1;
}

/* ---- readlink ---- */
ssize_t readlink(const char *pathname, char *buf, size_t bufsiz)
{
    (void)pathname; (void)buf; (void)bufsiz;
    errno = EINVAL; /* no symlinks */
    return -1;
}

/* ---- realpath ---- */
char *realpath(const char *path, char *resolved_path)
{
    if (!path) { errno = EINVAL; return NULL; }
    if (!resolved_path) {
        resolved_path = malloc(256);
        if (!resolved_path) { errno = ENOMEM; return NULL; }
    }
    /* Simple: just copy the path */
    if (path[0] == '/') {
        strncpy(resolved_path, path, 255);
        resolved_path[255] = '\0';
    } else {
        char cwd[256];
        if (!getcwd(cwd, sizeof(cwd))) return NULL;
        snprintf(resolved_path, 256, "%s/%s", cwd, path);
    }
    return resolved_path;
}

/* ---- sysconf ---- */
long sysconf(int name)
{
    switch (name) {
    case 2:  return 200112L; /* _SC_VERSION */
    case 8:  return 4096;    /* _SC_PAGESIZE */
    case 30: return 4096;    /* _SC_PAGE_SIZE */
    case 11: return 256;     /* _SC_OPEN_MAX */
    case 84: return 256;     /* _SC_ATEXIT_MAX */
    case 4:  return 128;     /* _SC_CHILD_MAX */
    case 5:  return 100;     /* _SC_CLK_TCK */
    case 0:  return 32;      /* _SC_ARG_MAX (bytes) - actually large */
    case 3:  return 8;       /* _SC_NGROUPS_MAX */
    case 1:  return 1;       /* _SC_NPROCESSORS_CONF */
    default: errno = EINVAL; return -1;
    }
}

/* ---- fchown ---- */
int fchown(int fd, uid_t owner, gid_t group)
{
    (void)fd; (void)owner; (void)group;
    return 0;
}

/* ---- clock_settime ---- */
#include <time.h>

int clock_settime(clockid_t clk, const struct timespec *tp)
{
    (void)clk; (void)tp;
    errno = EPERM;
    return -1;
}

/* ---- utimensat ---- */
int utimensat(int dirfd, const char *pathname,
              const struct timespec times[2], int flags)
{
    (void)dirfd; (void)pathname; (void)times; (void)flags;
    return 0;
}

/* ---- clearenv ---- */
extern char **environ;

int clearenv(void)
{
    environ = NULL;
    return 0;
}

/* ---- group database stubs ---- */
#include <grp.h>

static struct group _stub_grp;
static char _stub_grp_name[] = "root";

struct group *getgrnam(const char *name)
{
    (void)name;
    _stub_grp.gr_name = _stub_grp_name;
    _stub_grp.gr_gid = 0;
    _stub_grp.gr_mem = NULL;
    return &_stub_grp;
}

struct group *getgrgid(gid_t gid)
{
    (void)gid;
    _stub_grp.gr_name = _stub_grp_name;
    _stub_grp.gr_gid = gid;
    _stub_grp.gr_mem = NULL;
    return &_stub_grp;
}

/* ---- network stubs ---- */
#include <netinet/in.h>

struct hostent *gethostbyname(const char *name)
{
    (void)name;
    h_errno = HOST_NOT_FOUND;
    return NULL;
}

int sethostname(const char *name, size_t len)
{
    (void)name; (void)len;
    return 0;
}

static char _inet_buf[16];

char *inet_ntoa(struct in_addr in)
{
    unsigned char *b = (unsigned char *)&in.s_addr;
    snprintf(_inet_buf, sizeof(_inet_buf), "%u.%u.%u.%u", b[0], b[1], b[2], b[3]);
    return _inet_buf;
}

uint32_t htonl(uint32_t h) { return __builtin_bswap32(h); }
uint16_t htons(uint16_t h) { return __builtin_bswap16(h); }
uint32_t ntohl(uint32_t n) { return __builtin_bswap32(n); }
uint16_t ntohs(uint16_t n) { return __builtin_bswap16(n); }

/* ---- execv ---- */
int execv(const char *path, char *const argv[])
{
    return execve(path, argv, environ);
}

/* ---- dlopen/dlsym/dlclose/dlerror stubs ---- */
#include <dlfcn.h>

void *dlopen(const char *filename, int flags)
{
    (void)filename; (void)flags;
    return NULL;
}

void *dlsym(void *handle, const char *symbol)
{
    (void)handle; (void)symbol;
    return NULL;
}

int dlclose(void *handle)
{
    (void)handle;
    return 0;
}

char *dlerror(void)
{
    return "dlopen not supported on AdrOS";
}

/* ---- pathconf ---- */
long pathconf(const char *path, int name)
{
    (void)path;
    switch (name) {
    case 1:  return 255;     /* _PC_NAME_MAX */
    case 2:  return 4096;    /* _PC_PATH_MAX */
    case 3:  return 4096;    /* _PC_PIPE_BUF */
    case 5:  return 1;       /* _PC_LINK_MAX */
    default: errno = EINVAL; return -1;
    }
}

long fpathconf(int fd, int name)
{
    (void)fd;
    return pathconf("/", name);
}

/* ioctl — minimal stub for terminal queries */
#include <stdarg.h>
int ioctl(int fd, unsigned long request, ...)
{
    (void)fd;
    (void)request;
    errno = ENOSYS;
    return -1;
}

/* ---- ftw / nftw stubs ---- */
#include <ftw.h>

int ftw(const char *dirpath, int (*fn)(const char *, const struct stat *, int), int nopenfd)
{
    (void)dirpath; (void)fn; (void)nopenfd;
    errno = ENOSYS;
    return -1;
}

int nftw(const char *dirpath, int (*fn)(const char *, const struct stat *, int, struct FTW *), int nopenfd, int flags)
{
    (void)dirpath; (void)fn; (void)nopenfd; (void)flags;
    errno = ENOSYS;
    return -1;
}