Commit 8280d161 authored by Al Viro's avatar Al Viro

new helper: replace_fd()

analog of dup2(), except that it takes struct file * as source.
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent fe17f22d
......@@ -2041,23 +2041,14 @@ static void wait_for_dump_helpers(struct file *file)
static int umh_pipe_setup(struct subprocess_info *info, struct cred *new)
{
struct file *files[2];
struct fdtable *fdt;
struct coredump_params *cp = (struct coredump_params *)info->data;
struct files_struct *cf = current->files;
int err = create_pipe_files(files, 0);
if (err)
return err;
cp->file = files[1];
sys_close(0);
fd_install(0, files[0]);
spin_lock(&cf->file_lock);
fdt = files_fdtable(cf);
__set_open_fd(0, fdt);
__clear_close_on_exec(0, fdt);
spin_unlock(&cf->file_lock);
replace_fd(0, files[0], 0);
/* and disallow core files too */
current->signal->rlim[RLIMIT_CORE] = (struct rlimit){1, 1};
......
......@@ -821,29 +821,12 @@ bool get_close_on_exec(unsigned int fd)
return res;
}
SYSCALL_DEFINE3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags)
static int do_dup2(struct files_struct *files,
struct file *file, unsigned fd, unsigned flags)
{
int err = -EBADF;
struct file * file, *tofree;
struct files_struct * files = current->files;
struct file *tofree;
struct fdtable *fdt;
if ((flags & ~O_CLOEXEC) != 0)
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
......@@ -858,24 +841,74 @@ SYSCALL_DEFINE3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags)
* 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;
tofree = fdt->fd[fd];
if (!tofree && fd_is_open(fd, fdt))
goto Ebusy;
get_file(file);
rcu_assign_pointer(fdt->fd[newfd], file);
__set_open_fd(newfd, fdt);
rcu_assign_pointer(fdt->fd[fd], file);
__set_open_fd(fd, fdt);
if (flags & O_CLOEXEC)
__set_close_on_exec(newfd, fdt);
__set_close_on_exec(fd, fdt);
else
__clear_close_on_exec(newfd, fdt);
__clear_close_on_exec(fd, fdt);
spin_unlock(&files->file_lock);
if (tofree)
filp_close(tofree, files);
return newfd;
return fd;
Ebusy:
spin_unlock(&files->file_lock);
return -EBUSY;
}
int replace_fd(unsigned fd, struct file *file, unsigned flags)
{
int err;
struct files_struct *files = current->files;
if (!file)
return __close_fd(files, fd);
if (fd >= rlimit(RLIMIT_NOFILE))
return -EMFILE;
spin_lock(&files->file_lock);
err = expand_files(files, fd);
if (unlikely(err < 0))
goto out_unlock;
return do_dup2(files, file, fd, flags);
out_unlock:
spin_unlock(&files->file_lock);
return err;
}
SYSCALL_DEFINE3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags)
{
int err = -EBADF;
struct file *file;
struct files_struct *files = current->files;
if ((flags & ~O_CLOEXEC) != 0)
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;
}
return do_dup2(files, file, newfd, flags);
Ebadf:
err = -EBADF;
......
......@@ -31,6 +31,7 @@ extern struct file *fget_light(unsigned int fd, int *fput_needed);
extern struct file *fget_raw(unsigned int fd);
extern struct file *fget_raw_light(unsigned int fd, int *fput_needed);
extern int f_dupfd(unsigned int from, struct file *file, unsigned flags);
extern int replace_fd(unsigned fd, struct file *file, unsigned flags);
extern void set_close_on_exec(unsigned int fd, int flag);
extern bool get_close_on_exec(unsigned int fd);
extern void put_filp(struct file *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment