dup2的函数定义为:
#include <unistd.h> int dup2(int src_fd, int new_fd);
自己实现dup2函数有几个关键点:
1,检查给定的源fd是否有效,且都大于0,
2,检查目标fd是否超出了系统设定的范围,而这个值在书上是没有着重指出的,
比如mac限制了要小于256,ubuntu限制是1024。
3,源fd与目标fd是否相等,
4,利用系统的特性:dup总是返回最小可用的fd,不断重复dup,从而得到一个等于new_fd的fd值
再清除掉new_fd之前的临时fd
5,如果在4)的过程中。如果中途dup失败。则需要在返回失败前,关掉这些临时的fd。
因此close这些临时fd时,需要区别是创建new_fd成功还是失败了。
下面是代码,仅限于类Unix系统环境:
1 /* 2 * name : dup2.c 3 * func : implement of dup2 without fcntl.h 4 * author : jungle85gopy 5 * date : 2015.12.20 6 */ 7 8 /* 9 * Note : 10 * man dup() of Mac OSX 11 * Dup() duplicates an existing object descriptor and returns 12 * its value to the calling process (fildes2 = dup(fildes)). 13 * The value must be less than the size of the table, which is returned by 14 * getdtablesize(2). the size is 256 for Mac OSX 10.11. 15 * man dup() in ubuntu, there is no info about getdtablesize(2). 16 * but Ubuntu 14.04 still has getdtablesize limit of 1024. 17 */ 18 19 #include <unistd.h> 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include <sys/utsname.h> 23 24 25 #define INIT_FD -2 26 27 int my_dup2(int src_fd, int new_fd); 28 int chk_dup(int src_fd, int new_fd); 29 int do_dup2(int src_fd, int new_fd); 30 31 /* 32 * usage: dup2 src_fd, new_fd 33 */ 34 int main(int argc, char *argv[]) 35 { 36 if (argc != 3) { 37 printf("usage: dup2 src_fd new_fd\n"); 38 exit(1); 39 } 40 41 int new_fd = new_fd = my_dup2(atoi(argv[1]), atoi(argv[2]) ); 42 if (new_fd == -1) { 43 printf("dup to new_fd error!\n"); 44 exit(1); 45 } 46 printf("\n[main]: new fd is %d\n", new_fd); 47 return new_fd; 48 } 49 50 /* 51 * func: check the parameter of my_dup2 52 * return: 53 * -1: if error 54 * 0 : if success 55 */ 56 int chk_dup(int src_fd, int new_fd) 57 { 58 int tbl_size = getdtablesize(); 59 60 printf("[my_dup2]: parameter : src fd %d\n", src_fd); 61 printf("[my_dup2]: parameter : new fd %d\n\n", new_fd); 62 63 if (src_fd < 0 || new_fd < 0 ) { 64 printf("[my_dup2]: error: src or des parameter < 0.\n"); 65 return -1; 66 } 67 else if (new_fd >= tbl_size ) { 68 printf("[my_dup2]: error: des_fd out of system limit: %d\n", tbl_size); 69 return -1; 70 } 71 72 int index; 73 if ( (index = dup(src_fd)) == -1) { 74 printf("[my_dup2]: parameter src_fd is inactive!\n"); 75 return -1; 76 } else 77 close(index); 78 79 return 0; 80 } 81 82 83 /* 84 * func: dup a file descriptor from src_fd to new_fd 85 * return: 86 * new_fd if success 87 * -1 if error 88 */ 89 int my_dup2(int src_fd, int new_fd) 90 { 91 int ret; 92 93 if ( (ret = chk_dup(src_fd, new_fd)) == -1) 94 return -1; 95 if (src_fd == new_fd) 96 return src_fd; 97 98 // close new_fd, whether it is valid or not. ignore the return 99 close(new_fd); 100 101 if ( (ret = do_dup2(src_fd, new_fd)) == -1) { 102 printf("[my_dup2]: do dup failed!\n"); 103 return -1; 104 } else 105 return ret; 106 } 107 108 109 /* 110 * func: dup from 0 to new_fd 111 */ 112 int do_dup2(int src_fd, int new_fd) 113 { 114 int index, index_hit = -1, fd_array[new_fd]; 115 116 for (index = 0; index <= new_fd; index++) 117 fd_array[index] = INIT_FD; // initial to INIT_FD 118 119 printf("[my_dup2]: before dup temp fds\n"); 120 for (index = 0; index <= new_fd; index++) { 121 fd_array[index] = dup(src_fd); 122 printf("[my_dup2]: index: %d, create temp fd: %d\n", index, fd_array[index]); 123 124 if (fd_array[index] == -1) { 125 printf("[my_dup2]: dup process error!\n"); 126 break; 127 } else if (fd_array[index] == new_fd) { 128 index_hit = index; 129 break; 130 } 131 } 132 133 // close temp fd 134 printf("\n[my_dup2]: to close temp fds\n"); 135 136 if (index_hit == -1) { // break for loops with error 137 for (index = 0; index < new_fd; index++) { 138 if ((fd_array[index] == INIT_FD) || (fd_array[index] == -1)) 139 break; // no new temp dup in array 140 else { 141 close(fd_array[index]); 142 printf("[my_dup2]: index: %d, del temp fd: %d\n", index, fd_array[index]); 143 } 144 } 145 return -1; 146 } else { // break for loops with hit 147 for (index = 0; index < index_hit; index++) { 148 close(fd_array[index]); 149 printf("[my_dup2]: index: %d, temp fd: %d\n", index, fd_array[index]); 150 } 151 } 152 return new_fd; 153 }