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);