UNIX環境高階程式設計習題之第三章第二題

NO IMAGE

不呼叫fcntl函式實現dup2函式


問題描述

dup2函式頭定義為int dup2(int fd, int fd2),返回值為fd2指定的檔案描述符,指向fd指向的檔案,如果fd2已經開啟,則需先關閉;如果fd == fd2,則無需關閉fd2。

解題思路

1、尋找需要的檔案描述符
不能呼叫fcntl,那麼我們只能呼叫dup函式,這個函式會返回當前可用的檔案描述符中的最小值,迴圈n次呼叫直到返回值等於fd2。

2、呼叫dup的負面影響
這個時候我們開啟了n-1個無用的檔案,這些並不是我們需要或者預期的,返回前需關閉。否則不但會佔用大量系統資源,使得系統無法開啟新的檔案,甚至這些預期之外的檔案描述符也可以訪問或者修改檔案,形成安全隱患。

3、消除dup造成的隱患
線性結構記錄n-1個檔案描述符,並依次關閉

4、錯誤error處理
dup呼叫錯誤:包括指定的fd2過大,開啟的檔案描述符超出限制。在不考慮其他程式也呼叫此函式的情況下,我們可以通過sysconf函式來獲取開啟上限。

5、測試問題
定義一個檔案描述符x指向標準輸出,並通過x寫入一段特定的字元,檢視是否會在標準輸出是列印,也可以直接重定向到指定檔案檢視。

程式碼實現

本文采用c語言實現該邏輯:

#include "apue.h"
#include <myerr.h>
#include <limits.h>
#include <unistd.h>
#include <errno.h>
#ifdef OPEN_MAX
static long openmax = OPEN_MAX;
#else
static long openmax = 0;
#endif
int mydup(int fd, int fd2){
//獲取系統允許的最大的檔案數
errno = 0;
if (openmax == 0)
openmax = sysconf(_SC_OPEN_MAX);
if (openmax < 0){
if (errno != 0){ //這個值是不確定的
printf("OPEN_MAX這個值是不確定的,設為預設100\n");
openmax = 100;
}
else{ //獲取OPEN_MAX錯誤
printf("獲取OPEN_MAX錯誤,設為預設100\n");
openmax = 100;
}
}else
printf("OPEN_MAX獲取成功,其值是%ld\n", openmax);
//關閉指定的fd2檔案
errno = close(fd2);
//關閉檔案不一定會成功,因為有可能這個檔案本身就沒有開啟,所以錯誤也不退出
if (errno == -1) 
printf("關閉fd2錯誤:%d",errno);
//獲取待返回的檔案描述符fd1
long fd1 = -1;
int arr[openmax-1], idx = 0,i;
for (i = 0; i < openmax - 1; i  ){// 初始化線性結構
arr[i] = -1;
}
do{//迴圈呼叫dup函式直至返回的fd1 == fd2
fd1 = dup(fd);
if (fd1 > 0){//呼叫成功
if (fd1 == fd2){//如果呼叫成功,退出迴圈
break;
}else{
arr[idx] = fd1;
idx  ;
}
}
}while(fd1 < fd2);
//關閉開啟的多餘的檔案
for (i = 0; i < openmax - 1; i  ){
if (arr[i] == -1)
break;
else{
errno = close(arr[i]);
if (errno == -1){
printf("關閉檔案%ld錯誤",arr[i],stdout);
if (idx != i){
idx = i;
i--; //關閉失敗回退再關閉一次
}
}
}
}
return fd1;
}
int main(void){
int fdtest = dup(1);
char buf[] = "hello, mydup for dup2!\n";
printf("開啟的檔案是:%d,buf長度是%d\n",fdtest,strlen(buf));
int fd = mydup(STDOUT_FIFLNO,fdtest);
printf("mydup返回的檔案是:%d\n",fd);
//測試返回的檔案符是否可以直接操作標準輸出
if (write(fd, buf, strlen(buf)) != strlen(buf))
err_sys("buf write error\n");
exit(0);
}

在Linux環境下的執行結果如下:

開啟的檔案是:3,buf長度是23
OPEN_MAX獲取成功,其值是102400
mydup返回的檔案是:3
hello, mydup for dup2!

可見測試的buf成功通過獲取的檔案描述符寫入到了標準輸出中,至此測試完畢。