2017-04-18

 

概述

    在TV开发板中,可以在串口中直接使用grep命令。这是因为在/system/bin/下有一个'grep'链接。这个链接指向'/system/bin/toolbox'程序。
【图1】
当在串口中键入:
grep um
命令时也就等效于键入
toolbox grep um
 
  toolbox程序是Android系统中携带的工具​之一。其源码位于:
./system/core/toolbox/

【图2】

  由上图2可以看到该目录下包含有大多数常用命令的源代码。toolbox程序的意义就是将这些零散的程序的入口进行打包。根据用户在串口中键入的toolbox命令后面的参数不同来选择执行对应的程序。例如,当键入上述的 ‘toolbox grep um’命令时,系统会先将命令的参数通过toolbox的进行解析,最终调用grep.c中的grep_main()函数进行二次解析。

 

toolbox处理流程

./system/core/toolbox/toolbox.c
  该源码文件结构简单。内部仅两个函数:1.int main(int argc, char **argv);2.static int toolbox_main(int argc, char **argv);以及一个封装了各工具集入口函数的结构体数组tools[]。在这个源码中,最重要的就是这个静态结构体数组,其定义如下:
 #define TOOL(name) int name##_main(int, char**);
#include "tools.h"
#undef TOOL static struct
{
const char *name;
int (*func)(int, char**);
} tools[] = {
{ "toolbox", toolbox_main },
#define TOOL(name) { #name, name##_main },
#include "tools.h"
#undef TOOL
{ , },
};
  上述代码中,第1~3行的定义方式在我看来很新奇。但此处就简单把它理解成从tools.h中读取定义的信息,事实上也确实是这样。然后将这些字符串替换成相应的函数声明。tools.h是在本目录下的Android.mk文件中生成的。位于out目录下。
 
其内容类型如下
上述代码中,第1~3行是声明各工具的入口函数。第11~13行是使用这些外部函数。经过这样的声明以后,toolbox程序在运行时这个tools数组的实际值为
 tools[] = {
{ "toolbox", toolbox_main },
{"ls", ls_main},
.
.
.
{"grep", grep_main},
{ , },
};
而tools结构体的第二个参数又是一个函数指针,因此,tools数组中包含的就是toolbox目录下的所有工具的入口函数。估计这也是它会被取名为toolbox的原因吧。
 
  在运行toolbox程序的时候,首先会调用其主函数main()。在这个主函数main()中主要就是取跟在toolbox后面的参数来决定到底是要执行哪一个工具程序。如当键入:toolbox ls。则toolbox.c的执行顺序为:1.main();2.toolbox_main();3.main();4.ls_main()
 

grep

    grep程序的入口函数为:grep_main()
 ./system/core/toolbox/grep/grep.c
在这个文件的首部,定义了多个标志位用于区分不同的参数响应。
常用的功能及其执行参数都已标示了出来。
    在grep_main()函数中,首先判断了键入参数的首字符。 __progname[0]等效于argv[0][0]。一般我们使用grep命令时,都是键入grep -n "xx",这时,__progname[0]得到的值就是字符g。看注释貌似是说区分于二进制模式下的什么什么的。对于我们由串口键入命令来执行程序的情况,是统一解析成字符g的,故而不需要理会它的真实用意。
 
    然后会从环境变量中读取搜索环境。
读取到环境变量后做了什么事,我们姑且不管。不过这个的结果一般都是(null),因此实际上会执行如下操作:
    接下来就是去解析命令后面跟的参数了。
图【3】
函数getopt_long()的含义可查询百度。
不得不承认,这个函数的功能很强大。它能解析各种花式输入的参数。同时它还具有排序的功能,将花式输入的命令行重新排序成'grep'在前,参数在其中,需要筛选的字符串在末尾的顺序。具体功能验证如下系列图所示,getopt_long()的排序功能验证如下图7所示。

    总之,经过图3所示的while循环后,能够识别所有的参数。例如,识别-n参数的代码如下图所示。
    接下来就是筛减aargv中的参数。
其中,optind是getopt_long()函数中的一个变量,它的值是键入的'grep'字符串以及所有的参数的数量。
 
    接下来是去读取需要过滤的字符串。
