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

📄 ysh.c

📁 大学操作系统课程实验:Linux下实现的一个shell解释器。能够比较完整完好地执行Linux下的普通命令、重定向命令、管道命令等多种命令。
💻 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"

int main()
{
	initEnviron();
	
	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=delNode;
		sigfillset(&action.sa_mask);
		action.sa_flags=SA_SIGINFO;
		sigaction(SIGCHLD,&action,NULL);
		signal(SIGTSTP,ctrl_z_cmd);
		
		/*打印提示符*/
		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=(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);
					addHistory(input);
					free(input);
				}
				else
				{
					redirect(input,input_len);
					addHistory(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];
			}
		}
		
		/**内部命令**/
		/***exit命令***/
		if(strcmp(arg[0],"exit")==0)
		{
			addHistory(input);
			printf("Bye!\n");
			free(input);
			break;
		}
		/***history命令***/
		if(strcmp(arg[0],"history")==0)
		{
			addHistory(input);
			history_cmd();
			free(input);
			continue;
		}
		/***cd命令***/
		if(strcmp(arg[0],"cd")==0)
		{
			addHistory(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;
		}
		/***jobs命令***/
		if(strcmp(arg[0],"jobs")==0)
		{
			addHistory(input);
			jobs_cmd();
			free(input);
			continue;
		}
		/***bg命令***/
		if(strcmp(arg[0],"bg")==0)
		{
			addHistory(input);
			for(i=0;i<=input_len;i++)
				if(input[i]=='%')
					break;
			for(++i;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;
		}
		/***fg命令***/
		if(strcmp(arg[0],"fg")==0)
		{
			addHistory(input);
			for(i=0;i<=input_len;i++)
				if(input[i]=='%')
					break;
			for(++i;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(isFounded(arg[0])==0)
			{
				printf("This command is not founded!\n");
				for(i=0;i<=k;i++)
					free(arg[i]);
				continue;
			}
		}
		addHistory(input);
		
		/*执行命令*/
		if((pid=fork())==0)
		{
			if(is_bg==1)
				while(sig_flag==0)
					signal(SIGUSR1,setFlag);
				sig_flag=0;
				execv(buf,arg);
		}
		else
		{
			pid1=pid;
			if(is_bg==1)
			{
				addNode(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;
}

void initEnviron()
{
	int fd,n,i;
	char buf[80];
	
	if((fd=open("ysh_profile",O_RDONLY,660))==-1)
	{
		printf("init environment variable error!\n");
		exit(1);
	}
	while(n=getLine(fd,buf))
		getEnviron(n,buf);
	envhis.start=0;
	envhis.end=0;
	head=end=NULL;
}

void getEnviron(int n,char *s)
{
	int i=0,j=0,k=0;
	char c,buff[80],*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(sizeof(char)*(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;
}

/*重定向的处理 */
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;
	
	/*命令解析*/
	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++;
					if(in[i]=='<')
						is_in=num-1;
					else
						is_out=num-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(isFounded(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],O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR))==-1)
			{
				printf("Can't open %s \n",filename[is_out]);
				return 0;
			}
		}
		if(is_in!=-1)
		{
			if((fd_in=open(filename[is_in],O_RDONLY,S_IRUSR|S_IWUSR))==-1)
			{
				printf("Can't open %s \n",filename[is_out]);
				return 0;
			}
		}
		if(is_out!=-1)
		{
			if(dup2(fd_out,STDOUT_FILENO)==-1)
			{
				printf("Redirect standard out error!\n");
				exit(1);
			}
		}
		if(is_in!=-1)
		{
			if(dup2(fd_in,STDIN_FILENO)==-1)
			{
				printf("Redirect standard in error!\n");
			}
		}		
		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[10];
	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;
	
	/*命令解析*/
	for(i=0,j=0,k=0;i<=len;i++)
	{
		if(input[i]==' '||input[i]=='\t'||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't open pipe!\n");
			return 0;
		}
	}
	
	/*寻找命令文件*/
	for(i=0;i<li_cmd;i++)
	{
		if(isFounded(argv[i][0])==0)
		{
			printf("Can't 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't open %s \n",filename[0]);
					break;
				}
			}
			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;
}

/*查找命令文件*/
int isFounded(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;
}

/*history命令*/
void addHistory(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\t%s\n",j,envhis.his_cmd[i]);
			j++;
		}
	}
	else
	{
		for(i=envhis.start;i<HISNUM;i++)
		{
			printf("%d\t%s\n",j,envhis.his_cmd[i]);
			j++;
		}
		for(i=0;i<=envhis.end;i++)
		{
			printf("%d\t%s\n",j,envhis.his_cmd[i]);
			j++;
		}
	}
}

/*cd命令*/
void cd_cmd(char *route)
{
	if(route!=NULL)
		if(chdir(route)<0)
			printf("cd;%s Error file or directory!\n",route);
}

/*jobs命令*/
void jobs_cmd()
{
	NODE *p;
	int i=1;
	p=head;
	
	if(head!=NULL)
	{
		do
		{
			printf("%d %d %s\t%s\n",i,p->pid,p->state,p->cmd);
			i++;
			p-p->link;
		}while(p!=NULL);
	}
	else
		printf("No jobs!\n");
}

void addNode(char *input_cmd,int node_pid)
{
	NODE *p;
	p=(NODE *)malloc(sizeof(NODE));
	p->pid=node_pid;
	strcpy(p->cmd,input_cmd);
	strcpy(p->state,"running");
	p->link=NULL;
	if(head==NULL)
	{
		head=p;
		end=p;
	}
	else
	{
		end->link=p;
		end=p;
	}
}

void delNode(int sig,siginfo_t *sip)
{
	NODE *q,*p;
	int id;
	if(sig_z==1)
	{
		sig_z=0;
		return;
	}
	id=sip->si_pid;
	p=q=head;
	if(head==NULL)
		return;
	while(p->pid!=id&&p->link!=NULL)
		p=p->link;
	if(p->pid!=id)
		return;
	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);
	return;
}

void setFlag()
{
	sig_flag=1;
}

void ctrl_z_cmd()
{
	NODE *p;
	int i=1;
	if(pid1==0)
		return;
	if(head!=NULL)
	{
		p=head;
		while(p->pid!=pid1&&p->link!=NULL)
			p=p->link;
		if(p->pid==pid1)
			strcpy(p->state,"stopped");
		else
		{
			addNode(input,pid1);
			strcpy(end->state,"stopped");
		}
	}
	else
	{
		addNode(input,pid1);
		strcpy(end->state,"stopped");
	}
	sig_z=1;
	kill(pid1,SIGSTOP);
	for(p=head;p->pid!=pid1;p=p->link)
		i++;
	printf("[%d]\t%s\t%s\n",i,end->state,end->cmd);
	pid1=0;
	return;
}

/*前后台切换命令*/

void bg_cmd(int job_num)
{
	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)
{
	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_cmd);
	kill(p->pid,SIGCONT);
	waitpid(p->pid,NULL,0);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -