我正在Unix命令环境中编写C shell。到目前为止,所有内容都可以达到PAR,但是以下命令会导致我的代码正确执行,但使用SEG故障终止
1. ls | ls | ls
2. ls -al | ls -al > output.txt
底线:我相信分割故障来自" xxxx在这里开始"one_answers" xxxx在这里结束"之间的线。我也相信这与循环的第一个循环中的GetChar测试有关,尽管我可能会误解。如果您编译并运行此代码,您将在输入" LS -AL | LS -AL> outpt.txt"时看到所有内容都将执行,然后打印出SHHH> AAAAAA,然后是SEG故障。谁能确认或否认我的最初观察?
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <fcntl.h>
main()
{
char *path, *argv[20], buf[80], n, *p;
int m, status, inword, continu;
int inFlag, outFlag, bgFlag, k, count, j, pipes, pid, aCount, dirCount,
hCount;
int r_tube[2], l_tube[2];
char *hist;
char *h1[20] = { 0 };
aCount = 0;
dirCount = 0;
while (1)
{
inword = 0;
p = buf;
m = 0;
continu = 0;
inFlag = outFlag = bgFlag = k = count = j = pipes = pid = 0;
hCount = 0;
int loc[20] = { 0 };
char currD[50];
printf("nshhh> ");
while ((n = getchar()) != 'n' || continu) //XXXXXXXXX Starts here
{
if (n == ' ')
{
if (inword)
{
inword = 0;
*p++ = 0;
}
}
else if (n == 'n')
continu = 0;
else if (n == '\' && !inword)
continu = 1;
else
{
if (!inword)
{
inword = 1;
argv[m++] = p;
*p++ = n;
}
else
*p++ = n;
}
} //XXXXXXXX Ends here
*p++ = 0;
argv[m] = 0;
getcwd(currD, 50);
while (argv[k] != 0)
{ //stores all entered commands into history array
h1[aCount] = strdup(argv[k]);
aCount++;
k++;
}
k = 0;
if ((strcmp(argv[0], "history") == 0) ||
(strcmp(argv[0], "History") == 0))
{ //tests to see if history is asked for
printf("History: n");
for (k = 0; k < aCount; k++)
printf("%sn", h1[k]);
}
if (strcmp(argv[0], "cd") == 0)
{ //tests to see if CD is needed
if (strcmp(argv[1], "..") == 0)
chdir(currD);
else
{
while (argv[dirCount] != 0)
{
getcwd(currD, 50);
chdir(argv[dirCount]);
dirCount++;
}
}
}
char *outFile = NULL;
char *inFile = NULL;
loc[0] = 0;
while (argv[count] != 0)
{ //while loop sets the flags for input redirection,
// output redirection, background operator, and piping
if (strcmp(argv[count], "<") == 0)
{
inFile = strdup(argv[count + 1]);
argv[count] = argv[count + 1] = 0;
inFlag = 1;
}
else if (strcmp(argv[count], ">") == 0)
{
outFile = strdup(argv[count + 1]);
argv[count] = argv[count + 1] = 0;
outFlag = 1;
}
else if (strcmp(argv[count], "&") == 0)
{
argv[count] = 0;
bgFlag = 1;
}
else if (strcmp(argv[count], "|") == 0)
{
argv[count] = 0;
loc[pipes + 1] = count + 1;
pipes++;
printf("LOC0: %d ", loc[0]);
printf("LOC1: %d ", loc[1]);
printf("LOC2: %d ", loc[2]);
printf("DONE WITH IFn");
}
else
loc[count] = count;
count++;
}
for (k = 0; k <= pipes; k++)
{ //actual execution of commands
printf("IN FORn");
if (k < pipes)
{
pipe(r_tube);
j++;
}
pid = fork(); //fork child every time to exec
if (pid > 0)
{
if (j > 0)
{
close(l_tube[0]);
close(l_tube[1]);
}
l_tube[0] = r_tube[0];
l_tube[1] = r_tube[1];
}
else if (pid == 0)
{
if ((k == 0) && (inFlag == 1))
{
int n = open(inFile, O_RDONLY | O_CREAT);
if (n == -1)
{
printf("Couldn't open inFile!n");
exit(1);
}
close(0);
dup(n);
close(n);
}
else if ((k == pipes) && (outFlag == 1))
{
int out = open(outFile, O_WRONLY | O_CREAT, 0666);
if (out < 0)
{
printf("Could'nt open outFile!n");
exit(1);
}
close(1);
dup(out);
close(out);
}
printf("K: %d ", k);
printf("PIPES: %d ", pipes);
printf("PID: %dn", pid);
execvp(argv[loc[k]], &argv[loc[k]]);
}
printf("ONEn");
if (bgFlag == 0)
wait(NULL);
}
printf("TWOn");
if (strcmp(argv[0], "quit") == 0)
exit(0); //tests for exit/quit to end program
if (strcmp(argv[0], "exit") == 0)
exit(0);
printf("THREEn");
for (k = 0; k < 20; k++) //reset all of argv to NULL
argv[k] = 0;
printf("FOURn");
wait(&status);
}
}
处理分割故障的最简单方法是分析保存在内核产生的核心块中的堆栈跟踪。大多数发行版都禁用了Coredump节省,因此可以启用它
ulimit -c unlimited
Proc文件系统有几个文件来配置Corudump生产。最重要的是核心模式/proc/sys/kernel/core_pattern
,它指定了核心名称和后处理命令。
当过程收到分割故障信号时,内核将其状态保存在核心文件中,以后可以使用DGB检查:
gdb -c core ./binary_which_produced_the_core
bt
这将打印出您在分段故障发生时该程序正在执行的后背踪迹。
例如,对于您的程序
Program terminated with signal 11, Segmentation fault.
#0 main () at main.c:58
58 *p++ = n;
(gdb) bt
#0 main () at main.c:58
(gdb)
注意,我必须添加缺少的标题,因此行号为 2。
,请使用-Wall -Wextra
编译器选项报告所有警告并始终修复它们。例如,您的l_tube数组非专业化。