要求:
解释执行命令,支持输入输出重定向,支持管道,后台运行程序。
/************************************************************************* > File Name: shell.c > Author:wyf > Mail:Catherine199787@outlook.com > Created Time: 2016年07月30日 星期六 10时54分55秒 ************************************************************************/#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/wait.h>
#include<unistd.h>
#include<fcntl.h>
#include<stdlib.h>
#include<dirent.h>
#include<string.h>
#include<malloc.h>#define normal 0
#define out 1
#define in 2
#define pipe 3//自定义错误函数
void err(char* err_string, int line){perror(err_string);fprintf(stderr, "line:%d", line);return;
}//判断命名的正确性
int right(char *arg){DIR *dir;struct dirent* ptr;char *path[] = {
"./","/bin","/usr/bin/",NULL}; //环境变量PATH的路径int i;if(strncmp(arg, "./", 2) == 0){ //将路径改为当前目录arg = arg + 2; //指针移到/下一个字节}for(i = 0; path[i] != NULL; i++){ //查找命令dir = opendir(path[i]);if(dir == NULL){err("open_bin error", __LINE__);}while((ptr = readdir(dir)) != NULL){if(strcmp(ptr->d_name, arg) == 0){closedir(dir);return 1;}}closedir(dir);}return 0;
}//管道的执行函数
void argpipe(char *argn[], char *arg[]){int pid;int status;int fd;pid = fork();if(pid < 0){err("pipe_fork", __LINE__);}else if(pid == 0){if(!right(arg[0])){err("pipe arg", __LINE__);}fd = open("/tmp/youdonotknowfile", O_WRONLY | O_CREAT | O_TRUNC,0644);dup2(fd, 1);execvp(arg[0], arg);exit(0);}if(waitpid(pid, &status, 0) == -1){err("pipe_wait", __LINE__);}if(!right(argn[0])){err("pipe_arg", __LINE__);}fd = open("/tmp/youdonotknowfile", O_RDONLY);dup2(fd, 0);execvp(argn[0], argn);if(remove("/tmp/youdonotknowfile")){err("remove", __LINE__);}
}//输入函数
void arginput(char *buf){int len = 0;gets(buf);len = strlen(buf);if(len >= 255){err("arginput", __LINE__);}
}//解析输入的命令
void argexplain(char * buf, char arglist[][255], int *argcount)
{ int number = 0;int i = 0;while(1){if(buf[i] == '\0'){break;}else if(buf[i] != ' '){arglist[*argcount][number] = buf[i];number++;} else{arglist[*argcount][number] = '\0';number = 0;*argcount = *argcount + 1; //*argcount 为下标}i++;}
}//执行输入
void argdo(int argcount, char arglist[][255]){char *arg[argcount+1];int wrong = 0;int how = 0;int background = 0;int fd;int i;int status;char path[100]; //各种无法清空path的缓存,有八阿哥。char *argn[argcount+1];pid_t pid;for(i = 0; i <= argcount ; i++){ //准备execvp的第二个参数arg[i] = arglist[i];}arg[i] = NULL;for(i = 0; i <= argcount; i++){if(strcmp(arg[i], "&") == 0){if(i == (argcount - 1)){background = 1;arg[argcount-1] = NULL;break;}else{err("too many '&'", __LINE__);return;}} }for(i = 0; arg[i] != NULL; i++){if(strcmp(arg[i], ">") == 0){wrong++;how = out;if(arg[i+1] == NULL){wrong++;}}else if(strcmp(arg[i], "<") == 0){wrong++;how = in;if(arg[i+1] == NULL){wrong++;}}else if(strcmp(arg[i], "|") == 0){wrong++;how = pipe;if(arg[i+1] == NULL){wrong++;}else if(i == 0){wrong++;}}}if(wrong > 1){ err("too many arg", __LINE__);}pid = fork();if(pid < 0){err("fork error", __LINE__);}switch(how){case 0:{if(pid == 0){if( !right(arg[0]) ){// perror("wrong arg");exit(0);}execvp(arg[0], arg);exit(0);}}break;case 1:{for(i = 0; arg[i] != NULL; i++){if(strcmp(arg[i], ">") == 0){strcpy(path, arg[i+1]);arg[i] = NULL;}}if(pid == 0){if( !right(arg[0]) ){err("wrong arg", __LINE__);}printf("%s\n",path);fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0644);if(fd < 0){err("open faild", __LINE__);}dup2(fd, 1); //通过dup2实现标准输出execvp(arg[0], arg);}}break;case 2:{for(i = 0; arg[i] != NULL; i++){if(strcmp(arg[i], "<") == 0){strcpy(path, arg[i+1]);arg[i] = NULL;}}if(pid == 0){if( !right(arg[0]) ){err("wrong arg", __LINE__);}fd = open(path, O_RDONLY);if(fd < 0){err("open faild", __LINE__);}dup2(fd, 0);execvp(arg[0], arg);exit(0);}}break;
case 3:{for(i = 0; arg[i] != NULL; i++){if(strcmp(arg[i], "|") == 0){arg[i] = NULL;int j;for(j = i+1; arg[j] != NULL; j++){ //管道命令数组argn[j-i-1] = arg[j]; }argn[j-1-i] = NULL;break;}}if(pid == 0){argpipe(argn, arg);}
}
break;default:break;}//switchif(background == 1){ //后台运行父进程不管子进程直接返回return ;}if(waitpid(pid, &status, 0) == -1){ //他爸等他娃结束err("wait for chil error", __LINE__);}}/******************主函数***********************/int main(int argc,char *argv[]){char *buf;int argcount = 0, i;char arglist[100][255];char **arg = NULL;buf = (char *)malloc(255);if(buf == NULL){err("malloc", __LINE__);}while(1){memset(buf, 0 ,256);printf("my_shell$$");arginput(buf);if(strcmp(buf, "exit") == 0 || strcmp(buf, "logout") == 0){break;}for(i = 0; i < 100; i++){arglist[i][0] = '\0';}argcount = 0;argexplain(buf, arglist, &argcount);argdo(argcount, arglist);}if(buf != NULL){free(buf);buf = NULL;}return 0;
}
总结:
参考了课本,对于重定向,管道的概念不是很清晰,程序的布局把握的不好,二级指针的运用不是很熟练。
问题:
很多。