Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_fixcpp/sys/src/cmd/sh.C – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* sh - simple shell - great for early stages of porting */
2
#include "u.h"
3
#include "libc.h"
4
 
5
#define MAXLINE 200		/* maximum line length */
6
#define WORD 256		/* token code for words */
7
#define EOF -1			/* token code for end of file */
8
#define ispunct(c)		(c=='|' || c=='&' || c==';' || c=='<' || \
9
				 c=='>' || c=='(' || c==')' || c=='\n')
10
#define isspace(c)		(c==' ' || c=='\t')
11
#define execute(np)		(ignored = (np? (*(np)->op)(np) : 0))
12
 
13
typedef struct Node	Node;
14
struct Node{			/* parse tree node */
15
	int (*op)(Node *); 	/* operator function */
16
	Node *args[2];		/* argument nodes */
17
	char *argv[100];	/* argument pointers */
18
	char *io[3];		/* i/o redirection */
19
};
20
 
21
Node	nodes[25];		/* node pool */
22
Node	*nfree;			/* next available node */
23
char	strspace[10*MAXLINE];	/* string storage */
24
char	*sfree;			/* next free character in strspace */
25
int	t;			/* current token code */
26
char 	*token;			/* current token text (in strspace) */
27
int	putback = 0;		/* lookahead */
28
char	status[256];		/* exit status of most recent command */
29
int	cflag = 0;		/* command is argument to sh */
30
int	tflag = 0;		/* read only one line */
31
int	interactive = 0;	/* prompt */
32
char	*cflagp;		/* command line for cflag */
33
char	*path[] ={"/bin", 0};
34
int	ignored;
35
 
36
Node	*alloc(int (*op)(Node *));
37
int	builtin(Node *np);
38
Node	*command(void);
39
int	getch(void);
40
int	gettoken(void);
41
Node	*list(void);
42
void	error(char *s, char *t);
43
Node	*pipeline(void);
44
void	redirect(Node *np);
45
int	setio(Node *np);
46
Node	*simple(void);
47
int	xpipeline(Node *np);
48
int	xsimple(Node *np);
49
int	xsubshell(Node *np);
50
int	xnowait(Node *np);
51
int	xwait(Node *np);
52
 
53
void
54
main(int argc, char *argv[])
55
{
56
	Node *np;
57
 
58
	if(argc>1 && strcmp(argv[1], "-t")==0)
59
		tflag++;
60
	else if(argc>2 && strcmp(argv[1], "-c")==0){
61
		cflag++;
62
		cflagp = argv[2];
63
	}else if(argc>1){
64
		close(0);
65
		if(open(argv[1], 0) != 0){
66
			error(": can't open", argv[1]);
67
			exits("argument");
68
		}
69
	}else
70
		interactive = 1;
71
	for(;;){
72
		if(interactive)
73
			fprint(2, "%d$ ", getpid());
74
		nfree = nodes;
75
		sfree = strspace;
76
		if((t=gettoken()) == EOF)
77
			break;
78
		if(t != '\n')
79
			if(np = list())
80
				execute(np);
81
			else
82
				error("syntax error", "");
83
		while(t!=EOF && t!='\n')	/* flush syntax errors */
84
			t = gettoken();
85
	}
86
	exits(status);
87
}
88
 
89
/* alloc - allocate for op and return a node */
90
Node*
91
alloc(int (*op)(Node *))
92
{
93
	if(nfree < nodes+sizeof(nodes)){
94
		nfree->op = op;
95
		nfree->args[0] = nfree->args[1] = 0;
96
		nfree->argv[0] = nfree->argv[1] = 0;
97
		nfree->io[0] = nfree->io[1] = nfree->io[2] = 0;
98
		return nfree++;
99
	}
100
	error("node storage overflow", "");
101
	exits("node storage overflow");
102
	return nil;
103
}
104
 
