summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/unistd.h1
-rw-r--r--lib/libc/sys/Makefile.inc2
-rw-r--r--lib/libc/sys/Symbol.map3
-rw-r--r--lib/libc/sys/close.21
-rw-r--r--lib/libc/sys/closefrom.253
-rw-r--r--sys/compat/freebsd32/syscalls.master1
-rw-r--r--sys/kern/kern_descrip.c36
-rw-r--r--sys/kern/syscalls.master1
-rw-r--r--tools/regression/file/closefrom/Makefile9
-rw-r--r--tools/regression/file/closefrom/closefrom.c274
-rw-r--r--tools/regression/file/closefrom/closefrom.t10
11 files changed, 390 insertions, 1 deletions
diff --git a/include/unistd.h b/include/unistd.h
index 4b567b8..aa027c2 100644
--- a/include/unistd.h
+++ b/include/unistd.h
@@ -326,6 +326,7 @@ unsigned int alarm(unsigned int);
int chdir(const char *);
int chown(const char *, uid_t, gid_t);
int close(int);
+void closefrom(int);
int dup(int);
int dup2(int, int);
int execl(const char *, const char *, ...);
diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc
index a238efc..7e65aa4 100644
--- a/lib/libc/sys/Makefile.inc
+++ b/lib/libc/sys/Makefile.inc
@@ -63,7 +63,7 @@ MAN+= abort2.2 accept.2 access.2 acct.2 adjtime.2 \
aio_cancel.2 aio_error.2 aio_read.2 aio_return.2 \
aio_suspend.2 aio_waitcomplete.2 aio_write.2 \
bind.2 brk.2 chdir.2 chflags.2 \
- chmod.2 chown.2 chroot.2 clock_gettime.2 close.2 \
+ chmod.2 chown.2 chroot.2 clock_gettime.2 close.2 closefrom.2 \
connect.2 cpuset.2 cpuset_getaffinity.2 dup.2 execve.2 _exit.2 \
extattr_get_file.2 fcntl.2 fhopen.2 flock.2 fork.2 fsync.2 \
getdirentries.2 getdtablesize.2 \
diff --git a/lib/libc/sys/Symbol.map b/lib/libc/sys/Symbol.map
index 48ef400..9e19899 100644
--- a/lib/libc/sys/Symbol.map
+++ b/lib/libc/sys/Symbol.map
@@ -333,6 +333,7 @@ FBSD_1.0 {
};
FBSD_1.1 {
+ closefrom;
cpuset;
cpuset_getid;
cpuset_setid;
@@ -472,6 +473,8 @@ FBSDprivate_1.0 {
__sys_clock_settime;
_close;
__sys_close;
+ _closefrom;
+ __sys_closefrom;
_connect;
__sys_connect;
_cpuset;
diff --git a/lib/libc/sys/close.2 b/lib/libc/sys/close.2
index aef0379..524322b 100644
--- a/lib/libc/sys/close.2
+++ b/lib/libc/sys/close.2
@@ -120,6 +120,7 @@ before all pending data was delivered.
.El
.Sh SEE ALSO
.Xr accept 2 ,
+.Xr closefrom 2 ,
.Xr execve 2 ,
.Xr fcntl 2 ,
.Xr flock 2 ,
diff --git a/lib/libc/sys/closefrom.2 b/lib/libc/sys/closefrom.2
new file mode 100644
index 0000000..ffaa001
--- /dev/null
+++ b/lib/libc/sys/closefrom.2
@@ -0,0 +1,53 @@
+.\" Copyright (c) 2009 Advanced Computing Technologies LLC
+.\" Written by: John H. Baldwin <jhb@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 12, 2009
+.Dt CLOSEFROM 2
+.Os
+.Sh NAME
+.Nm closefrom
+.Nd delete open file descriptors
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft void
+.Fn closefrom "int lowfd"
+.Sh DESCRIPTION
+The
+.Fn closefrom
+system call deletes all open file descriptors greater than or equal to
+.Fa lowfd
+from the per-process object reference table.
+Any errors encountered while closing file descriptors are ignored.
+.Sh SEE ALSO
+.Xr close 2
+.Sh HISTORY
+The
+.Fn closefrom
+function first appeared in
+.Fx 8.0 .
diff --git a/sys/compat/freebsd32/syscalls.master b/sys/compat/freebsd32/syscalls.master
index 7da270b..f2a1700 100644
--- a/sys/compat/freebsd32/syscalls.master
+++ b/sys/compat/freebsd32/syscalls.master
@@ -889,3 +889,4 @@
507 AUE_NULL STD { int freebsd32_jail_set(struct iovec32 *iovp, \
unsigned int iovcnt, int flags); }
508 AUE_NULL NOPROTO { int jail_remove(int jid); }
+509 AUE_CLOSEFROM NOPROTO { int closefrom(int lowfd); }
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index 1221825..30bb84a 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -1128,6 +1128,42 @@ kern_close(td, fd)
return (error);
}
+/*
+ * Close open file descriptors.
+ */
+#ifndef _SYS_SYSPROTO_H_
+struct closefrom_args {
+ int lowfd;
+};
+#endif
+/* ARGSUSED */
+int
+closefrom(struct thread *td, struct closefrom_args *uap)
+{
+ struct filedesc *fdp;
+ int fd;
+
+ fdp = td->td_proc->p_fd;
+ AUDIT_ARG(fd, uap->lowfd);
+
+ /*
+ * Treat negative starting file descriptor values identical to
+ * closefrom(0) which closes all files.
+ */
+ if (uap->lowfd < 0)
+ uap->lowfd = 0;
+ FILEDESC_SLOCK(fdp);
+ for (fd = uap->lowfd; fd < fdp->fd_nfiles; fd++) {
+ if (fdp->fd_ofiles[fd] != NULL) {
+ FILEDESC_SUNLOCK(fdp);
+ (void)kern_close(td, fd);
+ FILEDESC_SLOCK(fdp);
+ }
+ }
+ FILEDESC_SUNLOCK(fdp);
+ return (0);
+}
+
#if defined(COMPAT_43)
/*
* Return status information about a file descriptor.
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
index ab5981e..466d4e3 100644
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -902,5 +902,6 @@
507 AUE_NULL STD { int jail_set(struct iovec *iovp, \
unsigned int iovcnt, int flags); }
508 AUE_NULL STD { int jail_remove(int jid); }
+509 AUE_CLOSEFROM STD { int closefrom(int lowfd); }
; Please copy any additions and changes to the following compatability tables:
; sys/compat/freebsd32/syscalls.master
diff --git a/tools/regression/file/closefrom/Makefile b/tools/regression/file/closefrom/Makefile
new file mode 100644
index 0000000..7ff2df8
--- /dev/null
+++ b/tools/regression/file/closefrom/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+PROG= closefrom
+MAN=
+WARNS?= 6
+
+LDADD= -lutil
+
+.include <bsd.prog.mk>
diff --git a/tools/regression/file/closefrom/closefrom.c b/tools/regression/file/closefrom/closefrom.c
new file mode 100644
index 0000000..e119f20
--- /dev/null
+++ b/tools/regression/file/closefrom/closefrom.c
@@ -0,0 +1,274 @@
+/*-
+ * Copyright (c) 2009 Advanced Computing Technologies LLC
+ * Written by: John H. Baldwin <jhb@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Regression tests for the closefrom(2) system call.
+ */
+
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <sys/user.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libutil.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+struct shared_info {
+ int failed;
+ char tag[64];
+ char message[0];
+};
+
+static int test = 1;
+
+static void
+ok(const char *descr)
+{
+
+ printf("ok %d - %s\n", test, descr);
+ test++;
+}
+
+static void
+fail(const char *descr, const char *fmt, ...)
+{
+ va_list ap;
+
+ printf("not ok %d - %s", test, descr);
+ test++;
+ if (fmt) {
+ va_start(ap, fmt);
+ printf(" # ");
+ vprintf(fmt, ap);
+ va_end(ap);
+ }
+ printf("\n");
+ exit(1);
+}
+
+#define fail_err(descr) fail((descr), "%s", strerror(errno))
+
+static void
+cok(struct shared_info *info, const char *descr)
+{
+
+ info->failed = 0;
+ strlcpy(info->tag, descr, sizeof(info->tag));
+ exit(0);
+}
+
+static void
+cfail(struct shared_info *info, const char *descr, const char *fmt, ...)
+{
+ va_list ap;
+
+ info->failed = 1;
+ strlcpy(info->tag, descr, sizeof(info->tag));
+ if (fmt) {
+ va_start(ap, fmt);
+ vsprintf(info->message, fmt, ap);
+ va_end(ap);
+ }
+ exit(0);
+}
+
+#define cfail_err(info, descr) cfail((info), (descr), "%s", strerror(errno))
+
+/*
+ * Use kinfo_getfile() to fetch the list of file descriptors and figure out
+ * the highest open file descriptor.
+ */
+static int
+highest_fd(void)
+{
+ struct kinfo_file *kif;
+ int cnt, i, highest;
+
+ kif = kinfo_getfile(getpid(), &cnt);
+ if (kif == NULL)
+ fail_err("kinfo_getfile");
+ highest = INT_MIN;
+ for (i = 0; i < cnt; i++)
+ if (kif[i].kf_fd > highest)
+ highest = kif[i].kf_fd;
+ free(kif);
+ return (highest);
+}
+
+static int
+devnull(void)
+{
+ int fd;
+
+ fd = open("/dev/null", O_RDONLY);
+ if (fd < 0)
+ fail_err("open(\"/dev/null\")");
+ return (fd);
+}
+
+int
+main(int __unused argc, char __unused *argv[])
+{
+ struct shared_info *info;
+ pid_t pid;
+ int fd, i;
+
+ printf("1..15\n");
+
+ /* We better start up with fd's 0, 1, and 2 open. */
+ fd = devnull();
+ if (fd != 3)
+ fail("open", "bad descriptor %d", fd);
+ ok("open");
+
+ /* Make sure highest_fd() works. */
+ fd = highest_fd();
+ if (fd != 3)
+ fail("highest_fd", "bad descriptor %d", fd);
+ ok("highest_fd");
+
+ /* Try to use closefrom() for just closing fd 3. */
+ closefrom(3);
+ fd = highest_fd();
+ if (fd != 2)
+ fail("closefrom", "highest fd %d", fd);
+ ok("closefrom");
+
+ /* Eat up 16 descriptors. */
+ for (i = 0; i < 16; i++)
+ (void)devnull();
+ fd = highest_fd();
+ if (fd != 18)
+ fail("open 16", "highest fd %d", fd);
+ ok("open 16");
+
+ /* Close half of them. */
+ closefrom(11);
+ fd = highest_fd();
+ if (fd != 10)
+ fail("closefrom", "highest fd %d", fd);
+ ok("closefrom");
+
+ /* Explicitly close descriptors 6 and 8 to create holes. */
+ if (close(6) < 0 || close(8) < 0)
+ fail_err("close2 ");
+ ok("close 2");
+
+ /* Verify that close on 6 and 8 fails with EBADF. */
+ if (close(6) == 0)
+ fail("close(6)", "did not fail");
+ if (errno != EBADF)
+ fail_err("close(6)");
+ ok("close(6)");
+ if (close(8) == 0)
+ fail("close(8)", "did not fail");
+ if (errno != EBADF)
+ fail_err("close(8)");
+ ok("close(8)");
+
+ /* Close from 4 on. */
+ closefrom(4);
+ fd = highest_fd();
+ if (fd != 3)
+ fail("closefrom", "highest fd %d", fd);
+ ok("closefrom");
+
+ /* Allocate a small SHM region for IPC with our child. */
+ info = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, MAP_ANON |
+ MAP_SHARED, -1, 0);
+ if (info == MAP_FAILED)
+ fail_err("mmap");
+ ok("mmap");
+
+ /* Fork a child process to test closefrom(0). */
+ pid = fork();
+ if (pid < 0)
+ fail_err("fork");
+ if (pid == 0) {
+ /* Child. */
+ closefrom(0);
+ fd = highest_fd();
+ if (fd >= 0)
+ cfail(info, "closefrom(0)", "highest fd %d", fd);
+ cok(info, "closefrom(0)");
+ }
+ if (wait(NULL) < 0)
+ fail_err("wait");
+ if (info->failed)
+ fail(info->tag, "%s", info->message);
+ ok(info->tag);
+
+ /* Fork a child process to test closefrom(-1). */
+ pid = fork();
+ if (pid < 0)
+ fail_err("fork");
+ if (pid == 0) {
+ /* Child. */
+ closefrom(-1);
+ fd = highest_fd();
+ if (fd >= 0)
+ cfail(info, "closefrom(-1)", "highest fd %d", fd);
+ cok(info, "closefrom(-1)");
+ }
+ if (wait(NULL) < 0)
+ fail_err("wait");
+ if (info->failed)
+ fail(info->tag, "%s", info->message);
+ ok(info->tag);
+
+ /* Dup stdout to 6. */
+ if (dup2(1, 6) < 0)
+ fail_err("dup2");
+ fd = highest_fd();
+ if (fd != 6)
+ fail("dup2", "highest fd %d", fd);
+ ok("dup2");
+
+ /* Do a closefrom() starting in a hole. */
+ closefrom(4);
+ fd = highest_fd();
+ if (fd != 3)
+ fail("closefrom", "highest fd %d", fd);
+ ok("closefrom");
+
+ /* Do a closefrom() beyond our highest open fd. */
+ closefrom(32);
+ fd = highest_fd();
+ if (fd != 3)
+ fail("closefrom", "highest fd %d", fd);
+ ok("closefrom");
+
+ return (0);
+}
diff --git a/tools/regression/file/closefrom/closefrom.t b/tools/regression/file/closefrom/closefrom.t
new file mode 100644
index 0000000..8bdfd03
--- /dev/null
+++ b/tools/regression/file/closefrom/closefrom.t
@@ -0,0 +1,10 @@
+#!/bin/sh
+# $FreeBSD$
+
+cd `dirname $0`
+
+executable=`basename $0 .t`
+
+make $executable 2>&1 > /dev/null
+
+exec ./$executable
OpenPOWER on IntegriCloud