/* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md * Copyright (C) 2012-2014 Kevin Lange */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include <_ansi.h> #include #include "syscall.h" #include extern void *malloc(size_t size); extern void free(void *ptr); extern void *calloc(size_t nmemb, size_t size); extern void *realloc(void *ptr, size_t size); extern void _init(); extern void _fini(); DEFN_SYSCALL1(exit, 0, int); DEFN_SYSCALL1(print, 1, const char *); DEFN_SYSCALL3(open, 2, const char *, int, int); DEFN_SYSCALL3(read, 3, int, char *, int); DEFN_SYSCALL3(write, 4, int, char *, int); DEFN_SYSCALL1(close, 5, int); DEFN_SYSCALL2(gettimeofday, 6, void *, void *); DEFN_SYSCALL3(execve, 7, char *, char **, char **); DEFN_SYSCALL0(fork, 8); DEFN_SYSCALL0(getpid, 9); DEFN_SYSCALL1(sbrk, 10, int); DEFN_SYSCALL0(getgraphicsaddress, 11); DEFN_SYSCALL1(uname, 12, void *); DEFN_SYSCALL5(openpty, 13, int *, int *, char *, void *, void *); DEFN_SYSCALL3(lseek, 14, int, int, int); DEFN_SYSCALL2(fstat, 15, int, void *); DEFN_SYSCALL1(setgraphicsoffset, 16, int); DEFN_SYSCALL1(wait, 17, unsigned int); DEFN_SYSCALL0(getgraphicswidth, 18); DEFN_SYSCALL0(getgraphicsheight, 19); DEFN_SYSCALL0(getgraphicsdepth, 20); DEFN_SYSCALL0(mkpipe, 21); DEFN_SYSCALL2(dup2, 22, int, int); DEFN_SYSCALL0(getuid, 23); DEFN_SYSCALL1(setuid, 24, unsigned int); DEFN_SYSCALL1(kernel_string_XXX, 25, char *); DEFN_SYSCALL0(reboot, 26); DEFN_SYSCALL3(readdir, 27, int, int, void *); DEFN_SYSCALL1(chdir, 28, char *); DEFN_SYSCALL2(getcwd, 29, char *, size_t); DEFN_SYSCALL3(clone, 30, uintptr_t, uintptr_t, void *); DEFN_SYSCALL1(sethostname, 31, char *); DEFN_SYSCALL1(gethostname, 32, char *); DEFN_SYSCALL0(mousedevice, 33); DEFN_SYSCALL2(mkdir, 34, char *, unsigned int); DEFN_SYSCALL2(shm_obtain, 35, char *, size_t *); DEFN_SYSCALL1(shm_release, 36, char *); DEFN_SYSCALL2(send_signal, 37, uint32_t, uint32_t); DEFN_SYSCALL2(signal, 38, uint32_t, void *); DEFN_SYSCALL2(share_fd, 39, int, int); DEFN_SYSCALL1(get_fd, 40, int); DEFN_SYSCALL0(gettid, 41); DEFN_SYSCALL0(yield, 42); DEFN_SYSCALL2(system_function, 43, int, char **); DEFN_SYSCALL1(open_serial, 44, int); DEFN_SYSCALL2(sleepabs, 45, unsigned long, unsigned long); DEFN_SYSCALL2(nanosleep, 46, unsigned long, unsigned long); DEFN_SYSCALL3(ioctl, 47, int, int, void *); DEFN_SYSCALL2(access, 48, char *, int); DEFN_SYSCALL2(stat, 49, char *, void *); DEFN_SYSCALL2(chmod, 50, char *, mode_t); DEFN_SYSCALL1(umask, 51, mode_t); DEFN_SYSCALL1(unlink, 52, char *); DEFN_SYSCALL3(waitpid, 53, int, int *, int); DEFN_SYSCALL1(pipe, 54, int *); #define DEBUG_STUB(...) { fprintf(stderr, "\033[1;32mUserspace Debug\033[0m pid%d ", getpid()); fprintf(stderr, __VA_ARGS__); } extern char ** environ; int ioctl(int fd, int request, void * argp); #define DEFAULT_PATH ".:/bin:/usr/bin" // --- Process Control --- int _exit(int val){ _fini(); return syscall_exit(val); } int execve(const char *name, char * const argv[], char * const envp[]) { return syscall_execve((char*)name,(char**)argv,(char**)envp); } int execvp(const char *file, char *const argv[]) { if (file && (!strstr(file, "/"))) { /* We don't quite understand "$PATH", so... */ char * path = getenv("PATH"); if (!path) { path = DEFAULT_PATH; } char * xpath = strdup(path); int found = 0; char * p, * tokens[10], * last; int i = 0; for ((p = strtok_r(xpath, ":", &last)); p; p = strtok_r(NULL, ":", &last)) { int r; struct stat stat_buf; char * exe = malloc(strlen(p) + strlen(file) + 2); strcpy(exe, p); strcat(exe, "/"); strcat(exe, file); r = stat(exe, &stat_buf); if (r != 0) { continue; } if (!(stat_buf.st_mode & 0111)) { continue; /* XXX not technically correct; need to test perms */ } return execve(exe, argv, environ); } free(xpath); errno = ENOENT; return -1; } else if (file) { return execve(file, argv, environ); } errno = ENOENT; return -1; } int execv(const char * file, char *const argv[]) { return execve(file,argv,environ); } /* * getpid -- only one process, so just return 1. */ int getpid() { return syscall_getpid(); } /* Fork. Duh. */ int fork(void) { return syscall_fork(); } int uname(struct utsname *__name) { return syscall_uname((void *)__name); } /* * kill -- go out via exit... */ int kill(int pid, int sig) { return syscall_send_signal(pid, sig); } sighandler_t signal(int signum, sighandler_t handler) { return (sighandler_t)syscall_signal(signum, (void *)handler); } #if 0 int raise(int sig) { kill(getpid(), sig); return 0; } #endif int waitpid(int pid, int *status, int options) { /* XXX: status, options? */ int i = syscall_waitpid(pid, status, options); if (i < 0) { errno = -i; return -1; } return i; } int wait(int *status) { return waitpid(-1, status, 0); } // --- I/O --- int isatty(int fd) { int dtype = ioctl(fd, IOCTLDTYPE, NULL); if (dtype == IOCTL_DTYPE_TTY) return 1; errno = EINVAL; return 0; } int close(int file) { return syscall_close(file); } int link(char *old, char *new) { DEBUG_STUB("[debug] pid %d: link(%s, %s);\n", getpid(), old, new); errno = EMLINK; return -1; } int lseek(int file, int ptr, int dir) { return syscall_lseek(file,ptr,dir); } int open(const char *name, int flags, ...) { va_list argp; int mode; int result; va_start(argp, flags); if (flags & O_CREAT) mode = va_arg(argp, int); va_end(argp); result = syscall_open(name, flags, mode); if (result == -1) { if (flags & O_CREAT) { errno = EACCES; } else { errno = ENOENT; } } return result; } int read(int file, char *ptr, int len) { return syscall_read(file,ptr,len); } int creat(const char *path, mode_t mode) { return open(path, O_WRONLY|O_CREAT|O_TRUNC, mode); } int fstat(int file, struct stat *st) { syscall_fstat(file, st); return 0; } int stat(const char *file, struct stat *st){ int ret = syscall_stat((char *)file, (void *)st); if (ret >= 0) { return ret; } else { errno = ENOENT; /* meh */ memset(st, 0x00, sizeof(struct stat)); return ret;; } } int write(int file, char *ptr, int len) { return syscall_write(file,ptr,len); } /* * sbrk: request a larger heap * [the kernel will give this to us] */ caddr_t sbrk(int nbytes){ return (caddr_t)syscall_sbrk(nbytes); } // --- Other --- int gettimeofday(struct timeval *p, void *z){ return syscall_gettimeofday(p,z); } int pipe(int fildes[2]) { int ret = syscall_pipe((int *)fildes); if (ret < 0) { errno = -ret; return -1; } return ret; } char *getcwd(char *buf, size_t size) { if (!buf) buf = malloc(size); return (char *)syscall_getcwd(buf, size); } char *getwd(char *buf) { return getcwd(buf, 256); } int lstat(const char *path, struct stat *buf) { return stat(path, buf); } int mkdir(const char *pathname, mode_t mode) { return syscall_mkdir((char *)pathname, mode); } int chdir(const char *path) { return syscall_chdir((char*)path); } unsigned int sleep(unsigned int seconds) { syscall_nanosleep(seconds, 0); return 0; } int usleep(useconds_t usec) { syscall_nanosleep(0, usec / 10000); return 0; } char _username[256]; char *getlogin(void) { #define LINE_LEN 4096 FILE * passwd = fopen("/etc/passwd", "r"); char line[LINE_LEN]; int uid = syscall_getuid(); while (fgets(line, LINE_LEN, passwd) != NULL) { line[strlen(line)-1] = '\0'; char *p, *tokens[10], *last; int i = 0; for ((p = strtok_r(line, ":", &last)); p; (p = strtok_r(NULL, ":", &last)), i++) { if (i < 511) tokens[i] = p; } tokens[i] = NULL; if (atoi(tokens[2]) == uid) { memcpy(_username, tokens[0], strlen(tokens[0])+1); break; } } fclose(passwd); return (char *)&_username; } int dup2(int oldfd, int newfd) { return syscall_dup2(oldfd, newfd); } DIR * opendir (const char * dirname) { int fd = open(dirname, O_RDONLY); if (fd == -1) { return NULL; } DIR * dir = (DIR *)malloc(sizeof(DIR)); dir->fd = fd; dir->cur_entry = -1; return dir; } int closedir (DIR * dir) { if (dir && (dir->fd != -1)) { return close(dir->fd); } else { return -1; } } struct dirent * readdir (DIR * dirp) { static struct dirent ent; int ret = syscall_readdir(dirp->fd, ++dirp->cur_entry, &ent); if (ret != 0) { memset(&ent, 0, sizeof(struct dirent)); return NULL; } return &ent; } void pre_main(int (*main)(int,char**), int argc, char * argv[]) { unsigned int x = 0; unsigned int nulls = 0; for (x = 0; 1; ++x) { if (!argv[x]) { ++nulls; if (nulls == 2) { break; } continue; } if (nulls == 1) { environ = &argv[x]; break; } } _init(); _exit(main(argc, argv)); } /* XXX Unimplemented functions */ unsigned int alarm(unsigned int seconds) { DEBUG_STUB("alarm(%s);\n", seconds); return 0; } clock_t times(struct tms *buf) { /* TODO: times() */ return -1; } int fcntl(int fd, int cmd, ...) { if (cmd == F_GETFD || cmd == F_SETFD) { return 0; } DEBUG_STUB("[user/debug] Unsupported operation [fcntl]\n"); /* Not supported */ return -1; } mode_t umask(mode_t mask) { return syscall_umask(mask); } int chmod(const char *path, mode_t mode) { return syscall_chmod((char *)path, mode); } int unlink(char *name) { return syscall_unlink(name); } int access(const char *pathname, int mode) { int result = syscall_access((char *)pathname, mode); if (result < 0) { errno = ENOENT; /* XXX */ } return result; } long pathconf(char *path, int name) { DEBUG_STUB("[user/debug] Unsupported operation [pathconf]\n"); /* Not supported */ return 0; } int utime(const char *filename, const struct utimbuf *times) { DEBUG_STUB("[user/debug] Unsupported operation [utime]\n"); return 0; } int chown(const char *path, uid_t owner, gid_t group) { DEBUG_STUB("[user/debug] Unsupported operation [chown]\n"); return 0; } int rmdir(const char *pathname) { DEBUG_STUB("[user/debug] Unsupported operation [rmdir]\n"); return 0; } char *ttyname(int fd) { errno = ENOTTY; return NULL; } long sysconf(int name) { switch (name) { case 8: return 4096; case 11: return 10000; default: DEBUG_STUB("sysconf(%d);\n", name); return -1; } } int ioctl(int fd, int request, void * argp) { return syscall_ioctl(fd, request, argp); } /* termios */ speed_t cfgetispeed(const struct termios * tio) { return 0; } speed_t cfgetospeed(const struct termios * tio) { return 0; } int cfsetispeed(struct termios * tio, speed_t speed) { /* hahahaha, yeah right */ return 0; } int cfsetospeed(struct termios * tio, speed_t speed) { return 0; } int tcdrain(int i) { DEBUG_STUB("tcdrain(%d)\n", i); return 0; } int tcflow(int fd, int arg) { return ioctl(fd, TCXONC, arg); } int tcflush(int fd, int arg) { return ioctl(fd, TCFLSH, arg); } pid_t tcgetsid(int fd) { DEBUG_STUB("tcgetsid(%d)\n", fd); return getpid(); } int tcsendbreak(int fd, int arg) { return ioctl(fd, TCSBRK, arg); } int tcgetattr(int fd, struct termios * tio) { return ioctl(fd, TCGETS, tio); } int tcsetattr(int fd, int actions, struct termios * tio) { switch (actions) { case TCSANOW: return ioctl(fd, TCSETS, tio); case TCSADRAIN: return ioctl(fd, TCSETSW, tio); case TCSAFLUSH: return ioctl(fd, TCSETSF, tio); default: return 0; } } int tcsetpgrp(int fd, pid_t pgrp) { return ioctl(fd, TIOCSPGRP, &pgrp); } pid_t tcgetpgrp(int fd) { pid_t pgrp; ioctl(fd, TIOCGPGRP, &pgrp); return pgrp; } int fpathconf(int file, int name) { DEBUG_STUB("fpathconf(%d,%d)\n", file, name); return 0; } int setuid(uid_t uid) { return syscall_setuid(uid); } int getuid() { return syscall_getuid(); } int getgid() { return getuid(); } int getpgrp() { /* XXX */ return getgid(); } int geteuid() { return getuid(); } int getegid() { return getgid(); } int getgroups(int size, gid_t list[]) { DEBUG_STUB("getgroups(...);\n"); return 0; } pid_t wait3(int *status, int options, void *rusage) { return wait(status); } int dup(int oldfd) { return dup2(oldfd, 0); } int sched_yield(void) { return syscall_yield(); } int sigprocmask(int how, const sigset_t *set, sigset_t *oldset) { DEBUG_STUB("sigprocmask(%d, 0x%x, 0x%x);\n", how, set, oldset); return -1; } int sigsuspend(const sigset_t * mask) { DEBUG_STUB("sigsuspend(0x%x);\n", mask); syscall_yield(); return -1; } int setpgid(pid_t pid, pid_t pgid) { DEBUG_STUB("setpgid(%d,%d);\n", pid, pgid); return -1; } int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact) { sighandler_t old; if (act) { old = signal(signum, act->sa_handler); } else { /* We don't have a way to query, so we need to set to something, then * set back to whatever it was... XXX */ old = signal(signum, NULL); signal(signum, old); } if (oldact) { oldact->sa_handler = old; } if (act) { DEBUG_STUB("sigaction(%d,...,0x%x);\n", signum, act->sa_flags); } return 0; } pid_t getppid() { DEBUG_STUB("getppid()\n"); return 0; } void sync() { DEBUG_STUB("sync();\n"); }