?? ysh.c
字號:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <math.h>#include <signal.h>#include <stdlib.h>
#include "ysh.h"
#define NO_PIPE -1
#define FD_READ 0
#define FD_WRITE 1
main()
{
/****************************聲明程序中用到的函數*****************************/ int redirect(); /*重定向命令的處理函數*/ int pipel(); /*管道命令的處理函數*/
int is_founded(); /*查找命令的函數*/ int getline(); /*讀取一行的函數*/ void init_environ(); /*初始化環境變量的函數*/
void getenviron(); /*初始化查找路徑的函數*/
void add_history(); /*記錄history命令的函數*/
void history_cmd(); /*顯示history命令的函數*/
void cd_cmd(); /*處理cd命令的函數*/ void jobs_cmd(); /*處理jobs命令的函數*/ void add_node(); /*向jobs命令的鏈表中增加節點函數*/ void del_node(); /*向jobs命令的鏈表中刪除節點函數*/ void ctrl_z(); /*處理用戶按下ctrl_z時的函數*/ void setflag(); /*將標志位置一的函數*/ void bg_cmd(); /*處理bg命令的函數*/ void fg_cmd(); /*處理fg命令的函數*/
init_environ(); /*初始化環境變量,將查找路徑至于envpath[]中,
初始化history,和jobs的頭尾指針*/
while (1)
{
char c,*arg[20];
int i=0,j=0,k=0,is_pr=0,is_bg=0,input_len=0,path,pid=0,status=0;
/**************************** 設置signal信號 *****************************/ 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=='\t'|| c==EOF)
; /*跳過空格等無用信息*/
if (c=='\n')
continue; /*輸入為空時結束本次循環打印提示符*/
while (c!='\n') {
buf[input_len++]=c;
c=getchar();
}
buf[input_len]='\0'; /*加上串結束符*/
/*分配動態存儲空間,將命令從緩存拷貝到input中*/
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);/*將指令或參數拷到arg中*/
j=0; /*準備取下一參數*/ }
}else{
/*如果字符串最后是“&”,將后臺命令標志置一*/
if (input[i]=='&' && input[i+1]=='\0'){
is_bg=1;
continue;
}
buf[j++]=input[i];
}
}
/********************** 內部命令的處理 ********************/
/*exit命令,退出*/
if (strcmp(arg[0],"exit")==0) {
add_history(input);
printf("Bye bye!\n"); free(input);
break;
}
/*history命令,顯示history數組中保存的歷史命令*/
if (strcmp(arg[0],"history")==0) {
add_history(input);
history_cmd(); free(input);
continue;
}
/*cd命令,改變當前路徑*/
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);/*將路徑保存到arg[1]中*/
cd_cmd(arg[1]);/*cd_cmd()函數,改變路徑到指定路徑*/ free(input);
continue;
}
/*jobs命令,顯示現有工作*/ if (strcmp(arg[0],"jobs")==0) { add_history(input); jobs_cmd();/*jobs_cmd()函數,遍歷鏈表,顯示所有工作*/ free(input); continue; } /*bg命令,將作業放到后臺執行*/ 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);/*將作業號保存在arg[1]中*/ bg_cmd(atoi(arg[1]));/*bg_cmd命令,將指定作業放到后臺運行*/ free(input); continue; } /*fg命令,將作業放到前臺執行*/ 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);/*將作業號保存在arg[1]中*/ fg_cmd(atoi(arg[1]));/*fg_cmd命令,將指定作業放到后臺運行*/ free(input); continue; }
/**************************** 尋找命令文件 *****************************/
if (is_pr==0){/*非管道、重定向命令*/
/*在使用exec執行命令時,最后的參數必須是NULL指針,所以將其置空*/
arg[k]=(char *) malloc(sizeof(char));
arg[k]=NULL;
if (is_founded(arg[0])==0){/*查找arg[0]中的命令是否存在*/
printf("This command is not founded!\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)/*若sig_flag==0,等待父進程完成增加節點*/
/*等待父進程SIGUSR1信號,表示節點已加到鏈表中*/ signal(SIGUSR1,setflag);/*收到信號,setflag函數將sig_flag置一
,以跳出循環*/ sig_flag=0;/*置零,為下一命令作準備*/
execv(buf,arg);/*執行命令*/
}else {/*父進程*/ pid1=pid;/*保存子進程進程號*/ if (is_bg==1) {/*后臺命令*/ add_node(input,pid1);/*增加節點*/ kill(pid,SIGUSR1);/*向子進程發信號,表示節點已加進鏈表*/ pid1=0;/*pid1置零,為下一命令作準備*/ }
if (is_bg==0) /*前臺命令*/ waitpid(pid,&status,0); } if (is_bg==1) sleep(1);/*等待命令(如:ls &)輸出后,再打印Shell提示符*/
for (i=0;i<k;i++)/*釋放空間*/
free (arg[i]); free(input);
}
}
/**************************** 主程序完 *****************************/
/**************************** 重定向的處理 *****************************/
int redirect(char*in,int len)
{
char *argv[20],*filename[20];
pid_t pid;
int i,j,k,fd_in,fd_out,is_in=-1,is_out=-1,num=0;
int is_back=0,status=0;
/************************命令解析*************************/
/*argv[]用于存放命令和參數,filename用于存放重定向文件名,
is_in,is_out分別是重定向輸入標記和輸出標記*/
for (i=0,j=0,k=0;i<=len;i++) {
if (in[i]==' '||in[i]=='\t'||in[i]=='\0'||in[i]=='<'||in[i]=='>') {
if (in[i]=='>'||in[i]=='<') {
if (num<3){/*num存放重定向符號的出現次數*/
num++;
if (in[i]=='<')
is_in=num-1;/*存在重定向輸入is_in置-1*/
else is_out=num-1;/*存在重定向輸出is_out置-1*/
if (j>0 && num==1) {/*處理命令和重定向符號相連的問題*/
buf[j++]='\0';
argv[k]=(char *) malloc(sizeof(char)*j);
strcpy(argv[k],buf);
k++;
j=0;/*為讀取下一命令或參數作準備*/
}
}else {
printf("Error command!\n");
return 0;
}
}
if (j==0)
continue;
else {
buf[j++]='\0';
if (num==0) {/*尚未遇到重定向符號,字符串是參數或命令*/
argv[k]=(char *) malloc(sizeof(char)*j);
strcpy(argv[k],buf);
k++;
j=0;
}else {/*遇到重定向符號,字符串是文件名*/
filename[status]=(char *) malloc(sizeof(char)*j);
strcpy(filename[status++],buf);
j=0;
}
}
}else {/*父進程*/
if (in[i]=='&' && in[i+1]=='\0') {/*是否為后臺命令*/
is_back=1;
continue;
}
buf[j++]=in[i];
}
}
/*************************尋找命令文件*************************/
argv[k]=(char *) malloc(sizeof(char));
argv[k]=(char *) 0;/*最后一參數置空*/
if (is_founded(argv[0])==0) {/*查找命令文件*/
printf("This command is not founded!\n");
for (i=0;i<=k;i++)
free(argv[i]);
return 0;
}
/************************命令的執行**************************/
if ((pid=fork())==0) {
if (is_out!=-1) {/*存在輸出重定向*/
if ((fd_out=open(filename[is_out],/*將文件描述符fd_out指向文件*/
O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR))==-1) {
printf ("Can not open %s \n",filename[is_out]);
return 0;
}
}
if (is_in!=-1) {/*存在輸入重定向*/
if ((fd_in=open(filename[is_in],/*將文件描述符fd_in指向文件*/
O_RDONLY,S_IRUSR|S_IWUSR))==-1) {
printf("Can not open %s \n",filename[is_in]);
return 0;
}
}
if (is_out!=-1) {
/*使用dup2函數將標準輸出重定向到fd_out上,
這樣原來輸出到標準輸出的內容,將輸出到fd_out
所指向的文件。這就達到了重定向的目的*/
if (dup2(fd_out,STDOUT_FILENO)==-1) {
printf("Redirect standard out error!\n");
exit(1);
}
}
if (is_in!=-1) {
/*使用dup2函數將標準輸入重定向到fd_in上,
這樣原來從標準輸入輸入的內容,將從fd_in
所指向的文件輸入。這就達到了重定向的目的*/
if (dup2(fd_in,STDIN_FILENO)==-1) {
printf("Redirect standard in error!\n");
exit(1);
}
}
execv(buf,argv);
}else {/*父進程*/
if (is_back==0)/*判斷是否需要等待子進程的完成*/
waitpid(pid,&status,0);
}
/**************************釋放空間*************************/
for (i=0;i<=k;i++)
free(argv[i]);
if (is_out!=-1) {
free(filename[is_out]);
close(fd_out);
}
if (is_in!=-1) {
free(filename[is_in]);
close(fd_in);
}
return 0;
}
/**************************** 管道的處理 *****************************/
int pipel(char *input,int len)
{
char *argv[10][30],*filename[0];
int i,j,k,is_bg=0;
int li_cmd=0,fd[10][1],pipe_in=-1,pipe_out=-1,flag=0;
pid_t pid;
/************************命令解析*************************/
/*此部分功能和結構與重定向時的命令解析相似*/
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -