我不知道这段代码有什么问题。它的输出有多个错误。该程序应该模仿 UNIX shell。只要它不包含任何管道,它就可以正常运行任何命令。然而,当我包含管道时,有趣的事情开始发生。
例如:当我输入sort < myshell1,c | grep main | cat > o.txt
它创建了一个额外的过程。您可以看到这一点,因为在代码中,perror(in)
被执行了 4 次(根据 GDB):
COP4338$ sort < myshell1.c | grep main | cat > o.txt
Detaching after fork from child process 16465.
Process ID: 16465
Process ID: 0
in: Success
Detaching after fork from child process 16466.
Process ID: 16466
Process ID: 0
in: Success
Something happened in i != numcommands - 1: Success
Detaching after fork from child process 16468.
Process ID: 16468
COP4338$ Process ID: 0
in: Success
ELSE STATEMENT!
Detaching after fork from child process 17403.
in: Bad address
然后,程序进入新行并且不打印 COP4338$: 就像它应该的那样。表现出未定义的行为。我对为什么会发生这种情况的猜测是因为第四个进程也在继续,因此就像父进程一样返回到 main(),但我无法确定它为什么会被创建。
当我尝试运行时,也会出现未定义的行为ls -l | cat > o.txt
这是 GDB 的输出:
至于试图解决这个问题,我还不确定是什么原因造成的。我尝试使用 gdb 调试器通过键入“set follow-fork-mode child”并在第三个子进程的第一行使用断点来调试第三个子进程,但没有任何反应。我只能通过这样做来调试第一个子进程。
/* This code was written by Dr. Raju Rangaswami and was expanded upon as per the instructions in Assignment3, by Michael Duboc(PID: 5706538)*/
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <string.h>
#define MAX_ARGS 20
#define BUFSIZ 1024
int get_args(char* cmdline, char* args[])
{
int i = 0;
/* if no args */
if((args[0] = strtok(cmdline, "\n\t ")) == NULL)
return 0;
while((args[++i] = strtok(NULL, "\n\t ")) != NULL)
{
if(i >= MAX_ARGS)
{
printf("Too many arguments!\n");
exit(1);
}
}
/* the last one is always NULL */
return i;
}
int customStrCpy(char** line1, char* line2)
{
int strlen1 = strlen(*line1), strlen2 = strlen(line2);
if(strlen1 < strlen2)
{
//Creates a dynamically allocated array that is big enough to store the contents of line2.
*line1 = calloc(strlen2, sizeof(char));
}
strcpy(*line1, line2);
}
void adjustArray(char* args[], int args_itr, int* nargs)
{
int i, j;
for(i = 0; i < 2; i++)
{
for(j = args_itr; j < (*nargs) - 1; j++)
{
customStrCpy(&args[j],args[j+1]);
}
args[(*nargs) - 1] = 0;
(*nargs)--;
}
}
int process(int* greaterthan, int* d_greaterthan, char* args_pipe[], int*
nargs_p, int* fileno_out, int* fileno_in, int* lessthan, FILE** fout,
FILE** fin)
{
int greaterthan_strcmp = strcmp(args_pipe[args_itr], ">");
int d_greaterthan_strcmp = strcmp(args_pipe[args_itr], ">>");
if(greaterthan_strcmp == 0 || d_greaterthan_strcmp == 0)
{
if(greaterthan_strcmp == 0)
*fout = fopen(args_pipe[args_itr + 1], "w");
else
*fout = fopen(args_pipe[args_itr + 1], "a");
*fileno_out = fileno(*fout);
*greaterthan = 1;
adjustArray(args_pipe, args_itr, nargs_p);
args_itr--;
int print_arr;
for(print_arr = 0; print_arr
(sizeof(args_pipe)/sizeof(args_pipe[0])); print_arr++)
printf("%s ",args_pipe[print_arr]);
printf("\n");
}
else if(strcmp(args_pipe[args_itr], "<") == 0)
{
*fin = fopen(args_pipe[args_itr + 1], "r");
*fileno_in = fileno(*fin);
*lessthan = 1;
adjustArray(args_pipe, args_itr, nargs_p);
args_itr--;
}
}
return 0;
}
void execute(char* cmdline)
{
int pid, async, lessthan = 0;
int greaterthan = 0, pipef = 0, d_greaterthan = 0;
int args_itr, pipe_flag = 0;
int flag_count = 0, fileno_in, fileno_out;
char* args_pipe[MAX_ARGS];/*5 and 3 are test numbers.*/
char* args[MAX_ARGS];
int nargs = get_args(cmdline, args);
if(nargs <= 0) return;
if(!strcmp(args[0], "quit") || !strcmp(args[0], "exit"))
{
exit(0);
}
/* check if async call */
if(!strcmp(args[nargs-1], "&")) { async = 1; args[--nargs] = 0; }
else async = 0;
FILE* fout = stdout;
FILE* fin = stdin;
for(args_itr = 0; args_itr < nargs; args_itr++)
{
if(!strcmp(args[args_itr], "|")) {pipe_flag = 1; flag_count++;}
}
if(pipe_flag)
{
int num_commands = flag_count + 1, i = 0, j = 0;
int fd[num_commands][2];
for(i = 0; i < flag_count; i++) {pipe(fd[i]);}
for(i = 0; i < num_commands; i++)
{
int nargs_p = 0, args_pipe_itr = 0;
while(j < nargs && strcmp(args[j], "|"))
{//Possibly make into for loop.
args_pipe[args_pipe_itr] = args[j];
args_pipe_itr++;
j++;
nargs_p++;
}
j++;
int pid = fork();
signal(SIGTTIN, SIG_IGN);
signal(SIGTTOU, SIG_IGN);
printf("Process ID: %d\n", pid);
if(pid < 0)
{
perror("Error forking!");
return;
}
else if(pid > 0) {continue;}
else //pid == 0
{
perror("in");
if(i == 0)
{
process(&greaterthan, &d_greaterthan, &args_pipe[i] ,&nargs_p, &fileno_out, &fileno_in, &lessthan, &fout, &fin);
printf("Lessthan = %d", lessthan);
if(lessthan) dup2(fileno_in, STDIN_FILENO);
dup2(fd[i][1], STDOUT_FILENO);
}
else if(i != num_commands - 1)
{
dup2(fd[i - 1][1], STDIN_FILENO);
//process(&greaterthan, &d_greaterthan, &args_pipe[i] ,&nargs_p, &fileno_out, &fileno_in, &lessthan, &fout, &fin);
dup2(fd[i][1], STDOUT_FILENO);
}
else
{
dup2(fd[i - 1][1], STDIN_FILENO);
process(&greaterthan, &d_greaterthan, &args_pipe[i] ,&nargs_p, &fileno_out, &fileno_in, &lessthan, &fout, &fin);
printf("greaterthan = %d", greaterthan);
printf("d_greaterthan = %d", d_greaterthan);
if(greaterthan || d_greaterthan) dup2(fileno_out, STDOUT_FILENO);
}
int close_pipes;
for(close_pipes = 0; close_pipes < flag_count; close_pipes++)
{
//close(fd[i][0]); close(fd[i][1]); JUST, WHY?!? THIS IS WHAT HAPPENS WHEN YOU DON'T THINK!
close(fd[close_pipes][0]);
close(fd[close_pipes][1]);
}
if(fout != stdout) fclose(fout);
if(fin != stdin) fclose(fin);
execvp(args_pipe[0], args_pipe);
perror("Something happened.");
exit(-1);
}//end child.
}
for(i = 0; i < flag_count; i++) {close(fd[i][0]); close(fd[i][1]);}
return;
}
}
int main (int argc, char* argv [])
{
for(;;)
{
printf("COP4338$ ");
if(fgets(cmdline, BUFSIZ, stdin) == NULL)
{
perror("fgets failed");
exit(1);
}
execute(cmdline);
int corpse;
int status;
while(corpse = wait(%status)) > 0)
perror(pid %d exited with status: 0x%.4X\n, corpse, status);
}
}
该程序应该将“ int main (int argc, char* argv [])
”打印到o.txt,但o.txt根本没有改变。
对于那些好奇的人,函数 process() 会扫描构成命令的参数字符串,并根据程序看到的符号设置标志。