文档章节

unix/linux中的dup()系统调用

猫七猫七
 猫七猫七
发布于 2017/05/31 11:07
字数 1118
阅读 18
收藏 0

在linux纷繁复杂的内核代码中,sys_dup()的代码也许称得上是最简单的之一了,但是就是这么一个简单的系统调用,却成就了unix/linux系统最著名的一个特性:输入/输出重定向。
    sys_dup()的主要工作就是用来“复制”一个打开的文件号,使两个文件号都指向同一个文件。既然说简单,我们就首先来看一下它的代码(定义在fs/fcntl.c中):

1 asmlinkage long sys_dup(unsigned int fildes)
 2 {
 3     int ret = -EBADF;
 4     struct file * file = fget(fildes);
 5 
 6     if (file)
 7         ret = dupfd(file, 0);
 8     return ret;
 9 }
10 

 

而sys_dup()的主体是dupfd()(定义在同一个文件中):

 

1 static int dupfd(struct file *file, int start)
 2 {
 3     struct files_struct * files = current->files;
 4     int ret;
 5 
 6     ret = locate_fd(files, file, start);
 7     if (ret < 0)
 8         goto out_putf;
 9     allocate_fd(files, file, ret);
10     return ret;
11 
12 out_putf:
13     write_unlock(&files->file_lock);
14     fput(file);
15     return ret;
16 }
17 

注:dup和dup2的原型如下:
#include <unistd.h>

int dup(int file_descriptor);
int dup2(int file_descriptor1, int file_descriptor2)
dup返回的文件描述符总是取最小的可用值
dup2返回的文件描述符或者与file_descriptor2相同,或者是第一个大于该参数的可用值。

    而这么一个简单的系统调用是如何完成重定向这个艰巨的任务的呢?我们不妨先看个例子。
    当我们在shell下输入如下命令:“echo hello!”,这条命令要求shell进程执行一个可执行文件echo,参数为“hello!”。当shell接收到命令之后,先找到 bin/echo,然后fork()出一个子进程让他执行bin/echo,并将参数传递给它,而这个进程从shell继承了三个标准文件,即标准输入 (stdin),标准输出(stdout)和标准出错信息(stderr),他们三个的文件号分别为0、1、2。而至于echo进程的工作很简单,就是将参数“hello!”写到标准输出文件中去,通常都是我们的显示器上。但是如果我们将命令改成“echo hello! > foo”,则在执行时输出将会被重定向到磁盘文件foo中(注:重定向于文件描述符有关)。我们假定在此之前该shell进程只有三个标准文件打开,文件号分别为0、1、2,以上命令行将按如下序列执行:
    (1) 打开或创建磁盘文件foo,如果foo中原来有内容,则清除原来内容,其文件号为3。
    (2) 通过dup()复制文件stdout,即将文件号1出的file结构指针复制到文件号4处,目的是将stdout的file指针暂时保存一下
    (3) 关闭stdout,即1号文件,但是由于4号文件对stdout也同时有个引用,所以stdout文件并未真正关闭,只是腾出1号文件号位置。
    (4) 通过dup(),复制3号文件(即磁盘文件foo),由于1号文件关闭,其位置空缺,故3号文件被复制到1号,即进程中原来指向stdout的指针指向了foo。
    (5) 通过系统调用fork()和exec()创建子进程并执行echo,子进程在执行echo前夕关闭3号和4号文件,只留下0、1、2三个文件,请注意,这 时的1号文件已经不是stdout而是磁盘文件foo了。当echo想向stdout文件写入“hello!”时自然就写入到了foo中。
    (6) 回到shell后,关闭指向foo的1号与3号文件文件,再用dup()和close()将2号恢复至stdout,这样shell就恢复了0、1、2三个标准输入/输出文件。

    由此可见,当echo程序(或其他)在运行的时候并不知道stdout(对于stdin和stderr同样)指向什么,进程与实际输出文件或设备的结合是在运行时由其父进程“包办”的。这样就简化了子进程的程序设计,因为在设计时只要跟三个逻辑上存在的文件打交道就可以了。可能有人会觉得这很像面向对象中 的多态和重载,没有什么新奇之处,但是如果你活在30甚至40年前,可能你会改变你的看法。  

    之前了解dup和dup2函数,但对于其真正对作用不太了解。这个例子,很好对说明其一个作用对功能->辅助重定向

