APUE习题8.7解答
APUE的8.7习题是关于exec的一个问题,书中描述了一句“POSIX.1明确要求再执行exec时关闭打开的目录流”。我们需要自己来验证下这个性质是否在自己的系统上有效,题目给我们提供了思路。
简单的分析下,我们首先需要打开一个目录,这个很简单,使用 opendir() 函数,我们现在获得是 DIR* 的变量,而我们要的是文件描述符fd,所以我们接着调用一个 dirfd() ,将获得目录的文件描述符。有了这些准备工作,我们就可以使用 fcntl() 获得执行时关闭状态(close-on-exec).
接着我们简单的判断一下此时这个状态是否打开的。这一步有利于我们接下来的判断。接着我们将这个fd写入到一个数组里面。用处在下面调用execl时最为参数使用。
我们创建一个进程,在子进程中我们调用execl函数,执行另一个程序,这个程序是利用刚才的描述符,尝试去在调用exec时候打开一个目录,看是否能打开。这就是这个程序的关键。
接着我们来尝试着code。
exercise8-7.c
1 #include<dirent> /* opendir() */ 2 #include<unistd.h> /* execl(),fcntl() */ 3 ... /* 一些必要的头文件 */ 4 5 int main( void ) 6 { 7 DIR * dir; 8 int val, fd; 9 char buf[ 10 ]; /* for save fd */ 10 11 dir = opendir( " / " ); 12 fd = dirfd(dir); 13 14 if ((val = fcntl(fd,F_GETFD, 0 )) < 0 ) 15 perror( " fcntl " ); 16 if (val & FD_CLOEXEC) 17 printf( " close-on-exec is on\n " ); 18 else 19 printf( " clsose-on-exec is off\n " ); 20 21 sprintf(buf, " %d\0 " ,fd); 22 23 if ((pid = fork()) < 0 ) 24 perror( " fork " ); 25 else if (pid == 0 ) 26 { 27 execl( " /home/jesse/test/exercise8.7_child " , " exercise8.7_child " ,buf,NULL); 28 exit( 0 ); 29 } 30 31 return 0 ; 32 }
上面就是我们的一个基本的框架,接着就是再exercise8.7_child.c中实现一个调用,这个就是很简单了。
exercise8.7_child.c
1 #include<fcntl.h> /* fcntl() */ 2 ... /* 一些必要的头文件 */ 3 4 int main( int argc , char * argv[]) 5 { 6 int fd,val; 7 8 sscanf(argv[ 1 ], " %d " , & fd); 9 if ((val = fcntl(fd,F_GETFD, 0 )) < 0 ) 10 perror( " fcntl " ); 11 if (val & FD_CLOEXEC) 12 printf( " close-on-exec is on\n " ); 13 else 14 printf( " clsose-on-exec is off\n " ); 15 return 0 ; 16 }
我们执行一下
1 jesse@jesse:~/APUE/process$ ./a. out 2 close-on-exec is on 3 jesse@jesse:~/APUE/process$ fcntl: Bad file descriptor
我们会发现,fcntl报错了。说明这个fd不存在,也就是验证了这个确实是在执行exec的时候,将文件描述符关闭了。
我们可以再延伸一些,我们试着将这个标志位关闭,看看结果如何,我们猜想应该是会显示“close-on-exec is off"
我们使用diff,看看哪儿需要更改
jesse@jesse:~/APUE/process$ diff -u exercise8. 7 .c exercise8.7_child.c --- exercise8. 7 .c 2014 - 04 - 25 10 : 57 : 23.004544016 + 0800 +++ exercise8.7_child.c 2014 - 04 - 25 11 : 11 : 14.064562979 + 0800 @@ - 19 , 8 + 19 , 6 @@ printf( " close-on-exec is on\n " ); else printf( " close-on-exec is off\n " ); - val &= ~ FD_CLOEXEC; - fcntl(fd,F_SETFD,val); sprintf(strfd, " %d\0 " ,fd); if ((pid = fork()) < 0 )
更改的就两行,利用F_SETFD,来实现的。
执行的结果
1 jesse@jesse:~/APUE/process$ ./a. out 2 close-on-exec is on 3 jesse@jesse:~/APUE/process$ close-on-exec is off
结果符合猜想。
系统默认的是保持FD_CLOEXEC这个标志打开的,也就是说执行exec的时候是会关闭打开的目录的。