[APUE]不用fcntl实现dup2函数功能

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
");
 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!
");
 44         exit(1);
 45     }
 46     printf("
[main]: new fd is %d
", 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
", src_fd);
 61     printf("[my_dup2]: parameter : new fd %d

", new_fd);
 62 
 63     if (src_fd < 0 || new_fd < 0 ) {
 64         printf("[my_dup2]: error: src or des parameter < 0.
");
 65         return -1;
 66     }
 67     else if (new_fd >= tbl_size ) {
 68         printf("[my_dup2]: error: des_fd out of system limit: %d
", 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!
");
 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!
");
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
");
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
", index, fd_array[index]);
123 
124         if (fd_array[index] == -1) {
125             printf("[my_dup2]: dup process error!
");
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("
[my_dup2]: to close temp fds
");
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
", 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
", index, fd_array[index]);
150         }
151     }
152     return new_fd;
153 }
原文地址:https://www.cnblogs.com/qinqiao/p/implement_dup2.html