diff --git a/libc/Makefile b/libc/Makefile index 1e4610ab..59fa2b92 100644 --- a/libc/Makefile +++ b/libc/Makefile @@ -397,6 +397,7 @@ unistd/chroot.o \ unistd/close.o \ unistd/confstr.o \ unistd/dup2.o \ +unistd/dup3.o \ unistd/dup.o \ unistd/execle.o \ unistd/execl.o \ diff --git a/libc/include/unistd.h b/libc/include/unistd.h index 692ef19d..cfa16d4c 100644 --- a/libc/include/unistd.h +++ b/libc/include/unistd.h @@ -298,6 +298,7 @@ int chroot(const char*); int close(int); size_t confstr(int, char*, size_t); int dup2(int, int); +int dup3(int, int, int); int dup(int); void _exit(int) __attribute__ ((noreturn)); int execl(const char*, const char*, ...); diff --git a/libc/unistd/dup3.cpp b/libc/unistd/dup3.cpp new file mode 100644 index 00000000..a8aae77b --- /dev/null +++ b/libc/unistd/dup3.cpp @@ -0,0 +1,34 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2013. + + This file is part of the Sortix C Library. + + The Sortix C Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or (at your + option) any later version. + + The Sortix C Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with the Sortix C Library. If not, see . + + unistd/dup3.cpp + Duplicates a file descriptor. + +*******************************************************************************/ + +#include + +#include + +DEFN_SYSCALL3(int, sys_dup3, SYSCALL_DUP3, int, int, int); + +extern "C" int dup3(int oldfd, int newfd, int flags) +{ + return sys_dup3(oldfd, newfd, flags); +} diff --git a/sortix/dtable.cpp b/sortix/dtable.cpp index 5a1ba073..f3786679 100644 --- a/sortix/dtable.cpp +++ b/sortix/dtable.cpp @@ -122,8 +122,10 @@ int DescriptorTable::Allocate(Ref desc, int flags) return i; } -int DescriptorTable::Copy(int from, int to) +int DescriptorTable::Copy(int from, int to, int flags) { + if ( flags & ~__FD_ALLOWED_FLAGS ) + return errno = EINVAL, -1; ScopedLock lock(&dtablelock); if ( from < 0 || to < 0 ) return errno = EINVAL, -1; @@ -131,6 +133,8 @@ int DescriptorTable::Copy(int from, int to) return errno = EBADF, -1; if ( !entries[from].desc ) return errno = EBADF, -1; + if ( from == to ) + return errno = EINVAL, -1; while ( !(to < numentries) ) if ( !Enlargen(to+1) ) return -1; @@ -139,8 +143,8 @@ int DescriptorTable::Copy(int from, int to) if ( entries[to].desc ) /* TODO: Should this be synced or otherwise properly closed? */{} entries[to].desc = entries[from].desc; - entries[to].flags = entries[from].flags; } + entries[to].flags = flags; return to; } diff --git a/sortix/include/sortix/kernel/dtable.h b/sortix/include/sortix/kernel/dtable.h index e4add5ec..5df265b3 100644 --- a/sortix/include/sortix/kernel/dtable.h +++ b/sortix/include/sortix/kernel/dtable.h @@ -45,7 +45,7 @@ public: Ref Fork(); Ref Get(int index); int Allocate(Ref desc, int flags); - int Copy(int from, int to); + int Copy(int from, int to, int flags); void Free(int index); Ref FreeKeep(int index); void OnExecute(); diff --git a/sortix/include/sortix/syscallnum.h b/sortix/include/sortix/syscallnum.h index 2e27189e..6c8cc0cf 100644 --- a/sortix/include/sortix/syscallnum.h +++ b/sortix/include/sortix/syscallnum.h @@ -143,6 +143,7 @@ #define SYSCALL_GETPRIORITY 119 #define SYSCALL_SETPRIORITY 120 #define SYSCALL_PRLIMIT 121 -#define SYSCALL_MAX_NUM 122 /* index of highest constant + 1 */ +#define SYSCALL_DUP3 122 +#define SYSCALL_MAX_NUM 123 /* index of highest constant + 1 */ #endif diff --git a/sortix/io.cpp b/sortix/io.cpp index e3077745..f69eb6a2 100644 --- a/sortix/io.cpp +++ b/sortix/io.cpp @@ -128,10 +128,25 @@ static int sys_dup(int fd) return dtable->Allocate(desc, 0); } +static int sys_dup3(int oldfd, int newfd, int flags) +{ + if ( flags & ~(O_CLOEXEC | O_CLOFORK) ) + return errno = EINVAL, -1; + int fd_flags = 0; + flags |= flags & O_CLOEXEC ? FD_CLOEXEC : 0; + flags |= flags & O_CLOFORK ? FD_CLOFORK : 0; + Ref dtable = CurrentProcess()->GetDTable(); + return dtable->Copy(oldfd, newfd, fd_flags); +} + static int sys_dup2(int oldfd, int newfd) { - Ref dtable = CurrentProcess()->GetDTable(); - return dtable->Copy(oldfd, newfd); + if ( oldfd < 0 || newfd < 0 ) + return errno = EINVAL, -1; + int ret = sys_dup3(oldfd, newfd, 0); + if ( ret < 0 && errno == EINVAL ) + return errno = 0, newfd; + return ret; } // TODO: If this function fails the file may still have been created. Does a @@ -949,6 +964,7 @@ void Init() Syscall::Register(SYSCALL_CLOSE, (void*) sys_close); Syscall::Register(SYSCALL_CONNECT, (void*) sys_connect); Syscall::Register(SYSCALL_DUP2, (void*) sys_dup2); + Syscall::Register(SYSCALL_DUP3, (void*) sys_dup3); Syscall::Register(SYSCALL_DUP, (void*) sys_dup); Syscall::Register(SYSCALL_FACCESSAT, (void*) sys_faccessat); Syscall::Register(SYSCALL_FCHDIRAT, (void*) sys_fchdirat);