105
/* builtin - check np for builtin command and, if found, execute it */
106
int
107
builtin(Node *np)
108
{
109
	int n = 0;
110
	char name[MAXLINE];
111
	Waitmsg *wmsg;
112
 
113
	if(np->argv[1])
114
		n = strtoul(np->argv[1], 0, 0);
115
	if(strcmp(np->argv[0], "cd") == 0){
116
		if(chdir(np->argv[1]? np->argv[1] : "/") == -1)
117
			error(": bad directory", np->argv[0]);
118
		return 1;
119
	}else if(strcmp(np->argv[0], "exit") == 0)
120
		exits(np->argv[1]? np->argv[1] : status);
121
	else if(strcmp(np->argv[0], "bind") == 0){
122
		if(np->argv[1]==0 || np->argv[2]==0)
123
			error("usage: bind new old", "");
124
		else if(bind(np->argv[1], np->argv[2], 0)==-1)
125
			error("bind failed", "");
126
		return 1;
127
#ifdef asdf
128
	}else if(strcmp(np->argv[0], "unmount") == 0){
129
		if(np->argv[1] == 0)
130
			error("usage: unmount [new] old", "");
131
		else if(np->argv[2] == 0){
132
			if(unmount((char *)0, np->argv[1]) == -1)
133
				error("unmount:", "");
134
		}else if(unmount(np->argv[1], np->argv[2]) == -1)
135
			error("unmount", "");
136
		return 1;
137
#endif
138
	}else if(strcmp(np->argv[0], "wait") == 0){
139
		while((wmsg = wait()) != nil){
140
			strncpy(status, wmsg->msg, sizeof(status)-1);
141
			if(n && wmsg->pid==n){
142
				n = 0;
143
				free(wmsg);
144
				break;
145
			}
146
			free(wmsg);
147
		}
148
		if(n)
149
			error("wait error", "");
150
		return 1;
151
	}else if(strcmp(np->argv[0], "rfork") == 0){
152
		char *p;
153
		int mask;
154
 
155
		p = np->argv[1];
156
		if(p == 0 || *p == 0)
157
			p = "ens";
158
		mask = 0;
159
 
160
		while(*p)
161
			switch(*p++){
162
			case 'n': mask |= RFNAMEG; break;
163
			case 'N': mask |= RFCNAMEG; break;
164
			case 'e': mask |= RFENVG; break;
165
			case 'E': mask |= RFCENVG; break;
166
			case 's': mask |= RFNOTEG; break;
167
			case 'f': mask |= RFFDG; break;
168
			case 'F': mask |= RFCFDG; break;
169
			case 'm': mask |= RFNOMNT; break;
170
			default: error(np->argv[1], "bad rfork flag");
171
			}
172
		rfork(mask);
173
 
174
		return 1;
175
	}else if(strcmp(np->argv[0], "exec") == 0){
176
		redirect(np);
177
		if(np->argv[1] == (char *) 0)
178
			return 1;
179
		exec(np->argv[1], &np->argv[1]);
180
		n = np->argv[1][0];
181
		if(n!='/' && n!='#' && (n!='.' || np->argv[1][1]!='/'))
182
			for(n = 0; path[n]; n++){
183
				sprint(name, "%s/%s", path[n], np->argv[1]);
184
				exec(name, &np->argv[1]);
185
			}
186
		error(": not found", np->argv[1]);
187
		return 1;
188
	}
189
	return 0;
190
}
191
 
192
/* command - ( list ) [ ( < | > | >> ) word ]* | simple */
193
Node*
194
command(void)
195
{
196
	Node *np;
197
 
198
	if(t != '(')
199
		return simple();
200
	np = alloc(xsubshell);
201
	t = gettoken();
202
	if((np->args[0]=list())==0 || t!=')')
203
		return 0;
204
	while((t=gettoken())=='<' || t=='>')
205
		if(!setio(np))
206
			return 0;
207
	return np;
208
}
209
 
210
/* getch - get next, possibly pushed back, input character */
211
int
212
getch(void)
213
{
214
	unsigned char c;
215
	static done=0;
216
 
217
	if(putback){
218
		c = putback;
219
		putback = 0;
220
	}else if(tflag){
221
		if(done || read(0, &c, 1)!=1){
222
			done = 1;
223
			return EOF;
224
		}
225
		if(c == '\n')
226
			done = 1;
227
	}else if(cflag){
228
		if(done)
229
			return EOF;
230
		if((c=*cflagp++) == 0){
231
			done = 1;
232
			c = '\n';
233
		}
234
	}else if(read(0, &c, 1) != 1)
235
		return EOF;
236
	return c;
237
}
238
 
