对于我的类,我们将实现一个带有输出重定向的shell。我有输出重定向工作,除了我的第一个命令总是被损坏,请参阅:
$ echo this doesn't work
H<@?4echo
No such file or directory
$ echo this does work
this does work
但之后的每个命令似乎都很好。我使用什么技术来查找导致此问题的错误?
我认为这与正确的fflushing有关。我把它洒在我的代码周围(这是愚蠢的),看看它是否会在循环中有所帮助,但事实并非如此。我也尝试打印出我的OrderedIds列表,它只是一个命令列表,用于检查我是否可以在任何地方找到H&lt; @?4,但即使我初始化它也没有用。
感谢您的帮助。
#define LENGTH 1000
#define MAXCMD 11
#define MAX_STR_LEN 20
void init(char *temp);
void clean(char **orderedIds);
void init_pid(int *temp);
void reap(int *temp,int ret_status);
void jobs(int *pid_list, char **orderedIds);
int ioRedir(char **orderedIds);
void reap(int *temp,int ret_status){//chainsaws all zombies
int a;
for (a=0; a<LENGTH; a++ ){
waitpid(temp[a],&ret_status,WNOHANG) == temp[a];
}
}
void init(char *temp){//Function to initialize/reset the cmd array
int i;
for(i=0; i<LENGTH; i++){
temp[i] = 0;
}
}
void init_pid(int *temp){//Function to initialize/reset the pid list
int i;
for(i=0; i<LENGTH; i++){
temp[i] = -777;
}
}
void clean(char **orderedIds){//garbage collection
int i;
for(i=0; i<MAXCMD; i++){
free(orderedIds[i]);
}
free(orderedIds);
}
void jobs(int *pid_list, char **orderedIds){//function to check for background proccesses
printf("Jobs:\n");
int y;
for(y=0; y<LENGTH; y++){
if(kill(pid_list[y], 0) == 0){
printf("%d\n", pid_list[y]);
}
}
clean(orderedIds);
printf("$ ");
}
int ioRedir(char **orderedIds){
int i;
for ( i = 0; i<MAXCMD; i++){
if(orderedIds[i] == NULL){
return -1;
}
if(strcmp(orderedIds[i],">")==0){
return (i+1);
}
}
}
int main (int argc, char *argv[], char *envp[])
{
char temp[LENGTH];
char * tok;
char c = '\0';
int saved_stdout;
int pid_list[LENGTH];
int ret_status;
int numFile;
int pid_counter = 0;
int outputfd = -1;
char outputFile[MAX_STR_LEN];
pid_t pid;
printf("$ ");
int i, j, y, background= 0;
init_pid(pid_list);
while(c !=EOF) { //while not ^D // Source: LinuxGazzette Ramankutty
outputfd = -1;
fflush(0);
c = getchar();
if(c=='\n'){ //entered command
reap(pid_list, ret_status);
char **orderedIds = malloc(MAXCMD * sizeof(char*));
for (i=0; i<MAXCMD; i++){
orderedIds[i] = malloc(MAXCMD * sizeof(char*));
}
int k=0;
tok = strtok(temp, " \n\t\r");
while (tok !=NULL){
strcpy(orderedIds[k], tok);
k++;
tok = strtok (NULL, " \n\t\r");
}
orderedIds[k] = NULL; //END with NULL
init(temp); //initialize the array
if(orderedIds[0] ==NULL){
printf("\n$ ");
continue;
}
numFile = ioRedir(orderedIds);
if(strcmp(orderedIds[0],"exit")==0){// if exit
printf("now exiting...\n");
break;
}
if(strcmp(orderedIds[k-1], "&")==0){//if background
orderedIds[k-1] = NULL;
background = 1;
}else background = 0;
if(strcmp(orderedIds[0], "jobs") == 0){//if jobs command
jobs(pid_list, orderedIds);
continue;
}
if(strcmp(orderedIds[0], "cd") == 0){ //if change directory command
chdir(orderedIds[1]);
printf("$ ");
continue;
}
pid = fork();
if (pid!=0 && background == 1)
{
//go to end of list in pid and put it in
pid_list[pid_counter] = pid;
pid_counter++;
printf("To the background: %d\n", pid);
} else if (pid==0 && background == 1) {
fclose(stdin); //close child's stdin
fopen("/dev/null", "r"); //open a new stdin that is always empty.
if(execvp(orderedIds[0], orderedIds)){
printf("%s\n", orderedIds[0]);
puts(strerror(errno));
exit(127);
}
}
if (pid != 0 && !background){
//printf("Waiting for child (%d)\n", pid);
fflush(0);
pid = wait(&ret_status);
} else if (pid == 0 && !background) {
if(numFile > 0){
strncpy(outputFile, orderedIds[numFile], strlen(orderedIds[numFile]));
numFile = 0;
//open the output file
outputfd = open(outputFile, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU | S_IRGRP | S_IROTH);
if (outputfd < 0) {
exit(EXIT_FAILURE);
}
//close STDOUT
if(close(STDOUT_FILENO) < 0 ){
perror("close(2) file: STDOUT_FILENO");
close(outputfd);
exit(EXIT_FAILURE);
}
//use dup to rerout the output
if(saved_stdout = dup(outputfd) != STDOUT_FILENO){
perror("dup(2)");
close(outputfd);
exit(EXIT_FAILURE);
}
close(outputfd);
}
if (execvp(orderedIds[0], orderedIds)){
printf("%s\n", orderedIds[0]);
puts(strerror(errno));
exit(127);
}
}
dup2(saved_stdout,outputfd);
clean(orderedIds);
fflush(0);
printf("$ ");
} else {
strncat(temp, &c, 1);
}
}
fflush(0);
return 0;
}
答案 0 :(得分:2)
垃圾的原因是你从未在temp
开头将main()
初始化为空字符串。在处理完每个命令后调用init(temp)
。
您的代码中还有很多其他问题:
orderedIds[i] = malloc(MAXCMD * sizeof(char*));
由于orderedIds[i]
是char数组,而不是char *,因此您应该将大小乘以sizeof(char)
。此外,还不清楚为什么使用MAXCMD
作为大小 - 在前一行中,这是一行中的最大字数,而不是单词中的字符数。
strcpy(orderedIds[k], tok);
您应该使用strncpy()
来确保不要复制超过orderedIds[k]
的大小。
另一个选项是不来首先预先分配所有orderedIds[i]
。不要使用strcpy()
,而是使用strdup()
并将其分配给orderedIds[k]
;如果你这样做,你必须记住free()
所有这些字符串。
第三种选择是根本不复制字符串。只需将strtok()
返回的指针分配给orderedIds[k]
即可。但是在这种情况下,你必须在分叉之后再调用init(tmp)
。
strncpy(outputFile, orderedIds[numFile], strlen(orderedIds[numFile]));
限制应为outputFile
的大小,而不是orderedIds[numFile]
的长度。 strncpy()
永远不会复制超过源的长度,您需要告诉它目的地的最大大小以防止缓冲区溢出。
outputfd = open(outputFile, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU | S_IRGRP | S_IROTH);
if (outputfd < 0) {
exit(EXIT_FAILURE);
}
您应致电perror()
报告open()
失败的原因。
puts(strerror(errno));
与其他地方一样致电perror()
。