2014-06-07 23:35:13 -07:00

661 lines
13 KiB
C

/* 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 <sys/types.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <sys/times.h>
#include <sys/errno.h>
#include <sys/time.h>
#include <sys/utsname.h>
#include <sys/termios.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <stdarg.h>
#include <utime.h>
#include <signal.h>
#include <_ansi.h>
#include <errno.h>
#include "syscall.h"
#include <bits/dirent.h>
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");
}