if(pthread_create(&debug_thread_id, NULL, (void*)debug_center, NULL))
{
MY_LOG(FATAL,"create debug center fail!\n");
return -1;
}
二、創建FIFO
為什麼要創建FIFO(有名管道)?因為我們需要跟我們的程序進行通信,我們需要把我們的指令告訴程序,那就需要一個通信途徑,FIFO就是一個很好的選擇。我們把我們的指令寫進管道,程序將指令從管道出,然後執行該指令,這樣子我們程序後門的通信模型就出來了。why解決了,是時候解決how了。
對於管道的操作,我是這麼做的:
system("rm /vob/ljsdpoenew3/exercise/debug_log"); //每次進入debug center我們都將原來的fifo文件刪除,避免影響後面操作
rc = mkfifo("/vob/ljsdpoenew3/exercise/debug_log", 0666); //創建fifo
if(rc < 0)
{
MY_LOG(DEBUG, "make fifo fail!\n");
pthread_exit(0);
}
fp = fopen("/vob/ljsdpoenew3/exercise/debug_log", "r"); //打開fifo,讀取指令
if(fp == NULL)
{
MY_LOG(DEBUG, "open debug_log fail!\n");
pthread_exit(0);
}
讀fifo我們解決了,那怎麼將我們的指令寫進fifo呢?這裡我打算使用shell的read指令,文章後面會解釋如何實現。
三、解析指令 解析指令又可以分為兩個步驟:static int get_args(FILE *inputFile)
{
char tmpBuffer[100];
char *line = tmpBuffer;
char separator[] = " ,\n\t";
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]) //解析指令,看每個指令對應哪些意思
{
case 'd': //display
switch(args[1][0])
{
case 'q': //display queue
show_MQ(fd);
break;
case 'd': //display debug
show_debug_level(fd);
break;
default:
help_manual(fd);
break;
}
break;
case 's': //set
switch(args[1][0])
{
case 'd': //set debug level
n = atoi(args[2]); //將字符串轉化為整數
fprintf(fd," debug level change from %d to %d",global.debug_level,n);
global.debug_level = n; //更改log級別
break;
default:
help_manual(fd);
break;
}
break;
default:
help_manual(fd);
break;
}
四、搭建debug界面
先上界面圖:
我們敲的每個命令都是通過該界面傳遞到程序那頭的,比如“d d”就表示展示出現在系統運行時的log級別,而“s d”就是設置我們想要看的log級別,這樣我們就可以實現通過程序後門動態修改程序走向了。
那該如何實現這個看似簡單的交互界面呢?實現該交互界面,有幾個關鍵點:
fd = fopen("/vob/ljsdpoenew3/exercise/debug_log2", "w+");
if(fd == NULL)
{
MY_LOG(DEBUG, "open debug_log2 fail!\n");
pthread_exit(0);
}
fprintf(fd," debug level change from %d to %d",global.debug_level,n);
這樣我們在debug center產生的打印都輸出到文件debug_log2上了。
2.利用腳本讀出內容且將內容寫入fifo
要做到這點需要shell編程的簡單知識,我們怎麼將我們的輸入放到fifo呢?我們怎麼把log文件的內容讀出來顯示在顯示屏呢?我想到首先是再寫個client,進行進程間通信嘛,將命令寫到fifo,同時也讀出log文件的內容。但是,我發現利用shell就可以做到以上的事了,而且只需花費幾行代碼。#!/bin/bash
my_inp_fifo=/vob/ljsdpoenew3/exercise/debug_log # 指定fifo文件
stty erase ^H
while [ true ];
do
read inp #循環讀入用戶輸入
if [ "$inp" == "quit" ];then #quit代表結束該界面
exit 0
fi
echo $inp > $my_inp_fifo #寫入fifo
cat debug_log2.txt #顯示log的內容
done
那看看這個命令行界面跑起來是怎麼的吧!
首先我們運行server進程 1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <math.h>
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <sys/prctl.h>
8 #include "msg_def.h"
9 #include "global.h"
10
11 extern Queue_t MsgQueue;
12 extern dashboard_t global;
13
14
15 #define MAX_NUM_ARGS 20
16 #define MAX_ARGS_SIZE 56
17
18 static char args[MAX_NUM_ARGS][MAX_ARGS_SIZE];
19
20 static int get_args(FILE *inputFile,FILE *fd)
21 {
22 char tmpBuffer[100];
23 char tmpBuffer2[100];
24 char *line = tmpBuffer;
25 char separator[] = " ,\n\t";
26 char *token;
27 int i;
28 char eof;
29
30 int num = 0;
31
32 eof = !fgets(line, sizeof(tmpBuffer), inputFile);
33 if (eof)
34 return num;
35
36 memcpy(tmpBuffer2,tmpBuffer,100);
37
38
39 token = strtok(line, separator);
40 while (num < MAX_NUM_ARGS && token)
41 {
42 strcpy(args[num], token);
43 num++;
44 token = strtok(NULL, separator);
45 }
46
47 for (i = num; i < MAX_NUM_ARGS; i++)
48 args[i][0] = 0;
49
50 if(num > 0)
51 {
52 fprintf(fd, "%s", tmpBuffer2);
53 }
54
55 return num;
56 }
57
58
59 static void help_manual(FILE* fd)
60 {
61 fprintf(fd,"\nd d : display current debug level\n");
62 fprintf(fd,"d q : display msg queue length, head and tail\n");
63 fprintf(fd,"s d [level] : set debug [level] \n");
64 }
65
66 static void show_MQ(FILE* fd)
67 {
68 fprintf(fd," msg queue length:%d head:%d tail:%d \n",abs(MsgQueue.head-MsgQueue.rear),MsgQueue.head,MsgQueue.rear);
69 }
70
71 static void show_debug_level(FILE* fd)
72 {
73 fprintf(fd," current debug level: %d\n", global.debug_level);
74 }
75
76
77
78 void debug_center()
79 {
80 int rc,num,n;
81 FILE* fp;
82 FILE* fd;
83
84 MY_LOG(DEBUG,"Hi,debug!\n");
85
86
87 system("rm /vob/ljsdpoenew3/exercise/debug_log");
88 system("rm /vob/ljsdpoenew3/exercise/debug_log2");
89 rc = mkfifo("/vob/ljsdpoenew3/exercise/debug_log", 0666);
90 if(rc < 0)
91 {
92 MY_LOG(DEBUG, "make fifo fail!\n");
93 pthread_exit(0);
94 }
95
96 fp = fopen("/vob/ljsdpoenew3/exercise/debug_log", "r");
97 if(fp == NULL)
98 {
99 MY_LOG(DEBUG, "open debug_log fail!\n");
100 pthread_exit(0);
101 }
102
103 fd = fopen("/vob/ljsdpoenew3/exercise/debug_log2", "w+");
104 if(fd == NULL)
105 {
106 MY_LOG(DEBUG, "open debug_log2 fail!\n");
107 pthread_exit(0);
108 }
109 //freopen("/vob/ljsdpoenew3/exercise/debug_log2.txt", "w+", fd);
110
111 fprintf(fd," \n==================================================\n");
112 fprintf(fd," Welcme to Debug Center!");
113 fprintf(fd," \n==================================================\n\n");
114 help_manual(fd);
115 //fflush(fd);
116
117 while(1)
118 {
119 fflush(fd);
120 fprintf(fd,"\n\nmy_diag>");
121 num = get_args(fp,fd);
122 if(num < 1)
123 {
124 freopen("/vob/ljsdpoenew3/exercise/debug_log", "r", fp);
125 fflush(fd);
126 continue;
127 }
128 fprintf(fd,"\n\nmy_diag>");
129 switch(args[0][0])
130 {
131 case 'd': //display
132 switch(args[1][0])
133 {
134 case 'q': //display queue
135 show_MQ(fd);
136 break;
137 case 'd': //display debug
138 show_debug_level(fd);
139 break;
140
141 default:
142 help_manual(fd);
143 break;
144 }
145 break;
146
147 case 's': //set
148 switch(args[1][0])
149 {
150 case 'd': //set debug level
151 n = atoi(args[2]);
152 fprintf(fd," debug level change from %d to %d",global.debug_level,n);
153 global.debug_level = n;
154 break;
155
156 default:
157 help_manual(fd);
158 break;
159 }
160 break;
161
162 default:
163 help_manual(fd);
164 break;
165 }
166
167 }
168 }