当键入的参数中包含-e  -f 时,needpattern的值就是0,否则为1。
由此处代码可知,grep命令仅能搜索一个参数。add_pattern()函数的实现如下图所示。
【图4】
    此函数的代码也算简单。grep命令是在pattern[]数组中保存要过滤的字符串的(pattern是一个二维数组)。而这个数组又被设计成“自动扩容”的形式。上图4所示代码中第230行的条件块就是一个自动扩容的处理流程了。grep_realloc()函数的定义位于
 ./system/core/toolbox/grep/util.c
然后将这个要过滤的字符串添加到pattern[]数组的末尾。至此,整个命令的解析就已经完成了。接下来就要开始执行过滤操作了。
    接下来就是
这个grepbehave在grep_main()的首部就已被赋值。对于我们由串口键入命令的情况来说,其值恒为GREP_BASIC。这里,不必理会。
 
    接下来是
这一块的作用我也不知道。程序一般会走694行。看695行的函数名fastcomp(),猜它应该是一个快速对比的功能。这个函数的定义位于
 ./system/core/toolbox/grep/fastgrep.c
有兴趣的话可以去详细阅读一下源码。这个函数返回0表示成功,返回-1表示失败。经测试,都是返回-1。此处略过这块代码。
 
    接下来是搜索前的最后的设置。
707行的lbflag是行缓冲。目前并不知道它的具体作用。经测试,由串口键入命令的方式,该值一般为0。此处暂时不予理会。
710行的Hflag,。该值默认为0。
由713行,当键入的过滤字符串只有一个时,就进行过滤操作,然后退出grep程序。
否则,就执行下面的代码。多个过滤字符串中后面的将会被认为是文件或目录的路径。这样就会被系统理解为在这个目录或文件中执行搜索命令。
dirbehave在键入的参数中有'-r'时其值会为DIR_RECURSE。其它情况,则执行else分支。
这里,暂时不讨论指定文件或目录的情况。
 
procfile()函数位于
 ./system/core/toolbox/grep/util.c
    这个函数内部定义了几个结构体变量。其中file与str结构体的定义位于
 ./system/core/toolbox/grep/grep.h

    file结构体结构简单,内部仅保存文件的句柄及这个文件是否是二进制文件的标志。str结构体也简单。其中*dat保存的是当前剩余要过滤的数据。对于在串口中使用grep而言,就是当前获得的文件流中的所有内容。
对于只有一个过滤字符串的情况,会执行上图所示代码中的197行代码块。且对于在串口中键入命令的情况,198行的fn得到的值是(standard input)。即标准输入流,而非某个文件流。接着去grep_open(NULL)函数,这个函数位于
 ./system/core/toolbox/grep/file.c
这个函数的结构也简单,
这个函数的重点在于第241行处。它会将文件结构体的文件句柄指向标准输入流处。
    接着再回到util.c处继续往下执行,现在就到了从流中过滤数据的时候了。核心代码如下图所示,
上面这个for循环语句就是用来过滤关键字并将结果打印在控制台用的。在第226行for循环的条件判断处可以看到两个状态位lflag与qflag。前面的状态位是标志是否只打印文件名,后面的状态位则是标志是否静默搜索(将结果输出到文件或其它什么的)。
 
    上图所示代码中,第228行的if语句的作用就是逐行读取源数据ln.dat。然后跳到第242行。这里调用了procline函数。上面的procfile是处理整个文件流,读取出一行数据后就传到procline中作进一步处理。随后procline在匹配到符合条件的行后,传到printline函数中打印出来。这三个函数均在util.c文件中。具体的实现流程就不再赘述了。
 
grep的详细流程在我看来是很复杂的,没有必要去弄懂这个流程中每一行代码的意义,只需要了解个大概流程就好了,毕竟是抱着扩充知识面而非研究代码的目的去学习的。

