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. */
switch(cmd) {
case F_DUPFD:
case F_DUPFD_CLOEXEC:
case F_SETFD:
case F_SETFL:
case F_SETNOSIGPIPE:

View file

@ -37,6 +37,13 @@ or equal to
.IR fd2 .
.RE
.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)"
.RS
Returns the file descriptor flags associated with file descriptor

View file

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

View file

@ -213,8 +213,8 @@ void test7c()
{
/* Test fcntl(). */
int fd, m, s, newfd, newfd2;
struct stat stat1, stat2, stat3;
int fd, m, s, newfd, newfd2, newfd3, newfd4;
struct stat stat1, stat2, stat3, stat4, stat5;
subtest = 3;
errno = -100;
@ -264,20 +264,42 @@ void test7c()
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 */
/* 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, &stat2) != 0) e(33);
if (fstat(fd, &stat3) != 0) e(34);
if (fstat(newfd, &stat2) != 0) e(33);
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 != 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 != 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) */
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(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 */
/* leave 12 and 15 as is */
if (fork()) {
wait(&s); /* parent just waits */
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
* out by forking, and then having the child exec test7 itself, but
* 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(6) != 0) e(1002); /* close should succeed */
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);
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) {
case F_DUPFD:
case F_DUPFD_CLOEXEC:
put_fd(proc, "fd2", m_out->m_lc_vfs_fcntl.arg_int);
break;
case F_SETFD: