VFS: add support for F_DUPFD_CLOEXEC
Change-Id: Ibe422c6c99fe5fd1385884843ff9e15111810309
This commit is contained in:
parent
6d315cbf9e
commit
424cad2cd6
@ -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:
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user