1 | #define Extern extern
|
---|
2 | #include <sys/types.h>
|
---|
3 | #include <signal.h>
|
---|
4 | #include <errno.h>
|
---|
5 | #include <setjmp.h>
|
---|
6 | #include <stddef.h>
|
---|
7 | #include <time.h>
|
---|
8 | #include <sys/times.h>
|
---|
9 | #include <sys/stat.h>
|
---|
10 | #include <sys/wait.h>
|
---|
11 | #undef NULL
|
---|
12 | #include "sh.h"
|
---|
13 |
|
---|
14 | /* -------- exec.c -------- */
|
---|
15 | /* #include "sh.h" */
|
---|
16 |
|
---|
17 | /*
|
---|
18 | * execute tree
|
---|
19 | */
|
---|
20 |
|
---|
21 | static char *signame[] = {
|
---|
22 | "Signal 0",
|
---|
23 | "Hangup",
|
---|
24 | (char *)NULL, /* interrupt */
|
---|
25 | "Quit",
|
---|
26 | "Illegal instruction",
|
---|
27 | "Trace/BPT trap",
|
---|
28 | "Abort",
|
---|
29 | "EMT trap",
|
---|
30 | "Floating exception",
|
---|
31 | "Killed",
|
---|
32 | "Bus error",
|
---|
33 | "Memory fault",
|
---|
34 | "Bad system call",
|
---|
35 | (char *)NULL, /* broken pipe */
|
---|
36 | "Alarm clock",
|
---|
37 | "Terminated",
|
---|
38 | };
|
---|
39 | #define NSIGNAL (sizeof(signame)/sizeof(signame[0]))
|
---|
40 |
|
---|
41 |
|
---|
42 | _PROTOTYPE(static int forkexec, (struct op *t, int *pin, int *pout, int act, char **wp, int *pforked ));
|
---|
43 | _PROTOTYPE(static int parent, (void));
|
---|
44 | _PROTOTYPE(int iosetup, (struct ioword *iop, int pipein, int pipeout ));
|
---|
45 | _PROTOTYPE(static void echo, (char **wp ));
|
---|
46 | _PROTOTYPE(static struct op **find1case, (struct op *t, char *w ));
|
---|
47 | _PROTOTYPE(static struct op *findcase, (struct op *t, char *w ));
|
---|
48 | _PROTOTYPE(static void brkset, (struct brkcon *bc ));
|
---|
49 | _PROTOTYPE(int dolabel, (void));
|
---|
50 | _PROTOTYPE(int dochdir, (struct op *t ));
|
---|
51 | _PROTOTYPE(int doshift, (struct op *t ));
|
---|
52 | _PROTOTYPE(int dologin, (struct op *t ));
|
---|
53 | _PROTOTYPE(int doumask, (struct op *t ));
|
---|
54 | _PROTOTYPE(int doexec, (struct op *t ));
|
---|
55 | _PROTOTYPE(int dodot, (struct op *t ));
|
---|
56 | _PROTOTYPE(int dowait, (struct op *t ));
|
---|
57 | _PROTOTYPE(int doread, (struct op *t ));
|
---|
58 | _PROTOTYPE(int doeval, (struct op *t ));
|
---|
59 | _PROTOTYPE(int dotrap, (struct op *t ));
|
---|
60 | _PROTOTYPE(int getsig, (char *s ));
|
---|
61 | _PROTOTYPE(void setsig, (int n, void (*f)()));
|
---|
62 | _PROTOTYPE(int getn, (char *as ));
|
---|
63 | _PROTOTYPE(int dobreak, (struct op *t ));
|
---|
64 | _PROTOTYPE(int docontinue, (struct op *t ));
|
---|
65 | _PROTOTYPE(static int brkcontin, (char *cp, int val ));
|
---|
66 | _PROTOTYPE(int doexit, (struct op *t ));
|
---|
67 | _PROTOTYPE(int doexport, (struct op *t ));
|
---|
68 | _PROTOTYPE(int doreadonly, (struct op *t ));
|
---|
69 | _PROTOTYPE(static void rdexp, (char **wp, void (*f)(), int key));
|
---|
70 | _PROTOTYPE(static void badid, (char *s ));
|
---|
71 | _PROTOTYPE(int doset, (struct op *t ));
|
---|
72 | _PROTOTYPE(void varput, (char *s, int out ));
|
---|
73 | _PROTOTYPE(int dotimes, (void));
|
---|
74 |
|
---|
75 | int
|
---|
76 | execute(t, pin, pout, act)
|
---|
77 | register struct op *t;
|
---|
78 | int *pin, *pout;
|
---|
79 | int act;
|
---|
80 | {
|
---|
81 | register struct op *t1;
|
---|
82 | int i, pv[2], rv, child, a;
|
---|
83 | char *cp, **wp, **wp2;
|
---|
84 | struct var *vp;
|
---|
85 | struct brkcon bc;
|
---|
86 |
|
---|
87 | if (t == NULL)
|
---|
88 | return(0);
|
---|
89 | rv = 0;
|
---|
90 | a = areanum++;
|
---|
91 | wp = (wp2 = t->words) != NULL
|
---|
92 | ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY)
|
---|
93 | : NULL;
|
---|
94 |
|
---|
95 | switch(t->type) {
|
---|
96 | case TPAREN:
|
---|
97 | case TCOM:
|
---|
98 | rv = forkexec(t, pin, pout, act, wp, &child);
|
---|
99 | if (child) {
|
---|
100 | exstat = rv;
|
---|
101 | leave();
|
---|
102 | }
|
---|
103 | break;
|
---|
104 |
|
---|
105 | case TPIPE:
|
---|
106 | if ((rv = openpipe(pv)) < 0)
|
---|
107 | break;
|
---|
108 | pv[0] = remap(pv[0]);
|
---|
109 | pv[1] = remap(pv[1]);
|
---|
110 | (void) execute(t->left, pin, pv, 0);
|
---|
111 | rv = execute(t->right, pv, pout, 0);
|
---|
112 | break;
|
---|
113 |
|
---|
114 | case TLIST:
|
---|
115 | (void) execute(t->left, pin, pout, 0);
|
---|
116 | rv = execute(t->right, pin, pout, 0);
|
---|
117 | break;
|
---|
118 |
|
---|
119 | case TASYNC:
|
---|
120 | i = parent();
|
---|
121 | if (i != 0) {
|
---|
122 | if (i != -1) {
|
---|
123 | setval(lookup("!"), putn(i));
|
---|
124 | if (pin != NULL)
|
---|
125 | closepipe(pin);
|
---|
126 | if (talking) {
|
---|
127 | prs(putn(i));
|
---|
128 | prs("\n");
|
---|
129 | }
|
---|
130 | } else
|
---|
131 | rv = -1;
|
---|
132 | setstatus(rv);
|
---|
133 | } else {
|
---|
134 | signal(SIGINT, SIG_IGN);
|
---|
135 | signal(SIGQUIT, SIG_IGN);
|
---|
136 | if (talking)
|
---|
137 | signal(SIGTERM, SIG_DFL);
|
---|
138 | talking = 0;
|
---|
139 | if (pin == NULL) {
|
---|
140 | close(0);
|
---|
141 | open("/dev/null", 0);
|
---|
142 | }
|
---|
143 | exit(execute(t->left, pin, pout, FEXEC));
|
---|
144 | }
|
---|
145 | break;
|
---|
146 |
|
---|
147 | case TOR:
|
---|
148 | case TAND:
|
---|
149 | rv = execute(t->left, pin, pout, 0);
|
---|
150 | if ((t1 = t->right)!=NULL && (rv == 0) == (t->type == TAND))
|
---|
151 | rv = execute(t1, pin, pout, 0);
|
---|
152 | break;
|
---|
153 |
|
---|
154 | case TFOR:
|
---|
155 | if (wp == NULL) {
|
---|
156 | wp = dolv+1;
|
---|
157 | if ((i = dolc) < 0)
|
---|
158 | i = 0;
|
---|
159 | } else {
|
---|
160 | i = -1;
|
---|
161 | while (*wp++ != NULL)
|
---|
162 | ;
|
---|
163 | }
|
---|
164 | vp = lookup(t->str);
|
---|
165 | while (setjmp(bc.brkpt))
|
---|
166 | if (isbreak)
|
---|
167 | goto broken;
|
---|
168 | brkset(&bc);
|
---|
169 | for (t1 = t->left; i-- && *wp != NULL;) {
|
---|
170 | setval(vp, *wp++);
|
---|
171 | rv = execute(t1, pin, pout, 0);
|
---|
172 | }
|
---|
173 | brklist = brklist->nextlev;
|
---|
174 | break;
|
---|
175 |
|
---|
176 | case TWHILE:
|
---|
177 | case TUNTIL:
|
---|
178 | while (setjmp(bc.brkpt))
|
---|
179 | if (isbreak)
|
---|
180 | goto broken;
|
---|
181 | brkset(&bc);
|
---|
182 | t1 = t->left;
|
---|
183 | while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE))
|
---|
184 | rv = execute(t->right, pin, pout, 0);
|
---|
185 | brklist = brklist->nextlev;
|
---|
186 | break;
|
---|
187 |
|
---|
188 | case TIF:
|
---|
189 | case TELIF:
|
---|
190 | if (t->right != NULL) {
|
---|
191 | rv = !execute(t->left, pin, pout, 0) ?
|
---|
192 | execute(t->right->left, pin, pout, 0):
|
---|
193 | execute(t->right->right, pin, pout, 0);
|
---|
194 | }
|
---|
195 | break;
|
---|
196 |
|
---|
197 | case TCASE:
|
---|
198 | if ((cp = evalstr(t->str, DOSUB|DOTRIM)) == 0)
|
---|
199 | cp = "";
|
---|
200 | if ((t1 = findcase(t->left, cp)) != NULL)
|
---|
201 | rv = execute(t1, pin, pout, 0);
|
---|
202 | break;
|
---|
203 |
|
---|
204 | case TBRACE:
|
---|
205 | /*
|
---|
206 | if (iopp = t->ioact)
|
---|
207 | while (*iopp)
|
---|
208 | if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
|
---|
209 | rv = -1;
|
---|
210 | break;
|
---|
211 | }
|
---|
212 | */
|
---|
213 | if (rv >= 0 && (t1 = t->left))
|
---|
214 | rv = execute(t1, pin, pout, 0);
|
---|
215 | break;
|
---|
216 | }
|
---|
217 |
|
---|
218 | broken:
|
---|
219 | t->words = wp2;
|
---|
220 | isbreak = 0;
|
---|
221 | freehere(areanum);
|
---|
222 | freearea(areanum);
|
---|
223 | areanum = a;
|
---|
224 | if (talking && intr) {
|
---|
225 | closeall();
|
---|
226 | fail();
|
---|
227 | }
|
---|
228 | if ((i = trapset) != 0) {
|
---|
229 | trapset = 0;
|
---|
230 | runtrap(i);
|
---|
231 | }
|
---|
232 | return(rv);
|
---|
233 | }
|
---|
234 |
|
---|
235 | static int
|
---|
236 | forkexec(t, pin, pout, act, wp, pforked)
|
---|
237 | register struct op *t;
|
---|
238 | int *pin, *pout;
|
---|
239 | int act;
|
---|
240 | char **wp;
|
---|
241 | int *pforked;
|
---|
242 | {
|
---|
243 | int i, rv, (*shcom)();
|
---|
244 | register int f;
|
---|
245 | char *cp;
|
---|
246 | struct ioword **iopp;
|
---|
247 | int resetsig;
|
---|
248 | char **owp;
|
---|
249 |
|
---|
250 | owp = wp;
|
---|
251 | resetsig = 0;
|
---|
252 | *pforked = 0;
|
---|
253 | shcom = NULL;
|
---|
254 | rv = -1; /* system-detected error */
|
---|
255 | if (t->type == TCOM) {
|
---|
256 | while ((cp = *wp++) != NULL)
|
---|
257 | ;
|
---|
258 | cp = *wp;
|
---|
259 |
|
---|
260 | /* strip all initial assignments */
|
---|
261 | /* not correct wrt PATH=yyy command etc */
|
---|
262 | if (flag['x'])
|
---|
263 | echo (cp ? wp: owp);
|
---|
264 | if (cp == NULL && t->ioact == NULL) {
|
---|
265 | while ((cp = *owp++) != NULL && assign(cp, COPYV))
|
---|
266 | ;
|
---|
267 | return(setstatus(0));
|
---|
268 | }
|
---|
269 | else if (cp != NULL)
|
---|
270 | shcom = inbuilt(cp);
|
---|
271 | }
|
---|
272 | t->words = wp;
|
---|
273 | f = act;
|
---|
274 | if (shcom == NULL && (f & FEXEC) == 0) {
|
---|
275 | i = parent();
|
---|
276 | if (i != 0) {
|
---|
277 | if (i == -1)
|
---|
278 | return(rv);
|
---|
279 | if (pin != NULL)
|
---|
280 | closepipe(pin);
|
---|
281 | return(pout==NULL? setstatus(waitfor(i,0)): 0);
|
---|
282 | }
|
---|
283 | if (talking) {
|
---|
284 | signal(SIGINT, SIG_IGN);
|
---|
285 | signal(SIGQUIT, SIG_IGN);
|
---|
286 | resetsig = 1;
|
---|
287 | }
|
---|
288 | talking = 0;
|
---|
289 | intr = 0;
|
---|
290 | (*pforked)++;
|
---|
291 | brklist = 0;
|
---|
292 | execflg = 0;
|
---|
293 | }
|
---|
294 | if (owp != NULL)
|
---|
295 | while ((cp = *owp++) != NULL && assign(cp, COPYV))
|
---|
296 | if (shcom == NULL)
|
---|
297 | export(lookup(cp));
|
---|
298 | #ifdef COMPIPE
|
---|
299 | if ((pin != NULL || pout != NULL) && shcom != NULL && shcom != doexec) {
|
---|
300 | err("piping to/from shell builtins not yet done");
|
---|
301 | return(-1);
|
---|
302 | }
|
---|
303 | #endif
|
---|
304 | if (pin != NULL) {
|
---|
305 | dup2(pin[0], 0);
|
---|
306 | closepipe(pin);
|
---|
307 | }
|
---|
308 | if (pout != NULL) {
|
---|
309 | dup2(pout[1], 1);
|
---|
310 | closepipe(pout);
|
---|
311 | }
|
---|
312 | if ((iopp = t->ioact) != NULL) {
|
---|
313 | if (shcom != NULL && shcom != doexec) {
|
---|
314 | prs(cp);
|
---|
315 | err(": cannot redirect shell command");
|
---|
316 | return(-1);
|
---|
317 | }
|
---|
318 | while (*iopp)
|
---|
319 | if (iosetup(*iopp++, pin!=NULL, pout!=NULL))
|
---|
320 | return(rv);
|
---|
321 | }
|
---|
322 | if (shcom)
|
---|
323 | return(setstatus((*shcom)(t)));
|
---|
324 | /* should use FIOCEXCL */
|
---|
325 | for (i=FDBASE; i<NOFILE; i++)
|
---|
326 | close(i);
|
---|
327 | if (resetsig) {
|
---|
328 | signal(SIGINT, SIG_DFL);
|
---|
329 | signal(SIGQUIT, SIG_DFL);
|
---|
330 | }
|
---|
331 | if (t->type == TPAREN)
|
---|
332 | exit(execute(t->left, NOPIPE, NOPIPE, FEXEC));
|
---|
333 | if (wp[0] == NULL)
|
---|
334 | exit(0);
|
---|
335 | cp = rexecve(wp[0], wp, makenv());
|
---|
336 | prs(wp[0]); prs(": "); warn(cp);
|
---|
337 | if (!execflg)
|
---|
338 | trap[0] = NULL;
|
---|
339 | leave();
|
---|
340 | /* NOTREACHED */
|
---|
341 | }
|
---|
342 |
|
---|
343 | /*
|
---|
344 | * common actions when creating a new child
|
---|
345 | */
|
---|
346 | static int
|
---|
347 | parent()
|
---|
348 | {
|
---|
349 | register int i;
|
---|
350 |
|
---|
351 | i = fork();
|
---|
352 | if (i != 0) {
|
---|
353 | if (i == -1)
|
---|
354 | warn("try again");
|
---|
355 | }
|
---|
356 | return(i);
|
---|
357 | }
|
---|
358 |
|
---|
359 | /*
|
---|
360 | * 0< 1> are ignored as required
|
---|
361 | * within pipelines.
|
---|
362 | */
|
---|
363 | int
|
---|
364 | iosetup(iop, pipein, pipeout)
|
---|
365 | register struct ioword *iop;
|
---|
366 | int pipein, pipeout;
|
---|
367 | {
|
---|
368 | register u;
|
---|
369 | char *cp, *msg;
|
---|
370 |
|
---|
371 | if (iop->io_unit == IODEFAULT) /* take default */
|
---|
372 | iop->io_unit = iop->io_flag&(IOREAD|IOHERE)? 0: 1;
|
---|
373 | if (pipein && iop->io_unit == 0)
|
---|
374 | return(0);
|
---|
375 | if (pipeout && iop->io_unit == 1)
|
---|
376 | return(0);
|
---|
377 | msg = iop->io_flag&(IOREAD|IOHERE)? "open": "create";
|
---|
378 | if ((iop->io_flag & IOHERE) == 0) {
|
---|
379 | cp = iop->io_name;
|
---|
380 | if ((cp = evalstr(cp, DOSUB|DOTRIM)) == NULL)
|
---|
381 | return(1);
|
---|
382 | }
|
---|
383 | if (iop->io_flag & IODUP) {
|
---|
384 | if (cp[1] || (!digit(*cp) && *cp != '-')) {
|
---|
385 | prs(cp);
|
---|
386 | err(": illegal >& argument");
|
---|
387 | return(1);
|
---|
388 | }
|
---|
389 | if (*cp == '-')
|
---|
390 | iop->io_flag = IOCLOSE;
|
---|
391 | iop->io_flag &= ~(IOREAD|IOWRITE);
|
---|
392 | }
|
---|
393 | switch (iop->io_flag) {
|
---|
394 | case IOREAD:
|
---|
395 | u = open(cp, 0);
|
---|
396 | break;
|
---|
397 |
|
---|
398 | case IOHERE:
|
---|
399 | case IOHERE|IOXHERE:
|
---|
400 | u = herein(iop->io_name, iop->io_flag&IOXHERE);
|
---|
401 | cp = "here file ";
|
---|
402 | break;
|
---|
403 |
|
---|
404 | case IOWRITE|IOCAT:
|
---|
405 | if ((u = open(cp, 1)) >= 0) {
|
---|
406 | lseek(u, (long)0, 2);
|
---|
407 | break;
|
---|
408 | }
|
---|
409 | case IOWRITE:
|
---|
410 | u = creat(cp, 0666);
|
---|
411 | break;
|
---|
412 |
|
---|
413 | case IODUP:
|
---|
414 | u = dup2(*cp-'0', iop->io_unit);
|
---|
415 | break;
|
---|
416 |
|
---|
417 | case IOCLOSE:
|
---|
418 | close(iop->io_unit);
|
---|
419 | return(0);
|
---|
420 | }
|
---|
421 | if (u < 0) {
|
---|
422 | int e=errno;
|
---|
423 | prs(cp);
|
---|
424 | if (iop->io_flag&IOHERE) prs(iop->io_name);
|
---|
425 | prs(": cannot ");
|
---|
426 | prs(msg);
|
---|
427 | prs(" (");
|
---|
428 | prs(strerror(e));
|
---|
429 | warn(")");
|
---|
430 | return(1);
|
---|
431 | } else {
|
---|
432 | if (u != iop->io_unit) {
|
---|
433 | dup2(u, iop->io_unit);
|
---|
434 | close(u);
|
---|
435 | }
|
---|
436 | }
|
---|
437 | return(0);
|
---|
438 | }
|
---|
439 |
|
---|
440 | static void
|
---|
441 | echo(wp)
|
---|
442 | register char **wp;
|
---|
443 | {
|
---|
444 | register i;
|
---|
445 |
|
---|
446 | prs("+");
|
---|
447 | for (i=0; wp[i]; i++) {
|
---|
448 | if (i)
|
---|
449 | prs(" ");
|
---|
450 | prs(wp[i]);
|
---|
451 | }
|
---|
452 | prs("\n");
|
---|
453 | }
|
---|
454 |
|
---|
455 | static struct op **
|
---|
456 | find1case(t, w)
|
---|
457 | struct op *t;
|
---|
458 | char *w;
|
---|
459 | {
|
---|
460 | register struct op *t1;
|
---|
461 | struct op **tp;
|
---|
462 | register char **wp, *cp;
|
---|
463 |
|
---|
464 | if (t == NULL)
|
---|
465 | return((struct op **)NULL);
|
---|
466 | if (t->type == TLIST) {
|
---|
467 | if ((tp = find1case(t->left, w)) != NULL)
|
---|
468 | return(tp);
|
---|
469 | t1 = t->right; /* TPAT */
|
---|
470 | } else
|
---|
471 | t1 = t;
|
---|
472 | for (wp = t1->words; *wp;)
|
---|
473 | if ((cp = evalstr(*wp++, DOSUB)) && gmatch(w, cp))
|
---|
474 | return(&t1->left);
|
---|
475 | return((struct op **)NULL);
|
---|
476 | }
|
---|
477 |
|
---|
478 | static struct op *
|
---|
479 | findcase(t, w)
|
---|
480 | struct op *t;
|
---|
481 | char *w;
|
---|
482 | {
|
---|
483 | register struct op **tp;
|
---|
484 |
|
---|
485 | return((tp = find1case(t, w)) != NULL? *tp: (struct op *)NULL);
|
---|
486 | }
|
---|
487 |
|
---|
488 | /*
|
---|
489 | * Enter a new loop level (marked for break/continue).
|
---|
490 | */
|
---|
491 | static void
|
---|
492 | brkset(bc)
|
---|
493 | struct brkcon *bc;
|
---|
494 | {
|
---|
495 | bc->nextlev = brklist;
|
---|
496 | brklist = bc;
|
---|
497 | }
|
---|
498 |
|
---|
499 | /*
|
---|
500 | * Wait for the last process created.
|
---|
501 | * Print a message for each process found
|
---|
502 | * that was killed by a signal.
|
---|
503 | * Ignore interrupt signals while waiting
|
---|
504 | * unless `canintr' is true.
|
---|
505 | */
|
---|
506 | int
|
---|
507 | waitfor(lastpid, canintr)
|
---|
508 | register int lastpid;
|
---|
509 | int canintr;
|
---|
510 | {
|
---|
511 | register int pid, rv;
|
---|
512 | int s;
|
---|
513 | int oheedint = heedint;
|
---|
514 |
|
---|
515 | heedint = 0;
|
---|
516 | rv = 0;
|
---|
517 | do {
|
---|
518 | pid = wait(&s);
|
---|
519 | if (pid == -1) {
|
---|
520 | if (errno != EINTR || canintr)
|
---|
521 | break;
|
---|
522 | } else {
|
---|
523 | if ((rv = WAITSIG(s)) != 0) {
|
---|
524 | if (rv < NSIGNAL) {
|
---|
525 | if (signame[rv] != NULL) {
|
---|
526 | if (pid != lastpid) {
|
---|
527 | prn(pid);
|
---|
528 | prs(": ");
|
---|
529 | }
|
---|
530 | prs(signame[rv]);
|
---|
531 | }
|
---|
532 | } else {
|
---|
533 | if (pid != lastpid) {
|
---|
534 | prn(pid);
|
---|
535 | prs(": ");
|
---|
536 | }
|
---|
537 | prs("Signal "); prn(rv); prs(" ");
|
---|
538 | }
|
---|
539 | if (WAITCORE(s))
|
---|
540 | prs(" - core dumped");
|
---|
541 | if (rv >= NSIGNAL || signame[rv])
|
---|
542 | prs("\n");
|
---|
543 | rv = -1;
|
---|
544 | } else
|
---|
545 | rv = WAITVAL(s);
|
---|
546 | }
|
---|
547 | } while (pid != lastpid);
|
---|
548 | heedint = oheedint;
|
---|
549 | if (intr)
|
---|
550 | if (talking) {
|
---|
551 | if (canintr)
|
---|
552 | intr = 0;
|
---|
553 | } else {
|
---|
554 | if (exstat == 0) exstat = rv;
|
---|
555 | onintr(0);
|
---|
556 | }
|
---|
557 | return(rv);
|
---|
558 | }
|
---|
559 |
|
---|
560 | int
|
---|
561 | setstatus(s)
|
---|
562 | register int s;
|
---|
563 | {
|
---|
564 | exstat = s;
|
---|
565 | setval(lookup("?"), putn(s));
|
---|
566 | return(s);
|
---|
567 | }
|
---|
568 |
|
---|
569 | /*
|
---|
570 | * PATH-searching interface to execve.
|
---|
571 | * If getenv("PATH") were kept up-to-date,
|
---|
572 | * execvp might be used.
|
---|
573 | */
|
---|
574 | char *
|
---|
575 | rexecve(c, v, envp)
|
---|
576 | char *c, **v, **envp;
|
---|
577 | {
|
---|
578 | register int i;
|
---|
579 | register char *sp, *tp;
|
---|
580 | int eacces = 0, asis = 0;
|
---|
581 |
|
---|
582 | sp = any('/', c)? "": path->value;
|
---|
583 | asis = *sp == '\0';
|
---|
584 | while (asis || *sp != '\0') {
|
---|
585 | asis = 0;
|
---|
586 | tp = e.linep;
|
---|
587 | for (; *sp != '\0'; tp++)
|
---|
588 | if ((*tp = *sp++) == ':') {
|
---|
589 | asis = *sp == '\0';
|
---|
590 | break;
|
---|
591 | }
|
---|
592 | if (tp != e.linep)
|
---|
593 | *tp++ = '/';
|
---|
594 | for (i = 0; (*tp++ = c[i++]) != '\0';)
|
---|
595 | ;
|
---|
596 | execve(e.linep, v, envp);
|
---|
597 | switch (errno) {
|
---|
598 | case ENOEXEC:
|
---|
599 | *v = e.linep;
|
---|
600 | tp = *--v;
|
---|
601 | *v = e.linep;
|
---|
602 | execve("/bin/sh", v, envp);
|
---|
603 | *v = tp;
|
---|
604 | return("no Shell");
|
---|
605 |
|
---|
606 | case ENOMEM:
|
---|
607 | return("program too big");
|
---|
608 |
|
---|
609 | case E2BIG:
|
---|
610 | return("argument list too long");
|
---|
611 |
|
---|
612 | case EACCES:
|
---|
613 | eacces++;
|
---|
614 | break;
|
---|
615 | }
|
---|
616 | }
|
---|
617 | return(errno==ENOENT ? "not found" : "cannot execute");
|
---|
618 | }
|
---|
619 |
|
---|
620 | /*
|
---|
621 | * Run the command produced by generator `f'
|
---|
622 | * applied to stream `arg'.
|
---|
623 | */
|
---|
624 | int
|
---|
625 | run(argp, f)
|
---|
626 | struct ioarg *argp;
|
---|
627 | int (*f)();
|
---|
628 | {
|
---|
629 | struct op *otree;
|
---|
630 | struct wdblock *swdlist;
|
---|
631 | struct wdblock *siolist;
|
---|
632 | jmp_buf ev, rt;
|
---|
633 | xint *ofail;
|
---|
634 | int rv;
|
---|
635 |
|
---|
636 | areanum++;
|
---|
637 | swdlist = wdlist;
|
---|
638 | siolist = iolist;
|
---|
639 | otree = outtree;
|
---|
640 | ofail = failpt;
|
---|
641 | rv = -1;
|
---|
642 | if (newenv(setjmp(errpt = ev)) == 0) {
|
---|
643 | wdlist = 0;
|
---|
644 | iolist = 0;
|
---|
645 | pushio(argp, f);
|
---|
646 | e.iobase = e.iop;
|
---|
647 | yynerrs = 0;
|
---|
648 | if (setjmp(failpt = rt) == 0 && yyparse() == 0)
|
---|
649 | rv = execute(outtree, NOPIPE, NOPIPE, 0);
|
---|
650 | quitenv();
|
---|
651 | }
|
---|
652 | wdlist = swdlist;
|
---|
653 | iolist = siolist;
|
---|
654 | failpt = ofail;
|
---|
655 | outtree = otree;
|
---|
656 | freearea(areanum--);
|
---|
657 | return(rv);
|
---|
658 | }
|
---|
659 |
|
---|
660 | /* -------- do.c -------- */
|
---|
661 | /* #include "sh.h" */
|
---|
662 |
|
---|
663 | /*
|
---|
664 | * built-in commands: doX
|
---|
665 | */
|
---|
666 |
|
---|
667 | int
|
---|
668 | dolabel()
|
---|
669 | {
|
---|
670 | return(0);
|
---|
671 | }
|
---|
672 |
|
---|
673 | int
|
---|
674 | dochdir(t)
|
---|
675 | register struct op *t;
|
---|
676 | {
|
---|
677 | register char *cp, *er;
|
---|
678 |
|
---|
679 | if ((cp = t->words[1]) == NULL && (cp = homedir->value) == NULL)
|
---|
680 | er = ": no home directory";
|
---|
681 | else if(chdir(cp) < 0)
|
---|
682 | er = ": bad directory";
|
---|
683 | else
|
---|
684 | return(0);
|
---|
685 | prs(cp != NULL? cp: "cd");
|
---|
686 | err(er);
|
---|
687 | return(1);
|
---|
688 | }
|
---|
689 |
|
---|
690 | int
|
---|
691 | doshift(t)
|
---|
692 | register struct op *t;
|
---|
693 | {
|
---|
694 | register n;
|
---|
695 |
|
---|
696 | n = t->words[1]? getn(t->words[1]): 1;
|
---|
697 | if(dolc < n) {
|
---|
698 | err("nothing to shift");
|
---|
699 | return(1);
|
---|
700 | }
|
---|
701 | dolv[n] = dolv[0];
|
---|
702 | dolv += n;
|
---|
703 | dolc -= n;
|
---|
704 | setval(lookup("#"), putn(dolc));
|
---|
705 | return(0);
|
---|
706 | }
|
---|
707 |
|
---|
708 | /*
|
---|
709 | * execute login and newgrp directly
|
---|
710 | */
|
---|
711 | int
|
---|
712 | dologin(t)
|
---|
713 | struct op *t;
|
---|
714 | {
|
---|
715 | register char *cp;
|
---|
716 |
|
---|
717 | if (talking) {
|
---|
718 | signal(SIGINT, SIG_DFL);
|
---|
719 | signal(SIGQUIT, SIG_DFL);
|
---|
720 | }
|
---|
721 | cp = rexecve(t->words[0], t->words, makenv());
|
---|
722 | prs(t->words[0]); prs(": "); err(cp);
|
---|
723 | return(1);
|
---|
724 | }
|
---|
725 |
|
---|
726 | int
|
---|
727 | doumask(t)
|
---|
728 | register struct op *t;
|
---|
729 | {
|
---|
730 | register int i, n;
|
---|
731 | register char *cp;
|
---|
732 |
|
---|
733 | if ((cp = t->words[1]) == NULL) {
|
---|
734 | i = umask(0);
|
---|
735 | umask(i);
|
---|
736 | for (n=3*4; (n-=3) >= 0;)
|
---|
737 | putc('0'+((i>>n)&07));
|
---|
738 | putc('\n');
|
---|
739 | } else {
|
---|
740 | for (n=0; *cp>='0' && *cp<='9'; cp++)
|
---|
741 | n = n*8 + (*cp-'0');
|
---|
742 | umask(n);
|
---|
743 | }
|
---|
744 | return(0);
|
---|
745 | }
|
---|
746 |
|
---|
747 | int
|
---|
748 | doexec(t)
|
---|
749 | register struct op *t;
|
---|
750 | {
|
---|
751 | register i;
|
---|
752 | jmp_buf ex;
|
---|
753 | xint *ofail;
|
---|
754 |
|
---|
755 | t->ioact = NULL;
|
---|
756 | for(i = 0; (t->words[i]=t->words[i+1]) != NULL; i++)
|
---|
757 | ;
|
---|
758 | if (i == 0)
|
---|
759 | return(1);
|
---|
760 | execflg = 1;
|
---|
761 | ofail = failpt;
|
---|
762 | if (setjmp(failpt = ex) == 0)
|
---|
763 | execute(t, NOPIPE, NOPIPE, FEXEC);
|
---|
764 | failpt = ofail;
|
---|
765 | execflg = 0;
|
---|
766 | return(1);
|
---|
767 | }
|
---|
768 |
|
---|
769 | int
|
---|
770 | dodot(t)
|
---|
771 | struct op *t;
|
---|
772 | {
|
---|
773 | register i;
|
---|
774 | register char *sp, *tp;
|
---|
775 | char *cp;
|
---|
776 |
|
---|
777 | if ((cp = t->words[1]) == NULL)
|
---|
778 | return(0);
|
---|
779 | sp = any('/', cp)? ":": path->value;
|
---|
780 | while (*sp) {
|
---|
781 | tp = e.linep;
|
---|
782 | while (*sp && (*tp = *sp++) != ':')
|
---|
783 | tp++;
|
---|
784 | if (tp != e.linep)
|
---|
785 | *tp++ = '/';
|
---|
786 | for (i = 0; (*tp++ = cp[i++]) != '\0';)
|
---|
787 | ;
|
---|
788 | if ((i = open(e.linep, 0)) >= 0) {
|
---|
789 | exstat = 0;
|
---|
790 | next(remap(i));
|
---|
791 | return(exstat);
|
---|
792 | }
|
---|
793 | }
|
---|
794 | prs(cp);
|
---|
795 | err(": not found");
|
---|
796 | return(-1);
|
---|
797 | }
|
---|
798 |
|
---|
799 | int
|
---|
800 | dowait(t)
|
---|
801 | struct op *t;
|
---|
802 | {
|
---|
803 | register i;
|
---|
804 | register char *cp;
|
---|
805 |
|
---|
806 | if ((cp = t->words[1]) != NULL) {
|
---|
807 | i = getn(cp);
|
---|
808 | if (i == 0)
|
---|
809 | return(0);
|
---|
810 | } else
|
---|
811 | i = -1;
|
---|
812 | setstatus(waitfor(i, 1));
|
---|
813 | return(0);
|
---|
814 | }
|
---|
815 |
|
---|
816 | int
|
---|
817 | doread(t)
|
---|
818 | struct op *t;
|
---|
819 | {
|
---|
820 | register char *cp, **wp;
|
---|
821 | register nb;
|
---|
822 | register int nl = 0;
|
---|
823 |
|
---|
824 | if (t->words[1] == NULL) {
|
---|
825 | err("Usage: read name ...");
|
---|
826 | return(1);
|
---|
827 | }
|
---|
828 | for (wp = t->words+1; *wp; wp++) {
|
---|
829 | for (cp = e.linep; !nl && cp < elinep-1; cp++)
|
---|
830 | if ((nb = read(0, cp, sizeof(*cp))) != sizeof(*cp) ||
|
---|
831 | (nl = (*cp == '\n')) ||
|
---|
832 | (wp[1] && any(*cp, ifs->value)))
|
---|
833 | break;
|
---|
834 | *cp = 0;
|
---|
835 | if (nb <= 0)
|
---|
836 | break;
|
---|
837 | setval(lookup(*wp), e.linep);
|
---|
838 | }
|
---|
839 | return(nb <= 0);
|
---|
840 | }
|
---|
841 |
|
---|
842 | int
|
---|
843 | doeval(t)
|
---|
844 | register struct op *t;
|
---|
845 | {
|
---|
846 | return(RUN(awordlist, t->words+1, wdchar));
|
---|
847 | }
|
---|
848 |
|
---|
849 | int
|
---|
850 | dotrap(t)
|
---|
851 | register struct op *t;
|
---|
852 | {
|
---|
853 | register int n, i;
|
---|
854 | register int resetsig;
|
---|
855 |
|
---|
856 | if (t->words[1] == NULL) {
|
---|
857 | for (i=0; i<=_NSIG; i++)
|
---|
858 | if (trap[i]) {
|
---|
859 | prn(i);
|
---|
860 | prs(": ");
|
---|
861 | prs(trap[i]);
|
---|
862 | prs("\n");
|
---|
863 | }
|
---|
864 | return(0);
|
---|
865 | }
|
---|
866 | resetsig = digit(*t->words[1]);
|
---|
867 | for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) {
|
---|
868 | n = getsig(t->words[i]);
|
---|
869 | xfree(trap[n]);
|
---|
870 | trap[n] = 0;
|
---|
871 | if (!resetsig) {
|
---|
872 | if (*t->words[1] != '\0') {
|
---|
873 | trap[n] = strsave(t->words[1], 0);
|
---|
874 | setsig(n, sig);
|
---|
875 | } else
|
---|
876 | setsig(n, SIG_IGN);
|
---|
877 | } else {
|
---|
878 | if (talking)
|
---|
879 | if (n == SIGINT)
|
---|
880 | setsig(n, onintr);
|
---|
881 | else
|
---|
882 | setsig(n, n == SIGQUIT ? SIG_IGN
|
---|
883 | : SIG_DFL);
|
---|
884 | else
|
---|
885 | setsig(n, SIG_DFL);
|
---|
886 | }
|
---|
887 | }
|
---|
888 | return(0);
|
---|
889 | }
|
---|
890 |
|
---|
891 | int
|
---|
892 | getsig(s)
|
---|
893 | char *s;
|
---|
894 | {
|
---|
895 | register int n;
|
---|
896 |
|
---|
897 | if ((n = getn(s)) < 0 || n > _NSIG) {
|
---|
898 | err("trap: bad signal number");
|
---|
899 | n = 0;
|
---|
900 | }
|
---|
901 | return(n);
|
---|
902 | }
|
---|
903 |
|
---|
904 | void
|
---|
905 | setsig(n, f)
|
---|
906 | register n;
|
---|
907 | _PROTOTYPE(void (*f), (int));
|
---|
908 | {
|
---|
909 | if (n == 0)
|
---|
910 | return;
|
---|
911 | if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
|
---|
912 | ourtrap[n] = 1;
|
---|
913 | signal(n, f);
|
---|
914 | }
|
---|
915 | }
|
---|
916 |
|
---|
917 | int
|
---|
918 | getn(as)
|
---|
919 | char *as;
|
---|
920 | {
|
---|
921 | register char *s;
|
---|
922 | register n, m;
|
---|
923 |
|
---|
924 | s = as;
|
---|
925 | m = 1;
|
---|
926 | if (*s == '-') {
|
---|
927 | m = -1;
|
---|
928 | s++;
|
---|
929 | }
|
---|
930 | for (n = 0; digit(*s); s++)
|
---|
931 | n = (n*10) + (*s-'0');
|
---|
932 | if (*s) {
|
---|
933 | prs(as);
|
---|
934 | err(": bad number");
|
---|
935 | }
|
---|
936 | return(n*m);
|
---|
937 | }
|
---|
938 |
|
---|
939 | int
|
---|
940 | dobreak(t)
|
---|
941 | struct op *t;
|
---|
942 | {
|
---|
943 | return(brkcontin(t->words[1], 1));
|
---|
944 | }
|
---|
945 |
|
---|
946 | int
|
---|
947 | docontinue(t)
|
---|
948 | struct op *t;
|
---|
949 | {
|
---|
950 | return(brkcontin(t->words[1], 0));
|
---|
951 | }
|
---|
952 |
|
---|
953 | static int
|
---|
954 | brkcontin(cp, val)
|
---|
955 | register char *cp;
|
---|
956 | int val;
|
---|
957 | {
|
---|
958 | register struct brkcon *bc;
|
---|
959 | register nl;
|
---|
960 |
|
---|
961 | nl = cp == NULL? 1: getn(cp);
|
---|
962 | if (nl <= 0)
|
---|
963 | nl = 999;
|
---|
964 | do {
|
---|
965 | if ((bc = brklist) == NULL)
|
---|
966 | break;
|
---|
967 | brklist = bc->nextlev;
|
---|
968 | } while (--nl);
|
---|
969 | if (nl) {
|
---|
970 | err("bad break/continue level");
|
---|
971 | return(1);
|
---|
972 | }
|
---|
973 | isbreak = val;
|
---|
974 | longjmp(bc->brkpt, 1);
|
---|
975 | /* NOTREACHED */
|
---|
976 | }
|
---|
977 |
|
---|
978 | int
|
---|
979 | doexit(t)
|
---|
980 | struct op *t;
|
---|
981 | {
|
---|
982 | register char *cp;
|
---|
983 |
|
---|
984 | execflg = 0;
|
---|
985 | if ((cp = t->words[1]) != NULL)
|
---|
986 | setstatus(getn(cp));
|
---|
987 | leave();
|
---|
988 | /* NOTREACHED */
|
---|
989 | }
|
---|
990 |
|
---|
991 | int
|
---|
992 | doexport(t)
|
---|
993 | struct op *t;
|
---|
994 | {
|
---|
995 | rdexp(t->words+1, export, EXPORT);
|
---|
996 | return(0);
|
---|
997 | }
|
---|
998 |
|
---|
999 | int
|
---|
1000 | doreadonly(t)
|
---|
1001 | struct op *t;
|
---|
1002 | {
|
---|
1003 | rdexp(t->words+1, ronly, RONLY);
|
---|
1004 | return(0);
|
---|
1005 | }
|
---|
1006 |
|
---|
1007 | static void
|
---|
1008 | rdexp(wp, f, key)
|
---|
1009 | register char **wp;
|
---|
1010 | void (*f)();
|
---|
1011 | int key;
|
---|
1012 | {
|
---|
1013 | if (*wp != NULL) {
|
---|
1014 | for (; *wp != NULL; wp++)
|
---|
1015 | if (checkname(*wp))
|
---|
1016 | (*f)(lookup(*wp));
|
---|
1017 | else
|
---|
1018 | badid(*wp);
|
---|
1019 | } else
|
---|
1020 | putvlist(key, 1);
|
---|
1021 | }
|
---|
1022 |
|
---|
1023 | static void
|
---|
1024 | badid(s)
|
---|
1025 | register char *s;
|
---|
1026 | {
|
---|
1027 | prs(s);
|
---|
1028 | err(": bad identifier");
|
---|
1029 | }
|
---|
1030 |
|
---|
1031 | int
|
---|
1032 | doset(t)
|
---|
1033 | register struct op *t;
|
---|
1034 | {
|
---|
1035 | register struct var *vp;
|
---|
1036 | register char *cp;
|
---|
1037 | register n;
|
---|
1038 |
|
---|
1039 | if ((cp = t->words[1]) == NULL) {
|
---|
1040 | for (vp = vlist; vp; vp = vp->next)
|
---|
1041 | varput(vp->name, 1);
|
---|
1042 | return(0);
|
---|
1043 | }
|
---|
1044 | if (*cp == '-') {
|
---|
1045 | /* bad: t->words++; */
|
---|
1046 | for(n = 0; (t->words[n]=t->words[n+1]) != NULL; n++)
|
---|
1047 | ;
|
---|
1048 | if (*++cp == 0)
|
---|
1049 | flag['x'] = flag['v'] = 0;
|
---|
1050 | else
|
---|
1051 | for (; *cp; cp++)
|
---|
1052 | switch (*cp) {
|
---|
1053 | case 'e':
|
---|
1054 | if (!talking)
|
---|
1055 | flag['e']++;
|
---|
1056 | break;
|
---|
1057 |
|
---|
1058 | default:
|
---|
1059 | if (*cp>='a' && *cp<='z')
|
---|
1060 | flag[*cp]++;
|
---|
1061 | break;
|
---|
1062 | }
|
---|
1063 | setdash();
|
---|
1064 | }
|
---|
1065 | if (t->words[1]) {
|
---|
1066 | t->words[0] = dolv[0];
|
---|
1067 | for (n=1; t->words[n]; n++)
|
---|
1068 | setarea((char *)t->words[n], 0);
|
---|
1069 | dolc = n-1;
|
---|
1070 | dolv = t->words;
|
---|
1071 | setval(lookup("#"), putn(dolc));
|
---|
1072 | setarea((char *)(dolv-1), 0);
|
---|
1073 | }
|
---|
1074 | return(0);
|
---|
1075 | }
|
---|
1076 |
|
---|
1077 | void
|
---|
1078 | varput(s, out)
|
---|
1079 | register char *s;
|
---|
1080 | int out;
|
---|
1081 | {
|
---|
1082 | if (letnum(*s)) {
|
---|
1083 | write(out, s, strlen(s));
|
---|
1084 | write(out, "\n", 1);
|
---|
1085 | }
|
---|
1086 | }
|
---|
1087 |
|
---|
1088 |
|
---|
1089 | #define SECS 60L
|
---|
1090 | #define MINS 3600L
|
---|
1091 |
|
---|
1092 | int
|
---|
1093 | dotimes()
|
---|
1094 | {
|
---|
1095 | struct tms tbuf;
|
---|
1096 |
|
---|
1097 | times(&tbuf);
|
---|
1098 |
|
---|
1099 | prn((int)(tbuf.tms_cutime / MINS));
|
---|
1100 | prs("m");
|
---|
1101 | prn((int)((tbuf.tms_cutime % MINS) / SECS));
|
---|
1102 | prs("s ");
|
---|
1103 | prn((int)(tbuf.tms_cstime / MINS));
|
---|
1104 | prs("m");
|
---|
1105 | prn((int)((tbuf.tms_cstime % MINS) / SECS));
|
---|
1106 | prs("s\n");
|
---|
1107 | return(0);
|
---|
1108 | }
|
---|
1109 |
|
---|
1110 | struct builtin {
|
---|
1111 | char *command;
|
---|
1112 | int (*fn)();
|
---|
1113 | };
|
---|
1114 | static struct builtin builtin[] = {
|
---|
1115 | ":", dolabel,
|
---|
1116 | "cd", dochdir,
|
---|
1117 | "shift", doshift,
|
---|
1118 | "exec", doexec,
|
---|
1119 | "wait", dowait,
|
---|
1120 | "read", doread,
|
---|
1121 | "eval", doeval,
|
---|
1122 | "trap", dotrap,
|
---|
1123 | "break", dobreak,
|
---|
1124 | "continue", docontinue,
|
---|
1125 | "exit", doexit,
|
---|
1126 | "export", doexport,
|
---|
1127 | "readonly", doreadonly,
|
---|
1128 | "set", doset,
|
---|
1129 | ".", dodot,
|
---|
1130 | "umask", doumask,
|
---|
1131 | "login", dologin,
|
---|
1132 | "newgrp", dologin,
|
---|
1133 | "times", dotimes,
|
---|
1134 | 0,
|
---|
1135 | };
|
---|
1136 |
|
---|
1137 | int (*inbuilt(s))()
|
---|
1138 | register char *s;
|
---|
1139 | {
|
---|
1140 | register struct builtin *bp;
|
---|
1141 |
|
---|
1142 | for (bp = builtin; bp->command != NULL; bp++)
|
---|
1143 | if (strcmp(bp->command, s) == 0)
|
---|
1144 | return(bp->fn);
|
---|
1145 | return((int(*)())NULL);
|
---|
1146 | }
|
---|
1147 |
|
---|