239
/* gettoken - get next token into string space, return token code */
240
int
241
gettoken(void)
242
{
243
	int c;
244
 
245
	while((c = getch()) != EOF)
246
		if(!isspace(c))
247
			break;
248
	if(c==EOF || ispunct(c))
249
		return c;
250
	token = sfree;
251
	do{
252
		if(sfree >= strspace+sizeof(strspace) - 1){
253
			error("string storage overflow", "");
254
			exits("string storage overflow");
255
		}
256
		*sfree++ = c;
257
	}while((c=getch()) != EOF && !ispunct(c) && !isspace(c));
258
	*sfree++ = 0;
259
	putback = c;
260
	return WORD;
261
}
262
 
263
/* list - pipeline ( ( ; | & ) pipeline )* [ ; | & ]  (not LL(1), but ok) */
264
Node*
265
list(void)
266
{
267
	Node *np, *np1;
268
 
269
	np = alloc(0);
270
	if((np->args[1]=pipeline()) == 0)
271
		return 0;
272
	while(t==';' || t=='&'){
273
		np->op = (t==';')? xwait : xnowait;
274
		t = gettoken();
275
		if(t==')' || t=='\n')	/* tests ~first(pipeline) */
276
			break;
277
		np1 = alloc(0);
278
		np1->args[0] = np;
279
		if((np1->args[1]=pipeline()) == 0)
280
			return 0;
281
		np = np1;
282
	}
283
	if(np->op == 0)
284
		np->op = xwait;
285
	return np;
286
}
287
 
288
/* error - print error message s, prefixed by t */
289
void
290
error(char *s, char *t)
291
{
292
	char buf[256];
293
 
294
	fprint(2, "%s%s", t, s);
295
	errstr(buf, sizeof buf);
296
	fprint(2, ": %s\n", buf);
297
}
298
 
299
/* pipeline - command ( | command )* */
300
Node*
301
pipeline(void)
302
{
303
	Node *np, *np1;
304
 
305
	if((np=command()) == 0)
306
		return 0;
307
	while(t == '|'){
308
		np1 = alloc(xpipeline);
309
		np1->args[0] = np;
310
		t = gettoken();
311
		if((np1->args[1]=command()) == 0)
312
			return 0;
313
		np = np1;
314
	}
315
	return np;
316
}
317
 
318
/* redirect - redirect i/o according to np->io[] values */
319
void
320
redirect(Node *np)
321
{
322
	int fd;
323
 
324
	if(np->io[0]){
325
		if((fd = open(np->io[0], 0)) < 0){
326
			error(": can't open", np->io[0]);
327
			exits("open");
328
		}
329
		dup(fd, 0);
330
		close(fd);
331
	}
332
	if(np->io[1]){
333
		if((fd = create(np->io[1], 1, 0666L)) < 0){
334
			error(": can't create", np->io[1]);
335
			exits("create");
336
		}
337
		dup(fd, 1);
338
		close(fd);
339
	}
340
	if(np->io[2]){
341
		if((fd = open(np->io[2], 1)) < 0 && (fd = create(np->io[2], 1, 0666L)) < 0){
342
			error(": can't write", np->io[2]);
343
			exits("write");
344
		}
345
		dup(fd, 1);
346
		close(fd);
347
		seek(1, 0, 2);
348
	}
349
}
350
 
351
/* setio - ( < | > | >> ) word; fill in np->io[] */
352
int
353
setio(Node *np)
354
{
355
	if(t == '<'){
356
		t = gettoken();
357
		np->io[0] = token;
358
	}else if(t == '>'){
359
		t = gettoken();
360
		if(t == '>'){
361
			t = gettoken();
362
			np->io[2] = token;
363
			}else
364
			np->io[1] = token;
365
	}else
366
		return 0;
367
	if(t != WORD)
368
		return 0;
369
	return 1;
370
}
371
 
