BSD 3 development
[unix-history] / .ref-BSD-2 / src / csh / sh.c
CommitLineData
07c89ddd
BJ
1/* Copyright (c) 1979 Regents of the University of California */
2#include "sh.h"
3
4/*
5 * C Shell
6 *
7 * Bill Joy, UC Berkeley
8 * October, 1978
9 */
10
11char *pathlist[] = { SRCHPATH, 0 };
12
13main(c, av)
14 int c;
15 char **av;
16{
17 register char **v, *cp;
18 int nofile = 0;
19 int reenter = 0;
20 bool nverbose = 0, nexececho = 0, quitit = 0, fast = 0, prompt = 1;
21 char *hp;
22
23 settimes(); /* Immed. estab. timing base */
24 hp = getenv("HOME");
25 v = av;
26 if (eq(v[0], "a.out")) /* A.out's are quittable */
27 quitit = 1;
28 uid = getuid();
29#ifdef V6
30 loginsh = eq(*v, "-"); /* To do .login/.logout */
31#else
32 loginsh = **v == '-';
33#endif
34 if (loginsh)
35 time(&chktim);
36
37 /*
38 * Move the descriptors to safe places.
39 * The variable didfds is 0 while we have only FSH* to work with.
40 * When didfds is true, we have 0,1,2 and prefer to use these.
41 */
42 initdesc();
43
44 /*
45 * Initialize the shell variables.
46 * ARGV and PROMPT are initialized later.
47 * STATUS is also munged in several places.
48 * CHILD is munged when forking/waiting
49 */
50
51 set("status", "0");
52 if (hp == 0)
53 fast++; /* No home -> can't read scripts */
54 else
55 set("home", hp);
56 if (uid == 0)
57 pathlist[0] = "/etc";
58 set1("path", saveblk(pathlist), &shvhed);
59 /*
60 * Re-initialize path if set in environment
61 *
62 cp = getenv("PATH");
63 if (cp != 0) {
64 register int i = 0;
65 register char *dp;
66 register char **pv;
67
68 for (dp = cp; *dp; dp++)
69 if (*dp == ':')
70 i++;
71 pv = calloc(i+1, sizeof (char **));
72 dp = cp;
73 i = 0;
74 while (*dp) {
75 if (*dp == ':') {
76 *dp = 0;
77 pv[i++] = savestr(cp);
78 *dp = ':';
79 } else if (*dp == 0) {
80 pv[i++] = savestr(cp);
81 break;
82 }
83 dp++;
84 }
85 pv[i] = 0;
86 set1("path", pv, &shvhed);
87 }
88*/
89 set("shell", SHELLPATH);
90
91 doldol = putn(getpid()); /* For $$ */
92 shtemp = strspl("/tmp/sh", doldol); /* For << */
93
94 /*
95 * Record the interrupt states from the parent process.
96 * If the parent is non-interruptible our hand must be forced
97 * or we (and our children) won't be either.
98 * Our children inherit termination from our parent.
99 * We catch it only if we are the login shell.
100 */
101 parintr = signal(SIGINT, SIG_IGN); /* parents interruptibility */
102 signal(SIGINT, parintr); /* ... restore */
103 parterm = signal(SIGTERM, SIG_IGN); /* parents terminability */
104 signal(SIGTERM, parterm); /* ... restore */
105
106 /*
107 * Process the arguments.
108 *
109 * Note that processing of -v/-x is actually delayed till after
110 * script processing.
111 *
112 * We set the first character of our name to be '-' if we are
113 * a shell running interruptible commands. Many programs which
114 * examine ps'es use this to filter such shells out.
115 */
116 c--, v++;
117 while (c > 0 && (cp = v[0])[0] == '-') {
118 do switch (*cp++) {
119
120 case 0: /* - Interruptible, no prompt */
121 prompt = 0;
122 **av = '-';
123 nofile++;
124 break;
125
126 case 'c': /* -c Command input from arg */
127 if (c == 1)
128 exit(0);
129 c--, v++;
130 arginp = v[0];
131 prompt = 0;
132 nofile++;
133 break;
134
135 case 'e': /* -e Exit on any error */
136 exiterr++;
137 break;
138
139 case 'f': /* -f Fast start */
140 fast++;
141 break;
142
143 case 'i': /* -i Interactive, even if !intty */
144 intact++;
145 **av = '-';
146 nofile++;
147 break;
148
149 case 'n': /* -n Don't execute */
150 noexec++;
151 break;
152
153 case 'q': /* -q (Undoc'd) ... die on quit */
154 quitit = 1;
155 break;
156
157 case 's': /* -s Read from std input */
158 nofile++;
159 if (isatty(SHIN))
160 **v = '-';
161 break;
162
163 case 't': /* -t Read one line from input */
164 onelflg = 2;
165 if (isatty(SHIN))
166 **v = '-';
167 prompt = 0;
168 nofile++;
169 break;
170
171 case 'v': /* -v Echo hist expanded input */
172 nverbose = 1; /* ... later */
173 break;
174
175 case 'x': /* -x Echo just before execution */
176 nexececho = 1; /* ... later */
177 break;
178
179 case 'V': /* -V Echo hist expanded input */
180 setNS("verbose"); /* NOW! */
181 break;
182
183 case 'X': /* -X Echo just before execution */
184 setNS("echo"); /* NOW! */
185 break;
186
187 } while (*cp);
188 v++, c--;
189 }
190
191 if (quitit) /* With all due haste, for debugging */
192 signal(SIGQUIT, SIG_DFL);
193
194 /*
195 * Unless prevented by -, -c, -i, -s, or -t, if there
196 * are remaining arguments the first of them is the name
197 * of a shell file from which to read commands.
198 */
199 if (nofile == 0 && c > 0) {
200 nofile = open(v[0], 0);
201 if (nofile < 0) {
202 child++; /* So this ... */
203 Perror(v[0]); /* ... doesn't return */
204 }
205 file = v[0];
206 SHIN = dmove(nofile, FSHIN); /* Replace FSHIN */
207 prompt = 0;
208 c--, v++;
209 }
210
211 /*
212 * Consider input a tty if it really is or we are interactive.
213 */
214 intty = intact || isatty(SHIN);
215#ifdef TELL
216 settell();
217#endif
218 /*
219 * Commands are interruptible if we are interactive
220 * or the process which created us was.
221 */
222 if (intact || parintr == SIG_DFL)
223 **av = '-';
224
225 /*
226 * Save the remaining arguments in ARGV.
227 * Normally the system-supplied argument list is ok as
228 * a zero terminated value block.
229 * On some version 6 systems, it is -1 terminated and setting it
230 * to zero messes up "ps" so we change it to zero, copy
231 * the block of pointers, and put it back the way it was.
232 */
233/*
234 if (c == 0)
235 set("argv", 0);
236 else
237 */
238 if ((int) v[c] == -1) {
239 /* ick */
240 v[c] = 0, setq("argv", copyblk(v), &shvhed), v[c] = (char *) -1;
241 } else
242 setq("argv", v, &shvhed);
243
244 /*
245 * Set up the prompt.
246 */
247 if (prompt)
248 set("prompt", uid == 0 ? "# " : "% ");
249
250 /*
251 * If we are an interactive shell, then start fiddling
252 * with the signals; this is a tricky game.
253 */
254 if (**av == '-') {
255 setintr++;
256 if (!quitit) /* Wary! */
257 signal(SIGQUIT, SIG_IGN);
258 signal(SIGINT, SIG_IGN);
259 signal(SIGTERM, SIG_IGN);
260 }
261
262 /*
263 * Set an exit here in case of an interrupt or error reading
264 * the shell start-up scripts.
265 */
266 setexit();
267 haderr = 0; /* In case second time through */
268 if (!fast && reenter == 0) {
269 reenter++;
270 /* Will have value("home") here because set fast if don't */
271 srccat(value("home"), "/.cshrc");
272 if (loginsh)
273#ifdef NOHELP
274 srccat("", ".login");
275#else
276 srccat(value("home"), "/.login");
277#endif
278 }
279
280 /*
281 * Now are ready for the -v and -x flags
282 */
283 if (nverbose)
284 setNS("verbose");
285 if (nexececho)
286 setNS("echo");
287
288 /*
289 * All the rest of the world is inside this call.
290 * The argument to process indicates whether it should
291 * catch "error unwinds". Thus if we are a interactive shell
292 * our call here will never return by being blown past on an error.
293 */
294 process(setintr);
295
296 /*
297 * Mop-up.
298 */
299 if (loginsh) {
300 printf("logout\n");
301 close(SHIN);
302 child++;
303 goodbye();
304 }
305 exitstat();
306}
307
308/*
309 * Source to the file which is the catenation of the argument names.
310 */
311srccat(cp, dp)
312 char *cp, *dp;
313{
314 register char *ep = strspl(cp, dp);
315 register int unit = dmove(open(ep, 0), -1);
316
317 /* ioctl(unit, FIOCLEX, NULL); */
318 xfree(ep);
319#ifdef INGRES
320 srcunit(unit, 0);
321#else
322 srcunit(unit, 1);
323#endif
324}
325
326/*
327 * Source to a unit. If onlyown it must be our file or
328 * we don't chance it. This occurs on ".cshrc"s and the like.
329 */
330srcunit(unit, onlyown)
331 register int unit;
332 bool onlyown;
333{
334 /* We have to push down a lot of state here */
335 /* All this could go into a structure */
336 int oSHIN = -1, oldintty = intty;
337 struct whyle *oldwhyl = whyles;
338 char *ogointr = gointr, *oarginp = arginp;
339 int oonelflg = onelflg;
340#ifdef TELL
341 bool otell = cantell;
342#endif
343 struct Bin saveB;
344
345 /* The (few) real local variables */
346 jmp_buf oldexit;
347 int reenter;
348 register int (*oldint)();
349
350 if (unit < 0)
351 return;
352 if (onlyown) {
353 struct stat stb;
354
355#ifdef CC
356 if (fstat(unit, &stb) < 0 || (stb.st_uid != uid && stb.st_uid != (uid &~ 0377))) {
357#endif
358#ifdef CORY
359 if (fstat(unit, &stb) < 0 || (stb.st_uid != uid && stb.st_uid != (uid &~ 0377))) {
360#endif
361#ifndef CC
362#ifndef CORY
363 if (fstat(unit, &stb) < 0 || stb.st_uid != uid) {
364#endif
365#endif
366 close(unit);
367 return;
368 }
369 }
370
371 /*
372 * There is a critical section here while we are pushing down the
373 * input stream since we have stuff in different structures.
374 * If we weren't careful an interrupt could corrupt SHIN's Bin
375 * structure and kill the shell.
376 *
377 * We could avoid the critical region by grouping all the stuff
378 * in a single structure and pointing at it to move it all at
379 * once. This is less efficient globally on many variable references
380 * however.
381 */
382 getexit(oldexit);
383 reenter = 0;
384 oldint = signal(SIGINT, SIG_IGN);
385 setexit();
386 reenter++;
387 if (reenter == 1) {
388 /* Setup the new values of the state stuff saved above */
389 copy(&saveB, &B, sizeof saveB);
390 fbuf = (char **) 0;
391 fseekp = feobp = fblocks = 0;
392 oSHIN = SHIN, SHIN = unit, arginp = 0, onelflg = 0;
393 intty = isatty(SHIN), whyles = 0, gointr = 0;
394 /*
395 * Now if we are allowing commands to be interrupted,
396 * we let ourselves be interrupted.
397 */
398 signal(SIGINT, setintr ? pintr : oldint);
399#ifdef TELL
400 settell();
401#endif
402 process(0); /* 0 -> blow away on errors */
403 }
404 signal(SIGINT, oldint);
405 if (oSHIN >= 0) {
406 register int i;
407
408 /* We made it to the new state... free up its storage */
409 /* This code could get run twice but xfree doesn't care */
410 for (i = 0; i < fblocks; i++)
411 xfree(fbuf[i]);
412 xfree(fbuf);
413
414 /* Reset input arena */
415 copy(&B, &saveB, sizeof B);
416
417 close(SHIN), SHIN = oSHIN;
418 arginp = oarginp, onelflg = oonelflg;
419 intty = oldintty, whyles = oldwhyl, gointr = ogointr;
420#ifdef TELL
421 cantell = otell;
422#endif
423 }
424
425 resexit(oldexit);
426 /*
427 * If process reset() (effectively an unwind) then
428 * we must also unwind.
429 */
430 if (reenter >= 2)
431 error(0);
432}
433
434goodbye()
435{
436
437 if (loginsh) {
438 signal(SIGQUIT, SIG_IGN);
439 signal(SIGINT, SIG_IGN);
440 signal(SIGTERM, SIG_IGN);
441 setintr = 0; /* No interrupts after "logout" */
442 if (adrof("home"))
443 srccat(value("home"), "/.logout");
444 }
445 exitstat();
446}
447
448exitstat()
449{
450
451 /*
452 * Note that if STATUS is corrupted (i.e. getn bombs)
453 * then error will exit directly because we poke child here.
454 * Otherwise we might continue unwarrantedly (sic).
455 */
456 child++;
457 exit(getn(value("status")));
458}
459
460/*
461 * Catch an interrupt, e.g. during lexical input.
462 * If we are an interactive shell, we reset the interrupt catch
463 * immediately. In any case we drain the shell output,
464 * and finally go through the normal error mechanism, which
465 * gets a chance to make the shell go away.
466 */
467pintr()
468{
469
470 if (setintr)
471 signal(SIGINT, SIG_IGN);
472 draino();
473
474 /*
475 * If we have an active "onintr" then we search for the label.
476 * Note that if one does "onintr -" then we shan't be interruptible
477 * so we needn't worry about that here.
478 */
479 if (gointr) {
480 search(ZGOTO, 0, gointr);
481 timflg = 0;
482 reset();
483 } else if (intty)
484 printf("\n"); /* Some like this, others don't */
485 error(0);
486}
487
488/*
489 * Process is the main driving routine for the shell.
490 * It runs all command processing, except for those within { ... }
491 * in expressions (which is run by a routine evalav in sh.exp.c which
492 * is a stripped down process), and `...` evaluation which is run
493 * also by a subset of this code in sh.glob.c in the routine backeval.
494 *
495 * The code here is a little strange because part of it is interruptible
496 * and hence freeing of structures appears to occur when none is necessary
497 * if this is ignored.
498 *
499 * Note that if catch is not set then we will unwind on any error.
500 * In an end-of-file occurs, we return.
501 */
502process(catch)
503 bool catch;
504{
505 register char *cp;
506 jmp_buf osetexit;
507 struct wordent paraml;
508 struct command *t;
509
510 getexit(osetexit);
511 for (;;) {
512 paraml.next = paraml.prev = &paraml;
513 paraml.word = "";
514 t = 0;
515 setexit();
516 justpr = 0; /* A chance to execute */
517
518 /*
519 * Interruptible during interactive reads
520 */
521 if (setintr)
522 signal(SIGINT, pintr);
523
524 /*
525 * For the sake of reset()
526 */
527 freelex(&paraml), freesyn(t), t = 0;
528
529 if (haderr) {
530 if (!catch) {
531 /* unwind */
532 doneinp = 0;
533 resexit(osetexit);
534 reset();
535 }
536 haderr = 0;
537 /*
538 * Every error is eventually caught here or
539 * the shell dies. It is at this
540 * point that we clean up any left-over open
541 * files, by closing all but a fixed number
542 * of pre-defined files. Thus routines don't
543 * have to worry about leaving files open due
544 * to deeper errors... they will get closed here.
545 */
546 closem();
547 continue;
548 }
549 if (doneinp) {
550 doneinp = 0;
551 break;
552 }
553 if (intty) {
554 mailchk();
555 /*
556 * If we are at the end of the input buffer
557 * then we are going to read fresh stuff.
558 * Otherwise, we are rereading input and don't
559 * need or want to prompt.
560 */
561 if (fseekp == feobp)
562 if (!whyles)
563 for (cp = value("prompt"); *cp; cp++)
564 if (*cp == '!')
565 printf("%d", eventno + 1);
566 else {
567 if (*cp == '\\' && cp[1] == '!')
568 cp++;
569 putchar(*cp | QUOTE);
570 }
571 else
572 /*
573 * Prompt for forward reading loop
574 * body content.
575 */
576 printf("? ");
577 flush();
578 }
579 err = 0;
580
581 /*
582 * Echo not only on VERBOSE, but also with history expansion.
583 * If there is a lexical error then we forego history echo.
584 */
585 if (lex(&paraml) && !err && intty || adrof("verbose")) {
586 haderr = 1;
587 prlex(&paraml);
588 haderr = 0;
589 }
590
591 /*
592 * The parser may lose space if interrupted.
593 */
594 if (setintr)
595 signal(SIGINT, SIG_IGN);
596
597 /*
598 * Save input text on the history list if it
599 * is from the terminal at the top level and not
600 * in a loop.
601 */
602 if (catch && intty && !whyles)
603 savehist(&paraml);
604
605 /*
606 * Print lexical error messages.
607 */
608 if (err)
609 error(err);
610
611 /*
612 * If had a history command :p modifier then
613 * this is as far as we should go
614 */
615 if (justpr)
616 reset();
617
618 alias(&paraml);
619
620 /*
621 * Parse the words of the input into a parse tree.
622 */
623 t = syntax(paraml.next, &paraml);
624 if (err)
625 error(err);
626
627 /*
628 * Execute the parse tree
629 */
630 execute(t);
631
632 /*
633 * Made it!
634 */
635 freelex(&paraml), freesyn(t);
636 }
637 resexit(osetexit);
638}
639
640dosource(t)
641 register char **t;
642{
643 register char *f;
644 register int u;
645
646 t++;
647 f = globone(*t);
648 u = dmove(open(f, 0), -1);
649 xfree(f);
650 if (u < 0)
651 Perror(f);
652 srcunit(u, 0);
653}
654
655/*
656 * Check for mail.
657 * If we are a login shell, then we don't want to tell
658 * about any mail file unless its been modified
659 * after the time we started.
660 * This prevents us from telling the user things he already
661 * knows, since the login program insist on saying
662 * "You have mail."
663 */
664mailchk()
665{
666 register struct varent *v;
667 register char **vp;
668 time_t t;
669 int intvl, cnt;
670
671 v = adrof("mail");
672 if (v == 0)
673 return;
674 time(&t);
675 vp = v->vec;
676 cnt = blklen(vp);
677 intvl = (cnt && number(*vp)) ? (--cnt, getn(*vp++)) : MAILINTVL;
678 if (intvl < 1)
679 intvl = 1;
680 if (chktim + intvl > t)
681 return;
682 for (; *vp; vp++) {
683 bool new;
684 struct stat stb;
685
686 if (stat(*vp, &stb) < 0)
687 continue;
688 /*
689 * We assume that a file has been read if the access time is
690 * greater than the mod time.
691 */
692#ifndef CORY
693 if (stb.st_size == 0)
694 continue;
695#endif
696 if (stb.st_atime > stb.st_mtime || stb.st_atime < chktim)
697 continue;
698 new = stb.st_mtime > time0;
699 if (loginsh && !new)
700 continue;
701 if (cnt == 1)
702 printf("You have %smail.\n", new ? "new " : "");
703 else
704 printf("%s in %s.\n", new ? "New mail" : "Mail", *vp);
705 }
706 chktim = t;
707}
708
709#include <pwd.h>
710/*
711 * Extract a home directory from the password file
712 * The argument points to a buffer where the name of the
713 * user whose home directory is sought is currently.
714 * We write the home directory of the user back there.
715 */
716gethdir(home)
717 char *home;
718{
719 register struct passwd *pp = getpwnam(home);
720
721 if (pp == 0)
722 return (1);
723 strcpy(home, pp->pw_dir);
724 return (0);
725}
726
727/*
728 * Move the initial descriptors to their eventual
729 * resting places, closin all other units.
730 */
731initdesc()
732{
733
734 didcch = 0; /* Havent closed for child */
735 didfds = 0; /* 0, 1, 2 aren't set up */
736 SHIN = dcopy(0, FSHIN);
737 SHOUT = dcopy(1, FSHOUT);
738 SHDIAG = dcopy(2, FSHDIAG);
739 OLDSTD = dcopy(SHIN, FOLDSTD);
740 closem();
741}
742
743#ifndef V6
744exit(i)
745 int i;
746{
747
748 _exit(i);
749}
750#endif