|
|
1.1 root 1: /*
2: * sh/exec3.c
3: * Bourne shell.
4: * Builtin commands.
5: */
6:
7: #include "sh.h"
8: #include <sys/times.h>
9: #include <sys/const.h> /* HZ defined here */
10:
11: #define HOUR (60L*60L*HZ)
12: #define MINUTE (60L*HZ)
13: #define SECOND HZ
14:
15: char *cd();
16:
17: extern s_colon();
18: extern s_dot();
19: extern s_break();
20: #define s_continue s_break
21: extern s_cd();
22: extern s_dirs();
23: extern s_eval();
24: extern s_exec();
25: extern s_exit();
26: extern s_export();
27: extern s_login();
28: #define s_newgrp s_login
29: extern s_popd();
30: extern s_pushd();
31: extern s_read();
32: #define s_readonly s_export
33: extern s_set();
34: extern s_shift();
35: extern s_times();
36: extern s_trap();
37: extern s_umask();
38: extern s_wait();
39: #define SNULL ((int (*)())0)
40:
41: typedef struct {
42: int i_hash;
43: char *i_name;
44: int (*i_func)();
45: } INLINE;
46:
47: INLINE inls[] = {
48: 0, ":", s_colon,
49: 0, ".", s_dot,
50: 0, "break", s_break,
51: 0, "continue", s_continue,
52: 0, "cd", s_cd,
53: 0, "dirs", s_dirs,
54: 0, "eval", s_eval,
55: 0, "exec", s_exec,
56: 0, "exit", s_exit,
57: 0, "export", s_export,
58: 0, "login", s_login,
59: 0, "newgrp", s_newgrp,
60: 0, "popd", s_popd,
61: 0, "pushd", s_pushd,
62: 0, "read", s_read,
63: 0, "readonly", s_readonly,
64: 0, "set", s_set,
65: 0, "shift", s_shift,
66: 0, "times", s_times,
67: 0, "trap", s_trap,
68: 0, "umask", s_umask,
69: 0, "wait", s_wait,
70: 0, NULL, SNULL
71: };
72:
73: inline()
74: {
75: register int (*s_func)();
76: register INLINE *ip;
77: register int ahash;
78: int pid, status;
79:
80: if (inls[0].i_hash==0)
81: for (ip=inls; ip->i_name!=NULL; ip++)
82: ip->i_hash = ihash(ip->i_name);
83: if (nargv[0] == NULL)
84: return 0;
85: ahash = ihash(nargv[0]);
86: for (ip=inls; ip->i_name!=NULL; ip++)
87: if (ip->i_hash==ahash && strcmp(nargv[0], ip->i_name)==0)
88: break;
89: if ((s_func=ip->i_func) == SNULL)
90: return 0;
91: if (*niovp != NULL && s_func != s_exec) {
92: /* Redirection with built-in command. */
93: /* Allowed only with eval, export, readonly, set, times. */
94: if (s_func != s_eval
95: && s_func != s_export
96: && s_func != s_set
97: && s_func != s_times) {
98: eredir();
99: slret = 1;
100: return 1;
101: }
102: if ((pid = clone()) == 0) {
103: /* Perform redirection in child process. */
104: if (redirect(niovp) < 0)
105: slret = 1;
106: else if (s_func == s_eval)
107: slret = (*s_func)();
108: else {
109: /* Kludge stderr output to stdout. */
110: dup2(1, 2);
111: close(1);
112: slret = (*s_func)();
113: }
114: exit(slret);
115: /* NOTREACHED */
116: } else {
117: /* Parent waits for child and takes its exit status. */
118: while (wait(&status) != pid)
119: ;
120: slret = status >> 8;
121: }
122: } else
123: slret = (*s_func)();
124: return 1;
125: }
126:
127: ihash(cp)
128: register char *cp;
129: {
130: register int i;
131: for (i=0; *cp; i+=*cp++);
132: return i;
133: }
134:
135: /*
136: * Actual builtin functions.
137: */
138: s_colon()
139: {
140: return 0;
141: }
142:
143: s_dot()
144: {
145: if (nargc==2) {
146: ffind(NULL);
147: if (ffind(vpath, nargv[1], 4))
148: return session(SFILE, duplstr(strt, 0));
149: else {
150: ecantfind(nargv[1]);
151: return 1;
152: }
153: } else if (nargc==1)
154: return 0;
155: syntax();
156: return 1;
157: }
158:
159: s_break()
160: {
161: register CON *cp;
162: register int t;
163: register int n;
164: int ret;
165:
166: ret = nargv[0][0]=='b' ? 2 : 1;
167: n = nargc>1 ? atoi(nargv[1]) : 1;
168: for (cp = sesp->s_con; cp; cp = cp->c_next) {
169: t = cp->c_node->n_type;
170: if ((t==NWHILE || t==NFOR || t==NUNTIL) && --n == 0) {
171: sesp->s_con = cp;
172: longjmp(cp->c_envl, ret);
173: break;
174: }
175: freebuf(cp->c_bpp);
176: }
177: printe("%s out of bounds", ret==1 ? "Continue" : "Break");
178: }
179:
180: /* s_continue is overlaid with s_break */
181:
182: s_cd()
183: {
184: register char *dir;
185:
186: if ((dir = cd((nargc<2) ? vhome : nargv[1])) == NULL)
187: return -1; /* cd failed */
188: if (dstack[dstkp] != NULL)
189: sfree(dstack[dstkp]);
190: dstack[dstkp] = duplstr(dir, 1); /* update dir stack */
191: return 0;
192: }
193:
194: s_dirs()
195: {
196: register int i;
197:
198: for (i = dstkp; i >= 0; i--)
199: fprintf(stderr, "%s ", dstack[i]);
200: fputc('\n', stderr);
201: }
202:
203: s_eval()
204: {
205: if (nargc>1)
206: return session(SARGV, ++nargv);
207: else
208: return 0;
209: }
210:
211: s_exec()
212: {
213: if (redirect(niovp) < 0) {
214: if (nargc>1) {
215: exit(1);
216: NOTREACHED;
217: }
218: return 1;
219: }
220: if (nargc==1)
221: return 0;
222: if (no1flag)
223: cleanup(2, NULL);
224: dflttrp(ICMD);
225: ++nargv;
226: --nargc;
227: nenvp = envlvar(nenvp);
228: flexec();
229: exit(1);
230: NOTREACHED;
231: }
232:
233: s_exit()
234: {
235: if (nargc > 1)
236: slret = atoi(nargv[1]);
237: reset(RUEXITS);
238: NOTREACHED;
239: }
240:
241: s_export()
242: {
243: register int flag;
244: register char **varv;
245:
246: flag = nargv[0][0]=='e' ? VEXP : VRDO;
247: if (nargc < 2)
248: tellvar(flag);
249: else
250: for (varv=++nargv; *varv; )
251: if (namevar(*varv))
252: flagvar(*varv++, flag);
253: else
254: eillvar(*varv++);
255: return 0;
256: }
257:
258: s_login()
259: {
260: register char *cmd;
261:
262: cmd = nargv[0][0]=='l' ? "/bin/login" : "/bin/newgrp";
263: execve(cmd, nargv, envlvar(nenvp));
264: ecantfind(cmd);
265: return 1;
266: }
267:
268: /* s_newgrp is overlaid with s_login */
269:
270: s_popd()
271: {
272: register int i, j, n, ret;
273:
274: if (nargc == 1)
275: return popd();
276: /*
277: * Kludge to pop one or more specific dir stack elements.
278: * Do args backwards so e.g. "popd 2 3 4" works as expected.
279: * Internal indices [0, dstkp] are user indices [dstkp, 0].
280: */
281: for (ret = 0, i = nargc-1; i > 0; i--) {
282: if ((n = atoi(nargv[i])) == 0)
283: ret |= popd();
284: else if (n < 0 || n > dstkp) {
285: printe("Illegal arg: %d", n);
286: ret = -1;
287: continue;
288: } else {
289: j = dstkp - n;
290: if (dstack[j] != NULL)
291: sfree(dstack[j]);
292: for ( ; j < dstkp; j++)
293: dstack[j] = dstack[j+1];
294: --dstkp;
295: }
296: }
297: return ret;
298: }
299:
300: s_pushd()
301: {
302: register char *dir;
303: register int i, ret;
304:
305: if (nargc == 1) {
306: /* Exchange top two stack elements. */
307: if (dstkp == 0)
308: return 1; /* only one element on stack */
309: dir = dstack[dstkp-1];
310: dstack[dstkp-1] = dstack[dstkp];
311: dstack[dstkp] = dir; /* exchange top two */
312: return ((cd(dir) == NULL) ? -1 : 0); /* and cd accordingly */
313: }
314: /* Push one or more directories to stack. */
315: for (ret = 0, i = 1; i < nargc; i++)
316: ret |= pushd(nargv[i]);
317: return ret;
318: }
319:
320: s_read()
321: {
322: SES s;
323: register int n, c;
324: register char **vp;
325: int eol;
326:
327: s.s_type = SSTR;
328: s.s_flag = 0;
329: s.s_ifp = stdin;
330: s.s_next = sesp;
331: sesp = &s;
332: for (eol=0, vp=++nargv, n=--nargc; n; n-=1, vp+=1) {
333: if (n==1 && ! eol) {
334: strp = strt;
335: c = collect('\n', 2);
336: if (c == '\n')
337: --strp;
338: *strp = '\0';
339: } else if (! eol) {
340: readflag = 1;
341: c = yylex();
342: readflag = 0;
343: } else
344: *strt = '\0';
345: if (namevar(*vp))
346: assnvar(*vp, duplstr(strt, 0));
347: else
348: eillvar(*vp);
349: eol = c=='\n' || c==EOF;
350: }
351: sesp = s.s_next;
352: return c==EOF;
353: }
354:
355: /* s_readonly overlaid with s_export */
356:
357: s_set()
358: {
359: if (nargc < 2) {
360: tellvar(0);
361: return 0;
362: }
363: return set(nargc, nargv, 0);
364: }
365:
366: s_shift()
367: {
368: register int n;
369:
370: n = nargc > 1 ? atoi(nargv[1]) : 1;
371: while (n > 0 && sargc > 0) {
372: n -= 1;
373: sargc -= 1;
374: sargp += 1;
375: }
376: return n!=0;
377: }
378:
379: s_times()
380: {
381: #if _I386
382: #define tb_cutime tms_cutime
383: #define tb_cstime tms_cstime
384: struct tms tb;
385: #else
386: struct tbuffer tb;
387:
388: #endif
389:
390: times(&tb);
391: ptime(tb.tb_cutime);
392: ptime(tb.tb_cstime);
393: prints("\n");
394: return 0;
395: }
396:
397: s_trap()
398: {
399: register char **vp;
400: register char *cp;
401: register int err;
402:
403: err = 0;
404: if (nargc==1)
405: return telltrp();
406: vp = ++nargv;
407: cp = *vp;
408: if (class(cp[0], MDIGI)
409: && (cp[1]=='\0' || (class(cp[1], MDIGI) && cp[2]=='\0')))
410: cp = NULL;
411: else
412: ++vp;
413: while (*vp) {
414: if (class(vp[0][0], MDIGI))
415: err |= setstrp(atoi(*vp++), cp);
416: else {
417: printe("Bad trap: %s", *vp++);
418: err |= 1;
419: }
420: }
421: return err;
422: }
423:
424: s_umask()
425: {
426: if (nargc < 2)
427: prints("%03o\n", ufmask);
428: else
429: umask(ufmask = atoi(nargv[1]));
430: return 0;
431: }
432:
433: s_wait()
434: {
435: register int f;
436:
437: f = (nargc > 1) ? atoi(nargv[1]) : 0;
438: if (f > 0)
439: f = -f;
440: waitc(f);
441: return slret;
442: }
443:
444: /*
445: * Change to given directory.
446: * Update global variable CWD accordingly.
447: * Return NULL if bad, otherwise full pathname of the directory.
448: */
449: char *
450: cd(dir) register char *dir;
451: {
452: if (chdir(dir) < 0) {
453: printe("%s: bad directory", dir);
454: return NULL;
455: }
456: if (*dir != '/') {
457: /*
458: * Find an absolute pathname for the dstack and $CWD.
459: * The directory now in dstack[dstkp] is "." if _getwd() failed
460: * for any reason (e.g., the user lacks search permission
461: * down the path to "/", or "." was rm'ed by another process).
462: * Avoid _getwd() in this case, it can undo the chdir() above.
463: */
464: if ((strcmp(dstack[dstkp], ".") == 0)
465: || ((dir = _getwd()) == NULL))
466: return NULL;
467: }
468: assnvar("CWD", dir);
469: return dir;
470: }
471:
472: /*
473: * Pop the directory stack and change to the previous stacked directory.
474: */
475: popd()
476: {
477: if (dstkp == 0) {
478: printe("Directory stack underflow");
479: return -1;
480: }
481: if (dstack[dstkp] != NULL)
482: sfree(dstack[dstkp]);
483: return (cd(dstack[--dstkp]) == NULL ? -1 : 0);
484: }
485:
486: /*
487: * Change to given directory and add it to the directory stack.
488: */
489: pushd(dir) register char *dir;
490: {
491: if ((dir = cd(dir)) == NULL)
492: return -1; /* cd failed */
493: if (++dstkp >= DSTACKN) {
494: --dstkp;
495: printe("Directory stack overflow");
496: return -1;
497: }
498: dstack[dstkp] = duplstr(dir, 1);
499: return 0;
500: }
501:
502: /*
503: * The set command. This is also called from `main' to set
504: * options from the command line. In this case `flag' is
505: * set.
506: */
507: set(argc, argv, flag)
508: register char *argv[];
509: {
510: int n;
511: register char *cp;
512:
513: if (flag) {
514: cflag = 0;
515: iflag = 0;
516: sflag = 0;
517: }
518: n = 0;
519: if (argc > 0)
520: n = 1;
521: if (argc>1 && argv[1][0]=='-') {
522: register char *fp;
523:
524: n++;
525: for (cp = &argv[1][1]; *cp; cp++) {
526: if ((fp=index(shfnams, *cp)) == NULL
527: || (fp+=shflags-shfnams) == NULL
528: || (fp != &lgnflag && fp > &xflag && flag == 0))
529: printe("-%c: Bad option", *cp);
530: else if (fp != &lgnflag)
531: *fp = *cp;
532: }
533: if (cp == &argv[1][1]) {
534: vflag = 0;
535: xflag = 0;
536: }
537: if (flag == 0 && argc == 2)
538: return errflag;
539: }
540: if (errflag)
541: return 1;
542: if (sargv != NULL)
543: vfree(sargv);
544: sargv = vdupl(argv);
545: sargc = argc - n;
546: sargp = sargv + n;
547: return 0;
548: }
549:
550: /*
551: * print the time as XmX.Xs
552: * as fixed by Randall.
553: */
554: ptime(t)
555: long t;
556: {
557: register int ticks, tenths, seconds;
558:
559: prints("%Dm", t/MINUTE);
560: ticks = t%MINUTE;
561: seconds = ticks/SECOND;
562: tenths = (ticks%SECOND + SECOND/20)/(SECOND/10);
563: if (tenths == 10) {
564: tenths = 0;
565: seconds++;
566: }
567: prints("%d.%ds ", seconds, tenths);
568: }
569:
570: /* end of sh/exec3.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.