编辑:我已经使这里的信息更具体,并执行了评论中的一些建议。
我有一个用 C 编写的外壳,使用时就像一个魅力。但是,我为名为 pipe_exec
的函数编写了一些测试,该函数会导致总线错误。我以为它最初来自我的 strtok
函数中的 split
(现在可能仍然如此)。
pipe_exec
函数基本上处理带有 ls -a | wc -l
之类的管道的命令。当我使用实际的 shell 时,它总是可以正常工作,但在测试中,如果管道命令涉及任何标志,总是会出现总线错误。
问题可能出在我的测试上。
但我不知道问题是什么。它追溯到我的 strtok
函数中的 split
,但它只有测试的总线问题,而在任何实际等效情况下都没有。
感谢这里的任何帮助。抱歉要查看这么多代码。
shell_exec_tests.c
static char *args1[20] = {"ls ", " wc"}; // works
static char *args2[20] = {"ls -a", "wc -l"}; // causes bus error
static int a = 0;
static int b = 0;
void test_setup(void)
{
a = pipe_exec(args1);
b = pipe_exec(args2);
}
void test_teardown(void)
{
// nothing
}
MU_TEST(test_check)
{
mu_check(a == EXIT_SUCCESS);
mu_check(b == EXIT_SUCCESS);
}
MU_TEST_SUITE(test_suite)
{
MU_SUITE_CONFIGURE(&test_setup, &test_teardown);
MU_RUN_TEST(test_check);
}
int main()
{
MU_RUN_SUITE(test_suite);
MU_REPORT();
return MU_EXIT_CODE;
}
pipe_exec.c
// make_proc: determine if a process goes to stdout or takes in data from stdin
void make_proc(int in, int out, char **cmd)
{
pid_t rc;
int status;
rc = fork();
if (rc < 0) {
perror("fork");
exit(1);
}
if (rc == 0) {
if (in != STDIN_FILENO) {
dup2(in, STDIN_FILENO);
close(in);
}
if (out != STDOUT_FILENO) {
dup2(out, STDOUT_FILENO);
close(out);
}
execvp(*cmd, cmd);
errmsg(*cmd);
exit(1);
}
waitpid(rc, &status, WUNTRACED);
return;
}
// pipe_exec: loop through each command, connecting each through a pipe
int pipe_exec(char **args)
{
int in, status, return_val;
int pipe_no; // keep track of no. of cmds seperated by pipes
int pfd[2];
pid_t rc;
char **cmd;
return_val = EXIT_SUCCESS;
in = 0;
pipe_no = 0;
while (*args) {
cmd = split(*args, " \t\r\n");
if (!args[1]) {
break;
}
if (pipe(pfd) < 0) {
perror("pipe");
}
make_proc(in, pfd[1], cmd);
close(pfd[1]);
in = pfd[0];
args++;
pipe_no++;
}
// move pointer back
args -= pipe_no;
rc = fork();
if (rc < 0) {
perror("fork");
exit(1);
}
if (rc == 0) {
if (in != 0) dup2(in, STDIN_FILENO);
execvp(*cmd, cmd);
errmsg(*cmd);
return_val = EXIT_FAILURE;
exit(1);
}
waitpid(rc, &status, WUNTRACED);
// pretty sure i need a pipe to get the EXIT_FAILURE from
// the child if the child fails, but for now im just working
// on finding that bus error issue
return return_val;
}
最后,我的 split
函数:
// trim: trim leading and trailing whitespace on a string
static char *trim(char *str)
{
char *end;
// Trim leading space
while(isspace((unsigned char)*str)) str++;
if(*str == 0) // All spaces?
return str;
// Trim trailing space
end = str + strlen(str) - 1;
while(end > str && isspace((unsigned char)*end)) end--;
// Write new null terminator character
end[1] = '\0';
return str;
}
// split: take a string and break it up into an array of strings based on delim
char **split(char *s, const char *delim)
{
char **split_s;
char *token;
size_t len;
int i;
len = strlen(s);
split_s = calloc(len*2, sizeof(char*));
if (split_s == NULL) {
fprintf(stderr, "split: could not allocate memory\n");
exit(EXIT_FAILURE);
}
i = 0;
token = strtok(s, delim);
while (token != NULL) {
split_s[i] = trim(token);
token = strtok(NULL, delim);
i++;
}
split_s[i] = NULL;
return split_s;
}