372
/* simple - word ( [ < | > | >> ] word )* */
373
Node*
374
simple(void)
375
{
376
	Node *np;
377
	int n = 1;
378
 
379
	if(t != WORD)
380
		return 0;
381
	np = alloc(xsimple);
382
	np->argv[0] = token;
383
	while((t = gettoken())==WORD || t=='<' || t=='>')
384
		if(t == WORD)
385
			np->argv[n++] = token;
386
		else if(!setio(np))
387
			return 0;
388
	np->argv[n] = 0;
389
	return np;
390
}
391
 
392
/* xpipeline - execute cmd | cmd */
393
int
394
xpipeline(Node *np)
395
{
396
	int pid, fd[2];
397
 
398
	if(pipe(fd) < 0){
399
		error("can't create pipe", "");
400
		return 0;
401
	}
402
	if((pid=fork()) == 0){	/* left side; redirect stdout */
403
		dup(fd[1], 1);
404
		close(fd[0]);
405
		close(fd[1]);
406
		execute(np->args[0]);
407
		exits(status);
408
	}else if(pid == -1){
409
		error("can't create process", "");
410
		return 0;
411
	}
412
	if((pid=fork()) == 0){	/* right side; redirect stdin */
413
		dup(fd[0], 0);
414
		close(fd[0]);
415
		close(fd[1]);
416
		pid = execute(np->args[1]); /*BUG: this is wrong sometimes*/
417
		if(pid > 0)
418
			while(waitpid()!=pid)
419
				;
420
		exits(0);
421
	}else if(pid == -1){
422
		error("can't create process", "");
423
		return 0;
424
	}
425
	close(fd[0]);	/* avoid using up fd's */
426
	close(fd[1]);
427
	return pid;
428
}
429
 
430
/* xsimple - execute a simple command */
431
int
432
xsimple(Node *np)
433
{
434
	char name[MAXLINE];
435
	int pid, i;
436
 
437
	if(builtin(np))
438
		return 0;
439
	if(pid = fork()){
440
		if(pid == -1)
441
			error(": can't create process", np->argv[0]);
442
		return pid;
443
	}
444
	redirect(np);	/* child process */
445
	exec(np->argv[0], &np->argv[0]);
446
	i = np->argv[0][0];
447
	if(i!='/' && i!='#' && (i!='.' || np->argv[0][1]!='/'))
448
		for(i = 0; path[i]; i++){
449
			sprint(name, "%s/%s", path[i], np->argv[0]);
450
			exec(name, &np->argv[0]);
451
		}
452
	error(": not found", np->argv[0]);
453
	exits("not found");
454
	return -1;		// suppress compiler warnings
455
}
456
 
457
/* xsubshell - execute (cmd) */
458
int
459
xsubshell(Node *np)
460
{
461
	int pid;
462
 
463
	if(pid = fork()){
464
		if(pid == -1)
465
			error("can't create process", "");
466
		return pid;
467
	}
468
	redirect(np);	/* child process */
469
	execute(np->args[0]);
470
	exits(status);
471
	return -1;		// suppress compiler warnings
472
}
473
 
474
/* xnowait - execute cmd & */
475
int
476
xnowait(Node *np)
477
{
478
	int pid;
479
 
480
	execute(np->args[0]);
481
	pid = execute(np->args[1]);
482
	if(interactive)
483
		fprint(2, "%d\n", pid);
484
	return 0;
485
}
486
 
487
/* xwait - execute cmd ; */
488
int xwait(Node *np)
489
{
490
	int pid;
491
	Waitmsg *wmsg;
492
 
493
	execute(np->args[0]);
494
	pid = execute(np->args[1]);
495
	if(pid > 0){
496
		while((wmsg = wait()) != nil){
497
			if(wmsg->pid == pid)
498
				break;
499
			free(wmsg);
500
		}
501
		if(wmsg == nil)
502
			error("wait error", "");
503
		else {
504
			strncpy(status, wmsg->msg, sizeof(status)-1);
505
			free(wmsg);
506
		}
507
	}
508
	return 0;
509
}