VFS: add support for F_DUPFD_CLOEXEC

Change-Id: Ibe422c6c99fe5fd1385884843ff9e15111810309
This commit is contained in:
David van Moolenbroek 2015-07-20 13:55:10 +00:00
parent 6d315cbf9e
commit 424cad2cd6
5 changed files with 44 additions and 7 deletions

View File

@ -21,6 +21,7 @@ int fcntl(int fd, int cmd, ...)
/* Adjust for the stupid cases. */ /* Adjust for the stupid cases. */
switch(cmd) { switch(cmd) {
case F_DUPFD: case F_DUPFD:
case F_DUPFD_CLOEXEC:
case F_SETFD: case F_SETFD:
case F_SETFL: case F_SETFL:
case F_SETNOSIGPIPE: case F_SETNOSIGPIPE:

View File

@ -37,6 +37,13 @@ or equal to
.IR fd2 . .IR fd2 .
.RE .RE
.SP .SP
.BI "fcntl(" fd ", F_DUPFD_CLOEXEC, int " fd2 ")"
.RS
As
.BR F_DUPFD ,
but the "close on exec" flag is set on the returned file descriptor.
.RE
.SP
.BI "fcntl(" fd ", F_GETFD)" .BI "fcntl(" fd ", F_GETFD)"
.RS .RS
Returns the file descriptor flags associated with file descriptor Returns the file descriptor flags associated with file descriptor

View File

@ -116,11 +116,15 @@ int do_fcntl(void)
switch (fcntl_req) { switch (fcntl_req) {
case F_DUPFD: case F_DUPFD:
case F_DUPFD_CLOEXEC:
/* This replaces the old dup() system call. */ /* This replaces the old dup() system call. */
if (fcntl_argx < 0 || fcntl_argx >= OPEN_MAX) r = EINVAL; if (fcntl_argx < 0 || fcntl_argx >= OPEN_MAX) r = EINVAL;
else if ((r = get_fd(fp, fcntl_argx, 0, &new_fd, NULL)) == OK) { else if ((r = get_fd(fp, fcntl_argx, 0, &new_fd, NULL)) == OK) {
f->filp_count++; f->filp_count++;
fp->fp_filp[new_fd] = f; fp->fp_filp[new_fd] = f;
assert(!FD_ISSET(new_fd, &fp->fp_cloexec_set));
if (fcntl_req == F_DUPFD_CLOEXEC)
FD_SET(new_fd, &fp->fp_cloexec_set);
r = new_fd; r = new_fd;
} }
break; break;

View File

@ -213,8 +213,8 @@ void test7c()
{ {
/* Test fcntl(). */ /* Test fcntl(). */
int fd, m, s, newfd, newfd2; int fd, m, s, newfd, newfd2, newfd3, newfd4;
struct stat stat1, stat2, stat3; struct stat stat1, stat2, stat3, stat4, stat5;
subtest = 3; subtest = 3;
errno = -100; errno = -100;
@ -264,20 +264,42 @@ void test7c()
if (fcntl(newfd2, F_GETFL) != (O_APPEND | m)) e(30); /* O_APPEND set */ if (fcntl(newfd2, F_GETFL) != (O_APPEND | m)) e(30); /* O_APPEND set */
if (fcntl(fd, F_SETFD, 0) != 0) e(31);/* turn FD_CLOEXEC off */ if (fcntl(fd, F_SETFD, 0) != 0) e(31);/* turn FD_CLOEXEC off */
/* Check if newfd and newfd2 are the same inode. */ /* Also test F_DUPFD_CLOEXEC. */
if ( (newfd3 = fcntl(fd, F_DUPFD_CLOEXEC, 0)) != 4) e(0);
if (fcntl(newfd3, F_GETFD) != FD_CLOEXEC) e(0); /* FD_CLOEXEC must be set */
if (close(newfd3) != 0) e(0);
if ( (newfd3 = fcntl(fd, F_DUPFD_CLOEXEC, 12)) != 12) e(0);
if (fcntl(newfd3, F_GETFD) != FD_CLOEXEC) e(0); /* FD_CLOEXEC must be set */
if ( (newfd4 = fcntl(newfd3, F_DUPFD, 0)) != 4) e(0);
if (fcntl(newfd4, F_GETFD) != 0) e(0); /* FD_CLOEXEC must be unset */
if (close(newfd4) != 0) e(0);
if ( (newfd4 = fcntl(newfd3, F_DUPFD_CLOEXEC, 15)) != 15) e(0);
if (fcntl(newfd4, F_GETFD) != FD_CLOEXEC) e(0); /* FD_CLOEXEC must be set */
if (fcntl(newfd4, F_SETFD, 0) != 0) e(0); /* turn FD_CLOEXEC off */
if (fcntl(newfd4, F_GETFD) != 0) e(0); /* FD_CLOEXEC must be unset */
/* Check if all file descriptors are for the same inode. */
if (fstat(fd, &stat1) != 0) e(32); if (fstat(fd, &stat1) != 0) e(32);
if (fstat(fd, &stat2) != 0) e(33); if (fstat(newfd, &stat2) != 0) e(33);
if (fstat(fd, &stat3) != 0) e(34); if (fstat(newfd2, &stat3) != 0) e(34);
if (fstat(newfd3, &stat4) != 0) e(0);
if (fstat(newfd4, &stat5) != 0) e(0);
if (stat1.st_dev != stat2.st_dev) e(35); if (stat1.st_dev != stat2.st_dev) e(35);
if (stat1.st_dev != stat3.st_dev) e(36); if (stat1.st_dev != stat3.st_dev) e(36);
if (stat1.st_dev != stat4.st_dev) e(0);
if (stat1.st_dev != stat5.st_dev) e(0);
if (stat1.st_ino != stat2.st_ino) e(37); if (stat1.st_ino != stat2.st_ino) e(37);
if (stat1.st_ino != stat3.st_ino) e(38); if (stat1.st_ino != stat3.st_ino) e(38);
if (stat1.st_ino != stat4.st_ino) e(0);
if (stat1.st_ino != stat5.st_ino) e(0);
/* Now check on the FD_CLOEXEC flag. Set it for fd (3) and newfd2 (10) */ /* Now check on the FD_CLOEXEC flag. Set it for fd (3) and newfd2 (10) */
if (fd != 3 || newfd2 != 10 || newfd != 6) e(39); if (fd != 3 || newfd2 != 10 || newfd3 != 12 || newfd4 != 15 || newfd != 6)
e(39);
if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) e(40); /* close 3 on exec */ if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) e(40); /* close 3 on exec */
if (fcntl(newfd2, F_SETFD, FD_CLOEXEC) != 0) e(41); /* close 10 on exec */ if (fcntl(newfd2, F_SETFD, FD_CLOEXEC) != 0) e(41); /* close 10 on exec */
if (fcntl(newfd, F_SETFD, 0) != 0) e(42); /* don't close 6 */ if (fcntl(newfd, F_SETFD, 0) != 0) e(42); /* don't close 6 */
/* leave 12 and 15 as is */
if (fork()) { if (fork()) {
wait(&s); /* parent just waits */ wait(&s); /* parent just waits */
if (WEXITSTATUS(s) != 0) e(43); if (WEXITSTATUS(s) != 0) e(43);
@ -630,12 +652,14 @@ void cloexec_test()
* closed upon exec, we have to exec something. The test is carried * closed upon exec, we have to exec something. The test is carried
* out by forking, and then having the child exec test7 itself, but * out by forking, and then having the child exec test7 itself, but
* with argument 0. This is detected, and control comes here. * with argument 0. This is detected, and control comes here.
* File descriptors 3 and 10 should be closed here, and 10 open. * File descriptors 3, 10, and 12 should be closed here, and 6 and 15 open.
*/ */
if (close(3) == 0) e(1001); /* close should fail; it was closed on exec */ if (close(3) == 0) e(1001); /* close should fail; it was closed on exec */
if (close(6) != 0) e(1002); /* close should succeed */ if (close(6) != 0) e(1002); /* close should succeed */
if (close(10) == 0) e(1003); /* close should fail */ if (close(10) == 0) e(1003); /* close should fail */
if (close(12) == 0) e(1004); /* close should fail */
if (close(15) != 0) e(1005); /* close should succeed */
fflush(stdout); fflush(stdout);
exit(0); exit(0);
} }

View File

@ -603,6 +603,7 @@ vfs_fcntl_out(struct trace_proc * proc, const message * m_out)
switch (m_out->m_lc_vfs_fcntl.cmd) { switch (m_out->m_lc_vfs_fcntl.cmd) {
case F_DUPFD: case F_DUPFD:
case F_DUPFD_CLOEXEC:
put_fd(proc, "fd2", m_out->m_lc_vfs_fcntl.arg_int); put_fd(proc, "fd2", m_out->m_lc_vfs_fcntl.arg_int);
break; break;
case F_SETFD: case F_SETFD: