Oct
29
GNU的tail源码阅读笔记
---# GNU的tail源码阅读笔记
---++ 获取源码
tail和head等原本是属于textutils软件包的,后来被统一合并到coreutils软件包中了。coreutils的主页是:http://www.gnu.org/software/coreutils/,可以从这里下载到所有的源码。如果你使用的是Ubuntu系统,还可以直接运行命令 apt-get source coreutils 直接从源中获取代码。
---++ 编译
先编译一下。跟其他开源软件基本上一致,先./configure一下,没有问题的话就make之。make结束以后,生成的可执行文件就在src目录下面
---++ 阅读
为了方便阅读,先ctags -R一下,生成tags;然后vim src/tail.c就打开了源码。代码比较细碎,零零散散2000多行,花了两三个小时才看完,大致读懂了代码的主干流程,这里记录一下。
* 初始化,有些乱七八糟的initialize_main/set_program_name/setlocale/bingtextdomain/textdomain都可以忽略,没做什么实事。atexit还算有点用,设置了退出的时候要把stdout关闭。
* 解析命令行参数。先上了个obsolete_parse_option(option都不加个复数s),貌似是为了兼容以前的命令行参数方式(posix2_version在200112这个版本以前的)。然后又来一个parse_options,这个就是按照man里面的格式来解析参数了。具体的参数man tail就可以看到,不多说。
* 判断一下输入是不是源于stdin,如果是的话,修改一下file和n_files。
* 然后给文件结构体分配空间,填进去每个文件的名字,然后是一个循环,调用tail_file来输出每个文件(传入结构体F[i]的指针)的内容
看看tail_file:
* 打开文件,失败的话当然就over了,return
* 看看要不要输出文件名(可以在命令后参数指定-q, -v)
* 调用tail函数输出需要输出的内容。tail函数根据是要输出行还是输出字符(命令行参数-c)来决定调用tail_lines还是tail_bytes。
* tail_lines: 如果是输出末尾n行,就调用file_lines函数,从文件的末尾开始,往前找到要开始输出的位置,调用dump_remainder输出;如果要输出第n行以后的内容,就调用start_lines跳过前n行,也是调用dump_remainder输出。
* tail_bytes和tail_lines的结构基本相同,不过那个函数是start_bytes了。
* 如果有-f参数(follow, 不断输出文件中新增加的内容), 检查一下文件的状态;否则就可以关闭了
* 如果指定了-f参数,那么执行if(forever && n_viable)这一段。其中n_viable是可以继续tail的文件的数量。
* 如果linux内核支持inotify特性(监控文件的变化,并发出通知),那么调用tail_forever_inotify函数来跟踪文件的变化(添加inotify的watch,然后用select来处理)。
* 否则使用tail_forever函数,做法是循环输出每个文件新增加的内容(上次读取的时候记录一下读取的位置),然后nanosleep一段时间(默认是1.0s)。
转载请注明出自 ,如是转载文则注明原出处,谢谢:)
RSS订阅地址: https://www.felix021.com/blog/feed.php 。
---++ 获取源码
tail和head等原本是属于textutils软件包的,后来被统一合并到coreutils软件包中了。coreutils的主页是:http://www.gnu.org/software/coreutils/,可以从这里下载到所有的源码。如果你使用的是Ubuntu系统,还可以直接运行命令 apt-get source coreutils 直接从源中获取代码。
---++ 编译
先编译一下。跟其他开源软件基本上一致,先./configure一下,没有问题的话就make之。make结束以后,生成的可执行文件就在src目录下面
---++ 阅读
为了方便阅读,先ctags -R一下,生成tags;然后vim src/tail.c就打开了源码。代码比较细碎,零零散散2000多行,花了两三个小时才看完,大致读懂了代码的主干流程,这里记录一下。
* 初始化,有些乱七八糟的initialize_main/set_program_name/setlocale/bingtextdomain/textdomain都可以忽略,没做什么实事。atexit还算有点用,设置了退出的时候要把stdout关闭。
* 解析命令行参数。先上了个obsolete_parse_option(option都不加个复数s),貌似是为了兼容以前的命令行参数方式(posix2_version在200112这个版本以前的)。然后又来一个parse_options,这个就是按照man里面的格式来解析参数了。具体的参数man tail就可以看到,不多说。
* 判断一下输入是不是源于stdin,如果是的话,修改一下file和n_files。
* 然后给文件结构体分配空间,填进去每个文件的名字,然后是一个循环,调用tail_file来输出每个文件(传入结构体F[i]的指针)的内容
看看tail_file:
* 打开文件,失败的话当然就over了,return
* 看看要不要输出文件名(可以在命令后参数指定-q, -v)
* 调用tail函数输出需要输出的内容。tail函数根据是要输出行还是输出字符(命令行参数-c)来决定调用tail_lines还是tail_bytes。
* tail_lines: 如果是输出末尾n行,就调用file_lines函数,从文件的末尾开始,往前找到要开始输出的位置,调用dump_remainder输出;如果要输出第n行以后的内容,就调用start_lines跳过前n行,也是调用dump_remainder输出。
* tail_bytes和tail_lines的结构基本相同,不过那个函数是start_bytes了。
* 如果有-f参数(follow, 不断输出文件中新增加的内容), 检查一下文件的状态;否则就可以关闭了
* 如果指定了-f参数,那么执行if(forever && n_viable)这一段。其中n_viable是可以继续tail的文件的数量。
* 如果linux内核支持inotify特性(监控文件的变化,并发出通知),那么调用tail_forever_inotify函数来跟踪文件的变化(添加inotify的watch,然后用select来处理)。
* 否则使用tail_forever函数,做法是循环输出每个文件新增加的内容(上次读取的时候记录一下读取的位置),然后nanosleep一段时间(默认是1.0s)。
欢迎扫码关注:
转载请注明出自 ,如是转载文则注明原出处,谢谢:)
RSS订阅地址: https://www.felix021.com/blog/feed.php 。
libiehua
2010-2-23 11:37
在看《unix/linux编程实践教程》,想看一下tail的真实代码,呵呵
sandy
2009-10-30 12:56
以为tail应该很简单的,居然2000多行。。。
felix021 回复于 2009-10-30 17:44
其实还有些辅助函数是coreutils公用的,没算在里面。
boluor
2009-10-30 12:10
没有ctags阅读源码实在是件相当痛苦的事情。。。我想起了当初我读mount源码的时候,1w多行,最后就读懂了一点。
分页: 1/1 1