⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 minish.c

📁 操作系统中的SHELL程序~在LINUX系统中也能运行
💻 C
📖 第 1 页 / 共 2 页
字号:
#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 "minish.h"

#define NO_PIPE -1
#define FD_READ 0
#define FD_WRITE 1

main()
{
/****************************声明程序中用到的函数*****************************/	int redirect();                                    /*重定向命令的处理函数*/	int pipel();                                         /*管道命令的处理函数*/	int getline();                                           /*读取一行的函数*/
	int is_founded();                                        /*查找命令的函数*/	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("qq@%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 + -