#include #include #include #include #include #include #include #include #include extern "C" long arch_invoke_syscall(long, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t); extern char** environ; extern "C" { pid_t fork(void) { long rc = syscall(SYS_fork); __errno_return(rc, int); } pid_t getpid(void) { return (pid_t)syscall(SYS_getpid); } pid_t getppid(void) { return (pid_t)syscall(SYS_getppid); } int execv(const char* path, char* const* argv) { return execve(path, argv, environ); } int execve(const char* path, char* const* argv, char* const* envp) { long rc = syscall(SYS_execve, path, argv, envp); __errno_return(rc, int); } int execvpe(const char* name, char* const* argv, char* const* envp) { if (strchr(name, '/')) return execve(name, argv, envp); char* path = getenv("PATH"); if (!path) path = const_cast("/bin:/sbin"); Vector paths; bool ok = StringView { path }.split(":").try_move_value_or_error(paths, errno); if (!ok) return -1; for (const auto& dir : paths) { // FIXME: Check for errors. StringBuilder sb; sb.add(dir); sb.add('/'); sb.add(StringView { name }); String file; ok = sb.string().try_move_value_or_error(file, errno); if (!ok) return -1; int err = errno; execve(file.chars(), argv, envp); if (errno != ENOENT && errno != EACCES && errno != ENOEXEC) return -1; if (errno == ENOEXEC) { Vector shell_argv; shell_argv.try_append(const_cast("sh")); char* const* arg = argv; do { shell_argv.try_append(*arg); } while (*(arg++)); execve("/bin/sh", shell_argv.data(), envp); errno = ENOEXEC; return -1; } if (err == EACCES) errno = err; } return -1; } int execvp(const char* name, char* const* argv) { return execvpe(name, argv, environ); } int execl(const char* path, const char* arg, ...) { va_list ap; va_start(ap, arg); Vector args; if (args.try_append(const_cast(arg)).has_error()) return -1; while (true) { char* str = va_arg(ap, char*); if (args.try_append(str).has_error()) return -1; if (!str) break; } va_end(ap); return execv(path, args.data()); } long syscall(long num, ...) { va_list ap; va_start(ap, num); uintptr_t arg0 = va_arg(ap, uintptr_t); uintptr_t arg1 = va_arg(ap, uintptr_t); uintptr_t arg2 = va_arg(ap, uintptr_t); uintptr_t arg3 = va_arg(ap, uintptr_t); uintptr_t arg4 = va_arg(ap, uintptr_t); long rc = arch_invoke_syscall(num, arg0, arg1, arg2, arg3, arg4); va_end(ap); return rc; } int usleep(useconds_t us) { long rc = syscall(SYS_usleep, us); __errno_return(rc, int); } unsigned long sleep(unsigned long seconds) { syscall(SYS_usleep, seconds * 1000000); return 0; } int close(int fd) { long rc = syscall(SYS_close, fd); __errno_return(rc, int); } ssize_t read(int fd, void* buf, size_t size) { long rc = syscall(SYS_read, fd, buf, size); __errno_return(rc, ssize_t); } ssize_t write(int fd, const void* buf, size_t size) { long rc = syscall(SYS_write, fd, buf, size); __errno_return(rc, ssize_t); } off_t lseek(int fd, off_t offset, int whence) { long rc = syscall(SYS_lseek, fd, offset, whence); __errno_return(rc, off_t); } int dup(int fd) { return fcntl(fd, F_DUPFD, 0); } }