#define ENOPROTOOPT 92
#define EOVERFLOW 75
#define ELOOP 40
+#define ENOTSOCK 88
+#define ENETUNREACH 101
#endif
int vfs_link(const char* old_path, const char* new_path);
int vfs_mount(const char* mountpoint, fs_node_t* root);
+int vfs_umount(const char* mountpoint);
// Global root of the filesystem
extern fs_node_t* fs_root;
SYSCALL_GETSOCKNAME = 135,
SYSCALL_UNAME = 136,
SYSCALL_GETRUSAGE = 137,
+ SYSCALL_UMOUNT2 = 138,
+ SYSCALL_WAIT4 = 139,
};
#endif
return 0;
}
+int vfs_umount(const char* mountpoint) {
+ char mp[128];
+ normalize_mountpoint(mountpoint, mp, sizeof(mp));
+
+ if (strcmp(mp, "/") == 0) return -EBUSY;
+
+ for (int i = 0; i < g_mount_count; i++) {
+ if (strcmp(g_mounts[i].mountpoint, mp) == 0) {
+ for (int j = i; j < g_mount_count - 1; j++)
+ g_mounts[j] = g_mounts[j + 1];
+ g_mount_count--;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
uint32_t vfs_read(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) {
if (node->f_ops && node->f_ops->read)
return node->f_ops->read(node, offset, size, buffer);
return;
}
+ if (syscall_no == SYSCALL_UMOUNT2) {
+ if (!current_process || current_process->euid != 0) {
+ sc_ret(regs) = (uint32_t)-EPERM;
+ return;
+ }
+ const char* user_target = (const char*)sc_arg0(regs);
+ char ktarget[128];
+ if (path_resolve_user(user_target, ktarget, sizeof(ktarget)) < 0) {
+ sc_ret(regs) = (uint32_t)-EFAULT;
+ return;
+ }
+ sc_ret(regs) = (uint32_t)vfs_umount(ktarget);
+ return;
+ }
+
+ if (syscall_no == SYSCALL_WAIT4) {
+ int pid = (int)sc_arg0(regs);
+ int* ustatus = (int*)sc_arg1(regs);
+ int options = (int)sc_arg2(regs);
+ void* urusage = (void*)sc_arg3(regs);
+
+ if (ustatus && user_range_ok(ustatus, sizeof(int)) == 0) {
+ sc_ret(regs) = (uint32_t)-EFAULT; return;
+ }
+
+ int kstatus = 0;
+ int ret = process_waitpid(pid, &kstatus, options);
+ if (ret < 0) {
+ sc_ret(regs) = (uint32_t)ret;
+ return;
+ }
+ if (ret > 0 && ustatus) {
+ (void)copy_to_user(ustatus, &kstatus, sizeof(kstatus));
+ }
+ if (ret > 0 && urusage) {
+ /* Zero out rusage — detailed accounting deferred */
+ char zeros[64];
+ memset(zeros, 0, sizeof(zeros));
+ (void)copy_to_user(urusage, zeros, sizeof(zeros));
+ }
+ sc_ret(regs) = (uint32_t)ret;
+ return;
+ }
+
sc_ret(regs) = (uint32_t)-ENOSYS;
}
--- /dev/null
+#ifndef ULIBC_AIO_H
+#define ULIBC_AIO_H
+
+#include <stddef.h>
+#include <signal.h>
+#include <time.h>
+
+struct aiocb {
+ int aio_fildes;
+ volatile void* aio_buf;
+ size_t aio_nbytes;
+ int aio_offset;
+ int aio_reqprio;
+ int aio_lio_opcode;
+ /* internal */
+ int __error;
+ int __return;
+};
+
+#define AIO_CANCELED 0
+#define AIO_NOTCANCELED 1
+#define AIO_ALLDONE 2
+
+int aio_read(struct aiocb* aiocbp);
+int aio_write(struct aiocb* aiocbp);
+int aio_error(const struct aiocb* aiocbp);
+int aio_return(struct aiocb* aiocbp);
+int aio_suspend(const struct aiocb* const list[], int nent,
+ const struct timespec* timeout);
+int aio_cancel(int fd, struct aiocb* aiocbp);
+
+#endif
--- /dev/null
+#ifndef ULIBC_ARPA_INET_H
+#define ULIBC_ARPA_INET_H
+
+#include <stdint.h>
+#include <netinet/in.h>
+
+in_addr_t inet_addr(const char* cp);
+int inet_aton(const char* cp, struct in_addr* inp);
+char* inet_ntoa(struct in_addr in);
+const char* inet_ntop(int af, const void* src, char* dst, socklen_t size);
+int inet_pton(int af, const char* src, void* dst);
+
+#endif
--- /dev/null
+#ifndef ULIBC_DLFCN_H
+#define ULIBC_DLFCN_H
+
+#define RTLD_LAZY 0x01
+#define RTLD_NOW 0x02
+#define RTLD_GLOBAL 0x100
+#define RTLD_LOCAL 0x000
+
+void* dlopen(const char* filename, int flags);
+void* dlsym(void* handle, const char* symbol);
+int dlclose(void* handle);
+char* dlerror(void);
+
+#endif
#define ENOPROTOOPT 92
#define EPROTONOSUPPORT 93
#define EOPNOTSUPP 95
+#define ENOTSOCK 88
+#define ENETUNREACH 101
#define EWOULDBLOCK EAGAIN
/* Convert raw syscall return to errno-style */
--- /dev/null
+#ifndef ULIBC_GLOB_H
+#define ULIBC_GLOB_H
+
+#include <stddef.h>
+
+#define GLOB_ERR 0x01
+#define GLOB_MARK 0x02
+#define GLOB_NOSORT 0x04
+#define GLOB_DOOFFS 0x08
+#define GLOB_NOCHECK 0x10
+#define GLOB_APPEND 0x20
+#define GLOB_NOESCAPE 0x40
+
+#define GLOB_NOSPACE 1
+#define GLOB_ABORTED 2
+#define GLOB_NOMATCH 3
+
+typedef struct {
+ size_t gl_pathc;
+ char** gl_pathv;
+ size_t gl_offs;
+ /* internal */
+ size_t __alloc;
+} glob_t;
+
+int glob(const char* pattern, int flags,
+ int (*errfunc)(const char*, int), glob_t* pglob);
+void globfree(glob_t* pglob);
+
+#endif
--- /dev/null
+#ifndef ULIBC_MQUEUE_H
+#define ULIBC_MQUEUE_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+typedef int mqd_t;
+
+struct mq_attr {
+ long mq_flags;
+ long mq_maxmsg;
+ long mq_msgsize;
+ long mq_curmsgs;
+};
+
+mqd_t mq_open(const char* name, int oflag, ...);
+int mq_close(mqd_t mqdes);
+int mq_send(mqd_t mqdes, const char* msg_ptr, size_t msg_len, unsigned int msg_prio);
+int mq_receive(mqd_t mqdes, char* msg_ptr, size_t msg_len, unsigned int* msg_prio);
+int mq_unlink(const char* name);
+int mq_getattr(mqd_t mqdes, struct mq_attr* attr);
+int mq_setattr(mqd_t mqdes, const struct mq_attr* newattr, struct mq_attr* oldattr);
+
+#endif
--- /dev/null
+#ifndef ULIBC_NETDB_H
+#define ULIBC_NETDB_H
+
+#include <stddef.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+struct addrinfo {
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ socklen_t ai_addrlen;
+ struct sockaddr* ai_addr;
+ char* ai_canonname;
+ struct addrinfo* ai_next;
+};
+
+struct hostent {
+ char* h_name;
+ char** h_aliases;
+ int h_addrtype;
+ int h_length;
+ char** h_addr_list;
+};
+
+#define AI_PASSIVE 0x01
+#define AI_CANONNAME 0x02
+#define AI_NUMERICHOST 0x04
+#define AI_NUMERICSERV 0x08
+
+#define NI_MAXHOST 1025
+#define NI_MAXSERV 32
+
+#define EAI_NONAME -2
+#define EAI_AGAIN -3
+#define EAI_FAIL -4
+#define EAI_FAMILY -6
+#define EAI_SOCKTYPE -7
+#define EAI_SERVICE -8
+#define EAI_MEMORY -10
+#define EAI_SYSTEM -11
+
+int getaddrinfo(const char* node, const char* service,
+ const struct addrinfo* hints, struct addrinfo** res);
+void freeaddrinfo(struct addrinfo* res);
+const char* gai_strerror(int errcode);
+
+#endif
--- /dev/null
+#ifndef ULIBC_NETINET_IN_H
+#define ULIBC_NETINET_IN_H
+
+#include <stdint.h>
+#include <sys/socket.h>
+
+typedef uint16_t in_port_t;
+typedef uint32_t in_addr_t;
+
+struct in_addr {
+ in_addr_t s_addr;
+};
+
+struct sockaddr_in {
+ sa_family_t sin_family;
+ in_port_t sin_port;
+ struct in_addr sin_addr;
+ unsigned char sin_zero[8];
+};
+
+struct in6_addr {
+ uint8_t s6_addr[16];
+};
+
+struct sockaddr_in6 {
+ sa_family_t sin6_family;
+ in_port_t sin6_port;
+ uint32_t sin6_flowinfo;
+ struct in6_addr sin6_addr;
+ uint32_t sin6_scope_id;
+};
+
+#define INADDR_ANY ((in_addr_t)0x00000000)
+#define INADDR_BROADCAST ((in_addr_t)0xFFFFFFFF)
+#define INADDR_LOOPBACK ((in_addr_t)0x7F000001)
+#define INADDR_NONE ((in_addr_t)0xFFFFFFFF)
+
+#define IPPROTO_IP 0
+#define IPPROTO_ICMP 1
+#define IPPROTO_TCP 6
+#define IPPROTO_UDP 17
+#define IPPROTO_RAW 255
+
+static inline uint16_t htons(uint16_t x) {
+ return (uint16_t)((x >> 8) | (x << 8));
+}
+static inline uint16_t ntohs(uint16_t x) { return htons(x); }
+
+static inline uint32_t htonl(uint32_t x) {
+ return ((x >> 24) & 0xFF) | ((x >> 8) & 0xFF00) |
+ ((x << 8) & 0xFF0000) | ((x << 24) & 0xFF000000U);
+}
+static inline uint32_t ntohl(uint32_t x) { return htonl(x); }
+
+#endif
/* Set stack size in thread attributes. */
int pthread_attr_setstacksize(pthread_attr_t* attr, size_t stacksize);
+/* Detach */
+int pthread_detach(pthread_t thread);
+
+/* Cancel */
+int pthread_cancel(pthread_t thread);
+int pthread_setcancelstate(int state, int* oldstate);
+int pthread_setcanceltype(int type, int* oldtype);
+void pthread_testcancel(void);
+
+#define PTHREAD_CANCEL_ENABLE 0
+#define PTHREAD_CANCEL_DISABLE 1
+#define PTHREAD_CANCEL_DEFERRED 0
+#define PTHREAD_CANCEL_ASYNCHRONOUS 1
+
+/* ---- Mutex ---- */
+typedef struct {
+ volatile int __lock;
+ int __owner;
+ int __type;
+ int __count;
+} pthread_mutex_t;
+
+typedef struct {
+ int __type;
+} pthread_mutexattr_t;
+
+#define PTHREAD_MUTEX_NORMAL 0
+#define PTHREAD_MUTEX_RECURSIVE 1
+#define PTHREAD_MUTEX_ERRORCHECK 2
+#define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL
+
+#define PTHREAD_MUTEX_INITIALIZER { 0, 0, 0, 0 }
+
+int pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexattr_t* attr);
+int pthread_mutex_destroy(pthread_mutex_t* mutex);
+int pthread_mutex_lock(pthread_mutex_t* mutex);
+int pthread_mutex_trylock(pthread_mutex_t* mutex);
+int pthread_mutex_unlock(pthread_mutex_t* mutex);
+
+int pthread_mutexattr_init(pthread_mutexattr_t* attr);
+int pthread_mutexattr_destroy(pthread_mutexattr_t* attr);
+int pthread_mutexattr_settype(pthread_mutexattr_t* attr, int type);
+int pthread_mutexattr_gettype(const pthread_mutexattr_t* attr, int* type);
+
+/* ---- Condition Variable ---- */
+typedef struct {
+ volatile int __seq;
+} pthread_cond_t;
+
+typedef struct {
+ int __dummy;
+} pthread_condattr_t;
+
+#define PTHREAD_COND_INITIALIZER { 0 }
+
+int pthread_cond_init(pthread_cond_t* cond, const pthread_condattr_t* attr);
+int pthread_cond_destroy(pthread_cond_t* cond);
+int pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex);
+int pthread_cond_signal(pthread_cond_t* cond);
+int pthread_cond_broadcast(pthread_cond_t* cond);
+
+/* ---- Read-Write Lock ---- */
+typedef struct {
+ volatile int __readers;
+ volatile int __writer;
+} pthread_rwlock_t;
+
+typedef struct {
+ int __dummy;
+} pthread_rwlockattr_t;
+
+#define PTHREAD_RWLOCK_INITIALIZER { 0, 0 }
+
+int pthread_rwlock_init(pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr);
+int pthread_rwlock_destroy(pthread_rwlock_t* rwlock);
+int pthread_rwlock_rdlock(pthread_rwlock_t* rwlock);
+int pthread_rwlock_wrlock(pthread_rwlock_t* rwlock);
+int pthread_rwlock_tryrdlock(pthread_rwlock_t* rwlock);
+int pthread_rwlock_trywrlock(pthread_rwlock_t* rwlock);
+int pthread_rwlock_unlock(pthread_rwlock_t* rwlock);
+
+/* ---- Thread-Specific Data (Keys) ---- */
+typedef unsigned int pthread_key_t;
+
+int pthread_key_create(pthread_key_t* key, void (*destructor)(void*));
+int pthread_key_delete(pthread_key_t key);
+void* pthread_getspecific(pthread_key_t key);
+int pthread_setspecific(pthread_key_t key, const void* value);
+
+/* ---- Once ---- */
+typedef volatile int pthread_once_t;
+#define PTHREAD_ONCE_INIT 0
+
+int pthread_once(pthread_once_t* once_control, void (*init_routine)(void));
+
+/* ---- Barrier (optional) ---- */
+typedef struct {
+ volatile int __count;
+ volatile int __total;
+ volatile int __seq;
+} pthread_barrier_t;
+
+typedef struct {
+ int __dummy;
+} pthread_barrierattr_t;
+
+#define PTHREAD_BARRIER_SERIAL_THREAD (-1)
+
+int pthread_barrier_init(pthread_barrier_t* barrier,
+ const pthread_barrierattr_t* attr, unsigned count);
+int pthread_barrier_destroy(pthread_barrier_t* barrier);
+int pthread_barrier_wait(pthread_barrier_t* barrier);
+
#endif
--- /dev/null
+#ifndef ULIBC_SEMAPHORE_H
+#define ULIBC_SEMAPHORE_H
+
+#include <stdint.h>
+
+typedef struct {
+ int __val;
+} sem_t;
+
+#define SEM_FAILED ((sem_t*)-1)
+
+sem_t* sem_open(const char* name, int oflag, ...);
+int sem_close(sem_t* sem);
+int sem_wait(sem_t* sem);
+int sem_trywait(sem_t* sem);
+int sem_post(sem_t* sem);
+int sem_unlink(const char* name);
+int sem_getvalue(sem_t* sem, int* sval);
+int sem_init(sem_t* sem, int pshared, unsigned int value);
+int sem_destroy(sem_t* sem);
+
+#endif
--- /dev/null
+#ifndef ULIBC_SPAWN_H
+#define ULIBC_SPAWN_H
+
+#include <stdint.h>
+#include <signal.h>
+
+typedef struct {
+ int __flags;
+ int __pgrp;
+ sigset_t __sd;
+ sigset_t __ss;
+} posix_spawnattr_t;
+
+typedef struct {
+ int __allocated;
+ int __used;
+ void* __actions;
+} posix_spawn_file_actions_t;
+
+int posix_spawn(int* pid, const char* path,
+ const posix_spawn_file_actions_t* file_actions,
+ const posix_spawnattr_t* attrp,
+ char* const argv[], char* const envp[]);
+
+int posix_spawnp(int* pid, const char* file,
+ const posix_spawn_file_actions_t* file_actions,
+ const posix_spawnattr_t* attrp,
+ char* const argv[], char* const envp[]);
+
+int posix_spawn_file_actions_init(posix_spawn_file_actions_t* fact);
+int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t* fact);
+int posix_spawnattr_init(posix_spawnattr_t* attr);
+int posix_spawnattr_destroy(posix_spawnattr_t* attr);
+
+#endif
int snprintf(char* buf, size_t size, const char* fmt, ...) __attribute__((format(printf, 3, 4)));
int vsnprintf(char* buf, size_t size, const char* fmt, va_list ap);
int sscanf(const char* str, const char* fmt, ...);
+int scanf(const char* fmt, ...);
+int fscanf(FILE* fp, const char* fmt, ...);
int remove(const char* path);
int rename(const char* oldpath, const char* newpath);
void qsort(void* base, size_t nmemb, size_t size,
int (*compar)(const void*, const void*));
+void* bsearch(const void* key, const void* base, size_t nmemb, size_t size,
+ int (*compar)(const void*, const void*));
+
+typedef struct { int quot; int rem; } div_t;
+typedef struct { long quot; long rem; } ldiv_t;
+div_t div(int numer, int denom);
+ldiv_t ldiv(long numer, long denom);
+
+int mkstemp(char* tmpl);
+double strtod(const char* nptr, char** endptr);
+float strtof(const char* nptr, char** endptr);
int system(const char* cmd);
void exit(int status) __attribute__((noreturn));
size_t strspn(const char* s, const char* accept);
size_t strcspn(const char* s, const char* reject);
char* strpbrk(const char* s, const char* accept);
+char* strsignal(int sig);
#endif
--- /dev/null
+#ifndef ULIBC_SYS_EPOLL_H
+#define ULIBC_SYS_EPOLL_H
+
+#include <stdint.h>
+
+#define EPOLL_CTL_ADD 1
+#define EPOLL_CTL_DEL 2
+#define EPOLL_CTL_MOD 3
+
+#define EPOLLIN 0x001
+#define EPOLLOUT 0x004
+#define EPOLLERR 0x008
+#define EPOLLHUP 0x010
+#define EPOLLRDHUP 0x2000
+#define EPOLLET (1U << 31)
+#define EPOLLONESHOT (1 << 30)
+
+typedef union epoll_data {
+ void* ptr;
+ int fd;
+ uint32_t u32;
+ uint64_t u64;
+} epoll_data_t;
+
+struct epoll_event {
+ uint32_t events;
+ epoll_data_t data;
+};
+
+int epoll_create(int size);
+int epoll_create1(int flags);
+int epoll_ctl(int epfd, int op, int fd, struct epoll_event* event);
+int epoll_wait(int epfd, struct epoll_event* events, int maxevents, int timeout);
+
+#endif
--- /dev/null
+#ifndef ULIBC_SYS_INOTIFY_H
+#define ULIBC_SYS_INOTIFY_H
+
+#include <stdint.h>
+
+#define IN_ACCESS 0x00000001
+#define IN_MODIFY 0x00000002
+#define IN_ATTRIB 0x00000004
+#define IN_CLOSE_WRITE 0x00000008
+#define IN_CLOSE_NOWRITE 0x00000010
+#define IN_OPEN 0x00000020
+#define IN_MOVED_FROM 0x00000040
+#define IN_MOVED_TO 0x00000080
+#define IN_CREATE 0x00000100
+#define IN_DELETE 0x00000200
+#define IN_DELETE_SELF 0x00000400
+#define IN_MOVE_SELF 0x00000800
+#define IN_CLOSE (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)
+#define IN_MOVE (IN_MOVED_FROM | IN_MOVED_TO)
+#define IN_ALL_EVENTS 0x00000FFF
+#define IN_NONBLOCK 0x00004000
+
+struct inotify_event {
+ int wd;
+ uint32_t mask;
+ uint32_t cookie;
+ uint32_t len;
+ char name[];
+};
+
+int inotify_init(void);
+int inotify_init1(int flags);
+int inotify_add_watch(int fd, const char* pathname, uint32_t mask);
+int inotify_rm_watch(int fd, int wd);
+
+#endif
--- /dev/null
+#ifndef ULIBC_SYS_SHM_H
+#define ULIBC_SYS_SHM_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#define IPC_CREAT 01000
+#define IPC_EXCL 02000
+#define IPC_NOWAIT 04000
+#define IPC_RMID 0
+#define IPC_SET 1
+#define IPC_STAT 2
+#define IPC_PRIVATE 0
+
+typedef int key_t;
+
+struct shmid_ds {
+ int shm_segsz;
+ int shm_nattch;
+ int shm_cpid;
+ int shm_lpid;
+ uint32_t shm_atime;
+ uint32_t shm_dtime;
+ uint32_t shm_ctime;
+};
+
+int shmget(key_t key, size_t size, int shmflg);
+void* shmat(int shmid, const void* shmaddr, int shmflg);
+int shmdt(const void* shmaddr);
+int shmctl(int shmid, int cmd, struct shmid_ds* buf);
+
+#endif
--- /dev/null
+#ifndef ULIBC_SYS_SOCKET_H
+#define ULIBC_SYS_SOCKET_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+/* Address families */
+#define AF_UNSPEC 0
+#define AF_UNIX 1
+#define AF_LOCAL AF_UNIX
+#define AF_INET 2
+#define AF_INET6 10
+
+/* Socket types */
+#define SOCK_STREAM 1
+#define SOCK_DGRAM 2
+#define SOCK_RAW 3
+#define SOCK_NONBLOCK 0x800
+#define SOCK_CLOEXEC 0x80000
+
+/* Protocol families (aliases) */
+#define PF_UNSPEC AF_UNSPEC
+#define PF_UNIX AF_UNIX
+#define PF_INET AF_INET
+#define PF_INET6 AF_INET6
+
+/* Socket options levels */
+#define SOL_SOCKET 1
+
+/* Socket options */
+#define SO_REUSEADDR 2
+#define SO_ERROR 4
+#define SO_BROADCAST 6
+#define SO_SNDBUF 7
+#define SO_RCVBUF 8
+#define SO_KEEPALIVE 9
+#define SO_LINGER 13
+#define SO_RCVTIMEO 20
+#define SO_SNDTIMEO 21
+
+/* shutdown() how */
+#define SHUT_RD 0
+#define SHUT_WR 1
+#define SHUT_RDWR 2
+
+/* MSG flags */
+#define MSG_PEEK 0x02
+#define MSG_DONTWAIT 0x40
+#define MSG_NOSIGNAL 0x4000
+
+typedef unsigned int socklen_t;
+typedef unsigned short sa_family_t;
+
+struct sockaddr {
+ sa_family_t sa_family;
+ char sa_data[14];
+};
+
+struct sockaddr_storage {
+ sa_family_t ss_family;
+ char __ss_pad[126];
+};
+
+struct msghdr {
+ void* msg_name;
+ socklen_t msg_namelen;
+ struct iovec* msg_iov;
+ int msg_iovlen;
+ void* msg_control;
+ socklen_t msg_controllen;
+ int msg_flags;
+};
+
+struct iovec;
+
+int socket(int domain, int type, int protocol);
+int bind(int sockfd, const struct sockaddr* addr, socklen_t addrlen);
+int listen(int sockfd, int backlog);
+int accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen);
+int connect(int sockfd, const struct sockaddr* addr, socklen_t addrlen);
+int send(int sockfd, const void* buf, size_t len, int flags);
+int recv(int sockfd, void* buf, size_t len, int flags);
+int sendto(int sockfd, const void* buf, size_t len, int flags,
+ const struct sockaddr* dest_addr, socklen_t addrlen);
+int recvfrom(int sockfd, void* buf, size_t len, int flags,
+ struct sockaddr* src_addr, socklen_t* addrlen);
+int sendmsg(int sockfd, const struct msghdr* msg, int flags);
+int recvmsg(int sockfd, struct msghdr* msg, int flags);
+int setsockopt(int sockfd, int level, int optname, const void* optval, socklen_t optlen);
+int getsockopt(int sockfd, int level, int optname, void* optval, socklen_t* optlen);
+int shutdown(int sockfd, int how);
+int getpeername(int sockfd, struct sockaddr* addr, socklen_t* addrlen);
+int getsockname(int sockfd, struct sockaddr* addr, socklen_t* addrlen);
+
+#endif
--- /dev/null
+#ifndef ULIBC_SYS_UN_H
+#define ULIBC_SYS_UN_H
+
+#include <sys/socket.h>
+
+#define UNIX_PATH_MAX 108
+
+struct sockaddr_un {
+ sa_family_t sun_family;
+ char sun_path[UNIX_PATH_MAX];
+};
+
+#endif
SYS_SETEGID = 91,
SYS_SETITIMER = 92,
SYS_GETITIMER = 93,
+ SYS_SHMGET = 46,
+ SYS_SHMAT = 47,
+ SYS_SHMDT = 48,
+ SYS_SHMCTL = 49,
+ SYS_LINK = 54,
+ SYS_SYMLINK = 55,
+ SYS_READLINK = 56,
+ SYS_SOCKET = 58,
+ SYS_BIND = 59,
+ SYS_LISTEN = 60,
+ SYS_ACCEPT = 61,
+ SYS_CONNECT = 62,
+ SYS_SEND = 63,
+ SYS_RECV = 64,
+ SYS_SENDTO = 65,
+ SYS_RECVFROM = 66,
+ SYS_WAITID = 94,
+ SYS_SIGQUEUE = 95,
+ SYS_POSIX_SPAWN = 96,
+ SYS_MQ_OPEN = 97,
+ SYS_MQ_CLOSE = 98,
+ SYS_MQ_SEND = 99,
+ SYS_MQ_RECEIVE = 100,
+ SYS_MQ_UNLINK = 101,
+ SYS_SEM_OPEN = 102,
+ SYS_SEM_CLOSE = 103,
+ SYS_SEM_WAIT = 104,
+ SYS_SEM_POST = 105,
+ SYS_SEM_UNLINK = 106,
+ SYS_SEM_GETVALUE = 107,
+ SYS_GETADDRINFO = 108,
+ SYS_DLOPEN = 109,
+ SYS_DLSYM = 110,
+ SYS_DLCLOSE = 111,
+ SYS_EPOLL_CREATE = 112,
+ SYS_EPOLL_CTL = 113,
+ SYS_EPOLL_WAIT = 114,
+ SYS_INOTIFY_INIT = 115,
+ SYS_INOTIFY_ADD_WATCH = 116,
+ SYS_INOTIFY_RM_WATCH = 117,
+ SYS_SENDMSG = 118,
+ SYS_RECVMSG = 119,
+ SYS_PIVOT_ROOT = 120,
+ SYS_AIO_READ = 121,
+ SYS_AIO_WRITE = 122,
+ SYS_AIO_ERROR = 123,
+ SYS_AIO_RETURN = 124,
+ SYS_AIO_SUSPEND = 125,
SYS_MOUNT = 126,
SYS_GETTIMEOFDAY = 127,
SYS_MPROTECT = 128,
SYS_GETSOCKNAME = 135,
SYS_UNAME = 136,
SYS_GETRUSAGE = 137,
+ SYS_UMOUNT2 = 138,
+ SYS_WAIT4 = 139,
};
/* Raw syscall wrappers — up to 5 args via INT 0x80 */
--- /dev/null
+#ifndef ULIBC_SYSLOG_H
+#define ULIBC_SYSLOG_H
+
+#define LOG_EMERG 0
+#define LOG_ALERT 1
+#define LOG_CRIT 2
+#define LOG_ERR 3
+#define LOG_WARNING 4
+#define LOG_NOTICE 5
+#define LOG_INFO 6
+#define LOG_DEBUG 7
+
+#define LOG_KERN (0<<3)
+#define LOG_USER (1<<3)
+#define LOG_DAEMON (3<<3)
+#define LOG_LOCAL0 (16<<3)
+
+#define LOG_PID 0x01
+#define LOG_CONS 0x02
+#define LOG_NDELAY 0x08
+#define LOG_NOWAIT 0x10
+
+void openlog(const char* ident, int option, int facility);
+void syslog(int priority, const char* format, ...);
+void closelog(void);
+
+#endif
#define TCSADRAIN 1
#define TCSAFLUSH 2
+typedef unsigned int speed_t;
+
+#define B0 0
+#define B9600 9600
+#define B19200 19200
+#define B38400 38400
+#define B115200 115200
+
+speed_t cfgetispeed(const struct termios* t);
+speed_t cfgetospeed(const struct termios* t);
+int cfsetispeed(struct termios* t, speed_t speed);
+int cfsetospeed(struct termios* t, speed_t speed);
+void cfmakeraw(struct termios* t);
+int tcdrain(int fd);
+int tcflush(int fd, int queue_selector);
+int tcflow(int fd, int action);
+int tcsendbreak(int fd, int duration);
+int tcgetpgrp(int fd);
+int tcsetpgrp(int fd, int pgrp);
+
+#define TCIFLUSH 0
+#define TCOFLUSH 1
+#define TCIOFLUSH 2
+#define TCOOFF 0
+#define TCOON 1
+#define TCIOFF 2
+#define TCION 3
+
#endif
int gethostname(char* name, size_t len);
char* ttyname(int fd);
int pipe2(int fds[2], int flags);
+int execle(const char* path, const char* arg, ...);
+char* getlogin(void);
+int getlogin_r(char* buf, size_t bufsize);
+int tcgetpgrp(int fd);
+int tcsetpgrp(int fd, int pgrp);
+
+#define _CS_PATH 0
+long confstr(int name, char* buf, size_t len);
+void* sbrk(int increment);
/* Environment pointer (set by crt0) */
extern char** __environ;
--- /dev/null
+#ifndef ULIBC_WORDEXP_H
+#define ULIBC_WORDEXP_H
+
+#include <stddef.h>
+
+#define WRDE_DOOFFS 0x01
+#define WRDE_APPEND 0x02
+#define WRDE_NOCMD 0x04
+#define WRDE_REUSE 0x08
+#define WRDE_SHOWERR 0x10
+#define WRDE_UNDEF 0x20
+
+#define WRDE_BADCHAR 1
+#define WRDE_BADVAL 2
+#define WRDE_CMDSUB 3
+#define WRDE_NOSPACE 4
+#define WRDE_SYNTAX 5
+
+typedef struct {
+ size_t we_wordc;
+ char** we_wordv;
+ size_t we_offs;
+} wordexp_t;
+
+int wordexp(const char* words, wordexp_t* pwordexp, int flags);
+void wordfree(wordexp_t* pwordexp);
+
+#endif
--- /dev/null
+#include "aio.h"
+#include "syscall.h"
+#include "errno.h"
+
+int aio_read(struct aiocb* aiocbp) {
+ return __syscall_ret(_syscall3(SYS_AIO_READ, aiocbp->aio_fildes,
+ (int)aiocbp->aio_buf, (int)aiocbp->aio_nbytes));
+}
+
+int aio_write(struct aiocb* aiocbp) {
+ return __syscall_ret(_syscall3(SYS_AIO_WRITE, aiocbp->aio_fildes,
+ (int)aiocbp->aio_buf, (int)aiocbp->aio_nbytes));
+}
+
+int aio_error(const struct aiocb* aiocbp) {
+ return _syscall1(SYS_AIO_ERROR, (int)aiocbp);
+}
+
+int aio_return(struct aiocb* aiocbp) {
+ return _syscall1(SYS_AIO_RETURN, (int)aiocbp);
+}
+
+int aio_suspend(const struct aiocb* const list[], int nent,
+ const struct timespec* timeout) {
+ return __syscall_ret(_syscall3(SYS_AIO_SUSPEND, (int)list, nent, (int)timeout));
+}
+
+int aio_cancel(int fd, struct aiocb* aiocbp) {
+ (void)fd;
+ (void)aiocbp;
+ return AIO_ALLDONE;
+}
--- /dev/null
+#include "dlfcn.h"
+#include "syscall.h"
+#include "errno.h"
+
+static char _dlerror_buf[64];
+static int _dlerror_set;
+
+void* dlopen(const char* filename, int flags) {
+ int ret = _syscall2(SYS_DLOPEN, (int)filename, flags);
+ if (ret < 0 && ret > -4096) {
+ _dlerror_set = 1;
+ errno = -ret;
+ return (void*)0;
+ }
+ return (void*)ret;
+}
+
+void* dlsym(void* handle, const char* symbol) {
+ int ret = _syscall2(SYS_DLSYM, (int)handle, (int)symbol);
+ if (ret < 0 && ret > -4096) {
+ _dlerror_set = 1;
+ errno = -ret;
+ return (void*)0;
+ }
+ return (void*)ret;
+}
+
+int dlclose(void* handle) {
+ return __syscall_ret(_syscall1(SYS_DLCLOSE, (int)handle));
+}
+
+char* dlerror(void) {
+ if (_dlerror_set) {
+ _dlerror_set = 0;
+ /* minimal message */
+ _dlerror_buf[0] = 'd'; _dlerror_buf[1] = 'l';
+ _dlerror_buf[2] = ' '; _dlerror_buf[3] = 'e';
+ _dlerror_buf[4] = 'r'; _dlerror_buf[5] = 'r';
+ _dlerror_buf[6] = 'o'; _dlerror_buf[7] = 'r';
+ _dlerror_buf[8] = '\0';
+ return _dlerror_buf;
+ }
+ return (void*)0;
+}
--- /dev/null
+#include "sys/epoll.h"
+#include "syscall.h"
+#include "errno.h"
+
+int epoll_create(int size) {
+ (void)size;
+ return __syscall_ret(_syscall1(SYS_EPOLL_CREATE, 0));
+}
+
+int epoll_create1(int flags) {
+ return __syscall_ret(_syscall1(SYS_EPOLL_CREATE, flags));
+}
+
+int epoll_ctl(int epfd, int op, int fd, struct epoll_event* event) {
+ return __syscall_ret(_syscall4(SYS_EPOLL_CTL, epfd, op, fd, (int)event));
+}
+
+int epoll_wait(int epfd, struct epoll_event* events, int maxevents, int timeout) {
+ return __syscall_ret(_syscall4(SYS_EPOLL_WAIT, epfd, (int)events, maxevents, timeout));
+}
--- /dev/null
+#include "glob.h"
+#include "fnmatch.h"
+#include "string.h"
+#include "stdlib.h"
+#include "unistd.h"
+#include "dirent.h"
+#include "errno.h"
+
+static int glob_add(glob_t* g, const char* path) {
+ if (g->gl_pathc + 1 >= g->__alloc) {
+ size_t newalloc = g->__alloc ? g->__alloc * 2 : 16;
+ char** nv = (char**)realloc(g->gl_pathv, newalloc * sizeof(char*));
+ if (!nv) return GLOB_NOSPACE;
+ g->gl_pathv = nv;
+ g->__alloc = newalloc;
+ }
+ g->gl_pathv[g->gl_pathc] = strdup(path);
+ if (!g->gl_pathv[g->gl_pathc]) return GLOB_NOSPACE;
+ g->gl_pathc++;
+ g->gl_pathv[g->gl_pathc] = (void*)0;
+ return 0;
+}
+
+int glob(const char* pattern, int flags,
+ int (*errfunc)(const char*, int), glob_t* pglob) {
+ (void)errfunc;
+
+ if (!(flags & GLOB_APPEND)) {
+ pglob->gl_pathc = 0;
+ pglob->gl_pathv = (void*)0;
+ pglob->__alloc = 0;
+ }
+
+ /* Split pattern into directory + basename */
+ char dir[256], base[256];
+ const char* last_slash = strrchr(pattern, '/');
+ if (last_slash) {
+ size_t dlen = (size_t)(last_slash - pattern);
+ if (dlen == 0) dlen = 1;
+ if (dlen >= sizeof(dir)) dlen = sizeof(dir) - 1;
+ memcpy(dir, pattern, dlen);
+ dir[dlen] = '\0';
+ strncpy(base, last_slash + 1, sizeof(base) - 1);
+ base[sizeof(base) - 1] = '\0';
+ } else {
+ strcpy(dir, ".");
+ strncpy(base, pattern, sizeof(base) - 1);
+ base[sizeof(base) - 1] = '\0';
+ }
+
+ /* Open directory and match entries */
+ int dfd = open(dir, 0);
+ if (dfd < 0) {
+ if (flags & GLOB_NOCHECK)
+ return glob_add(pglob, pattern);
+ return GLOB_ABORTED;
+ }
+
+ struct dirent de;
+ char path[512];
+ int found = 0;
+
+ while (getdents(dfd, &de, sizeof(de)) > 0) {
+ if (de.d_name[0] == '\0') continue;
+ if (fnmatch(base, de.d_name, 0) == 0) {
+ if (last_slash) {
+ snprintf(path, sizeof(path), "%s/%s", dir, de.d_name);
+ } else {
+ strncpy(path, de.d_name, sizeof(path) - 1);
+ path[sizeof(path) - 1] = '\0';
+ }
+ int rc = glob_add(pglob, path);
+ if (rc) { close(dfd); return rc; }
+ found++;
+ }
+ }
+
+ close(dfd);
+
+ if (found == 0) {
+ if (flags & GLOB_NOCHECK)
+ return glob_add(pglob, pattern);
+ return GLOB_NOMATCH;
+ }
+
+ if (!(flags & GLOB_NOSORT) && pglob->gl_pathc > 1) {
+ /* Simple insertion sort */
+ for (size_t i = 1; i < pglob->gl_pathc; i++) {
+ char* tmp = pglob->gl_pathv[i];
+ size_t j = i;
+ while (j > 0 && strcmp(pglob->gl_pathv[j - 1], tmp) > 0) {
+ pglob->gl_pathv[j] = pglob->gl_pathv[j - 1];
+ j--;
+ }
+ pglob->gl_pathv[j] = tmp;
+ }
+ }
+
+ return 0;
+}
+
+void globfree(glob_t* pglob) {
+ if (!pglob || !pglob->gl_pathv) return;
+ for (size_t i = 0; i < pglob->gl_pathc; i++)
+ free(pglob->gl_pathv[i]);
+ free(pglob->gl_pathv);
+ pglob->gl_pathv = (void*)0;
+ pglob->gl_pathc = 0;
+ pglob->__alloc = 0;
+}
--- /dev/null
+#include "arpa/inet.h"
+#include "string.h"
+#include "errno.h"
+
+in_addr_t inet_addr(const char* cp) {
+ struct in_addr addr;
+ if (inet_aton(cp, &addr))
+ return addr.s_addr;
+ return INADDR_NONE;
+}
+
+int inet_aton(const char* cp, struct in_addr* inp) {
+ uint32_t val = 0;
+ int parts = 0;
+ uint32_t part = 0;
+ for (const char* p = cp; ; p++) {
+ if (*p >= '0' && *p <= '9') {
+ part = part * 10 + (unsigned)(*p - '0');
+ if (part > 255) return 0;
+ } else if (*p == '.' || *p == '\0') {
+ val = (val << 8) | part;
+ part = 0;
+ parts++;
+ if (*p == '\0') break;
+ if (parts >= 4) return 0;
+ } else {
+ return 0;
+ }
+ }
+ if (parts != 4) return 0;
+ if (inp) inp->s_addr = htonl(val);
+ return 1;
+}
+
+static char _ntoa_buf[16];
+char* inet_ntoa(struct in_addr in) {
+ uint32_t addr = ntohl(in.s_addr);
+ int pos = 0;
+ for (int i = 3; i >= 0; i--) {
+ unsigned int octet = (addr >> (i * 8)) & 0xFF;
+ if (octet >= 100) _ntoa_buf[pos++] = '0' + (char)(octet / 100);
+ if (octet >= 10) _ntoa_buf[pos++] = '0' + (char)((octet / 10) % 10);
+ _ntoa_buf[pos++] = '0' + (char)(octet % 10);
+ if (i > 0) _ntoa_buf[pos++] = '.';
+ }
+ _ntoa_buf[pos] = '\0';
+ return _ntoa_buf;
+}
+
+const char* inet_ntop(int af, const void* src, char* dst, socklen_t size) {
+ if (af == AF_INET) {
+ struct in_addr a;
+ memcpy(&a, src, sizeof(a));
+ char* s = inet_ntoa(a);
+ size_t len = strlen(s);
+ if (len >= size) { errno = ENOSPC; return (void*)0; }
+ memcpy(dst, s, len + 1);
+ return dst;
+ }
+ errno = EAFNOSUPPORT;
+ return (void*)0;
+}
+
+int inet_pton(int af, const char* src, void* dst) {
+ if (af == AF_INET) {
+ struct in_addr addr;
+ if (!inet_aton(src, &addr)) return 0;
+ memcpy(dst, &addr, sizeof(addr));
+ return 1;
+ }
+ errno = EAFNOSUPPORT;
+ return -1;
+}
--- /dev/null
+#include "sys/inotify.h"
+#include "syscall.h"
+#include "errno.h"
+
+int inotify_init(void) {
+ return __syscall_ret(_syscall0(SYS_INOTIFY_INIT));
+}
+
+int inotify_init1(int flags) {
+ return __syscall_ret(_syscall1(SYS_INOTIFY_INIT, flags));
+}
+
+int inotify_add_watch(int fd, const char* pathname, uint32_t mask) {
+ return __syscall_ret(_syscall3(SYS_INOTIFY_ADD_WATCH, fd, (int)pathname, (int)mask));
+}
+
+int inotify_rm_watch(int fd, int wd) {
+ return __syscall_ret(_syscall2(SYS_INOTIFY_RM_WATCH, fd, wd));
+}
--- /dev/null
+#include "mqueue.h"
+#include "syscall.h"
+#include "errno.h"
+
+mqd_t mq_open(const char* name, int oflag, ...) {
+ return (mqd_t)__syscall_ret(_syscall2(SYS_MQ_OPEN, (int)name, oflag));
+}
+
+int mq_close(mqd_t mqdes) {
+ return __syscall_ret(_syscall1(SYS_MQ_CLOSE, mqdes));
+}
+
+int mq_send(mqd_t mqdes, const char* msg_ptr, size_t msg_len, unsigned int msg_prio) {
+ (void)msg_prio;
+ return __syscall_ret(_syscall3(SYS_MQ_SEND, mqdes, (int)msg_ptr, (int)msg_len));
+}
+
+int mq_receive(mqd_t mqdes, char* msg_ptr, size_t msg_len, unsigned int* msg_prio) {
+ (void)msg_prio;
+ return __syscall_ret(_syscall3(SYS_MQ_RECEIVE, mqdes, (int)msg_ptr, (int)msg_len));
+}
+
+int mq_unlink(const char* name) {
+ return __syscall_ret(_syscall1(SYS_MQ_UNLINK, (int)name));
+}
+
+int mq_getattr(mqd_t mqdes, struct mq_attr* attr) {
+ (void)mqdes;
+ (void)attr;
+ errno = ENOSYS;
+ return -1;
+}
+
+int mq_setattr(mqd_t mqdes, const struct mq_attr* newattr, struct mq_attr* oldattr) {
+ (void)mqdes;
+ (void)newattr;
+ (void)oldattr;
+ errno = ENOSYS;
+ return -1;
+}
--- /dev/null
+#include "netdb.h"
+#include "syscall.h"
+#include "errno.h"
+#include "stdlib.h"
+#include "string.h"
+
+int getaddrinfo(const char* node, const char* service,
+ const struct addrinfo* hints, struct addrinfo** res) {
+ (void)service;
+ if (!res) return EAI_FAIL;
+
+ /* Use kernel getaddrinfo syscall for DNS resolution */
+ struct sockaddr_in addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+
+ int ret = _syscall3(SYS_GETADDRINFO, (int)node, (int)&addr.sin_addr, 0);
+ if (ret < 0) return EAI_NONAME;
+
+ struct addrinfo* ai = (struct addrinfo*)calloc(1, sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
+ if (!ai) return EAI_MEMORY;
+
+ struct sockaddr_in* sa = (struct sockaddr_in*)(ai + 1);
+ memcpy(sa, &addr, sizeof(struct sockaddr_in));
+
+ ai->ai_family = AF_INET;
+ ai->ai_socktype = hints ? hints->ai_socktype : SOCK_STREAM;
+ ai->ai_protocol = hints ? hints->ai_protocol : 0;
+ ai->ai_addrlen = sizeof(struct sockaddr_in);
+ ai->ai_addr = (struct sockaddr*)sa;
+ ai->ai_next = (void*)0;
+ *res = ai;
+ return 0;
+}
+
+void freeaddrinfo(struct addrinfo* res) {
+ while (res) {
+ struct addrinfo* next = res->ai_next;
+ free(res);
+ res = next;
+ }
+}
+
+const char* gai_strerror(int errcode) {
+ switch (errcode) {
+ case 0: return "Success";
+ case EAI_NONAME: return "Name does not resolve";
+ case EAI_AGAIN: return "Temporary failure in name resolution";
+ case EAI_FAIL: return "Non-recoverable failure in name resolution";
+ case EAI_MEMORY: return "Memory allocation failure";
+ case EAI_FAMILY: return "Address family not supported";
+ case EAI_SOCKTYPE: return "Socket type not supported";
+ case EAI_SERVICE: return "Service not supported";
+ case EAI_SYSTEM: return "System error";
+ default: return "Unknown error";
+ }
+}
attr->stack_size = stacksize;
return 0;
}
+
+int pthread_detach(pthread_t thread) {
+ (void)thread;
+ return 0;
+}
+
+int pthread_cancel(pthread_t thread) {
+ (void)thread;
+ return 0;
+}
+
+int pthread_setcancelstate(int state, int* oldstate) {
+ if (oldstate) *oldstate = 0;
+ (void)state;
+ return 0;
+}
+
+int pthread_setcanceltype(int type, int* oldtype) {
+ if (oldtype) *oldtype = 0;
+ (void)type;
+ return 0;
+}
+
+void pthread_testcancel(void) {}
+
+/* ---- Futex helpers ---- */
+#define FUTEX_WAIT 0
+#define FUTEX_WAKE 1
+
+static int futex_wait(volatile int* addr, int val) {
+ return _syscall3(SYS_FUTEX, (int)addr, FUTEX_WAIT, val);
+}
+
+static int futex_wake(volatile int* addr, int count) {
+ return _syscall3(SYS_FUTEX, (int)addr, FUTEX_WAKE, count);
+}
+
+static int atomic_cas(volatile int* ptr, int old, int new_val) {
+ int prev;
+ __asm__ volatile("lock cmpxchgl %2, %1"
+ : "=a"(prev), "+m"(*ptr)
+ : "r"(new_val), "0"(old)
+ : "memory");
+ return prev;
+}
+
+static int atomic_xchg(volatile int* ptr, int val) {
+ __asm__ volatile("xchgl %0, %1"
+ : "=r"(val), "+m"(*ptr)
+ : "0"(val)
+ : "memory");
+ return val;
+}
+
+static void atomic_add(volatile int* ptr, int val) {
+ __asm__ volatile("lock addl %1, %0" : "+m"(*ptr) : "r"(val) : "memory");
+}
+
+/* ---- Mutex ---- */
+int pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexattr_t* attr) {
+ if (!mutex) return 22;
+ mutex->__lock = 0;
+ mutex->__owner = 0;
+ mutex->__type = attr ? attr->__type : PTHREAD_MUTEX_NORMAL;
+ mutex->__count = 0;
+ return 0;
+}
+
+int pthread_mutex_destroy(pthread_mutex_t* mutex) {
+ (void)mutex;
+ return 0;
+}
+
+int pthread_mutex_lock(pthread_mutex_t* mutex) {
+ if (!mutex) return 22;
+ int tid = _syscall0(SYS_GETTID);
+
+ if (mutex->__type == PTHREAD_MUTEX_RECURSIVE && mutex->__owner == tid) {
+ mutex->__count++;
+ return 0;
+ }
+
+ while (atomic_xchg(&mutex->__lock, 1) != 0) {
+ futex_wait(&mutex->__lock, 1);
+ }
+ mutex->__owner = tid;
+ mutex->__count = 1;
+ return 0;
+}
+
+int pthread_mutex_trylock(pthread_mutex_t* mutex) {
+ if (!mutex) return 22;
+ int tid = _syscall0(SYS_GETTID);
+
+ if (mutex->__type == PTHREAD_MUTEX_RECURSIVE && mutex->__owner == tid) {
+ mutex->__count++;
+ return 0;
+ }
+
+ if (atomic_cas(&mutex->__lock, 0, 1) == 0) {
+ mutex->__owner = tid;
+ mutex->__count = 1;
+ return 0;
+ }
+ return 16; /* EBUSY */
+}
+
+int pthread_mutex_unlock(pthread_mutex_t* mutex) {
+ if (!mutex) return 22;
+
+ if (mutex->__type == PTHREAD_MUTEX_RECURSIVE) {
+ if (--mutex->__count > 0) return 0;
+ }
+
+ mutex->__owner = 0;
+ mutex->__count = 0;
+ atomic_xchg(&mutex->__lock, 0);
+ futex_wake(&mutex->__lock, 1);
+ return 0;
+}
+
+int pthread_mutexattr_init(pthread_mutexattr_t* attr) {
+ if (!attr) return 22;
+ attr->__type = PTHREAD_MUTEX_NORMAL;
+ return 0;
+}
+
+int pthread_mutexattr_destroy(pthread_mutexattr_t* attr) {
+ (void)attr;
+ return 0;
+}
+
+int pthread_mutexattr_settype(pthread_mutexattr_t* attr, int type) {
+ if (!attr) return 22;
+ attr->__type = type;
+ return 0;
+}
+
+int pthread_mutexattr_gettype(const pthread_mutexattr_t* attr, int* type) {
+ if (!attr || !type) return 22;
+ *type = attr->__type;
+ return 0;
+}
+
+/* ---- Condition Variable ---- */
+int pthread_cond_init(pthread_cond_t* cond, const pthread_condattr_t* attr) {
+ (void)attr;
+ if (!cond) return 22;
+ cond->__seq = 0;
+ return 0;
+}
+
+int pthread_cond_destroy(pthread_cond_t* cond) {
+ (void)cond;
+ return 0;
+}
+
+int pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex) {
+ int seq = cond->__seq;
+ pthread_mutex_unlock(mutex);
+ futex_wait(&cond->__seq, seq);
+ pthread_mutex_lock(mutex);
+ return 0;
+}
+
+int pthread_cond_signal(pthread_cond_t* cond) {
+ atomic_add(&cond->__seq, 1);
+ futex_wake(&cond->__seq, 1);
+ return 0;
+}
+
+int pthread_cond_broadcast(pthread_cond_t* cond) {
+ atomic_add(&cond->__seq, 1);
+ futex_wake(&cond->__seq, 0x7FFFFFFF);
+ return 0;
+}
+
+/* ---- Read-Write Lock ---- */
+int pthread_rwlock_init(pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr) {
+ (void)attr;
+ if (!rwlock) return 22;
+ rwlock->__readers = 0;
+ rwlock->__writer = 0;
+ return 0;
+}
+
+int pthread_rwlock_destroy(pthread_rwlock_t* rwlock) {
+ (void)rwlock;
+ return 0;
+}
+
+int pthread_rwlock_rdlock(pthread_rwlock_t* rwlock) {
+ while (1) {
+ while (rwlock->__writer)
+ futex_wait(&rwlock->__writer, 1);
+ atomic_add(&rwlock->__readers, 1);
+ if (!rwlock->__writer) return 0;
+ atomic_add(&rwlock->__readers, -1);
+ }
+}
+
+int pthread_rwlock_wrlock(pthread_rwlock_t* rwlock) {
+ while (atomic_xchg(&rwlock->__writer, 1) != 0)
+ futex_wait(&rwlock->__writer, 1);
+ while (rwlock->__readers > 0)
+ futex_wait(&rwlock->__readers, rwlock->__readers);
+ return 0;
+}
+
+int pthread_rwlock_tryrdlock(pthread_rwlock_t* rwlock) {
+ if (rwlock->__writer) return 16; /* EBUSY */
+ atomic_add(&rwlock->__readers, 1);
+ if (rwlock->__writer) {
+ atomic_add(&rwlock->__readers, -1);
+ return 16;
+ }
+ return 0;
+}
+
+int pthread_rwlock_trywrlock(pthread_rwlock_t* rwlock) {
+ if (atomic_cas(&rwlock->__writer, 0, 1) != 0) return 16;
+ if (rwlock->__readers > 0) {
+ rwlock->__writer = 0;
+ return 16;
+ }
+ return 0;
+}
+
+int pthread_rwlock_unlock(pthread_rwlock_t* rwlock) {
+ if (rwlock->__writer) {
+ rwlock->__writer = 0;
+ futex_wake(&rwlock->__writer, 0x7FFFFFFF);
+ } else {
+ atomic_add(&rwlock->__readers, -1);
+ if (rwlock->__readers == 0)
+ futex_wake(&rwlock->__readers, 1);
+ }
+ return 0;
+}
+
+/* ---- Thread-Specific Data ---- */
+#define PTHREAD_KEYS_MAX 32
+static void* _tsd_values[PTHREAD_KEYS_MAX];
+static void (*_tsd_destructors[PTHREAD_KEYS_MAX])(void*);
+static int _tsd_used[PTHREAD_KEYS_MAX];
+static int _tsd_next_key = 0;
+
+int pthread_key_create(pthread_key_t* key, void (*destructor)(void*)) {
+ if (!key) return 22;
+ if (_tsd_next_key >= PTHREAD_KEYS_MAX) return 11; /* EAGAIN */
+ int k = _tsd_next_key++;
+ _tsd_used[k] = 1;
+ _tsd_destructors[k] = destructor;
+ _tsd_values[k] = (void*)0;
+ *key = (pthread_key_t)k;
+ return 0;
+}
+
+int pthread_key_delete(pthread_key_t key) {
+ if (key >= PTHREAD_KEYS_MAX || !_tsd_used[key]) return 22;
+ _tsd_used[key] = 0;
+ _tsd_destructors[key] = (void*)0;
+ _tsd_values[key] = (void*)0;
+ return 0;
+}
+
+void* pthread_getspecific(pthread_key_t key) {
+ if (key >= PTHREAD_KEYS_MAX) return (void*)0;
+ return _tsd_values[key];
+}
+
+int pthread_setspecific(pthread_key_t key, const void* value) {
+ if (key >= PTHREAD_KEYS_MAX) return 22;
+ _tsd_values[key] = (void*)(uintptr_t)value;
+ return 0;
+}
+
+/* ---- Once ---- */
+int pthread_once(pthread_once_t* once_control, void (*init_routine)(void)) {
+ if (!once_control || !init_routine) return 22;
+ if (atomic_cas(once_control, 0, 1) == 0) {
+ init_routine();
+ *once_control = 2;
+ futex_wake(once_control, 0x7FFFFFFF);
+ } else {
+ while (*once_control == 1)
+ futex_wait(once_control, 1);
+ }
+ return 0;
+}
+
+/* ---- Barrier ---- */
+int pthread_barrier_init(pthread_barrier_t* barrier,
+ const pthread_barrierattr_t* attr, unsigned count) {
+ (void)attr;
+ if (!barrier || count == 0) return 22;
+ barrier->__count = 0;
+ barrier->__total = (int)count;
+ barrier->__seq = 0;
+ return 0;
+}
+
+int pthread_barrier_destroy(pthread_barrier_t* barrier) {
+ (void)barrier;
+ return 0;
+}
+
+int pthread_barrier_wait(pthread_barrier_t* barrier) {
+ int seq = barrier->__seq;
+ int n;
+ atomic_add(&barrier->__count, 1);
+ n = barrier->__count;
+ if (n >= barrier->__total) {
+ barrier->__count = 0;
+ atomic_add(&barrier->__seq, 1);
+ futex_wake(&barrier->__seq, 0x7FFFFFFF);
+ return PTHREAD_BARRIER_SERIAL_THREAD;
+ }
+ while (barrier->__seq == seq)
+ futex_wait(&barrier->__seq, seq);
+ return 0;
+}
#include "pwd.h"
#include "grp.h"
+#include "stdio.h"
+#include "string.h"
+#include "stdlib.h"
#include <stddef.h>
-/* Minimal /etc/passwd and /etc/group stubs.
- * AdrOS has a single-user model (uid=0 root). */
+/* /etc/passwd and /etc/group parsing with static fallback.
+ * Format: name:passwd:uid:gid:gecos:dir:shell */
static struct passwd _root = {
.pw_name = "root",
.pw_shell = "/bin/sh",
};
+static struct passwd _parsed_pw;
+static char _pw_line[256];
+static FILE* _pw_fp = (void*)0;
static int _pw_idx = 0;
+static struct passwd* parse_passwd_line(char* line) {
+ char* fields[7];
+ int n = 0;
+ char* p = line;
+ fields[n++] = p;
+ while (*p && n < 7) {
+ if (*p == ':') { *p = '\0'; fields[n++] = p + 1; }
+ p++;
+ }
+ if (n < 7) return (struct passwd*)0;
+ _parsed_pw.pw_name = fields[0];
+ _parsed_pw.pw_passwd = fields[1];
+ _parsed_pw.pw_uid = atoi(fields[2]);
+ _parsed_pw.pw_gid = atoi(fields[3]);
+ _parsed_pw.pw_gecos = fields[4];
+ _parsed_pw.pw_dir = fields[5];
+ _parsed_pw.pw_shell = fields[6];
+ /* Strip trailing newline */
+ size_t sl = strlen(_parsed_pw.pw_shell);
+ if (sl > 0 && _parsed_pw.pw_shell[sl - 1] == '\n')
+ _parsed_pw.pw_shell[sl - 1] = '\0';
+ return &_parsed_pw;
+}
+
struct passwd* getpwnam(const char* name) {
if (!name) return (struct passwd*)0;
- /* strcmp inline to avoid header dependency issues */
- const char* a = name;
- const char* b = "root";
- while (*a && *a == *b) { a++; b++; }
- if (*a == *b) return &_root;
+ FILE* fp = fopen("/etc/passwd", "r");
+ if (fp) {
+ while (fgets(_pw_line, (int)sizeof(_pw_line), fp)) {
+ struct passwd* pw = parse_passwd_line(_pw_line);
+ if (pw && strcmp(pw->pw_name, name) == 0) {
+ fclose(fp);
+ return pw;
+ }
+ }
+ fclose(fp);
+ }
+ if (strcmp(name, "root") == 0) return &_root;
return (struct passwd*)0;
}
struct passwd* getpwuid(int uid) {
+ FILE* fp = fopen("/etc/passwd", "r");
+ if (fp) {
+ while (fgets(_pw_line, (int)sizeof(_pw_line), fp)) {
+ struct passwd* pw = parse_passwd_line(_pw_line);
+ if (pw && pw->pw_uid == uid) {
+ fclose(fp);
+ return pw;
+ }
+ }
+ fclose(fp);
+ }
if (uid == 0) return &_root;
return (struct passwd*)0;
}
-void setpwent(void) { _pw_idx = 0; }
-void endpwent(void) { _pw_idx = 0; }
+void setpwent(void) {
+ if (_pw_fp) fclose(_pw_fp);
+ _pw_fp = fopen("/etc/passwd", "r");
+ _pw_idx = 0;
+}
+
+void endpwent(void) {
+ if (_pw_fp) { fclose(_pw_fp); _pw_fp = (void*)0; }
+ _pw_idx = 0;
+}
struct passwd* getpwent(void) {
+ if (_pw_fp) {
+ if (fgets(_pw_line, (int)sizeof(_pw_line), _pw_fp))
+ return parse_passwd_line(_pw_line);
+ return (struct passwd*)0;
+ }
if (_pw_idx == 0) { _pw_idx++; return &_root; }
return (struct passwd*)0;
}
.gr_mem = _root_members,
};
+static struct group _parsed_gr;
+static char _gr_line[256];
+static char* _gr_members[16];
+static FILE* _gr_fp = (void*)0;
static int _gr_idx = 0;
+static struct group* parse_group_line(char* line) {
+ /* Format: name:passwd:gid:member1,member2,... */
+ char* fields[4];
+ int n = 0;
+ char* p = line;
+ fields[n++] = p;
+ while (*p && n < 4) {
+ if (*p == ':') { *p = '\0'; fields[n++] = p + 1; }
+ p++;
+ }
+ if (n < 3) return (struct group*)0;
+ _parsed_gr.gr_name = fields[0];
+ _parsed_gr.gr_passwd = (n >= 2) ? fields[1] : "x";
+ _parsed_gr.gr_gid = atoi(fields[2]);
+ /* Parse members */
+ int mi = 0;
+ if (n >= 4 && fields[3][0] != '\0' && fields[3][0] != '\n') {
+ char* mp = fields[3];
+ _gr_members[mi++] = mp;
+ while (*mp && mi < 15) {
+ if (*mp == ',' || *mp == '\n') { *mp = '\0'; _gr_members[mi++] = mp + 1; }
+ mp++;
+ }
+ }
+ _gr_members[mi] = (char*)0;
+ _parsed_gr.gr_mem = _gr_members;
+ return &_parsed_gr;
+}
+
struct group* getgrnam(const char* name) {
if (!name) return (struct group*)0;
- const char* a = name;
- const char* b = "root";
- while (*a && *a == *b) { a++; b++; }
- if (*a == *b) return &_root_grp;
+ FILE* fp = fopen("/etc/group", "r");
+ if (fp) {
+ while (fgets(_gr_line, (int)sizeof(_gr_line), fp)) {
+ struct group* gr = parse_group_line(_gr_line);
+ if (gr && strcmp(gr->gr_name, name) == 0) {
+ fclose(fp);
+ return gr;
+ }
+ }
+ fclose(fp);
+ }
+ if (strcmp(name, "root") == 0) return &_root_grp;
return (struct group*)0;
}
struct group* getgrgid(int gid) {
+ FILE* fp = fopen("/etc/group", "r");
+ if (fp) {
+ while (fgets(_gr_line, (int)sizeof(_gr_line), fp)) {
+ struct group* gr = parse_group_line(_gr_line);
+ if (gr && gr->gr_gid == gid) {
+ fclose(fp);
+ return gr;
+ }
+ }
+ fclose(fp);
+ }
if (gid == 0) return &_root_grp;
return (struct group*)0;
}
-void setgrent(void) { _gr_idx = 0; }
-void endgrent(void) { _gr_idx = 0; }
+void setgrent(void) {
+ if (_gr_fp) fclose(_gr_fp);
+ _gr_fp = fopen("/etc/group", "r");
+ _gr_idx = 0;
+}
+
+void endgrent(void) {
+ if (_gr_fp) { fclose(_gr_fp); _gr_fp = (void*)0; }
+ _gr_idx = 0;
+}
struct group* getgrent(void) {
+ if (_gr_fp) {
+ if (fgets(_gr_line, (int)sizeof(_gr_line), _gr_fp))
+ return parse_group_line(_gr_line);
+ return (struct group*)0;
+ }
if (_gr_idx == 0) { _gr_idx++; return &_root_grp; }
return (struct group*)0;
}
--- /dev/null
+#include "semaphore.h"
+#include "syscall.h"
+#include "errno.h"
+
+sem_t* sem_open(const char* name, int oflag, ...) {
+ int ret = _syscall2(SYS_SEM_OPEN, (int)name, oflag);
+ if (ret < 0 && ret > -4096) {
+ errno = -ret;
+ return SEM_FAILED;
+ }
+ return (sem_t*)(long)ret;
+}
+
+int sem_close(sem_t* sem) {
+ return __syscall_ret(_syscall1(SYS_SEM_CLOSE, (int)sem));
+}
+
+int sem_wait(sem_t* sem) {
+ return __syscall_ret(_syscall1(SYS_SEM_WAIT, (int)sem));
+}
+
+int sem_trywait(sem_t* sem) {
+ return __syscall_ret(_syscall1(SYS_SEM_WAIT, (int)sem));
+}
+
+int sem_post(sem_t* sem) {
+ return __syscall_ret(_syscall1(SYS_SEM_POST, (int)sem));
+}
+
+int sem_unlink(const char* name) {
+ return __syscall_ret(_syscall1(SYS_SEM_UNLINK, (int)name));
+}
+
+int sem_getvalue(sem_t* sem, int* sval) {
+ return __syscall_ret(_syscall2(SYS_SEM_GETVALUE, (int)sem, (int)sval));
+}
+
+int sem_init(sem_t* sem, int pshared, unsigned int value) {
+ (void)pshared;
+ if (sem) sem->__val = (int)value;
+ return 0;
+}
+
+int sem_destroy(sem_t* sem) {
+ (void)sem;
+ return 0;
+}
--- /dev/null
+#include "sys/shm.h"
+#include "syscall.h"
+#include "errno.h"
+
+int shmget(key_t key, size_t size, int shmflg) {
+ return __syscall_ret(_syscall3(SYS_SHMGET, key, (int)size, shmflg));
+}
+
+void* shmat(int shmid, const void* shmaddr, int shmflg) {
+ int ret = _syscall3(SYS_SHMAT, shmid, (int)shmaddr, shmflg);
+ if (ret < 0 && ret > -4096) {
+ errno = -ret;
+ return (void*)-1;
+ }
+ return (void*)ret;
+}
+
+int shmdt(const void* shmaddr) {
+ return __syscall_ret(_syscall1(SYS_SHMDT, (int)shmaddr));
+}
+
+int shmctl(int shmid, int cmd, struct shmid_ds* buf) {
+ return __syscall_ret(_syscall3(SYS_SHMCTL, shmid, cmd, (int)buf));
+}
--- /dev/null
+#include "sys/socket.h"
+#include "syscall.h"
+#include "errno.h"
+
+int socket(int domain, int type, int protocol) {
+ return __syscall_ret(_syscall3(SYS_SOCKET, domain, type, protocol));
+}
+
+int bind(int sockfd, const struct sockaddr* addr, socklen_t addrlen) {
+ return __syscall_ret(_syscall3(SYS_BIND, sockfd, (int)addr, (int)addrlen));
+}
+
+int listen(int sockfd, int backlog) {
+ return __syscall_ret(_syscall2(SYS_LISTEN, sockfd, backlog));
+}
+
+int accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen) {
+ return __syscall_ret(_syscall3(SYS_ACCEPT, sockfd, (int)addr, (int)addrlen));
+}
+
+int connect(int sockfd, const struct sockaddr* addr, socklen_t addrlen) {
+ return __syscall_ret(_syscall3(SYS_CONNECT, sockfd, (int)addr, (int)addrlen));
+}
+
+int send(int sockfd, const void* buf, size_t len, int flags) {
+ return __syscall_ret(_syscall4(SYS_SEND, sockfd, (int)buf, (int)len, flags));
+}
+
+int recv(int sockfd, void* buf, size_t len, int flags) {
+ return __syscall_ret(_syscall4(SYS_RECV, sockfd, (int)buf, (int)len, flags));
+}
+
+int sendto(int sockfd, const void* buf, size_t len, int flags,
+ const struct sockaddr* dest_addr, socklen_t addrlen) {
+ return __syscall_ret(_syscall5(SYS_SENDTO, sockfd, (int)buf, (int)len, flags, (int)dest_addr));
+}
+
+int recvfrom(int sockfd, void* buf, size_t len, int flags,
+ struct sockaddr* src_addr, socklen_t* addrlen) {
+ return __syscall_ret(_syscall5(SYS_RECVFROM, sockfd, (int)buf, (int)len, flags, (int)src_addr));
+}
+
+int sendmsg(int sockfd, const struct msghdr* msg, int flags) {
+ return __syscall_ret(_syscall3(SYS_SENDMSG, sockfd, (int)msg, flags));
+}
+
+int recvmsg(int sockfd, struct msghdr* msg, int flags) {
+ return __syscall_ret(_syscall3(SYS_RECVMSG, sockfd, (int)msg, flags));
+}
+
+int setsockopt(int sockfd, int level, int optname, const void* optval, socklen_t optlen) {
+ return __syscall_ret(_syscall5(SYS_SETSOCKOPT, sockfd, level, optname, (int)optval, (int)optlen));
+}
+
+int getsockopt(int sockfd, int level, int optname, void* optval, socklen_t* optlen) {
+ return __syscall_ret(_syscall5(SYS_GETSOCKOPT, sockfd, level, optname, (int)optval, (int)optlen));
+}
+
+int shutdown(int sockfd, int how) {
+ return __syscall_ret(_syscall2(SYS_SHUTDOWN, sockfd, how));
+}
+
+int getpeername(int sockfd, struct sockaddr* addr, socklen_t* addrlen) {
+ return __syscall_ret(_syscall3(SYS_GETPEERNAME, sockfd, (int)addr, (int)addrlen));
+}
+
+int getsockname(int sockfd, struct sockaddr* addr, socklen_t* addrlen) {
+ return __syscall_ret(_syscall3(SYS_GETSOCKNAME, sockfd, (int)addr, (int)addrlen));
+}
--- /dev/null
+#include "spawn.h"
+#include "syscall.h"
+#include "errno.h"
+#include "string.h"
+
+int posix_spawn(int* pid, const char* path,
+ const posix_spawn_file_actions_t* file_actions,
+ const posix_spawnattr_t* attrp,
+ char* const argv[], char* const envp[]) {
+ (void)file_actions;
+ (void)attrp;
+ (void)envp;
+ int ret = _syscall2(SYS_POSIX_SPAWN, (int)path, (int)argv);
+ if (ret < 0) {
+ errno = -ret;
+ return -ret;
+ }
+ if (pid) *pid = ret;
+ return 0;
+}
+
+int posix_spawnp(int* pid, const char* file,
+ const posix_spawn_file_actions_t* file_actions,
+ const posix_spawnattr_t* attrp,
+ char* const argv[], char* const envp[]) {
+ return posix_spawn(pid, file, file_actions, attrp, argv, envp);
+}
+
+int posix_spawn_file_actions_init(posix_spawn_file_actions_t* fact) {
+ memset(fact, 0, sizeof(*fact));
+ return 0;
+}
+
+int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t* fact) {
+ (void)fact;
+ return 0;
+}
+
+int posix_spawnattr_init(posix_spawnattr_t* attr) {
+ memset(attr, 0, sizeof(*attr));
+ return 0;
+}
+
+int posix_spawnattr_destroy(posix_spawnattr_t* attr) {
+ (void)attr;
+ return 0;
+}
if (s) { strcpy(s, buf); return s; }
return buf;
}
+
+int fscanf(FILE* fp, const char* fmt, ...) {
+ /* Read a line, then delegate to sscanf */
+ char line[512];
+ if (!fgets(line, (int)sizeof(line), fp)) return EOF;
+ va_list ap;
+ va_start(ap, fmt);
+ /* We can't pass va_list to sscanf directly, so use a manual approach
+ * that matches sscanf's minimal implementation for %d and %s */
+ int count = 0;
+ const char* s = line;
+ const char* f = fmt;
+ while (*f && *s) {
+ if (*f == '%') {
+ f++;
+ if (*f == 'd' || *f == 'i') {
+ f++;
+ int* out = va_arg(ap, int*);
+ int neg = 0;
+ while (*s == ' ') s++;
+ if (*s == '-') { neg = 1; s++; }
+ else if (*s == '+') { s++; }
+ if (*s < '0' || *s > '9') break;
+ int val = 0;
+ while (*s >= '0' && *s <= '9') { val = val * 10 + (*s - '0'); s++; }
+ *out = neg ? -val : val;
+ count++;
+ } else if (*f == 's') {
+ f++;
+ char* out = va_arg(ap, char*);
+ while (*s == ' ') s++;
+ int i = 0;
+ while (*s && *s != ' ' && *s != '\n' && *s != '\t') out[i++] = *s++;
+ out[i] = '\0';
+ count++;
+ } else if (*f == 'c') {
+ f++;
+ char* out = va_arg(ap, char*);
+ *out = *s++;
+ count++;
+ } else {
+ break;
+ }
+ } else if (*f == ' ') {
+ f++;
+ while (*s == ' ') s++;
+ } else {
+ if (*f != *s) break;
+ f++; s++;
+ }
+ }
+ va_end(ap);
+ return count;
+}
+
+int scanf(const char* fmt, ...) {
+ char line[512];
+ if (!fgets(line, (int)sizeof(line), stdin)) return EOF;
+ va_list ap;
+ va_start(ap, fmt);
+ int count = 0;
+ const char* s = line;
+ const char* f = fmt;
+ while (*f && *s) {
+ if (*f == '%') {
+ f++;
+ if (*f == 'd' || *f == 'i') {
+ f++;
+ int* out = va_arg(ap, int*);
+ int neg = 0;
+ while (*s == ' ') s++;
+ if (*s == '-') { neg = 1; s++; }
+ else if (*s == '+') { s++; }
+ if (*s < '0' || *s > '9') break;
+ int val = 0;
+ while (*s >= '0' && *s <= '9') { val = val * 10 + (*s - '0'); s++; }
+ *out = neg ? -val : val;
+ count++;
+ } else if (*f == 's') {
+ f++;
+ char* out = va_arg(ap, char*);
+ while (*s == ' ') s++;
+ int i = 0;
+ while (*s && *s != ' ' && *s != '\n' && *s != '\t') out[i++] = *s++;
+ out[i] = '\0';
+ count++;
+ } else {
+ break;
+ }
+ } else if (*f == ' ') {
+ f++;
+ while (*s == ' ') s++;
+ } else {
+ if (*f != *s) break;
+ f++; s++;
+ }
+ }
+ va_end(ap);
+ return count;
+}
(void)cmd;
return -1;
}
+
+void* bsearch(const void* key, const void* base, size_t nmemb, size_t size,
+ int (*compar)(const void*, const void*)) {
+ const char* b = (const char*)base;
+ size_t lo = 0, hi = nmemb;
+ while (lo < hi) {
+ size_t mid = lo + (hi - lo) / 2;
+ int cmp = compar(key, b + mid * size);
+ if (cmp == 0) return (void*)(b + mid * size);
+ if (cmp < 0) hi = mid;
+ else lo = mid + 1;
+ }
+ return (void*)0;
+}
+
+div_t div(int numer, int denom) {
+ div_t r;
+ r.quot = numer / denom;
+ r.rem = numer % denom;
+ return r;
+}
+
+ldiv_t ldiv(long numer, long denom) {
+ ldiv_t r;
+ r.quot = numer / denom;
+ r.rem = numer % denom;
+ return r;
+}
+
+int mkstemp(char* tmpl) {
+ size_t len = strlen(tmpl);
+ if (len < 6) return -1;
+ char* suffix = tmpl + len - 6;
+ /* Check template ends with XXXXXX */
+ for (int i = 0; i < 6; i++)
+ if (suffix[i] != 'X') return -1;
+ /* Generate unique name using pid + counter */
+ extern int getpid(void);
+ static int counter = 0;
+ int id = getpid() * 1000 + (counter++ % 1000);
+ for (int i = 5; i >= 0; i--) {
+ suffix[i] = (char)('0' + id % 10);
+ id /= 10;
+ }
+ int fd = open(tmpl, 1 | 0x40 | 0x80 /* O_WRONLY|O_CREAT|O_EXCL */);
+ return fd;
+}
+
+double strtod(const char* nptr, char** endptr) {
+ const char* s = nptr;
+ int neg = 0;
+ while (*s == ' ' || *s == '\t') s++;
+ if (*s == '-') { neg = 1; s++; }
+ else if (*s == '+') { s++; }
+ double val = 0.0;
+ while (*s >= '0' && *s <= '9') { val = val * 10.0 + (*s - '0'); s++; }
+ if (*s == '.') {
+ s++;
+ double frac = 0.1;
+ while (*s >= '0' && *s <= '9') { val += (*s - '0') * frac; frac *= 0.1; s++; }
+ }
+ if (*s == 'e' || *s == 'E') {
+ s++;
+ int eneg = 0;
+ if (*s == '-') { eneg = 1; s++; }
+ else if (*s == '+') { s++; }
+ int exp = 0;
+ while (*s >= '0' && *s <= '9') { exp = exp * 10 + (*s - '0'); s++; }
+ double mult = 1.0;
+ for (int i = 0; i < exp; i++) mult *= 10.0;
+ if (eneg) val /= mult; else val *= mult;
+ }
+ if (endptr) *endptr = (char*)s;
+ return neg ? -val : val;
+}
+
+float strtof(const char* nptr, char** endptr) {
+ return (float)strtod(nptr, endptr);
+}
}
return (void*)0;
}
+
+static char _sigbuf[24];
+char* strsignal(int sig) {
+ static const char* const names[] = {
+ [0] = "Signal 0",
+ [1] = "Hangup",
+ [2] = "Interrupt",
+ [3] = "Quit",
+ [4] = "Illegal instruction",
+ [5] = "Trace/breakpoint trap",
+ [6] = "Aborted",
+ [7] = "Bus error",
+ [8] = "Floating point exception",
+ [9] = "Killed",
+ [10] = "User defined signal 1",
+ [11] = "Segmentation fault",
+ [12] = "User defined signal 2",
+ [13] = "Broken pipe",
+ [14] = "Alarm clock",
+ [15] = "Terminated",
+ [17] = "Child exited",
+ [18] = "Continued",
+ [19] = "Stopped (signal)",
+ [20] = "Stopped",
+ };
+ if (sig >= 0 && sig <= 20 && names[sig])
+ return (char*)names[sig];
+ /* fallback: "Signal N" */
+ char* p = _sigbuf;
+ const char* prefix = "Signal ";
+ while (*prefix) *p++ = *prefix++;
+ if (sig < 0) { *p++ = '-'; sig = -sig; }
+ char digits[8];
+ int n = 0;
+ do { digits[n++] = (char)('0' + sig % 10); sig /= 10; } while (sig);
+ while (n > 0) *p++ = digits[--n];
+ *p = '\0';
+ return _sigbuf;
+}
--- /dev/null
+#include "syslog.h"
+#include <stdarg.h>
+
+static const char* _syslog_ident = "";
+static int _syslog_facility = 0;
+
+void openlog(const char* ident, int option, int facility) {
+ (void)option;
+ _syslog_ident = ident ? ident : "";
+ _syslog_facility = facility;
+}
+
+void syslog(int priority, const char* format, ...) {
+ (void)priority;
+ (void)format;
+ /* Stub: AdrOS has no syslog daemon. Messages are silently dropped. */
+}
+
+void closelog(void) {
+ _syslog_ident = "";
+ _syslog_facility = 0;
+}
--- /dev/null
+#include "termios.h"
+#include "syscall.h"
+#include "errno.h"
+#include "string.h"
+
+speed_t cfgetispeed(const struct termios* t) {
+ (void)t;
+ return B115200;
+}
+
+speed_t cfgetospeed(const struct termios* t) {
+ (void)t;
+ return B115200;
+}
+
+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;
+}
+
+void cfmakeraw(struct termios* t) {
+ t->c_iflag &= ~(ICRNL | IGNCR | INLCR);
+ t->c_oflag &= ~OPOST;
+ t->c_lflag &= ~(ECHO | ICANON | ISIG);
+ t->c_cc[VMIN] = 1;
+ t->c_cc[VTIME] = 0;
+}
+
+int tcdrain(int fd) {
+ return __syscall_ret(_syscall2(SYS_IOCTL, fd, TCSETSW));
+}
+
+int tcflush(int fd, int queue_selector) {
+ (void)queue_selector;
+ return __syscall_ret(_syscall2(SYS_IOCTL, fd, TCSETSF));
+}
+
+int tcflow(int fd, int action) {
+ (void)fd; (void)action;
+ return 0;
+}
+
+int tcsendbreak(int fd, int duration) {
+ (void)fd; (void)duration;
+ return 0;
+}
+
+int tcgetpgrp(int fd) {
+ int pgrp = 0;
+ int ret = _syscall3(SYS_IOCTL, fd, TIOCGPGRP, (int)&pgrp);
+ if (ret < 0) { errno = -ret; return -1; }
+ return pgrp;
+}
+
+int tcsetpgrp(int fd, int pgrp) {
+ return __syscall_ret(_syscall3(SYS_IOCTL, fd, TIOCSPGRP, (int)&pgrp));
+}
}
int link(const char* oldpath, const char* newpath) {
- /* Use SYS_UNLINKAT slot 38 — AdrOS doesn't have a dedicated link syscall yet,
- * use a direct int $0x80 with the link syscall number if available */
- (void)oldpath; (void)newpath;
- return -1; /* TODO: implement when kernel has SYS_LINK */
+ return __syscall_ret(_syscall2(SYS_LINK, (int)oldpath, (int)newpath));
}
int symlink(const char* target, const char* linkpath) {
- (void)target; (void)linkpath;
- return -1; /* TODO: implement when kernel has SYS_SYMLINK */
+ return __syscall_ret(_syscall2(SYS_SYMLINK, (int)target, (int)linkpath));
}
int readlink(const char* path, char* buf, size_t bufsiz) {
- (void)path; (void)buf; (void)bufsiz;
- return -1; /* TODO: implement when kernel has SYS_READLINK */
+ return __syscall_ret(_syscall3(SYS_READLINK, (int)path, (int)buf, (int)bufsiz));
}
int tcgetattr(int fd, struct termios* t) {
* Cannot use hlt — it's privileged and causes #GP in ring 3. */
for (;;) __asm__ volatile("nop");
}
+
+int execle(const char* path, const char* arg, ...) {
+ /* Walk varargs to find argv[] and the trailing envp */
+ extern int execve(const char*, const char* const*, const char* const*);
+ const char* args[32];
+ int n = 0;
+ __builtin_va_list ap;
+ __builtin_va_start(ap, arg);
+ args[n++] = arg;
+ while (n < 31) {
+ const char* a = __builtin_va_arg(ap, const char*);
+ args[n++] = a;
+ if (!a) break;
+ }
+ args[n] = (void*)0;
+ char* const* envp = __builtin_va_arg(ap, char* const*);
+ __builtin_va_end(ap);
+ return execve(path, (const char* const*)args, (const char* const*)envp);
+}
+
+static char _login_buf[32] = "root";
+char* getlogin(void) {
+ return _login_buf;
+}
+
+int getlogin_r(char* buf, size_t bufsize) {
+ extern size_t strlen(const char*);
+ extern void* memcpy(void*, const void*, size_t);
+ const char* name = getlogin();
+ size_t len = strlen(name);
+ if (len + 1 > bufsize) return 34; /* ERANGE */
+ memcpy(buf, name, len + 1);
+ return 0;
+}
+
+long confstr(int name, char* buf, size_t len) {
+ (void)name;
+ const char* val = "/bin:/usr/bin";
+ extern size_t strlen(const char*);
+ size_t vlen = strlen(val) + 1;
+ if (buf && len > 0) {
+ size_t copy = vlen < len ? vlen : len;
+ extern void* memcpy(void*, const void*, size_t);
+ memcpy(buf, val, copy);
+ if (copy < vlen && len > 0) buf[len - 1] = '\0';
+ }
+ return (long)vlen;
+}
+
+void* sbrk(int increment) {
+ void* cur = brk((void*)0);
+ if (increment == 0) return cur;
+ void* new_end = (void*)((char*)cur + increment);
+ void* result = brk(new_end);
+ if ((unsigned int)result < (unsigned int)new_end) return (void*)-1;
+ return cur;
+}
--- /dev/null
+#include "wordexp.h"
+#include "string.h"
+#include "stdlib.h"
+
+int wordexp(const char* words, wordexp_t* pwordexp, int flags) {
+ if (!words || !pwordexp) return WRDE_BADCHAR;
+
+ if (!(flags & WRDE_APPEND)) {
+ pwordexp->we_wordc = 0;
+ pwordexp->we_wordv = (void*)0;
+ }
+
+ /* Minimal implementation: split on whitespace, no shell expansion */
+ char* copy = strdup(words);
+ if (!copy) return WRDE_NOSPACE;
+
+ size_t alloc = 8;
+ size_t offs = (flags & WRDE_DOOFFS) ? pwordexp->we_offs : 0;
+ char** wv = (char**)calloc(alloc + offs + 1, sizeof(char*));
+ if (!wv) { free(copy); return WRDE_NOSPACE; }
+
+ size_t count = 0;
+ char* saveptr;
+ char* tok = strtok_r(copy, " \t\n", &saveptr);
+ while (tok) {
+ if (count + offs + 1 >= alloc) {
+ alloc *= 2;
+ char** nv = (char**)realloc(wv, (alloc + offs + 1) * sizeof(char*));
+ if (!nv) {
+ for (size_t i = 0; i < count; i++) free(wv[offs + i]);
+ free(wv); free(copy);
+ return WRDE_NOSPACE;
+ }
+ wv = nv;
+ }
+ wv[offs + count] = strdup(tok);
+ if (!wv[offs + count]) {
+ for (size_t i = 0; i < count; i++) free(wv[offs + i]);
+ free(wv); free(copy);
+ return WRDE_NOSPACE;
+ }
+ count++;
+ tok = strtok_r((void*)0, " \t\n", &saveptr);
+ }
+ wv[offs + count] = (void*)0;
+
+ free(copy);
+ pwordexp->we_wordc = count;
+ pwordexp->we_wordv = wv;
+ return 0;
+}
+
+void wordfree(wordexp_t* pwordexp) {
+ if (!pwordexp || !pwordexp->we_wordv) return;
+ for (size_t i = 0; pwordexp->we_wordv[i]; i++)
+ free(pwordexp->we_wordv[i]);
+ free(pwordexp->we_wordv);
+ pwordexp->we_wordv = (void*)0;
+ pwordexp->we_wordc = 0;
+}