背景:项目有个功能是查看版本号(像什么内核版本号、驱动版本号,等等),是通过管道来实现的,网上也有这方面的介绍,就不多说了。
在一次测试过程中,发现不断查看版本号竟然会导致系统复位(比如查看20次、40次、100次),这个bug发现晚的原因是没有谁那么无聊连续查看100次版本号,当然,发现也是碰巧在几次查看之后系统就挂了。后来发现是因为某个地方卡住导致某个线程超时而复位。后来跟踪到了这个管道函数中来。解决的方法是使用读取文件的方法来获取系统版本号(如内核版本)。不过真正原因还没有找到,可能出在popen这类函数中。
下面给出示例代码:
#include <stdio
.h>
#include <stdlib .h>
#include <string .h>
#include <unistd .h>
#include <signal .h>
static void OnSignal( int signalno)
{
printf( "receive signal num: %d\n", signalno);
int bExit = true;
for ( int i = 0; i < 100; i++)
{
if (signalno == 17 || signalno == 13)
{
bExit = false;
break;
}
}
if (bExit)
{
printf( "exit process.\n");
}
}
// 通过管道读取执行命令后的信息
void GetSystemCmdInfo( const char* cmd, char* buf, int len)
{
char info[ 256] = { 0};
FILE* fp = popen(cmd, "r");
if (fp)
{
fread(info, 1, sizeof(info), fp);
if ( buf != NULL && len > ( int)strlen(info) )
{
strcpy(buf, info);
}
pclose(fp);
}
}
// 通过文件读取到信息
// 这种方法是读文件,上面的方法是执行命令,两者不是一回事
void ReadKernelVersion( char* file, char* buf, int len)
{
FILE* fp = NULL;
char info[ 256] = { 0};
fp = fopen(file, "r");
if (fp == NULL)
{
perror( "open file error");
return;
}
fread(info, 1, sizeof(info), fp);
if ( buf != NULL && len > ( int)strlen(info) )
{
strcpy(buf, info);
}
fclose(fp);
}
int main( void)
{
char szValue[ 512] = { 0};
char buf[ 1024] = { 0};
int iLen = 0;
for ( int i = 0; i < 255; i++)
{
if (i != SIGILL && i != SIGBUS && i != SIGSEGV)
{
signal(i, OnSignal);
}
}
// 执行此函数时,会有SIGCHLD信号
GetSystemCmdInfo( "cat /proc/version", szValue, sizeof(szValue));
//ReadKernelVersion("/proc/version", szValue, sizeof(szValue));
iLen = sprintf(buf, "[Kernel ver]: %s\r\n", szValue);
printf( "%s", buf);
return 0;
}
#include <stdlib .h>
#include <string .h>
#include <unistd .h>
#include <signal .h>
static void OnSignal( int signalno)
{
printf( "receive signal num: %d\n", signalno);
int bExit = true;
for ( int i = 0; i < 100; i++)
{
if (signalno == 17 || signalno == 13)
{
bExit = false;
break;
}
}
if (bExit)
{
printf( "exit process.\n");
}
}
// 通过管道读取执行命令后的信息
void GetSystemCmdInfo( const char* cmd, char* buf, int len)
{
char info[ 256] = { 0};
FILE* fp = popen(cmd, "r");
if (fp)
{
fread(info, 1, sizeof(info), fp);
if ( buf != NULL && len > ( int)strlen(info) )
{
strcpy(buf, info);
}
pclose(fp);
}
}
// 通过文件读取到信息
// 这种方法是读文件,上面的方法是执行命令,两者不是一回事
void ReadKernelVersion( char* file, char* buf, int len)
{
FILE* fp = NULL;
char info[ 256] = { 0};
fp = fopen(file, "r");
if (fp == NULL)
{
perror( "open file error");
return;
}
fread(info, 1, sizeof(info), fp);
if ( buf != NULL && len > ( int)strlen(info) )
{
strcpy(buf, info);
}
fclose(fp);
}
int main( void)
{
char szValue[ 512] = { 0};
char buf[ 1024] = { 0};
int iLen = 0;
for ( int i = 0; i < 255; i++)
{
if (i != SIGILL && i != SIGBUS && i != SIGSEGV)
{
signal(i, OnSignal);
}
}
// 执行此函数时,会有SIGCHLD信号
GetSystemCmdInfo( "cat /proc/version", szValue, sizeof(szValue));
//ReadKernelVersion("/proc/version", szValue, sizeof(szValue));
iLen = sprintf(buf, "[Kernel ver]: %s\r\n", szValue);
printf( "%s", buf);
return 0;
}
popen算是重型武器了,一般的小场合可不必使用,像查看内核版本,可能使用cat /proc/version命令,也可以读取/proc/version文件。
还是那名话说得好,具体情况具体分析,因地制宜采用不同的策略方能制胜。
语法高亮由迟思堂工作室强力支持
李迟 代码随笔 即日