xref: /plan9-contrib/sys/src/cmd/sh.C (revision dc5a79c1208f0704eeb474acc990728f8b4854f5)
1219b2ee8SDavid du Colombier /* sh - simple shell - great for early stages of porting */
23e12c5d1SDavid du Colombier #include "u.h"
33e12c5d1SDavid du Colombier #include "libc.h"
43e12c5d1SDavid du Colombier 
53e12c5d1SDavid du Colombier #define MAXLINE 200		/* maximum line length */
63e12c5d1SDavid du Colombier #define WORD 256		/* token code for words */
73e12c5d1SDavid du Colombier #define EOF -1			/* token code for end of file */
83e12c5d1SDavid du Colombier #define ispunct(c)		(c=='|' || c=='&' || c==';' || c=='<' || \
93e12c5d1SDavid du Colombier 				 c=='>' || c=='(' || c==')' || c=='\n')
103e12c5d1SDavid du Colombier #define isspace(c)		(c==' ' || c=='\t')
11*dc5a79c1SDavid du Colombier #define execute(np)		(ignored = (np? (*(np)->op)(np) : 0))
123e12c5d1SDavid du Colombier 
133e12c5d1SDavid du Colombier typedef struct Node	Node;
143e12c5d1SDavid du Colombier struct Node{			/* parse tree node */
153e12c5d1SDavid du Colombier 	int (*op)(Node *); 	/* operator function */
163e12c5d1SDavid du Colombier 	Node *args[2];		/* argument nodes */
173e12c5d1SDavid du Colombier 	char *argv[100];	/* argument pointers */
183e12c5d1SDavid du Colombier 	char *io[3];		/* i/o redirection */
193e12c5d1SDavid du Colombier };
203e12c5d1SDavid du Colombier 
213e12c5d1SDavid du Colombier Node	nodes[25];		/* node pool */
223e12c5d1SDavid du Colombier Node	*nfree;			/* next available node */
233e12c5d1SDavid du Colombier char	strspace[10*MAXLINE];	/* string storage */
243e12c5d1SDavid du Colombier char	*sfree;			/* next free character in strspace */
253e12c5d1SDavid du Colombier int	t;			/* current token code */
263e12c5d1SDavid du Colombier char 	*token;			/* current token text (in strspace) */
273e12c5d1SDavid du Colombier int	putback = 0;		/* lookahead */
28*dc5a79c1SDavid du Colombier char	status[256];		/* exit status of most recent command */
293e12c5d1SDavid du Colombier int	cflag = 0;		/* command is argument to sh */
303e12c5d1SDavid du Colombier int	tflag = 0;		/* read only one line */
313e12c5d1SDavid du Colombier int	interactive = 0;	/* prompt */
323e12c5d1SDavid du Colombier char	*cflagp;		/* command line for cflag */
333e12c5d1SDavid du Colombier char	*path[] ={"/bin", 0};
34*dc5a79c1SDavid du Colombier int	ignored;
353e12c5d1SDavid du Colombier 
363e12c5d1SDavid du Colombier Node	*alloc(int (*op)(Node *));
373e12c5d1SDavid du Colombier int	builtin(Node *np);
383e12c5d1SDavid du Colombier Node	*command(void);
393e12c5d1SDavid du Colombier int	getch(void);
403e12c5d1SDavid du Colombier int	gettoken(void);
413e12c5d1SDavid du Colombier Node	*list(void);
423e12c5d1SDavid du Colombier void	error(char *s, char *t);
433e12c5d1SDavid du Colombier Node	*pipeline(void);
443e12c5d1SDavid du Colombier void	redirect(Node *np);
453e12c5d1SDavid du Colombier int	setio(Node *np);
463e12c5d1SDavid du Colombier Node	*simple(void);
473e12c5d1SDavid du Colombier int	xpipeline(Node *np);
483e12c5d1SDavid du Colombier int	xsimple(Node *np);
493e12c5d1SDavid du Colombier int	xsubshell(Node *np);
503e12c5d1SDavid du Colombier int	xnowait(Node *np);
513e12c5d1SDavid du Colombier int	xwait(Node *np);
523e12c5d1SDavid du Colombier 
53*dc5a79c1SDavid du Colombier void
main(int argc,char * argv[])543e12c5d1SDavid du Colombier main(int argc, char *argv[])
553e12c5d1SDavid du Colombier {
563e12c5d1SDavid du Colombier 	Node *np;
573e12c5d1SDavid du Colombier 
583e12c5d1SDavid du Colombier 	if(argc>1 && strcmp(argv[1], "-t")==0)
593e12c5d1SDavid du Colombier 		tflag++;
603e12c5d1SDavid du Colombier 	else if(argc>2 && strcmp(argv[1], "-c")==0){
613e12c5d1SDavid du Colombier 		cflag++;
623e12c5d1SDavid du Colombier 		cflagp = argv[2];
633e12c5d1SDavid du Colombier 	}else if(argc>1){
643e12c5d1SDavid du Colombier 		close(0);
653e12c5d1SDavid du Colombier 		if(open(argv[1], 0) != 0){
663e12c5d1SDavid du Colombier 			error(": can't open", argv[1]);
673e12c5d1SDavid du Colombier 			exits("argument");
683e12c5d1SDavid du Colombier 		}
693e12c5d1SDavid du Colombier 	}else
703e12c5d1SDavid du Colombier 		interactive = 1;
713e12c5d1SDavid du Colombier 	for(;;){
723e12c5d1SDavid du Colombier 		if(interactive)
733e12c5d1SDavid du Colombier 			fprint(2, "%d$ ", getpid());
743e12c5d1SDavid du Colombier 		nfree = nodes;
753e12c5d1SDavid du Colombier 		sfree = strspace;
763e12c5d1SDavid du Colombier 		if((t=gettoken()) == EOF)
773e12c5d1SDavid du Colombier 			break;
783e12c5d1SDavid du Colombier 		if(t != '\n')
793e12c5d1SDavid du Colombier 			if(np = list())
803e12c5d1SDavid du Colombier 				execute(np);
813e12c5d1SDavid du Colombier 			else
823e12c5d1SDavid du Colombier 				error("syntax error", "");
833e12c5d1SDavid du Colombier 		while(t!=EOF && t!='\n')	/* flush syntax errors */
843e12c5d1SDavid du Colombier 			t = gettoken();
853e12c5d1SDavid du Colombier 	}
86*dc5a79c1SDavid du Colombier 	exits(status);
873e12c5d1SDavid du Colombier }
883e12c5d1SDavid du Colombier 
893e12c5d1SDavid du Colombier /* alloc - allocate for op and return a node */
903e12c5d1SDavid du Colombier Node*
alloc(int (* op)(Node *))913e12c5d1SDavid du Colombier alloc(int (*op)(Node *))
923e12c5d1SDavid du Colombier {
933e12c5d1SDavid du Colombier 	if(nfree < nodes+sizeof(nodes)){
943e12c5d1SDavid du Colombier 		nfree->op = op;
953e12c5d1SDavid du Colombier 		nfree->args[0] = nfree->args[1] = 0;
963e12c5d1SDavid du Colombier 		nfree->argv[0] = nfree->argv[1] = 0;
973e12c5d1SDavid du Colombier 		nfree->io[0] = nfree->io[1] = nfree->io[2] = 0;
983e12c5d1SDavid du Colombier 		return nfree++;
993e12c5d1SDavid du Colombier 	}
1003e12c5d1SDavid du Colombier 	error("node storage overflow", "");
1013e12c5d1SDavid du Colombier 	exits("node storage overflow");
102*dc5a79c1SDavid du Colombier 	return nil;
1033e12c5d1SDavid du Colombier }
1043e12c5d1SDavid du Colombier 
1053e12c5d1SDavid du Colombier /* builtin - check np for builtin command and, if found, execute it */
1063e12c5d1SDavid du Colombier int
builtin(Node * np)1073e12c5d1SDavid du Colombier builtin(Node *np)
1083e12c5d1SDavid du Colombier {
1093e12c5d1SDavid du Colombier 	int n = 0;
110*dc5a79c1SDavid du Colombier 	char name[MAXLINE];
111*dc5a79c1SDavid du Colombier 	Waitmsg *wmsg;
1123e12c5d1SDavid du Colombier 
1133e12c5d1SDavid du Colombier 	if(np->argv[1])
1143e12c5d1SDavid du Colombier 		n = strtoul(np->argv[1], 0, 0);
1153e12c5d1SDavid du Colombier 	if(strcmp(np->argv[0], "cd") == 0){
1163e12c5d1SDavid du Colombier 		if(chdir(np->argv[1]? np->argv[1] : "/") == -1)
1173e12c5d1SDavid du Colombier 			error(": bad directory", np->argv[0]);
1183e12c5d1SDavid du Colombier 		return 1;
1193e12c5d1SDavid du Colombier 	}else if(strcmp(np->argv[0], "exit") == 0)
120*dc5a79c1SDavid du Colombier 		exits(np->argv[1]? np->argv[1] : status);
1213e12c5d1SDavid du Colombier 	else if(strcmp(np->argv[0], "bind") == 0){
1223e12c5d1SDavid du Colombier 		if(np->argv[1]==0 || np->argv[2]==0)
1233e12c5d1SDavid du Colombier 			error("usage: bind new old", "");
1243e12c5d1SDavid du Colombier 		else if(bind(np->argv[1], np->argv[2], 0)==-1)
1253e12c5d1SDavid du Colombier 			error("bind failed", "");
1263e12c5d1SDavid du Colombier 		return 1;
1273e12c5d1SDavid du Colombier #ifdef asdf
1283e12c5d1SDavid du Colombier 	}else if(strcmp(np->argv[0], "unmount") == 0){
1293e12c5d1SDavid du Colombier 		if(np->argv[1] == 0)
1303e12c5d1SDavid du Colombier 			error("usage: unmount [new] old", "");
1313e12c5d1SDavid du Colombier 		else if(np->argv[2] == 0){
1323e12c5d1SDavid du Colombier 			if(unmount((char *)0, np->argv[1]) == -1)
1333e12c5d1SDavid du Colombier 				error("unmount:", "");
1343e12c5d1SDavid du Colombier 		}else if(unmount(np->argv[1], np->argv[2]) == -1)
1353e12c5d1SDavid du Colombier 			error("unmount", "");
1363e12c5d1SDavid du Colombier 		return 1;
1373e12c5d1SDavid du Colombier #endif
1383e12c5d1SDavid du Colombier 	}else if(strcmp(np->argv[0], "wait") == 0){
139*dc5a79c1SDavid du Colombier 		while((wmsg = wait()) != nil){
140*dc5a79c1SDavid du Colombier 			strncpy(status, wmsg->msg, sizeof(status)-1);
141*dc5a79c1SDavid du Colombier 			if(n && wmsg->pid==n){
1423e12c5d1SDavid du Colombier 				n = 0;
143*dc5a79c1SDavid du Colombier 				free(wmsg);
1443e12c5d1SDavid du Colombier 				break;
1453e12c5d1SDavid du Colombier 			}
146*dc5a79c1SDavid du Colombier 			free(wmsg);
147*dc5a79c1SDavid du Colombier 		}
1483e12c5d1SDavid du Colombier 		if(n)
1493e12c5d1SDavid du Colombier 			error("wait error", "");
1503e12c5d1SDavid du Colombier 		return 1;
151*dc5a79c1SDavid du Colombier 	}else if(strcmp(np->argv[0], "rfork") == 0){
152*dc5a79c1SDavid du Colombier 		char *p;
153*dc5a79c1SDavid du Colombier 		int mask;
154*dc5a79c1SDavid du Colombier 
155*dc5a79c1SDavid du Colombier 		p = np->argv[1];
156*dc5a79c1SDavid du Colombier 		if(p == 0 || *p == 0)
157*dc5a79c1SDavid du Colombier 			p = "ens";
158*dc5a79c1SDavid du Colombier 		mask = 0;
159*dc5a79c1SDavid du Colombier 
160*dc5a79c1SDavid du Colombier 		while(*p)
161*dc5a79c1SDavid du Colombier 			switch(*p++){
162*dc5a79c1SDavid du Colombier 			case 'n': mask |= RFNAMEG; break;
163*dc5a79c1SDavid du Colombier 			case 'N': mask |= RFCNAMEG; break;
164*dc5a79c1SDavid du Colombier 			case 'e': mask |= RFENVG; break;
165*dc5a79c1SDavid du Colombier 			case 'E': mask |= RFCENVG; break;
166*dc5a79c1SDavid du Colombier 			case 's': mask |= RFNOTEG; break;
167*dc5a79c1SDavid du Colombier 			case 'f': mask |= RFFDG; break;
168*dc5a79c1SDavid du Colombier 			case 'F': mask |= RFCFDG; break;
169*dc5a79c1SDavid du Colombier 			case 'm': mask |= RFNOMNT; break;
170*dc5a79c1SDavid du Colombier 			default: error(np->argv[1], "bad rfork flag");
171*dc5a79c1SDavid du Colombier 			}
172*dc5a79c1SDavid du Colombier 		rfork(mask);
173*dc5a79c1SDavid du Colombier 
1743e12c5d1SDavid du Colombier 		return 1;
1753e12c5d1SDavid du Colombier 	}else if(strcmp(np->argv[0], "exec") == 0){
1763e12c5d1SDavid du Colombier 		redirect(np);
1773e12c5d1SDavid du Colombier 		if(np->argv[1] == (char *) 0)
1783e12c5d1SDavid du Colombier 			return 1;
1793e12c5d1SDavid du Colombier 		exec(np->argv[1], &np->argv[1]);
1803e12c5d1SDavid du Colombier 		n = np->argv[1][0];
1813e12c5d1SDavid du Colombier 		if(n!='/' && n!='#' && (n!='.' || np->argv[1][1]!='/'))
1823e12c5d1SDavid du Colombier 			for(n = 0; path[n]; n++){
1833e12c5d1SDavid du Colombier 				sprint(name, "%s/%s", path[n], np->argv[1]);
1843e12c5d1SDavid du Colombier 				exec(name, &np->argv[1]);
1853e12c5d1SDavid du Colombier 			}
1863e12c5d1SDavid du Colombier 		error(": not found", np->argv[1]);
1873e12c5d1SDavid du Colombier 		return 1;
1883e12c5d1SDavid du Colombier 	}
1893e12c5d1SDavid du Colombier 	return 0;
1903e12c5d1SDavid du Colombier }
1913e12c5d1SDavid du Colombier 
1923e12c5d1SDavid du Colombier /* command - ( list ) [ ( < | > | >> ) word ]* | simple */
1933e12c5d1SDavid du Colombier Node*
command(void)1943e12c5d1SDavid du Colombier command(void)
1953e12c5d1SDavid du Colombier {
1963e12c5d1SDavid du Colombier 	Node *np;
1973e12c5d1SDavid du Colombier 
1983e12c5d1SDavid du Colombier 	if(t != '(')
1993e12c5d1SDavid du Colombier 		return simple();
2003e12c5d1SDavid du Colombier 	np = alloc(xsubshell);
2013e12c5d1SDavid du Colombier 	t = gettoken();
2023e12c5d1SDavid du Colombier 	if((np->args[0]=list())==0 || t!=')')
2033e12c5d1SDavid du Colombier 		return 0;
2043e12c5d1SDavid du Colombier 	while((t=gettoken())=='<' || t=='>')
2053e12c5d1SDavid du Colombier 		if(!setio(np))
2063e12c5d1SDavid du Colombier 			return 0;
2073e12c5d1SDavid du Colombier 	return np;
2083e12c5d1SDavid du Colombier }
2093e12c5d1SDavid du Colombier 
2103e12c5d1SDavid du Colombier /* getch - get next, possibly pushed back, input character */
2113e12c5d1SDavid du Colombier int
getch(void)2123e12c5d1SDavid du Colombier getch(void)
2133e12c5d1SDavid du Colombier {
2143e12c5d1SDavid du Colombier 	unsigned char c;
2153e12c5d1SDavid du Colombier 	static done=0;
2163e12c5d1SDavid du Colombier 
2173e12c5d1SDavid du Colombier 	if(putback){
2183e12c5d1SDavid du Colombier 		c = putback;
2193e12c5d1SDavid du Colombier 		putback = 0;
2203e12c5d1SDavid du Colombier 	}else if(tflag){
2213e12c5d1SDavid du Colombier 		if(done || read(0, &c, 1)!=1){
2223e12c5d1SDavid du Colombier 			done = 1;
2233e12c5d1SDavid du Colombier 			return EOF;
2243e12c5d1SDavid du Colombier 		}
2253e12c5d1SDavid du Colombier 		if(c == '\n')
2263e12c5d1SDavid du Colombier 			done = 1;
2273e12c5d1SDavid du Colombier 	}else if(cflag){
2283e12c5d1SDavid du Colombier 		if(done)
2293e12c5d1SDavid du Colombier 			return EOF;
2303e12c5d1SDavid du Colombier 		if((c=*cflagp++) == 0){
2313e12c5d1SDavid du Colombier 			done = 1;
2323e12c5d1SDavid du Colombier 			c = '\n';
2333e12c5d1SDavid du Colombier 		}
2343e12c5d1SDavid du Colombier 	}else if(read(0, &c, 1) != 1)
2353e12c5d1SDavid du Colombier 		return EOF;
2363e12c5d1SDavid du Colombier 	return c;
2373e12c5d1SDavid du Colombier }
2383e12c5d1SDavid du Colombier 
2393e12c5d1SDavid du Colombier /* gettoken - get next token into string space, return token code */
2403e12c5d1SDavid du Colombier int
gettoken(void)2413e12c5d1SDavid du Colombier gettoken(void)
2423e12c5d1SDavid du Colombier {
2433e12c5d1SDavid du Colombier 	int c;
2443e12c5d1SDavid du Colombier 
2453e12c5d1SDavid du Colombier 	while((c = getch()) != EOF)
2463e12c5d1SDavid du Colombier 		if(!isspace(c))
2473e12c5d1SDavid du Colombier 			break;
2483e12c5d1SDavid du Colombier 	if(c==EOF || ispunct(c))
2493e12c5d1SDavid du Colombier 		return c;
2503e12c5d1SDavid du Colombier 	token = sfree;
2513e12c5d1SDavid du Colombier 	do{
2523e12c5d1SDavid du Colombier 		if(sfree >= strspace+sizeof(strspace) - 1){
2533e12c5d1SDavid du Colombier 			error("string storage overflow", "");
2543e12c5d1SDavid du Colombier 			exits("string storage overflow");
2553e12c5d1SDavid du Colombier 		}
2563e12c5d1SDavid du Colombier 		*sfree++ = c;
2573e12c5d1SDavid du Colombier 	}while((c=getch()) != EOF && !ispunct(c) && !isspace(c));
2583e12c5d1SDavid du Colombier 	*sfree++ = 0;
2593e12c5d1SDavid du Colombier 	putback = c;
2603e12c5d1SDavid du Colombier 	return WORD;
2613e12c5d1SDavid du Colombier }
2623e12c5d1SDavid du Colombier 
2633e12c5d1SDavid du Colombier /* list - pipeline ( ( ; | & ) pipeline )* [ ; | & ]  (not LL(1), but ok) */
2643e12c5d1SDavid du Colombier Node*
list(void)2653e12c5d1SDavid du Colombier list(void)
2663e12c5d1SDavid du Colombier {
2673e12c5d1SDavid du Colombier 	Node *np, *np1;
2683e12c5d1SDavid du Colombier 
2693e12c5d1SDavid du Colombier 	np = alloc(0);
2703e12c5d1SDavid du Colombier 	if((np->args[1]=pipeline()) == 0)
2713e12c5d1SDavid du Colombier 		return 0;
2723e12c5d1SDavid du Colombier 	while(t==';' || t=='&'){
2733e12c5d1SDavid du Colombier 		np->op = (t==';')? xwait : xnowait;
2743e12c5d1SDavid du Colombier 		t = gettoken();
2753e12c5d1SDavid du Colombier 		if(t==')' || t=='\n')	/* tests ~first(pipeline) */
2763e12c5d1SDavid du Colombier 			break;
2773e12c5d1SDavid du Colombier 		np1 = alloc(0);
2783e12c5d1SDavid du Colombier 		np1->args[0] = np;
2793e12c5d1SDavid du Colombier 		if((np1->args[1]=pipeline()) == 0)
2803e12c5d1SDavid du Colombier 			return 0;
2813e12c5d1SDavid du Colombier 		np = np1;
2823e12c5d1SDavid du Colombier 	}
2833e12c5d1SDavid du Colombier 	if(np->op == 0)
2843e12c5d1SDavid du Colombier 		np->op = xwait;
2853e12c5d1SDavid du Colombier 	return np;
2863e12c5d1SDavid du Colombier }
2873e12c5d1SDavid du Colombier 
2883e12c5d1SDavid du Colombier /* error - print error message s, prefixed by t */
2893e12c5d1SDavid du Colombier void
error(char * s,char * t)2903e12c5d1SDavid du Colombier error(char *s, char *t)
2913e12c5d1SDavid du Colombier {
292*dc5a79c1SDavid du Colombier 	char buf[256];
2933e12c5d1SDavid du Colombier 
2943e12c5d1SDavid du Colombier 	fprint(2, "%s%s", t, s);
295*dc5a79c1SDavid du Colombier 	errstr(buf, sizeof buf);
2963e12c5d1SDavid du Colombier 	fprint(2, ": %s\n", buf);
2973e12c5d1SDavid du Colombier }
2983e12c5d1SDavid du Colombier 
2993e12c5d1SDavid du Colombier /* pipeline - command ( | command )* */
3003e12c5d1SDavid du Colombier Node*
pipeline(void)3013e12c5d1SDavid du Colombier pipeline(void)
3023e12c5d1SDavid du Colombier {
3033e12c5d1SDavid du Colombier 	Node *np, *np1;
3043e12c5d1SDavid du Colombier 
3053e12c5d1SDavid du Colombier 	if((np=command()) == 0)
3063e12c5d1SDavid du Colombier 		return 0;
3073e12c5d1SDavid du Colombier 	while(t == '|'){
3083e12c5d1SDavid du Colombier 		np1 = alloc(xpipeline);
3093e12c5d1SDavid du Colombier 		np1->args[0] = np;
3103e12c5d1SDavid du Colombier 		t = gettoken();
3113e12c5d1SDavid du Colombier 		if((np1->args[1]=command()) == 0)
3123e12c5d1SDavid du Colombier 			return 0;
3133e12c5d1SDavid du Colombier 		np = np1;
3143e12c5d1SDavid du Colombier 	}
3153e12c5d1SDavid du Colombier 	return np;
3163e12c5d1SDavid du Colombier }
3173e12c5d1SDavid du Colombier 
3183e12c5d1SDavid du Colombier /* redirect - redirect i/o according to np->io[] values */
3193e12c5d1SDavid du Colombier void
redirect(Node * np)3203e12c5d1SDavid du Colombier redirect(Node *np)
3213e12c5d1SDavid du Colombier {
3223e12c5d1SDavid du Colombier 	int fd;
3233e12c5d1SDavid du Colombier 
3243e12c5d1SDavid du Colombier 	if(np->io[0]){
3253e12c5d1SDavid du Colombier 		if((fd = open(np->io[0], 0)) < 0){
3263e12c5d1SDavid du Colombier 			error(": can't open", np->io[0]);
3273e12c5d1SDavid du Colombier 			exits("open");
3283e12c5d1SDavid du Colombier 		}
3293e12c5d1SDavid du Colombier 		dup(fd, 0);
3303e12c5d1SDavid du Colombier 		close(fd);
3313e12c5d1SDavid du Colombier 	}
3323e12c5d1SDavid du Colombier 	if(np->io[1]){
3333e12c5d1SDavid du Colombier 		if((fd = create(np->io[1], 1, 0666L)) < 0){
3343e12c5d1SDavid du Colombier 			error(": can't create", np->io[1]);
3353e12c5d1SDavid du Colombier 			exits("create");
3363e12c5d1SDavid du Colombier 		}
3373e12c5d1SDavid du Colombier 		dup(fd, 1);
3383e12c5d1SDavid du Colombier 		close(fd);
3393e12c5d1SDavid du Colombier 	}
3403e12c5d1SDavid du Colombier 	if(np->io[2]){
3413e12c5d1SDavid du Colombier 		if((fd = open(np->io[2], 1)) < 0 && (fd = create(np->io[2], 1, 0666L)) < 0){
3423e12c5d1SDavid du Colombier 			error(": can't write", np->io[2]);
3433e12c5d1SDavid du Colombier 			exits("write");
3443e12c5d1SDavid du Colombier 		}
3453e12c5d1SDavid du Colombier 		dup(fd, 1);
3463e12c5d1SDavid du Colombier 		close(fd);
3473e12c5d1SDavid du Colombier 		seek(1, 0, 2);
3483e12c5d1SDavid du Colombier 	}
3493e12c5d1SDavid du Colombier }
3503e12c5d1SDavid du Colombier 
3513e12c5d1SDavid du Colombier /* setio - ( < | > | >> ) word; fill in np->io[] */
3523e12c5d1SDavid du Colombier int
setio(Node * np)3533e12c5d1SDavid du Colombier setio(Node *np)
3543e12c5d1SDavid du Colombier {
3553e12c5d1SDavid du Colombier 	if(t == '<'){
3563e12c5d1SDavid du Colombier 		t = gettoken();
3573e12c5d1SDavid du Colombier 		np->io[0] = token;
3583e12c5d1SDavid du Colombier 	}else if(t == '>'){
3593e12c5d1SDavid du Colombier 		t = gettoken();
3603e12c5d1SDavid du Colombier 		if(t == '>'){
3613e12c5d1SDavid du Colombier 			t = gettoken();
3623e12c5d1SDavid du Colombier 			np->io[2] = token;
3633e12c5d1SDavid du Colombier 			}else
3643e12c5d1SDavid du Colombier 			np->io[1] = token;
3653e12c5d1SDavid du Colombier 	}else
3663e12c5d1SDavid du Colombier 		return 0;
3673e12c5d1SDavid du Colombier 	if(t != WORD)
3683e12c5d1SDavid du Colombier 		return 0;
3693e12c5d1SDavid du Colombier 	return 1;
3703e12c5d1SDavid du Colombier }
3713e12c5d1SDavid du Colombier 
3723e12c5d1SDavid du Colombier /* simple - word ( [ < | > | >> ] word )* */
3733e12c5d1SDavid du Colombier Node*
simple(void)3743e12c5d1SDavid du Colombier simple(void)
3753e12c5d1SDavid du Colombier {
3763e12c5d1SDavid du Colombier 	Node *np;
3773e12c5d1SDavid du Colombier 	int n = 1;
3783e12c5d1SDavid du Colombier 
3793e12c5d1SDavid du Colombier 	if(t != WORD)
3803e12c5d1SDavid du Colombier 		return 0;
3813e12c5d1SDavid du Colombier 	np = alloc(xsimple);
3823e12c5d1SDavid du Colombier 	np->argv[0] = token;
3833e12c5d1SDavid du Colombier 	while((t = gettoken())==WORD || t=='<' || t=='>')
3843e12c5d1SDavid du Colombier 		if(t == WORD)
3853e12c5d1SDavid du Colombier 			np->argv[n++] = token;
3863e12c5d1SDavid du Colombier 		else if(!setio(np))
3873e12c5d1SDavid du Colombier 			return 0;
3883e12c5d1SDavid du Colombier 	np->argv[n] = 0;
3893e12c5d1SDavid du Colombier 	return np;
3903e12c5d1SDavid du Colombier }
3913e12c5d1SDavid du Colombier 
3923e12c5d1SDavid du Colombier /* xpipeline - execute cmd | cmd */
3933e12c5d1SDavid du Colombier int
xpipeline(Node * np)3943e12c5d1SDavid du Colombier xpipeline(Node *np)
3953e12c5d1SDavid du Colombier {
3963e12c5d1SDavid du Colombier 	int pid, fd[2];
3973e12c5d1SDavid du Colombier 
3983e12c5d1SDavid du Colombier 	if(pipe(fd) < 0){
3993e12c5d1SDavid du Colombier 		error("can't create pipe", "");
4003e12c5d1SDavid du Colombier 		return 0;
4013e12c5d1SDavid du Colombier 	}
4023e12c5d1SDavid du Colombier 	if((pid=fork()) == 0){	/* left side; redirect stdout */
4033e12c5d1SDavid du Colombier 		dup(fd[1], 1);
4043e12c5d1SDavid du Colombier 		close(fd[0]);
4053e12c5d1SDavid du Colombier 		close(fd[1]);
4063e12c5d1SDavid du Colombier 		execute(np->args[0]);
407*dc5a79c1SDavid du Colombier 		exits(status);
4083e12c5d1SDavid du Colombier 	}else if(pid == -1){
4093e12c5d1SDavid du Colombier 		error("can't create process", "");
4103e12c5d1SDavid du Colombier 		return 0;
4113e12c5d1SDavid du Colombier 	}
4123e12c5d1SDavid du Colombier 	if((pid=fork()) == 0){	/* right side; redirect stdin */
4133e12c5d1SDavid du Colombier 		dup(fd[0], 0);
4143e12c5d1SDavid du Colombier 		close(fd[0]);
4153e12c5d1SDavid du Colombier 		close(fd[1]);
4163e12c5d1SDavid du Colombier 		pid = execute(np->args[1]); /*BUG: this is wrong sometimes*/
4173e12c5d1SDavid du Colombier 		if(pid > 0)
418*dc5a79c1SDavid du Colombier 			while(waitpid()!=pid)
4193e12c5d1SDavid du Colombier 				;
4203e12c5d1SDavid du Colombier 		exits(0);
4213e12c5d1SDavid du Colombier 	}else if(pid == -1){
4223e12c5d1SDavid du Colombier 		error("can't create process", "");
4233e12c5d1SDavid du Colombier 		return 0;
4243e12c5d1SDavid du Colombier 	}
4253e12c5d1SDavid du Colombier 	close(fd[0]);	/* avoid using up fd's */
4263e12c5d1SDavid du Colombier 	close(fd[1]);
4273e12c5d1SDavid du Colombier 	return pid;
4283e12c5d1SDavid du Colombier }
4293e12c5d1SDavid du Colombier 
4303e12c5d1SDavid du Colombier /* xsimple - execute a simple command */
4313e12c5d1SDavid du Colombier int
xsimple(Node * np)4323e12c5d1SDavid du Colombier xsimple(Node *np)
4333e12c5d1SDavid du Colombier {
4343e12c5d1SDavid du Colombier 	char name[MAXLINE];
4353e12c5d1SDavid du Colombier 	int pid, i;
4363e12c5d1SDavid du Colombier 
4373e12c5d1SDavid du Colombier 	if(builtin(np))
4383e12c5d1SDavid du Colombier 		return 0;
4393e12c5d1SDavid du Colombier 	if(pid = fork()){
4403e12c5d1SDavid du Colombier 		if(pid == -1)
4413e12c5d1SDavid du Colombier 			error(": can't create process", np->argv[0]);
4423e12c5d1SDavid du Colombier 		return pid;
4433e12c5d1SDavid du Colombier 	}
4443e12c5d1SDavid du Colombier 	redirect(np);	/* child process */
4453e12c5d1SDavid du Colombier 	exec(np->argv[0], &np->argv[0]);
4463e12c5d1SDavid du Colombier 	i = np->argv[0][0];
4473e12c5d1SDavid du Colombier 	if(i!='/' && i!='#' && (i!='.' || np->argv[0][1]!='/'))
4483e12c5d1SDavid du Colombier 		for(i = 0; path[i]; i++){
4493e12c5d1SDavid du Colombier 			sprint(name, "%s/%s", path[i], np->argv[0]);
4503e12c5d1SDavid du Colombier 			exec(name, &np->argv[0]);
4513e12c5d1SDavid du Colombier 		}
4523e12c5d1SDavid du Colombier 	error(": not found", np->argv[0]);
4533e12c5d1SDavid du Colombier 	exits("not found");
454*dc5a79c1SDavid du Colombier 	return -1;		// suppress compiler warnings
4553e12c5d1SDavid du Colombier }
4563e12c5d1SDavid du Colombier 
4573e12c5d1SDavid du Colombier /* xsubshell - execute (cmd) */
4583e12c5d1SDavid du Colombier int
xsubshell(Node * np)4593e12c5d1SDavid du Colombier xsubshell(Node *np)
4603e12c5d1SDavid du Colombier {
4613e12c5d1SDavid du Colombier 	int pid;
4623e12c5d1SDavid du Colombier 
4633e12c5d1SDavid du Colombier 	if(pid = fork()){
4643e12c5d1SDavid du Colombier 		if(pid == -1)
4653e12c5d1SDavid du Colombier 			error("can't create process", "");
4663e12c5d1SDavid du Colombier 		return pid;
4673e12c5d1SDavid du Colombier 	}
4683e12c5d1SDavid du Colombier 	redirect(np);	/* child process */
4693e12c5d1SDavid du Colombier 	execute(np->args[0]);
470*dc5a79c1SDavid du Colombier 	exits(status);
471*dc5a79c1SDavid du Colombier 	return -1;		// suppress compiler warnings
4723e12c5d1SDavid du Colombier }
4733e12c5d1SDavid du Colombier 
4743e12c5d1SDavid du Colombier /* xnowait - execute cmd & */
4753e12c5d1SDavid du Colombier int
xnowait(Node * np)4763e12c5d1SDavid du Colombier xnowait(Node *np)
4773e12c5d1SDavid du Colombier {
4783e12c5d1SDavid du Colombier 	int pid;
4793e12c5d1SDavid du Colombier 
4803e12c5d1SDavid du Colombier 	execute(np->args[0]);
4813e12c5d1SDavid du Colombier 	pid = execute(np->args[1]);
4823e12c5d1SDavid du Colombier 	if(interactive)
4833e12c5d1SDavid du Colombier 		fprint(2, "%d\n", pid);
4843e12c5d1SDavid du Colombier 	return 0;
4853e12c5d1SDavid du Colombier }
4863e12c5d1SDavid du Colombier 
4873e12c5d1SDavid du Colombier /* xwait - execute cmd ; */
xwait(Node * np)4883e12c5d1SDavid du Colombier int xwait(Node *np)
4893e12c5d1SDavid du Colombier {
4903e12c5d1SDavid du Colombier 	int pid;
491*dc5a79c1SDavid du Colombier 	Waitmsg *wmsg;
4923e12c5d1SDavid du Colombier 
4933e12c5d1SDavid du Colombier 	execute(np->args[0]);
4943e12c5d1SDavid du Colombier 	pid = execute(np->args[1]);
4953e12c5d1SDavid du Colombier 	if(pid > 0){
496*dc5a79c1SDavid du Colombier 		while((wmsg = wait()) != nil){
497*dc5a79c1SDavid du Colombier 			if(wmsg->pid == pid)
498*dc5a79c1SDavid du Colombier 				break;
499*dc5a79c1SDavid du Colombier 			free(wmsg);
500*dc5a79c1SDavid du Colombier 		}
501*dc5a79c1SDavid du Colombier 		if(wmsg == nil)
5023e12c5d1SDavid du Colombier 			error("wait error", "");
503*dc5a79c1SDavid du Colombier 		else {
504*dc5a79c1SDavid du Colombier 			strncpy(status, wmsg->msg, sizeof(status)-1);
505*dc5a79c1SDavid du Colombier 			free(wmsg);
506*dc5a79c1SDavid du Colombier 		}
5073e12c5d1SDavid du Colombier 	}
5083e12c5d1SDavid du Colombier 	return 0;
5093e12c5d1SDavid du Colombier }
510