![[APUE]不用fcntl实现dup2函数功能 [APUE]不用fcntl实现dup2函数功能](https://image.shishitao.com:8440/aHR0cHM6Ly9ia3FzaW1nLmlrYWZhbi5jb20vdXBsb2FkL2NoYXRncHQtcy5wbmc%2FIQ%3D%3D.png?!?w=700&webp=1)
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系统环境:
/*
* name : dup2.c
* func : implement of dup2 without fcntl.h
* author : jungle85gopy
* date : 2015.12.20
*/ /*
* Note :
* man dup() of Mac OSX
* Dup() duplicates an existing object descriptor and returns
* its value to the calling process (fildes2 = dup(fildes)).
* The value must be less than the size of the table, which is returned by
* getdtablesize(2). the size is 256 for Mac OSX 10.11.
* man dup() in ubuntu, there is no info about getdtablesize(2).
* but Ubuntu 14.04 still has getdtablesize limit of 1024.
*/ #include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/utsname.h> #define INIT_FD -2 int my_dup2(int src_fd, int new_fd);
int chk_dup(int src_fd, int new_fd);
int do_dup2(int src_fd, int new_fd); /*
* usage: dup2 src_fd, new_fd
*/
int main(int argc, char *argv[])
{
if (argc != ) {
printf("usage: dup2 src_fd new_fd\n");
exit();
} int new_fd = new_fd = my_dup2(atoi(argv[]), atoi(argv[]) );
if (new_fd == -) {
printf("dup to new_fd error!\n");
exit();
}
printf("\n[main]: new fd is %d\n", new_fd);
return new_fd;
} /*
* func: check the parameter of my_dup2
* return:
* -1: if error
* 0 : if success
*/
int chk_dup(int src_fd, int new_fd)
{
int tbl_size = getdtablesize(); printf("[my_dup2]: parameter : src fd %d\n", src_fd);
printf("[my_dup2]: parameter : new fd %d\n\n", new_fd); if (src_fd < || new_fd < ) {
printf("[my_dup2]: error: src or des parameter < 0.\n");
return -;
}
else if (new_fd >= tbl_size ) {
printf("[my_dup2]: error: des_fd out of system limit: %d\n", tbl_size);
return -;
} int index;
if ( (index = dup(src_fd)) == -) {
printf("[my_dup2]: parameter src_fd is inactive!\n");
return -;
} else
close(index); return ;
} /*
* func: dup a file descriptor from src_fd to new_fd
* return:
* new_fd if success
* -1 if error
*/
int my_dup2(int src_fd, int new_fd)
{
int ret; if ( (ret = chk_dup(src_fd, new_fd)) == -)
return -;
if (src_fd == new_fd)
return src_fd; // close new_fd, whether it is valid or not. ignore the return
close(new_fd); if ( (ret = do_dup2(src_fd, new_fd)) == -) {
printf("[my_dup2]: do dup failed!\n");
return -;
} else
return ret;
} /*
* func: dup from 0 to new_fd
*/
int do_dup2(int src_fd, int new_fd)
{
int index, index_hit = -, fd_array[new_fd]; for (index = ; index <= new_fd; index++)
fd_array[index] = INIT_FD; // initial to INIT_FD printf("[my_dup2]: before dup temp fds\n");
for (index = ; index <= new_fd; index++) {
fd_array[index] = dup(src_fd);
printf("[my_dup2]: index: %d, create temp fd: %d\n", index, fd_array[index]); if (fd_array[index] == -) {
printf("[my_dup2]: dup process error!\n");
break;
} else if (fd_array[index] == new_fd) {
index_hit = index;
break;
}
} // close temp fd
printf("\n[my_dup2]: to close temp fds\n"); if (index_hit == -) { // break for loops with error
for (index = ; index < new_fd; index++) {
if ((fd_array[index] == INIT_FD) || (fd_array[index] == -))
break; // no new temp dup in array
else {
close(fd_array[index]);
printf("[my_dup2]: index: %d, del temp fd: %d\n", index, fd_array[index]);
}
}
return -;
} else { // break for loops with hit
for (index = ; index < index_hit; index++) {
close(fd_array[index]);
printf("[my_dup2]: index: %d, temp fd: %d\n", index, fd_array[index]);
}
}
return new_fd;
}