实习题目: shell程序 | |||
完成人 | 姓名: | 组号: | 学号 |
" 实习内容简要描述 | 本实验要实现一个简单的命令解释器,也就是Linux中的shell程序。 实验程序起名为ysh,要求其设计类似于目前流行的shell解释程序,如bash、csh、tcsh,但不需要具备那么复杂的功能。ysh程序应当具有如下一些重要的特征: 能够执行外部程序命令,命令可以带参数。 能够执行fg、bg、cd、history、exit等内部命令。 使用管道和输入输出重定向。 支持前后台作业,提供作业控制功能,包括打印作业的清单,改变 当前运行作业的前台/后台状态,以及控制作业的挂起、中止和继续 运行。除此之外,在这个实验中还须做到: 使用make工具建立工程。 使用调试器gdb来调试程序。 提供清晰、详细的设计文档和解决方案。 | ||
c 主要代码结构 (附注释) | #include #include #include #include #include #include #include #include #include #include #include #include "ysh.h" #define NO_PIPE -1 #define FD_READ 0 #define FD_WRITE 1 int is_founded(char * cmd) { int k = 0; while(envpath[k] != NULL){ strcpy(buf,envpath[k]); strcat(buf,cmd); if(access(buf,F_OK) == 0){ return 1; } k++; } return 0; } void getenviron(int n,char * s) { int i = 0,j = 0,k = 0; char c; char buff[80]; char * p; while((c=s[i]) != '=') { buff[i++] = c; } buff[i++] = '\\0'; if(strcmp(buff,"PATH") == 0) { while(s[i] != '\\0'){ if(s[i] == ':') { buff[j++] = '/'; buff[j] = '\\0'; p = (char *)malloc(strlen(buff) + 1); strcpy(p,buff); envpath[k++] = p; envpath[k] = NULL; j = 0; i++; } else { buff[j] = s[i]; j++; i++; } } } else fprintf(stderr,"No match"); } int getline(int fd,char * buf) { int i = 0; char c; while(read(fd,& c,1)) { buf[i++] = c; if(c == '\\n') { buf[i-1] = '\\0'; return i; } } return i; } void init_environ() { int fd,n; char buf[80]; if((fd = open("ysh_profile",O_RDONLY,660)) == -1) { printf("init environ variable error!\\n"); exit(1); } while((n = getline(fd,buf)) != 0) { getenviron(n,buf); } envhis.start = 0; envhis.end = 0; head = end = NULL; } int pipel(char * input,int len) { char * argv[10][30]; char * filename[0]; int i,j,k,is_bg = 0; int li_cmd = 0; int fd[10][1],pipe_in = -1; int pipe_out = -1,flag = 0; pid_t pid; for(i = 0,j = 0,k = 0;i <= len;i++) { if((input[i] == ' ') || (input[i] == '\') || (input[i] == '\\0') || (input[i] == '|') || (input[i] == '>') || (input[i] == '\\n')){ if((input[i] == '|') || (input[i] == '>')){ if(input[i] == '>') { flag =1; } if(j > 0 ) { buf[j++] = '\\0'; argv[li_cmd][k] = (char *)malloc(sizeof(char) * j); strcpy(argv[li_cmd][k],buf); k++; } argv[li_cmd][k] = (char *)0; li_cmd++; k = 0; j = 0; } if(j == 0) { continue; } else { buf[j++] = '\\0'; if(flag == 0) { argv[li_cmd][k] = (char *)malloc(sizeof(char) * j); strcpy(argv[li_cmd][k],buf); k++; } else{ filename[0] = (char *)malloc(sizeof(char) * j); strcpy(filename[0],buf); } } j = 0; }else { if((input[i] == '&') && (input[i] == '\\0')) { is_bg = 1; continue; } buf[j++] = input[i]; } } argv[li_cmd][k++] = NULL; for(i = 0;i <= 10;i++) { fd[i][FD_READ] = NO_PIPE; fd[i][FD_WRITE] = NO_PIPE; } for(i = 0;i < li_cmd;i++) { if(pipe(fd[i]) == -1) { printf("Can not open pipe!\\n"); return 0; } } for(i = 0;i < li_cmd;i++) { if(is_founded(argv[i][0]) == 0) { printf("Can not found command!\\n"); break; } } if(i != 0) { pipe_in = fd[i - 1][FD_READ]; } else { pipe_in = NO_PIPE; } if(i != li_cmd) { pipe_out = fd[i][FD_WRITE]; } else { if(flag == 1) { if((pipe_out = open(filename[0],O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) == -1) { printf("Can not open %s\\n",filename[0]); return 0; } } else { pipe_out = NO_PIPE; } } if((pid = fork()) < 0) { printf("Fork failed!\\n"); return 0; } if(pid == 0) { if(pipe_in == NO_PIPE) { close(pipe_in); } if(pipe_out == NO_PIPE) { close(pipe_out); } if(pipe_out != NO_PIPE) { dup2(pipe_out,1); close(pipe_out); } if(pipe_in != NO_PIPE) { dup2(pipe_in,0); close(pipe_in); } execv(buf,argv[i]); } else { if(is_bg == 0) { waitpid(pid,NULL,0); } close(pipe_in); close(pipe_out); } return 0; } void add_history(char * inputcmd) { envhis.end = (envhis.end + 1) % HISNUM; if(envhis.end == envhis.start) { envhis.start = (envhis.start + 1) % HISNUM; } strcpy(envhis.his_cmd[envhis.end],inputcmd); } void history_cmd() { int i,j = 0; if(envhis.start == envhis.end) { return; } else if(envhis.start < envhis.end) { for(i = envhis.start + 1;i <= envhis.end;i++) { printf("%d\%s\\n",j,envhis.his_cmd[i]); j++; } } else { for(i = envhis.start + 1;i < HISNUM;i++) { printf("%d\%s\\n",j,envhis.his_cmd[i]); j++; } for(i = 0;i <= envhis.end;i++) { printf("%d\%s\\n",j,envhis.his_cmd[i]); j++; } } } void cd_cmd(char * route) { if(route != NULL) { if(chdir(route) < 0) printf("cd;%s Error file or directory!\\n",route); } } void jobs_cmd() { struct NODE * p; int i = 1; p = head; if(head != NULL) { do { printf("%d %d %s\%s\\n",i,p -> pid,p -> state,p -> cmd); i++; p = p -> link; }while(p != NULL); } else printf("No jobs!\\n"); } void add_node(char * input_cmd,int node_pid) { struct NODE * p; p = (struct NODE *)malloc(sizeof(struct NODE)); p -> pid = node_pid; strcpy(p -> state,input_cmd); strcpy(p -> state,"running"); p -> link = NULL; if(head == NULL) { head = p; end = p; } else { end -> link = p; end = p; } } void del_node(int sig,siginfo_t * sip) { struct NODE * q; struct NODE * p; int id; if(sig_z == 1) { sig_z = 0; goto out; } id = sip -> si_pid; p = q = head; if(head == NULL) goto out; while(p -> pid != id && p -> link != NULL) { p = p -> link; } if(p -> pid != id) goto out; if(p == head) head = head -> link; else { while(q -> link != p) { q = q -> link; } if(p == end) { end = q; q -> link = NULL; } else { q -> link = p -> link; } } free(p); out:return; } void setflag(){ sig_flag = 1; } void ctrl_z() { struct NODE * p; int i = 1; if(pid1 == 0) { goto out; } if(head != NULL) { p = head; while((p -> pid != pid1) && (p -> link != NULL)) { p = p -> link; } if(p -> pid == pid1) { strcpy(p -> state,"stopped"); } else { add_node(input,pid1); strcpy(end -> state,"stopped"); } } else { add_node(input,pid1); strcpy(end -> state,"stopped"); } sig_z = 1; kill(pid1,SIGSTOP); for(p = head;p -> pid != pid1;p = p -> link) { i++; } printf("[%d]\%s\%s\\n",i,end -> state,end -> cmd); pid1 = 0; out:return; } void bg_cmd(int job_num) { struct NODE * p; int i = 0; p = head; for(i = 1;i < job_num;i++) { p = p -> link; } kill(p -> pid,SIGCONT); strcpy(p -> state,"running"); } void fg_cmd(int job_num) { struct NODE * p; int i = 0; p = head; for(i = 1;i < job_num;i++) { p = p -> link; } strcpy(p -> state,"running"); strcpy(input,p -> cmd); pid1 = p -> pid; signal(SIGTSTP,ctrl_z); kill(p -> pid,SIGCONT); waitpid(p -> pid,NULL,0); } int main() { init_environ(); while(1) { char c; char * arg[20]; int i = 0,j = 0,k = 0; int is_pr = 0,is_bg = 0; int input_len = 0,path; int pid = 0,status = 0; struct sigaction action; action.sa_sigaction = del_node; sigfillset(& action.sa_mask); action.sa_flags = SA_SIGINFO; sigaction(SIGCHLD,& action,NULL); signal(SIGTSTP,ctrl_z); path = get_current_dir_name(); printf("ysh@%s ",path); while(((c = getchar()) == ' ') || (c == '\') || (c == EOF)) { ; } if(c == '\\n') { continue; } while(c != '\\n') { buf[input_len++] = c; c = getchar(); } buf[input_len] = '\\0'; input = (char *)malloc(sizeof(char) * (input_len + 1)); strcpy(input,buf); for(i = 0,j = 0,k = 0;i <= input_len;i++) { if((input[i] == '<') || (input[i] == '>') || (input[i] == '|')) { if(input[i] == '|') { pipel(input,input_len); add_history(input); free(input); } else { redirect(input,input_len); add_history(input); free(input); } is_pr = 1; break; } } if(is_pr == 1) { continue; } for(i = 0,j = 0,k = 0;i <= input_len;i++) { if((input[i] == ' ') || (input[i] == '\\0')) { if(j == 0) { continue; } else { buf[j++] = '\\0'; arg[k] = (char *)malloc(sizeof(char) * j); strcpy(arg[k++],buf); j = 0; } } else { if((input[i] == '&') && (input[i + 1] == '\\0')) { is_bg = 1; continue; } buf[j++] = input[i]; } } if(strcmp(arg[0],"exit") == 0) { add_history(input); printf("Bye bye!\\n"); free(input); break; } if(strcmp(arg[0],"history") == 0) { add_history(input); history_cmd(); free(input); continue; } if(strcmp(arg[0],"cd") == 0) { add_history(input); for(i = 3,j = 0;i <= input_len;i++) { buf[j++] = input[i]; } buf[j] = '\\0'; arg[1] = (char *)malloc(sizeof(char) * j); strcpy(arg[1],buf); cd_cmd(arg[1]); free(input); continue; } if(strcmp(arg[0],"jobs") == 0) { add_history(input); jobs_cmd(); free(input); continue; } if(strcmp(arg[0],"bg") == 0) { add_history(input); for(i = 0;i <= input_len;i++) { if(input[i] == '%') { break; } } i++; for(;i <= input_len;i++) { buf[j++] = input[i]; } buf[j] = '\\0'; arg[1] = (char *)malloc(sizeof(char) * j); strcpy(arg[1],buf); bg_cmd(atoi(arg[1])); free(input); continue; } if(strcmp(arg[0],"fg") == 0) { add_history(input); for(i = 0;i <= input_len;i++) { if(input[i] == '%'){ break; } } i++; for(;i <= input_len;i++) { buf[j++] = input[i]; } buf[j] = '\\0'; arg[1] = (char *)malloc(sizeof(char) * j); strcpy(arg[1],buf); fg_cmd(atoi(arg[1])); free(input); continue; } if(is_pr == 0) { arg[k] = (char *)malloc(sizeof(char)); arg[k] = NULL; if(is_founded(arg[0]) == 0) { printf("This command is not founed!\\n"); for(i = 0;i <= k;i++) { free(arg[i]); } continue; } } add_history(input); if((pid = fork()) == 0) { if(is_bg == 1) { while(sig_flag == 0) { signal(SIGUSR1,setflag); } sig_flag = 0; } }else{ pid1 = pid; if(is_bg == 1) { add_node(input,pid1); kill(pid,SIGUSR1); pid1 = 0; } if(is_bg == 0){ waitpid(pid,& status,0); } }if(is_bg == 1) { sleep(1); }for(i = 0;i < k;i++) { free(arg[i]); free(input); } } return 0; } | ||
" 结果分析(或错误原因分析) | 通过本次实验使我们熟悉使用Linux下的软件开发工具,例如gcc、gdb和make。 在编写系统应用程序时熟练使用man帮助手册。 学习使用POSIX/UNIX系统调用、对进程进行管理和完成进程之间的通信,例如使用信号和管道进行进程间通信。 理解并发程序中的同步问题。 锻炼在团队成员之间的交流与合作能力 | ||
注释:如果上述表格空间不够,可以另附表格进行说明 |