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

📄 sh.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
/* sh - simple shell - great for early stages of porting */#include "u.h"#include "libc.h"#define MAXLINE 200		/* maximum line length */#define WORD 256		/* token code for words */#define EOF -1			/* token code for end of file */#define ispunct(c)		(c=='|' || c=='&' || c==';' || c=='<' || \				 c=='>' || c=='(' || c==')' || c=='\n')#define isspace(c)		(c==' ' || c=='\t')#define execute(np)		(ignored = (np? (*(np)->op)(np) : 0))typedef struct Node	Node;struct Node{			/* parse tree node */	int (*op)(Node *); 	/* operator function */	Node *args[2];		/* argument nodes */	char *argv[100];	/* argument pointers */	char *io[3];		/* i/o redirection */};Node	nodes[25];		/* node pool */Node	*nfree;			/* next available node */char	strspace[10*MAXLINE];	/* string storage */char	*sfree;			/* next free character in strspace */int	t;			/* current token code */char 	*token;			/* current token text (in strspace) */int	putback = 0;		/* lookahead */char	status[256];		/* exit status of most recent command */int	cflag = 0;		/* command is argument to sh */int	tflag = 0;		/* read only one line */int	interactive = 0;	/* prompt */char	*cflagp;		/* command line for cflag */char	*path[] ={"/bin", 0};int	ignored;Node	*alloc(int (*op)(Node *));int	builtin(Node *np);Node	*command(void);int	getch(void);int	gettoken(void);Node	*list(void);void	error(char *s, char *t);Node	*pipeline(void);void	redirect(Node *np);int	setio(Node *np);Node	*simple(void);int	xpipeline(Node *np);int	xsimple(Node *np);int	xsubshell(Node *np);int	xnowait(Node *np);int	xwait(Node *np);voidmain(int argc, char *argv[]){	Node *np;	if(argc>1 && strcmp(argv[1], "-t")==0)		tflag++;	else if(argc>2 && strcmp(argv[1], "-c")==0){		cflag++;		cflagp = argv[2];	}else if(argc>1){		close(0);		if(open(argv[1], 0) != 0){			error(": can't open", argv[1]);			exits("argument");		}	}else		interactive = 1;	for(;;){		if(interactive)			fprint(2, "%d$ ", getpid());		nfree = nodes;		sfree = strspace;		if((t=gettoken()) == EOF)			break;		if(t != '\n')			if(np = list())				execute(np);			else				error("syntax error", "");		while(t!=EOF && t!='\n')	/* flush syntax errors */			t = gettoken();	}	exits(status);}/* alloc - allocate for op and return a node */Node*alloc(int (*op)(Node *)){	if(nfree < nodes+sizeof(nodes)){		nfree->op = op;		nfree->args[0] = nfree->args[1] = 0;		nfree->argv[0] = nfree->argv[1] = 0;		nfree->io[0] = nfree->io[1] = nfree->io[2] = 0;		return nfree++;	}	error("node storage overflow", "");	exits("node storage overflow");	return nil;}/* builtin - check np for builtin command and, if found, execute it */intbuiltin(Node *np){	int n = 0;	char name[MAXLINE];	Waitmsg *wmsg;	if(np->argv[1])		n = strtoul(np->argv[1], 0, 0);	if(strcmp(np->argv[0], "cd") == 0){		if(chdir(np->argv[1]? np->argv[1] : "/") == -1)			error(": bad directory", np->argv[0]);		return 1;	}else if(strcmp(np->argv[0], "exit") == 0)		exits(np->argv[1]? np->argv[1] : status);	else if(strcmp(np->argv[0], "bind") == 0){		if(np->argv[1]==0 || np->argv[2]==0)			error("usage: bind new old", "");		else if(bind(np->argv[1], np->argv[2], 0)==-1)			error("bind failed", "");		return 1;#ifdef asdf	}else if(strcmp(np->argv[0], "unmount") == 0){		if(np->argv[1] == 0)			error("usage: unmount [new] old", "");		else if(np->argv[2] == 0){			if(unmount((char *)0, np->argv[1]) == -1)				error("unmount:", "");		}else if(unmount(np->argv[1], np->argv[2]) == -1)			error("unmount", "");		return 1;#endif	}else if(strcmp(np->argv[0], "wait") == 0){		while((wmsg = wait()) != nil){			strncpy(status, wmsg->msg, sizeof(status)-1);			if(n && wmsg->pid==n){				n = 0;				free(wmsg);				break;			}			free(wmsg);		}		if(n)			error("wait error", "");		return 1;	}else if(strcmp(np->argv[0], "rfork") == 0){		char *p;		int mask;		p = np->argv[1];		if(p == 0 || *p == 0)			p = "ens";		mask = 0;		while(*p)			switch(*p++){			case 'n': mask |= RFNAMEG; break;			case 'N': mask |= RFCNAMEG; break;			case 'e': mask |= RFENVG; break;			case 'E': mask |= RFCENVG; break;			case 's': mask |= RFNOTEG; break;			case 'f': mask |= RFFDG; break;			case 'F': mask |= RFCFDG; break;			case 'm': mask |= RFNOMNT; break;			default: error(np->argv[1], "bad rfork flag");			}		rfork(mask);		return 1;	}else if(strcmp(np->argv[0], "exec") == 0){		redirect(np);		if(np->argv[1] == (char *) 0)			return 1;		exec(np->argv[1], &np->argv[1]);		n = np->argv[1][0];		if(n!='/' && n!='#' && (n!='.' || np->argv[1][1]!='/'))			for(n = 0; path[n]; n++){				sprint(name, "%s/%s", path[n], np->argv[1]);				exec(name, &np->argv[1]);			}		error(": not found", np->argv[1]);		return 1;	}	return 0;}/* command - ( list ) [ ( < | > | >> ) word ]* | simple */Node*command(void){	Node *np;	if(t != '(')		return simple();	np = alloc(xsubshell);	t = gettoken();	if((np->args[0]=list())==0 || t!=')')		return 0;	while((t=gettoken())=='<' || t=='>')		if(!setio(np))			return 0;	return np;}/* getch - get next, possibly pushed back, input character */intgetch(void){	unsigned char c;	static done=0;	if(putback){		c = putback;		putback = 0;	}else if(tflag){		if(done || read(0, &c, 1)!=1){			done = 1;			return EOF;		}		if(c == '\n')			done = 1;	}else if(cflag){		if(done)			return EOF;		if((c=*cflagp++) == 0){			done = 1;			c = '\n';		}	}else if(read(0, &c, 1) != 1)		return EOF;	return c;}/* gettoken - get next token into string space, return token code */intgettoken(void){	int c;	while((c = getch()) != EOF)		if(!isspace(c))			break;	if(c==EOF || ispunct(c))		return c;	token = sfree;	do{		if(sfree >= strspace+sizeof(strspace) - 1){			error("string storage overflow", "");			exits("string storage overflow");		}		*sfree++ = c;	}while((c=getch()) != EOF && !ispunct(c) && !isspace(c));	*sfree++ = 0;	putback = c;	return WORD;}/* list - pipeline ( ( ; | & ) pipeline )* [ ; | & ]  (not LL(1), but ok) */Node*list(void){	Node *np, *np1;	np = alloc(0);	if((np->args[1]=pipeline()) == 0)		return 0;	while(t==';' || t=='&'){		np->op = (t==';')? xwait : xnowait;		t = gettoken();		if(t==')' || t=='\n')	/* tests ~first(pipeline) */			break;		np1 = alloc(0);		np1->args[0] = np;		if((np1->args[1]=pipeline()) == 0)			return 0;		np = np1;	}	if(np->op == 0)		np->op = xwait;	return np;}/* error - print error message s, prefixed by t */voiderror(char *s, char *t){	char buf[256];	fprint(2, "%s%s", t, s);	errstr(buf, sizeof buf);	fprint(2, ": %s\n", buf);}/* pipeline - command ( | command )* */Node*pipeline(void){	Node *np, *np1;	if((np=command()) == 0)		return 0;	while(t == '|'){		np1 = alloc(xpipeline);		np1->args[0] = np;		t = gettoken();		if((np1->args[1]=command()) == 0)			return 0;		np = np1;	}	return np;}/* redirect - redirect i/o according to np->io[] values */voidredirect(Node *np){	int fd;	if(np->io[0]){		if((fd = open(np->io[0], 0)) < 0){			error(": can't open", np->io[0]);			exits("open");		}		dup(fd, 0);		close(fd);	}	if(np->io[1]){		if((fd = create(np->io[1], 1, 0666L)) < 0){			error(": can't create", np->io[1]);			exits("create");		}		dup(fd, 1);		close(fd);	}	if(np->io[2]){		if((fd = open(np->io[2], 1)) < 0 && (fd = create(np->io[2], 1, 0666L)) < 0){			error(": can't write", np->io[2]);			exits("write");		}		dup(fd, 1);		close(fd);		seek(1, 0, 2);	}}/* setio - ( < | > | >> ) word; fill in np->io[] */intsetio(Node *np){	if(t == '<'){		t = gettoken();		np->io[0] = token;	}else if(t == '>'){		t = gettoken();		if(t == '>'){			t = gettoken();			np->io[2] = token;			}else			np->io[1] = token;	}else		return 0;	if(t != WORD)		return 0;	return 1;}			/* simple - word ( [ < | > | >> ] word )* */Node*simple(void){	Node *np;	int n = 1;	if(t != WORD)		return 0;	np = alloc(xsimple);	np->argv[0] = token;	while((t = gettoken())==WORD || t=='<' || t=='>')		if(t == WORD)			np->argv[n++] = token;		else if(!setio(np))			return 0;	np->argv[n] = 0;	return np;}/* xpipeline - execute cmd | cmd */intxpipeline(Node *np){	int pid, fd[2];	if(pipe(fd) < 0){		error("can't create pipe", "");		return 0;	}	if((pid=fork()) == 0){	/* left side; redirect stdout */		dup(fd[1], 1);		close(fd[0]);		close(fd[1]);		execute(np->args[0]);		exits(status);	}else if(pid == -1){		error("can't create process", "");		return 0;	}	if((pid=fork()) == 0){	/* right side; redirect stdin */		dup(fd[0], 0);		close(fd[0]);		close(fd[1]);		pid = execute(np->args[1]); /*BUG: this is wrong sometimes*/		if(pid > 0)			while(waitpid()!=pid)				;		exits(0);	}else if(pid == -1){		error("can't create process", "");		return 0;	}	close(fd[0]);	/* avoid using up fd's */	close(fd[1]);	return pid;}/* xsimple - execute a simple command */intxsimple(Node *np){	char name[MAXLINE];	int pid, i;	if(builtin(np))		return 0;	if(pid = fork()){		if(pid == -1)			error(": can't create process", np->argv[0]);		return pid;	}	redirect(np);	/* child process */	exec(np->argv[0], &np->argv[0]);	i = np->argv[0][0];	if(i!='/' && i!='#' && (i!='.' || np->argv[0][1]!='/'))		for(i = 0; path[i]; i++){			sprint(name, "%s/%s", path[i], np->argv[0]);			exec(name, &np->argv[0]);		}	error(": not found", np->argv[0]);	exits("not found");	return -1;		// suppress compiler warnings}/* xsubshell - execute (cmd) */intxsubshell(Node *np){	int pid;	if(pid = fork()){		if(pid == -1)			error("can't create process", "");		return pid;	}	redirect(np);	/* child process */	execute(np->args[0]);	exits(status);	return -1;		// suppress compiler warnings}/* xnowait - execute cmd & */intxnowait(Node *np){	int pid;	execute(np->args[0]);	pid = execute(np->args[1]);	if(interactive)		fprint(2, "%d\n", pid);	return 0;}/* xwait - execute cmd ; */int xwait(Node *np){	int pid;	Waitmsg *wmsg;	execute(np->args[0]);	pid = execute(np->args[1]);	if(pid > 0){		while((wmsg = wait()) != nil){			if(wmsg->pid == pid)				break;			free(wmsg);		}		if(wmsg == nil)			error("wait error", "");		else {			strncpy(status, wmsg->msg, sizeof(status)-1);			free(wmsg);		}	}	return 0;}

⌨️ 快捷键说明

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