【发布时间】:2017-05-03 11:38:00
【问题描述】:
我正在使用popen() 在我的 Ubuntu 机器(16.04 LTS)中运行 shell 命令,出于某种原因,popen 更改了命令字符串,然后运行更改后的命令字符串,导致错误,因为没有这样的命令(它将/021/001 添加到字符串的末尾)。
我在具有不同 Ubuntu 版本 (14.04 LTS) 的等效机器上运行相同的代码,popen 不会更改命令字符串并且可以完美运行。
知道为什么会这样吗?
我正在运行的代码:
char* runShellReadCmd(char* command) {
FILE *fp;
int outputCurrentSize = 0, outputArrSize = READ_INITIAL_SIZE;
char readChunk[READ_CHUNK], *tmpOutputStrArr = NULL, *data = NULL;
fp = popen(command, "r");
data = (char*)calloc(READ_INITIAL_SIZE, sizeof(char));
while (fgets(readChunk, READ_CHUNK, fp) != NULL)
{
// If string size equals to the array size, need to expand the array.
if (outputCurrentSize >= outputArrSize) {
outputArrSize *= 2;
// Re allocate array, save it in a temporary array.
tmpOutputStrArr = realloc(data, outputArrSize * sizeof(char));
// If re-allocationg failed, stop and return NULL to indicate that a problem has occured.
if (!tmpOutputStrArr) {
free(tmpOutputStrArr);
free(data);
return NULL;
}
data = tmpOutputStrArr;
}
// Concatenate the recently read 100 chars to the data arr.
strcat(data, readChunk);
// Save current string length.
outputCurrentSize += READ_CHUNK;
}
pclose(fp);
return data;
}
命令:
"/sbin/iwlist wlp2s0 scan"
funcs.c:
// Runs a shell command using given command string and returns the output.
char* runShellReadCmd(char* command) {
FILE *fp;
int outputCurrentSize = 0, outputArrSize = READ_INITIAL_SIZE, elementsRead = 0;
char readChunk[READ_CHUNK], *tmpOutputStrArr = NULL, *data = NULL;
printf("%s", command);
fflush(stdout);
fp = popen(command, "r");
data = (char*)calloc(READ_INITIAL_SIZE, sizeof(char));
// while (fgets(readChunk, READ_CHUNK, fp) != NULL)
while (elementsRead = fread(readChunk, sizeof(char), READ_CHUNK, fp) != READ_CHUNK)
{
// If string size equals to the array size, need to expand the array.
if (outputCurrentSize >= outputArrSize) {
outputArrSize *= 2;
// Re allocate array, save it in a temporary array.
tmpOutputStrArr = realloc(data, outputArrSize * sizeof(char));
// If re-allocationg failed, stop and return NULL to indicate that a problem has occured.
if (!tmpOutputStrArr) {
free(tmpOutputStrArr);
free(data);
return NULL;
}
data = tmpOutputStrArr;
}
// Concatenate the recently read 100 chars to the data arr.
strcat(data, readChunk);
// Save current string length.
outputCurrentSize += READ_CHUNK;
}
pclose(fp);
return data;
}
// Returns the number of times the given substring appears in the given string.
int getNumOfMatches(char* string, char* substring) {
int count = 0;
char* temp = string;
while ((temp = strstr(temp, substring))) {
count++;
temp++;
}
return count;
}
// Returns the first wlan device name thats available in the system.
char* getWlanDeviceName() {
int size = 0, i;
char* device, *tmpPointer, *deviceNameStartPointer;
char* str = runShellReadCmd("/sbin/ifconfig");
deviceNameStartPointer = strstr(str, WIFI_DEVICE_PREFIX);
tmpPointer = deviceNameStartPointer;
while (*tmpPointer != ' ') {
size++;
tmpPointer++;
}
device = (char*)calloc(size, sizeof(char));
tmpPointer = deviceNameStartPointer;
for(i = 0; i < size; i++) {
device[i] = *tmpPointer;
tmpPointer++;
}
free(str);
return device;
}
test_funcs.c:
// Tests whether the wifi device can find wifi networks (at least 1).
int testWifi() {
int testOk = 0, length;
char* command, *output, *device = getWlanDeviceName();
length = strlen("/sbin/iwlist ") + strlen(device) + strlen(" scan");
command = (char*) calloc(length, sizeof(char));
strncpy(command, "/sbin/iwlist ", strlen("/sbin/iwlist "));
//strcat(command, "/sbin/iwlist ");
strcat(command, device);
strcat(command, " scan");
output = runShellReadCmd(command);
printf("%s\n", output);
testOk = getNumOfMatches(output, WIFI_NETWORK_START_STR) > 0;
//printf("%d", getNumOfMatches(WIFI_NETWORK_START_STR, output));
free(device);
return testOk;
}
【问题讨论】:
-
outputCurrentSize += READ_CHUNK;这个增量可能太大了。 -
aside:
if (!tmpOutputStrArr) { free(tmpOutputStrArr);:你不需要那个free。 -
READ_CHUNK和READ_INITIAL_SIZE是什么?无论实际大小如何,您总是添加行的最大大小。也许你最好在这里使用fread而不是fgets。 -
可能您的命令缓冲区过小,并被您用于输出的后续
malloc和realloc覆盖。我非常怀疑popen有这样的错误。向我们展示调用您的例程的代码。 -
当你拼凑
command时,你的length需要一个额外的字节作为空终止符。可能值得考虑asprintf而不是重复的strcats 加上手动分配。