这里说的“后门”并不是教你做坏事,而是让你做好事,搭建自己的调试工具更好地进行调试开发。我们都知道,当程序发生异常错误时,我们需要定位到错误,有时我们还想,我们在不修改程序的前提下,就能通过log来定位错误呢?有人会说,我在我的程序里加多点打印就好了,程序每做一步我就加一行打印,到时一查log就知道程序在哪一步死掉的了。这个方法在小程序里也许会行得通,但是,在一个大型系统,每秒的log达到几百条,那时我们怎么能在这繁多的log里找出我们想要的那条的log的?这工作量大得夸张。工程中的解决方法就是给自己的程序开个后门专门给开发人员来调试程序。
我在上篇文章:《Linux编程之定制带级别的log》里介绍了如何自定义自己的带级别log,我们就可以在我们后门程序里修改log 的level,从而使得log的级别发生改变,而无需重新修改程序。比如我们初始化我们的log级别是FATAL,那么此时只会打印出FATAL的信息,但是有一次程序发生了错误,但是我们无法从FATAL的log里看出问题,那我们通过后台修改log的级别为ALARM,我们通过ALARM的log查出了程序错误的原因。当然我们通过后门能做的不仅仅是这些,具体来说,后门就是我们程序眼和跑着的程序交流的一道门。
搭建这么一个程序后门主要有这么几个关键点:
一、创建debug center线程
这个就没什么好说了,我使用了上篇文章《Linux编程之自定义消息队列》所搭建的消息队列框架,将其中的msg_sender1改造为debug_center线程,作为我们的程序后门,我们跟程序交互就是从这里开始的。
if(pthread_create(&debug_thread_id, NULL, (void*)debug_center, NULL)) { MY_LOG(FATAL,); return -1; }
二、创建FIFO
为什么要创建FIFO(有名管道)?因为我们需要跟我们的程序进行通信,我们需要把我们的指令告诉程序,那就需要一个通信途径,FIFO就是一个很好的选择。我们把我们的指令写进管道,程序将指令从管道出,然后执行该指令,这样子我们程序后门的通信模型就出来了。why解决了,是时候解决how了。
对于管道的操作,我是这么做的:
system(); //每次进入debug center我们都将原来的fifo文件删除,避免影响后面操作 rc = mkfifo(, (rc < 0) { MY_LOG(DEBUG, ); pthread_exit(0); } fp = fopen(, ); (fp == NULL) { MY_LOG(DEBUG, ); pthread_exit(0); }
读fifo我们解决了,那怎么将我们的指令写进fifo呢?这里我打算使用shell的read指令,文章后面会解释如何实现。
三、解析指令
解析指令又可以分为两个步骤:
格式处理:
static int get_args(FILE *inputFile) { char tmpBuffer[100]; char *line = tmpBuffer; ; char *token; int i; char eof; int num = 0; eof = !fgets(line, sizeof(tmpBuffer), inputFile); if (eof) return num; token = strtok(line, separator); while (num < MAX_NUM_ARGS && token) { strcpy(args[num], token); num++; token = strtok(NULL, separator); } for (i = num; i < MAX_NUM_ARGS; i++) args[i][0] = 0; return num; }
命令解析:
switch(args[0][0]) //解析指令,看每个指令对应哪些意思 { : (args[1][0]) { : //display queue show_MQ(fd); break; : //display debug show_debug_level(fd); break; default: help_manual(fd); break; } break; : (args[1][0]) { : //set debug level n = atoi(args[2]); //将字符串转化为整数 fprintf(fd,,global.debug_level,n); ; default: help_manual(fd); break; } break; default: help_manual(fd); break; }
四、搭建debug界面
先上界面图:
我们敲的每个命令都是通过该界面传递到程序那头的,比如“d d”就表示展示出现在系统运行时的log级别,而“s d”就是设置我们想要看的log级别,这样我们就可以实现通过程序后门动态修改程序走向了。
那该如何实现这个看似简单的交互界面呢?实现该交互界面,有几个关键点:
以上三点就是做成界面的最重要的技术问题。