本文转载自:http://www.blogjava.net/lihao336/archive/2011/12/13/366231.html

共有 人打赏支持
猫七猫七
粉丝 0
博文 3
码字总数 513
作品 0
温州
私信 提问
我闻到了linux新内核的坏味道

最近翻出了linux2.6.27的邮件列表,发现大牛们在讨论一个问题,就是说该如何扩展系统调用,是对每个需要扩展的系统调用都封装一个新的系统调用,还是添加仅仅一个系统调用来封装所有的需要扩...

晨曦之光
2012/04/10
84
0
man综述--系统调用和库函数的关系

Tips: 用man查询函数时候有些并不能直接man + 函数名查到,例如:man fopen man 2 open 所以可以用man+数字+函数名来试试,具体的内容可以查看 /usr/local/share/man/下面对应的目录 _ Linu...

AlphaJay
2011/07/28
0
0
I/O重定向和管道——《Unix/Linux编程实践教程》读书笔记(第10章)

1、I/O重定向的概念与原因 及 标准输入、输出的标准错误的定义 所以的Unix I/O重定向都基于标准数据流的原理。三个数据了分别如下: 1)标准输入——需要处理的数据流 2)标准输出——结果数...

木子叶
2014/08/06
0
0
linux常用文件I/O操作之文件共享的实现方式

1、文件共享的三种实现方式 1、什么是文件共享: (1)文件共享就是同一个文件(同一个文件指的是同一个inode,同一个pathname)被多个独立的读写体(几乎可以理解为多个文件描述符)去同时(一...

捕风的xiao_k
2018/06/26
0
0
linux内核中的dup系统调用

linux内核中的dup系统调用 内核版本:2.6.14 嵌入式开发交流群:289195589,欢迎加入! dup系统调用的服务例程为sys_dup函数,定义在fs/fcntl.c中。sys_dup()的代码也许称得上是最简单的之一...

长平狐
2013/06/03
112
0

没有更多内容

加载失败,请刷新页面

加载更多

Cookie 显示用户上次访问的时间

import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.Cookie;import javax.servlet.http.HttpServlet;import javax.serv......

gwl_
今天
1
0
网络编程

第14天 网络编程 今日内容介绍  网络通信协议  UDP通信  TCP通信 今日学习目标  能够辨别UDP和TCP协议特点  能够说出UDP协议下两个常用类名称  能够说出TCP协议下两个常用类名称...

stars永恒
今天
1
0
二进制相关

二进制 众所周知计算机使用的是二进制,数字的二进制是如何表示的呢? 实际就是逢二进一。比如 2 用二进制就是 10。那么根据此可以推算出 5的二进制等于 10*10+1 即为 101。 在计算机中,负数以...

NotFound403
昨天
3
0
day22:

1、写一个getinterface.sh 脚本可以接受选项[i,I],完成下面任务: 1)使用格式:getinterface.sh [-i interface | -I ip] 2)当用户使用-i选项时,显示指定网卡的IP地址;当用户使用-I选项...

芬野de博客
昨天
2
0
Spring Cloud Alibaba基础教程:使用Nacos实现服务注册与发现

自Spring Cloud Alibaba发布第一个Release以来,就备受国内开发者的高度关注。虽然Spring Cloud Alibaba还没能纳入Spring Cloud的主版本管理中,但是凭借阿里中间件团队的背景,还是得到不少...

程序猿DD
昨天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部