当我只是管道ls -l |与此类似,程序只是无限地从ls -l中吐出结果。任何人都可以看到什么是错的? 假设您只需要查看main函数。不过,这将编译。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/wait.h>
#define COMMAND_LINE_LENGTH 256
#define HISTORY_LENGTH 10
#define TOKEN_MAX 50
#define DIRECTORY_LENGTH 5
#define DIRECTORY_PREFIX "/bin/"
struct prog_def
{
//Binary location
char *bin;
//Is this program expecting a pipe?
int expecting_pipe;
//Arguments
char *args[TOKEN_MAX + 1];
pid_t pid;
} prog_def;
int get_prog_defs(const char* buf, struct prog_def prog_defs[])
{
char *line = malloc(strlen(buf) + 1);
int prog_count = 0;
char* token;
strcpy(line, buf);
line[strlen(buf)] = 0;
while(1)
{
int arg_count = 0;
//The first time through we have to pass the line
token = strtok(line, " ");
//Each subsequent call we have to pass NULL
//http://www.cplusplus.com/reference/cstring/strtok/
line = NULL;
//Start building the binary location string
prog_defs[prog_count].bin = (char*)malloc(strlen(token) + DIRECTORY_LENGTH + 1);
//Concatenate the directory prefix and command name
strcat(prog_defs[prog_count].bin, DIRECTORY_PREFIX);
strcat(prog_defs[prog_count].bin, token);
//The first argument execvp will expect is the binary location itself
//Redundant but if I wasn't too lazy to read the doc then I'd know why
prog_defs[prog_count].args[arg_count++] = prog_defs[prog_count].bin;
while(1)
{
prog_defs[prog_count].expecting_pipe = 0;
//Check next token for end, pipe, IO redirection, or argument
token = strtok(NULL, " ");
//If we've consumed all tokens
if (token == NULL)
break;
//Pipe
if (strcmp(token, "|") == 0)
{
prog_defs[prog_count - 1].expecting_pipe = 1;
break;
}
//Regular argument
prog_defs[prog_count].args[arg_count++] = token;
}
++prog_count;
if (token == NULL) break;
}
return prog_count;
}
int main(int argc, char** argv)
{
char command[COMMAND_LINE_LENGTH] = {0};
//Generic loop counter
int x = 0;
while(1)
{
printf(">");
//Get the command
gets(command);
struct prog_def prog_defs[TOKEN_MAX];
int prog_count = get_prog_defs(command, prog_defs);
//Keep the previous out fd for the in of the subsequent process
int prev_out_fd = open("/dev/null", O_RDONLY);
for (x = 0; x < prog_count; ++x)
{
//Create a pipe for both processes to share
int pipefd[2];
if (x != prog_count -1)
{
pipe(pipefd);
}
prog_defs[x].pid = fork();
if(prog_defs[x].pid == 0)
{
dup2(prev_out_fd, STDIN_FILENO);
close(pipefd[1]);
if(x != prog_count - 1)
{
dup2(pipefd[1], STDOUT_FILENO);
close(pipefd[0]);
close(pipefd[1]);
}
execvp(prog_defs[x].bin, prog_defs[x].args);
prev_out_fd = pipefd[0];
close(pipefd[1]);
}
close(prev_out_fd);
prev_out_fd = pipefd[0];
close(pipefd[1]);
}
printf("\n");
for (x = 0; x < prog_count; ++x)
{
waitpid(prog_defs[x].pid, NULL, 0);
}
}
}
答案 0 :(得分:1)
你调用malloc
为字符串获取一些内存,这将是未初始化的,因此包含随机垃圾。然后调用strcat
,它将尝试将另一个字符串附加到随机垃圾中,几乎肯定会在malloc空间的末尾运行,导致随机混乱的行为和崩溃。
在递增prog_defs[prog_count - 1]
之前你也使用prog_count
,所以第一次通过循环,(当prog_count == 0
时)这将在数组开始之前写入,这也会导致随机混乱的行为和崩溃。