浅析Android设备中grep命令处理流程的更多相关文章

  1. 通过ADB命令行卸载或删除你的Android设备中的应用(转载)

    转自:http://mytiankong.com/?p=11755 如果你对你的Android设备在与命令行的交互间有一定的兴趣,那你可能想学习一些使用ADB卸载设备中已安装应用的技巧.为了使这种方法 ...

  2. bat如何创建多级文件夹(在android设备中)

    在android设备中要创建多个或者多级文件夹时,手动去创建费时费力(有点傻),一个bat文件就能很好的实现这个功能. 1.首先创建同级多个文件夹且在该文件夹下生成一个文件 @echo off ech ...

  3. Android开发中adb命令的常用方法

    Android的SDK中提供了很多有用的工具,在开发过程中如果能熟练使用这些工具,会让我们的开发事半功倍.adb是SDK提供的一个常用的命令行工具,全称为Android Debug Bridge,用于 ...

  4. 从Android设备中提取内核和逆向分析

    本文博客链接:http://blog.csdn.net/qq1084283172/article/details/57074695 一.手机设备环境 Model number: Nexus 5 OS ...

  5. 12个 Linux 中 grep 命令的超级用法实例

    12个 Linux 中 grep 命令的超级用法实例 你是否遇到过需要在文件中查找一个特定的字符串或者样式,但是不知道从哪儿开始?那么,就请grep来帮你吧. grep是每个Linux发行版都预装的一 ...

  6. linux中grep命令的使用

    转载:http://blog.csdn.net/universsky/article/details/8866402 linux中grep命令的使用 grep (global search regul ...

  7. 在桌面chrome中调试android设备中的web页面

    准备工作 1, 桌面版chrome 2, Android设备(安装有chrome浏览器) 3, Android-sdk Android-sdk安装及设置 SKD安装 从http://developer ...

  8. 如何获得Android设备名称(ADB命令详细介绍)

    豌豆荚.360手机管家等软件可以获取android设备名称,显示在界面上,如下图: 我们自己如何来获取设备名称 呢?答案如下: 在命令行中输入“adb shell”进入shell之后,再输入“cat ...

  9. shell 中grep命令详解

    用‘grep’搜索文本文件如果您要在几个文本文件中查找一字符串,可以使用‘grep’命令.‘grep’在文本中搜索指定的字符串.举个例子:假设您正在‘/usr/src/linux/Documentat ...

随机推荐

  1. 为什么大公司一定要使用DevOps?

    0 DevOps的意图 究竟什么是DevOps? 要想回答这个问题,首先要明确DevOps这个过程参与的人员是谁?即开发团队和IT运维团队!那么,DevOps的意图是什么呢?即在两个团队之间,建立良好 ...

  2. 一篇 JPA 总结

    概述 下面是 JDBC 在 Java 应用和数据库之间的位置,充当着一个中间者,供 Java 应用程序访问所有类别的数据库,建立一个标准 JPA 如同 JDBC 一样,为 Java 应用程序使用 OR ...

  3. 不容错过的超赞项目管理PPT

    不容错过的超赞项目管理PPT(转载) 大公司的一个好处,是各个领域都有牛人,可以为你提供经验分享交流.腾讯庞大的培训体系更是保证了:如果你想学点什么东西,你总可以学到.腾讯内部资源30页PPT曝光 — ...

  4. linux if -d -e -f表达的意思

    文件表达式-e filename 如果 filename存在,则为真-d filename 如果 filename为目录,则为真 -f filename 如果 filename为常规文件,则为真-L ...

  5. Django Rest framework基础使用之Request/Response

    1.Request restframework提供了一个Request对象(rest_framework.request.Request) Request对象继承了Django默认的HttpReque ...

  6. itoa函数实现

    1.      整数字符转化为字符串数 // 将整数转换成字符串数,不用函数itoa // 思路:采用加'0',然后在逆序的方法 #include <iostream> using nam ...

  7. Python-os模块-60

    os 模块: 和操作系统打交道的模块 os模块是与操作系统交互的一个接口 os.makedirs('dirname1/dirname2') 可生成多层递归目录 os.removedirs('dirna ...

  8. java的instanceof关键字

    java 中的instanceof 运算符是用来判断对象是否是 特定类或这个特定类的子类 的一个实例. 用法: result = object instanceof class 参数: Result: ...

  9. git更新提交代码常用命令

    git pull 拉取代码 git add -A 提交所有变化(包括删除.新增.修改) git commit -m "注释" 本地仓库提交 git push origin mast ...

  10. ios 后台下载,断点续传总结

    2018年12月05日 16:09:00 weixin_34101784 阅读数:5 https://blog.csdn.net/weixin_34101784/article/details/875 ...