/* * Copyright 2021 The Emscripten Authors. All rights reserved. * Emscripten is available under two separate licenses, the MIT license and the * University of Illinois/NCSA Open Source License. Both these licenses can be * found in the LICENSE file. * * Unimplemented/dummy syscall implementations. These fall into 3 categories. * * 1. Fake it, use dummy/placeholder values and return success. * 2. Fake it, as above but warn at runtime if called. * 3. Return ENOSYS and warn at runtime if called. */ #include #include #include #include #include #include #include #include #include #include #include #include #include static int g_pid = 42; static int g_pgid = 42; static int g_ppid = 1; static int g_sid = 42; #ifdef NDEBUG #define REPORT(name) #else #define REPORT(name) \ emscripten_err("warning: unsupported syscall: __syscall_" #name); #endif #define UNIMPLEMENTED(name, args) \ weak int __syscall_##name args { \ REPORT(name); \ return -ENOSYS; \ } #define STRINGIFY(s) #s #define STR(s) STRINGIFY(s) weak int __syscall_uname(intptr_t buf) { if (!buf) { return -EFAULT; } const char* full_version = STR(__EMSCRIPTEN_MAJOR__) "." \ STR(__EMSCRIPTEN_MINOR__) "." \ STR(__EMSCRIPTEN_TINY__); struct utsname *utsname = (struct utsname *)buf; strcpy(utsname->sysname, "Emscripten"); strcpy(utsname->nodename, "emscripten"); strcpy(utsname->release, full_version); strcpy(utsname->version, "#1"); #ifdef __wasm64__ strcpy(utsname->machine, "wasm64"); #else strcpy(utsname->machine, "wasm32"); #endif return 0; } weak int __syscall_setpgid(int pid, int pgid) { if (pid && pid != g_pid) { return -ESRCH; } if (pgid && pgid != g_pgid) { return -EPERM; } return 0; } weak int __syscall_sync() { return 0; } weak int __syscall_getsid(int pid) { if (pid && pid != g_pid) { return -ESRCH; } return g_sid; } weak int __syscall_getpgid(int pid) { if (pid && pid != g_pid) { return -ESRCH; } return g_pgid; } weak int __syscall_getpid() { return g_pid; } weak int __syscall_getppid() { return g_ppid; } weak int __syscall_linkat(int olddirfd, intptr_t oldpath, int newdirfd, intptr_t newpath, int flags) { return -EMLINK; // no hardlinks for us } weak int __syscall_getgroups32(int size, intptr_t list) { if (size < 1) { return -EINVAL; } ((gid_t*)list)[0] = 0; return 1; } weak int __syscall_setsid() { return 0; // no-op } struct kusage { long utime_tv_sec; long utime_tv_usec; long stime_tv_sec; long stime_tv_usec; }; weak int __syscall_getrusage(int who, intptr_t usage) { REPORT(getrusage); struct kusage *u = (struct kusage*)usage; u->utime_tv_sec = 1; u->utime_tv_usec = 2; u->stime_tv_sec = 3; u->stime_tv_usec = 4; return 0; } weak int __syscall_getpriority(int which, int who) { return 0; } weak int __syscall_setpriority(int which, int who, int prio) { return -EPERM; } weak int __syscall_setdomainname(intptr_t name, size_t size) { return -EPERM; } weak int __syscall_getuid32(void) { return 0; } weak int __syscall_getgid32(void) { return 0; } weak int __syscall_geteuid32(void) { return 0; } weak int __syscall_getegid32(void) { return 0; } weak int __syscall_getresuid32(intptr_t ruid, intptr_t euid, intptr_t suid) { *((uid_t *)ruid) = 0; *((uid_t *)euid) = 0; *((uid_t *)suid) = 0; return 0; } weak int __syscall_getresgid32(intptr_t ruid, intptr_t euid, intptr_t suid) { REPORT(getresgid32); *((uid_t *)ruid) = 0; *((uid_t *)euid) = 0; *((uid_t *)suid) = 0; return 0; } weak int __syscall_pause() { REPORT(pause); return -EINTR; // we can't pause } weak int __syscall_madvise(intptr_t addr, size_t length, int advice) { REPORT(madvise); // advice is welcome, but ignored return 0; } weak int __syscall_mlock(intptr_t addr, size_t len) { REPORT(mlock); return 0; } weak int __syscall_munlock(intptr_t addr, size_t len) { REPORT(munlock); return 0; } weak int __syscall_mprotect(size_t addr, size_t len, int prot) { REPORT(mprotect); return 0; // let's not and say we did } weak int __syscall_mremap(intptr_t old_addr, size_t old_size, size_t new_size, int flags, intptr_t new_addr) { REPORT(mremap); return -ENOMEM; // never succeed } weak int __syscall_mlockall(int flags) { REPORT(mlockall); return 0; } weak int __syscall_munlockall() { REPORT(munlockall); return 0; } weak int __syscall_prlimit64(int pid, int resource, intptr_t new_limit, intptr_t old_limit) { REPORT(prlimit64); struct rlimit *old = (struct rlimit *)old_limit; if (new_limit) { return -EPERM; } if (old) { if (resource == RLIMIT_NOFILE) { // See FS.MAX_OPEN_FDS in src/lib/libfs.js old->rlim_cur = 4096; old->rlim_max = 4096; } else if (resource == RLIMIT_STACK) { uintptr_t end = emscripten_stack_get_end(); uintptr_t base = emscripten_stack_get_base(); old->rlim_cur = base - end; // we can not change the stack size, so the maximum is the same as the current old->rlim_max = base - end; } else { // Just report no limits old->rlim_cur = RLIM_INFINITY; old->rlim_max = RLIM_INFINITY; } } return 0; } weak int __syscall_setsockopt(int sockfd, int level, int optname, intptr_t optval, size_t optlen, int dummy) { REPORT(setsockopt); return -ENOPROTOOPT; // The option is unknown at the level indicated. } UNIMPLEMENTED(acct, (intptr_t filename)) UNIMPLEMENTED(mincore, (intptr_t addr, size_t length, intptr_t vec)) UNIMPLEMENTED(recvmmsg, (int sockfd, intptr_t msgvec, size_t vlen, int flags, ...)) UNIMPLEMENTED(sendmmsg, (int sockfd, intptr_t msgvec, size_t vlen, int flags, ...)) UNIMPLEMENTED(shutdown, (int sockfd, int how, int dummy, int dummy2, int dummy3, int dummy4)) UNIMPLEMENTED(socketpair, (int domain, int type, int protocol, intptr_t fds, int dummy, int dummy2)) UNIMPLEMENTED(wait4,(int pid, intptr_t wstatus, int options, int rusage))