diff options
-rw-r--r-- | src/init/syscalls.c | 4 | ||||
-rw-r--r-- | src/init/tests/main.c | 54 | ||||
-rw-r--r-- | src/kernel/syscalls.c | 27 | ||||
-rw-r--r-- | src/shared/syscalls.h | 4 |
4 files changed, 88 insertions, 1 deletions
diff --git a/src/init/syscalls.c b/src/init/syscalls.c index 25fa134..7c2bb68 100644 --- a/src/init/syscalls.c +++ b/src/init/syscalls.c @@ -26,6 +26,10 @@ int _syscall_mount(handle_t h, const char __user *path, int len) { return _syscall(_SYSCALL_MOUNT, (int)h, (int)path, len, 0); } +handle_t _syscall_dup(handle_t from, handle_t to, int flags) { + return (handle_t)_syscall(_SYSCALL_DUP, (int)from, (int)to, flags, 0); +} + int _syscall_read(handle_t h, void __user *buf, size_t len, int offset) { return _syscall(_SYSCALL_READ, (int)h, (int)buf, (int)len, offset); } diff --git a/src/init/tests/main.c b/src/init/tests/main.c index 9adb50c..97ed798 100644 --- a/src/init/tests/main.c +++ b/src/init/tests/main.c @@ -113,6 +113,59 @@ static void test_memflag(void) { // TODO check if reclaims } +static void test_dup(void) { + handle_t pipe[2]; + handle_t h1, h2; + assert(_syscall_pipe(pipe, 0) >= 0); + + if (!_syscall_fork(0, NULL)) { + _syscall_close(pipe[0]); + + h1 = _syscall_dup(pipe[1], -1, 0); + assert(h1 >= 0); + assert(h1 != pipe[1]); + h2 = _syscall_dup(h1, -1, 0); + assert(h2 >= 0); + assert(h2 != pipe[1] && h2 != h1); + + _syscall_write(pipe[1], "og", 2, 0); + _syscall_write(h1, "h1", 2, 0); + _syscall_write(h2, "h2", 2, 0); + + _syscall_close(pipe[1]); + _syscall_write(h1, "h1", 2, 0); + _syscall_write(h2, "h2", 2, 0); + + assert(_syscall_dup(h1, pipe[1], 0) == pipe[1]); + assert(_syscall_dup(h2, pipe[1], 0) == pipe[1]); + assert(_syscall_dup(h1, pipe[1], 0) == pipe[1]); + assert(_syscall_dup(h2, pipe[1], 0) == pipe[1]); + _syscall_close(h1); + _syscall_close(h2); + + assert(_syscall_dup(pipe[1], h2, 0) == h2); + _syscall_write(h2, "h2", 2, 0); + _syscall_close(h2); + + assert(_syscall_dup(pipe[1], h1, 0) == h1); + _syscall_write(h1, "h1", 2, 0); + _syscall_close(h1); + + _syscall_exit(0); + } else { + char buf[16]; + size_t count = 0; + _syscall_close(pipe[1]); + while (_syscall_read(pipe[0], buf, sizeof buf, 0) >= 0) + count++; + assert(count == 7); + _syscall_await(); + } + + + _syscall_close(pipe[0]); +} + static void test_malloc(void) { // not really a test void *p1, *p2; @@ -144,6 +197,7 @@ void test_all(void) { run_forked(test_interrupted_fs); run_forked(test_orphaned_fs); run_forked(test_memflag); + run_forked(test_dup); run_forked(test_malloc); run_forked(test_pipe); run_forked(test_semaphore); diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c index 421b5ce..1d18ad1 100644 --- a/src/kernel/syscalls.c +++ b/src/kernel/syscalls.c @@ -176,6 +176,30 @@ fail: SYSCALL_RETURN(-1); } +handle_t _syscall_dup(handle_t from, handle_t to, int flags) { + struct handle *fromh, **toh; + if (flags) SYSCALL_RETURN(-1); + + if (to < 0) { + to = process_find_free_handle(process_current, 0); + if (to < 0) SYSCALL_RETURN(-1); + } else if (to >= HANDLE_MAX) { + SYSCALL_RETURN(-1); + } + + if (to == from) + SYSCALL_RETURN(to); + toh = &process_current->handles[to]; + fromh = (from >= 0 && from < HANDLE_MAX) ? + process_current->handles[from] : NULL; + + if (*toh) handle_close(*toh); + *toh = fromh; + if (fromh) fromh->refcount++; + + SYSCALL_RETURN(to); +} + int _syscall_read(handle_t handle_num, void __user *buf, size_t len, int offset) { struct handle *h = process_handle_get(process_current, handle_num); if (!h) SYSCALL_RETURN(-1); @@ -360,6 +384,9 @@ int _syscall(int num, int a, int b, int c, int d) { case _SYSCALL_MOUNT: _syscall_mount(a, (userptr_t)b, c); break; + case _SYSCALL_DUP: + _syscall_dup(a, b, c); + break; case _SYSCALL_READ: _syscall_read(a, (userptr_t)b, c, d); break; diff --git a/src/shared/syscalls.h b/src/shared/syscalls.h index f19f05a..1383ebd 100644 --- a/src/shared/syscalls.h +++ b/src/shared/syscalls.h @@ -15,6 +15,7 @@ enum { _SYSCALL_OPEN, _SYSCALL_MOUNT, + _SYSCALL_DUP, _SYSCALL_READ, _SYSCALL_WRITE, @@ -53,8 +54,9 @@ int _syscall_await(void); int _syscall_fork(int flags, handle_t __user *fs_front); handle_t _syscall_open(const char __user *path, int len, int flags); - int _syscall_mount(handle_t h, const char __user *path, int len); +handle_t _syscall_dup(handle_t from, handle_t to, int flags); + int _syscall_read(handle_t h, void __user *buf, size_t len, int offset); int _syscall_write(handle_t h, const void __user *buf, size_t len, int offset); int _syscall_close(handle_t h); |