📄 execute.c
字号:
#include <string.h>#include <ctype.h>#include <unistd.h>#include <fcntl.h>#include <math.h>#include <errno.h>#include <signal.h>#include <stddef.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/wait.h>#include <sys/ioctl.h>#include <sys/termios.h>#include "global.h"int goon = 0, ingnore = 0; //用于设置signal信号量char *envPath[10], cmdBuff[40]; //外部命令的存放路径及读取外部命令的缓冲空间History history; //历史命令Job *head = NULL; //作业头指针pid_t fgPid; //当前前台作业的进程号/******************************************************* 工具以及辅助方法********************************************************/
/*判断命令是否存在*/int exists(char *cmdFile){ int i = 0; if((cmdFile[0] == '/' || cmdFile[0] == '.') && access(cmdFile, F_OK) == 0){ //命令在当前目录 strcpy(cmdBuff, cmdFile); return 1; }else{ //查找ysh.conf文件中指定的目录,确定命令是否存在 while(envPath[i] != NULL){ //查找路径已在初始化时设置在envPath[i]中 strcpy(cmdBuff, envPath[i]); strcat(cmdBuff, cmdFile); if(access(cmdBuff, F_OK) == 0){ //命令文件被找到 return 1; } i++; } } return 0; }/*将字符串转换为整型的Pid*/int str2Pid(char *str, int start, int end){ int i, j; char chs[20]; for(i = start, j= 0; i < end; i++, j++){ if(str[i] < '0' || str[i] > '9'){ return -1; }else{ chs[j] = str[i]; } } chs[j] = '\0'; return atoi(chs);}
/*调整部分外部命令的格式*/void justArgs(char *str){ int i, j, len; len = strlen(str); for(i = 0, j = -1; i < len; i++){ if(str[i] == '/'){ j = i; } }
if(j != -1){ //找到符号'/'
for(i = 0, j++; j < len; i++, j++){
str[i] = str[j];
}
str[i] = '\0';
}}
/*设置goon*/void setGoon(){ goon = 1;}
/*释放环境变量空间*/void release(){ int i; for(i = 0; strlen(envPath[i]) > 0; i++){ free(envPath[i]); }}
/*******************************************************
信号以及jobs相关
********************************************************/
/*添加新的作业*/Job* addJob(pid_t pid){ Job *now = NULL, *last = NULL, *job = (Job*)malloc(sizeof(Job));
//初始化新的job job->pid = pid; strcpy(job->cmd, inputBuff); strcpy(job->state, RUNNING); job->next = NULL; if(head == NULL){ //若是第一个job,则设置为头指针 head = job; }else{ //否则,根据pid将新的job插入到链表的合适位置
now = head;
while(now != NULL && now->pid < pid){
last = now;
now = now->next;
} last->next = job; job->next = now; } return job;}
/*移除一个作业*/void rmJob(int sig, siginfo_t *sip, void* noused){ pid_t pid; Job *now = NULL, *last = NULL; if(ingnore == 1){ ingnore = 0; return; } pid = sip->si_pid;
now = head;
while(now != NULL && now->pid < pid){
last = now;
now = now->next;
} if(now == NULL){ //作业不存在,则不进行处理直接返回 return; }
//开始移除该作业 if(now == head){ head = now->next; }else{ last->next = now->next; } free(now);}
/*组合键命令ctrl+z*/void ctrl_Z(){ Job *now = NULL; if(fgPid == 0){ //前台没有作业则直接返回 return; } //SIGCHLD信号产生自ctrl+z ingnore = 1;
now = head;
while(now != NULL && now->pid != fgPid)
now = now->next; if(now == NULL){ //未找到前台作业,则根据fgPid添加前台作业 now = addJob(fgPid); }
//修改前台作业的状态及相应的命令格式,并打印提示信息 strcpy(now->state, STOPPED); now->cmd[strlen(now->cmd)] = '&'; now->cmd[strlen(now->cmd) + 1] = '\0'; printf("[%d]\t%s\t\t%s\n", now->pid, now->state, now->cmd);
//发送SIGSTOP信号给正在前台运作的工作,将其停止 kill(fgPid, SIGSTOP); fgPid = 0;}
/*fg命令*/void fg_exec(int pid){ Job *now = NULL;
int i; //SIGCHLD信号产生自此函数 ingnore = 1;
//根据pid查找作业
now = head;
while(now != NULL && now->pid != pid)
now = now->next; if(now == NULL){ //未找到作业 printf("pid为7%d 的作业不存在!\n", pid); return; }
//记录前台作业的pid,修改对应作业状态 fgPid = now->pid; strcpy(now->state, RUNNING); signal(SIGTSTP, ctrl_Z); //设置signal信号,为下一次按下组合键Ctrl+Z做准备 i = strlen(now->cmd) - 1;
while(i >= 0 && now->cmd[i] != '&')
i--; now->cmd[i] = '\0'; printf("%s\n", now->cmd); kill(now->pid, SIGCONT); //向对象作业发送SIGCONT信号,使其运行 waitpid(fgPid, NULL, 0); //父进程等待前台进程的运行}
/*bg命令*/void bg_exec(int pid){ Job *now = NULL; //SIGCHLD信号产生自此函数 ingnore = 1;
//根据pid查找作业
now = head;
while(now != NULL && now->pid != pid)
now = now->next; if(now == NULL){ //未找到作业 printf("pid为7%d 的作业不存在!\n", pid); return; } strcpy(now->state, RUNNING); //修改对象作业的状态 printf("[%d]\t%s\t\t%s\n", now->pid, now->state, now->cmd); kill(now->pid, SIGCONT); //向对象作业发送SIGCONT信号,使其运行}
/*******************************************************
命令历史记录
********************************************************/void addHistory(char *cmd){ if(history.end == -1){ //第一次使用history命令 history.end = 0; strcpy(history.cmds[history.end], cmd); return; } history.end = (history.end + 1)%HISTORY_LEN; //end前移一位 strcpy(history.cmds[history.end], cmd); //将命令拷贝到end指向的数组中 if(history.end == history.start){ //end和start指向同一位置 history.start = (history.start + 1)%HISTORY_LEN; //start前移一位 }}/*******************************************************
初始化环境
********************************************************/
/*通过路径文件获取环境路径*/void getEnvPath(int len, char *buf){ int i, j, last = 0, pathIndex = 0, temp; char path[40]; for(i = 0, j = 0; i < len; i++){ if(buf[i] == ':'){ //将以冒号(:)分隔的查找路径分别设置到envPath[]中 if(path[j-1] != '/'){ path[j++] = '/'; } path[j] = '\0'; j = 0; temp = strlen(path); envPath[pathIndex] = (char*)malloc(sizeof(char) * (temp + 1)); strcpy(envPath[pathIndex], path); pathIndex++; }else{ path[j++] = buf[i]; } } envPath[pathIndex] = NULL;}/*初始化操作*/void init(){ int fd, n, len; char c, buf[80];
//打开查找路径文件ysh.conf if((fd = open("ysh.conf", O_RDONLY, 660)) == -1){ perror("init environment failed\n"); exit(1); }
//初始化history链表
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -