|
@@ -26,127 +26,6 @@
|
|
|
#include <asm/siginfo.h>
|
|
|
#include <asm/uaccess.h>
|
|
|
|
|
|
-void set_close_on_exec(unsigned int fd, int flag)
|
|
|
-{
|
|
|
- struct files_struct *files = current->files;
|
|
|
- struct fdtable *fdt;
|
|
|
- spin_lock(&files->file_lock);
|
|
|
- fdt = files_fdtable(files);
|
|
|
- if (flag)
|
|
|
- __set_close_on_exec(fd, fdt);
|
|
|
- else
|
|
|
- __clear_close_on_exec(fd, fdt);
|
|
|
- spin_unlock(&files->file_lock);
|
|
|
-}
|
|
|
-
|
|
|
-static bool get_close_on_exec(unsigned int fd)
|
|
|
-{
|
|
|
- struct files_struct *files = current->files;
|
|
|
- struct fdtable *fdt;
|
|
|
- bool res;
|
|
|
- rcu_read_lock();
|
|
|
- fdt = files_fdtable(files);
|
|
|
- res = close_on_exec(fd, fdt);
|
|
|
- rcu_read_unlock();
|
|
|
- return res;
|
|
|
-}
|
|
|
-
|
|
|
-SYSCALL_DEFINE3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags)
|
|
|
-{
|
|
|
- int err = -EBADF;
|
|
|
- struct file * file, *tofree;
|
|
|
- struct files_struct * files = current->files;
|
|
|
- struct fdtable *fdt;
|
|
|
-
|
|
|
- if ((flags & ~O_CLOEXEC) != 0)
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- if (unlikely(oldfd == newfd))
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- if (newfd >= rlimit(RLIMIT_NOFILE))
|
|
|
- return -EMFILE;
|
|
|
-
|
|
|
- spin_lock(&files->file_lock);
|
|
|
- err = expand_files(files, newfd);
|
|
|
- file = fcheck(oldfd);
|
|
|
- if (unlikely(!file))
|
|
|
- goto Ebadf;
|
|
|
- if (unlikely(err < 0)) {
|
|
|
- if (err == -EMFILE)
|
|
|
- goto Ebadf;
|
|
|
- goto out_unlock;
|
|
|
- }
|
|
|
- /*
|
|
|
- * We need to detect attempts to do dup2() over allocated but still
|
|
|
- * not finished descriptor. NB: OpenBSD avoids that at the price of
|
|
|
- * extra work in their equivalent of fget() - they insert struct
|
|
|
- * file immediately after grabbing descriptor, mark it larval if
|
|
|
- * more work (e.g. actual opening) is needed and make sure that
|
|
|
- * fget() treats larval files as absent. Potentially interesting,
|
|
|
- * but while extra work in fget() is trivial, locking implications
|
|
|
- * and amount of surgery on open()-related paths in VFS are not.
|
|
|
- * FreeBSD fails with -EBADF in the same situation, NetBSD "solution"
|
|
|
- * deadlocks in rather amusing ways, AFAICS. All of that is out of
|
|
|
- * scope of POSIX or SUS, since neither considers shared descriptor
|
|
|
- * tables and this condition does not arise without those.
|
|
|
- */
|
|
|
- err = -EBUSY;
|
|
|
- fdt = files_fdtable(files);
|
|
|
- tofree = fdt->fd[newfd];
|
|
|
- if (!tofree && fd_is_open(newfd, fdt))
|
|
|
- goto out_unlock;
|
|
|
- get_file(file);
|
|
|
- rcu_assign_pointer(fdt->fd[newfd], file);
|
|
|
- __set_open_fd(newfd, fdt);
|
|
|
- if (flags & O_CLOEXEC)
|
|
|
- __set_close_on_exec(newfd, fdt);
|
|
|
- else
|
|
|
- __clear_close_on_exec(newfd, fdt);
|
|
|
- spin_unlock(&files->file_lock);
|
|
|
-
|
|
|
- if (tofree)
|
|
|
- filp_close(tofree, files);
|
|
|
-
|
|
|
- return newfd;
|
|
|
-
|
|
|
-Ebadf:
|
|
|
- err = -EBADF;
|
|
|
-out_unlock:
|
|
|
- spin_unlock(&files->file_lock);
|
|
|
- return err;
|
|
|
-}
|
|
|
-
|
|
|
-SYSCALL_DEFINE2(dup2, unsigned int, oldfd, unsigned int, newfd)
|
|
|
-{
|
|
|
- if (unlikely(newfd == oldfd)) { /* corner case */
|
|
|
- struct files_struct *files = current->files;
|
|
|
- int retval = oldfd;
|
|
|
-
|
|
|
- rcu_read_lock();
|
|
|
- if (!fcheck_files(files, oldfd))
|
|
|
- retval = -EBADF;
|
|
|
- rcu_read_unlock();
|
|
|
- return retval;
|
|
|
- }
|
|
|
- return sys_dup3(oldfd, newfd, 0);
|
|
|
-}
|
|
|
-
|
|
|
-SYSCALL_DEFINE1(dup, unsigned int, fildes)
|
|
|
-{
|
|
|
- int ret = -EBADF;
|
|
|
- struct file *file = fget_raw(fildes);
|
|
|
-
|
|
|
- if (file) {
|
|
|
- ret = get_unused_fd();
|
|
|
- if (ret >= 0)
|
|
|
- fd_install(ret, file);
|
|
|
- else
|
|
|
- fput(file);
|
|
|
- }
|
|
|
- return ret;
|
|
|
-}
|
|
|
-
|
|
|
#define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT | O_NOATIME)
|
|
|
|
|
|
static int setfl(int fd, struct file * filp, unsigned long arg)
|
|
@@ -376,14 +255,10 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
|
|
|
|
|
|
switch (cmd) {
|
|
|
case F_DUPFD:
|
|
|
+ err = f_dupfd(arg, filp, 0);
|
|
|
+ break;
|
|
|
case F_DUPFD_CLOEXEC:
|
|
|
- if (arg >= rlimit(RLIMIT_NOFILE))
|
|
|
- break;
|
|
|
- err = alloc_fd(arg, cmd == F_DUPFD_CLOEXEC ? O_CLOEXEC : 0);
|
|
|
- if (err >= 0) {
|
|
|
- get_file(filp);
|
|
|
- fd_install(err, filp);
|
|
|
- }
|
|
|
+ err = f_dupfd(arg, filp, FD_CLOEXEC);
|
|
|
break;
|
|
|
case F_GETFD:
|
|
|
err = get_close_on_exec(fd) ? FD_CLOEXEC : 0;
|