BSD 3 development
[unix-history] / usr / src / cmd / csh / sh.c
CommitLineData
4528f86f
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 (!fast && !arginp && !onelflg)
273 dohash();
274 if (loginsh)
275#ifdef NOHELP
276 srccat("", ".login");
277#else
278 srccat(value("home"), "/.login");
279#endif
280 }
281
282 /*
283 * Now are ready for the -v and -x flags
284 */
285 if (nverbose)
286 setNS("verbose");
287 if (nexececho)
288 setNS("echo");
289
290 /*
291 * All the rest of the world is inside this call.
292 * The argument to process indicates whether it should
293 * catch "error unwinds". Thus if we are a interactive shell
294 * our call here will never return by being blown past on an error.
295 */
296 process(setintr);
297
298 /*
299 * Mop-up.
300 */
301 if (loginsh) {
302 printf("logout\n");
303 close(SHIN);
304 child++;
305 goodbye();
306 }
307 exitstat();
308}
309
310/*
311 * Source to the file which is the catenation of the argument names.
312 */
313srccat(cp, dp)
314 char *cp, *dp;
315{
316 register char *ep = strspl(cp, dp);
317 register int unit = dmove(open(ep, 0), -1);
318
319 /* ioctl(unit, FIOCLEX, NULL); */
320 xfree(ep);
321 srcunit(unit, 0);
322}
323
324/*
325 * Source to a unit. If onlyown it must be our file or
326 * we don't chance it. This occurs on ".cshrc"s and the like.
327 */
328srcunit(unit, onlyown)
329 register int unit;
330 bool onlyown;
331{
332 /* We have to push down a lot of state here */
333 /* All this could go into a structure */
334 int oSHIN = -1, oldintty = intty;
335 struct whyle *oldwhyl = whyles;
336 char *ogointr = gointr, *oarginp = arginp;
337 int oonelflg = onelflg;
338#ifdef TELL
339 bool otell = cantell;
340#endif
341 struct Bin saveB;
342
343 /* The (few) real local variables */
344 jmp_buf oldexit;
345 int reenter;
346 register int (*oldint)();
347
348 if (unit < 0)
349 return;
350 if (onlyown) {
351 struct stat stb;
352
353#ifdef CC
354 if (fstat(unit, &stb) < 0 || (stb.st_uid != uid && stb.st_uid != (uid &~ 0377))) {
355#endif
356#ifdef CORY
357 if (fstat(unit, &stb) < 0 || (stb.st_uid != uid && stb.st_uid != (uid &~ 0377))) {
358#endif
359#ifndef CC
360#ifndef CORY
361 if (fstat(unit, &stb) < 0 || stb.st_uid != uid) {
362#endif
363#endif
364 close(unit);
365 return;
366 }
367 }
368
369 /*
370 * There is a critical section here while we are pushing down the
371 * input stream since we have stuff in different structures.
372 * If we weren't careful an interrupt could corrupt SHIN's Bin
373 * structure and kill the shell.
374 *
375 * We could avoid the critical region by grouping all the stuff
376 * in a single structure and pointing at it to move it all at
377 * once. This is less efficient globally on many variable references
378 * however.
379 */
380 getexit(oldexit);
381 reenter = 0;
382 oldint = signal(SIGINT, SIG_IGN);
383 setexit();
384 reenter++;
385 if (reenter == 1) {
386 /* Setup the new values of the state stuff saved above */
387 copy(&saveB, &B, sizeof saveB);
388 fbuf = (char **) 0;
389 fseekp = feobp = fblocks = 0;
390 oSHIN = SHIN, SHIN = unit, arginp = 0, onelflg = 0;
391 intty = isatty(SHIN), whyles = 0, gointr = 0;
392 /*
393 * Now if we are allowing commands to be interrupted,
394 * we let ourselves be interrupted.
395 */
396 signal(SIGINT, setintr ? pintr : oldint);
397#ifdef TELL
398 settell();
399#endif
400 process(0); /* 0 -> blow away on errors */
401 }
402 signal(SIGINT, oldint);
403 if (oSHIN >= 0) {
404 register int i;
405
406 /* We made it to the new state... free up its storage */
407 /* This code could get run twice but xfree doesn't care */
408 for (i = 0; i < fblocks; i++)
409 xfree(fbuf[i]);
410 xfree(fbuf);
411
412 /* Reset input arena */
413 copy(&B, &saveB, sizeof B);
414
415 close(SHIN), SHIN = oSHIN;
416 arginp = oarginp, onelflg = oonelflg;
417 intty = oldintty, whyles = oldwhyl, gointr = ogointr;
418#ifdef TELL
419 cantell = otell;
420#endif
421 }
422
423 resexit(oldexit);
424 /*
425 * If process reset() (effectively an unwind) then
426 * we must also unwind.
427 */
428 if (reenter >= 2)
429 error(0);
430}
431
432goodbye()
433{
434
435 if (loginsh) {
436 signal(SIGQUIT, SIG_IGN);
437 signal(SIGINT, SIG_IGN);
438 signal(SIGTERM, SIG_IGN);
439 setintr = 0; /* No interrupts after "logout" */
440 if (adrof("home"))
441 srccat(value("home"), "/.logout");
442 }
443 exitstat();
444}
445
446exitstat()
447{
448
449 /*
450 * Note that if STATUS is corrupted (i.e. getn bombs)
451 * then error will exit directly because we poke child here.
452 * Otherwise we might continue unwarrantedly (sic).
453 */
454 child++;
455 exit(getn(value("status")));
456}
457
458/*
459 * Catch an interrupt, e.g. during lexical input.
460 * If we are an interactive shell, we reset the interrupt catch
461 * immediately. In any case we drain the shell output,
462 * and finally go through the normal error mechanism, which
463 * gets a chance to make the shell go away.
464 */
465pintr()
466{
467 register char **v;
468
469 if (setintr)
470 signal(SIGINT, SIG_IGN);
471 draino();
472
473 /*
474 * If we have an active "onintr" then we search for the label.
475 * Note that if one does "onintr -" then we shan't be interruptible
476 * so we needn't worry about that here.
477 */
478 if (gointr) {
479 search(ZGOTO, 0, gointr);
480 timflg = 0;
481 if (v = pargv)
482 pargv = 0, blkfree(v);
483 if (v = gargv)
484 gargv = 0, blkfree(v);
485 reset();
486 } else if (intty)
487 printf("\n"); /* Some like this, others don't */
488 error(0);
489}
490
491/*
492 * Process is the main driving routine for the shell.
493 * It runs all command processing, except for those within { ... }
494 * in expressions (which is run by a routine evalav in sh.exp.c which
495 * is a stripped down process), and `...` evaluation which is run
496 * also by a subset of this code in sh.glob.c in the routine backeval.
497 *
498 * The code here is a little strange because part of it is interruptible
499 * and hence freeing of structures appears to occur when none is necessary
500 * if this is ignored.
501 *
502 * Note that if catch is not set then we will unwind on any error.
503 * In an end-of-file occurs, we return.
504 */
505process(catch)
506 bool catch;
507{
508 register char *cp;
509 jmp_buf osetexit;
510 struct wordent paraml;
511 struct command *t;
512
513 getexit(osetexit);
514 for (;;) {
515 paraml.next = paraml.prev = &paraml;
516 paraml.word = "";
517 t = 0;
518 setexit();
519 justpr = 0; /* A chance to execute */
520
521 /*
522 * Interruptible during interactive reads
523 */
524 if (setintr)
525 signal(SIGINT, pintr);
526
527 /*
528 * For the sake of reset()
529 */
530 freelex(&paraml), freesyn(t), t = 0;
531
532 if (haderr) {
533 if (!catch) {
534 /* unwind */
535 doneinp = 0;
536 resexit(osetexit);
537 reset();
538 }
539 haderr = 0;
540 /*
541 * Every error is eventually caught here or
542 * the shell dies. It is at this
543 * point that we clean up any left-over open
544 * files, by closing all but a fixed number
545 * of pre-defined files. Thus routines don't
546 * have to worry about leaving files open due
547 * to deeper errors... they will get closed here.
548 */
549 closem();
550 continue;
551 }
552 if (doneinp) {
553 doneinp = 0;
554 break;
555 }
556 if (intty) {
557 mailchk();
558 /*
559 * If we are at the end of the input buffer
560 * then we are going to read fresh stuff.
561 * Otherwise, we are rereading input and don't
562 * need or want to prompt.
563 */
564 if (fseekp == feobp)
565 if (!whyles)
566 for (cp = value("prompt"); *cp; cp++)
567 if (*cp == '!')
568 printf("%d", eventno + 1);
569 else {
570 if (*cp == '\\' && cp[1] == '!')
571 cp++;
572 putchar(*cp | QUOTE);
573 }
574 else
575 /*
576 * Prompt for forward reading loop
577 * body content.
578 */
579 printf("? ");
580 flush();
581 }
582 err = 0;
583
584 /*
585 * Echo not only on VERBOSE, but also with history expansion.
586 * If there is a lexical error then we forego history echo.
587 */
588 if (lex(&paraml) && !err && intty || adrof("verbose")) {
589 haderr = 1;
590 prlex(&paraml);
591 haderr = 0;
592 }
593
594 /*
595 * The parser may lose space if interrupted.
596 */
597 if (setintr)
598 signal(SIGINT, SIG_IGN);
599
600 /*
601 * Save input text on the history list if it
602 * is from the terminal at the top level and not
603 * in a loop.
604 */
605 if (catch && intty && !whyles)
606 savehist(&paraml);
607
608 /*
609 * Print lexical error messages.
610 */
611 if (err)
612 error(err);
613
614 /*
615 * If had a history command :p modifier then
616 * this is as far as we should go
617 */
618 if (justpr)
619 reset();
620
621 alias(&paraml);
622
623 /*
624 * Parse the words of the input into a parse tree.
625 */
626 t = syntax(paraml.next, &paraml);
627 if (err)
628 error(err);
629
630 /*
631 * Execute the parse tree
632 */
633 execute(t);
634
635 /*
636 * Made it!
637 */
638 freelex(&paraml), freesyn(t);
639 }
640 resexit(osetexit);
641}
642
643dosource(t)
644 register char **t;
645{
646 register char *f;
647 register int u;
648
649 t++;
650 f = globone(*t);
651 u = dmove(open(f, 0), -1);
652 xfree(f);
653 if (u < 0)
654 Perror(f);
655 didfds = 0;
656 srcunit(u, 0);
657}
658
659/*
660 * Check for mail.
661 * If we are a login shell, then we don't want to tell
662 * about any mail file unless its been modified
663 * after the time we started.
664 * This prevents us from telling the user things he already
665 * knows, since the login program insist on saying
666 * "You have mail."
667 */
668mailchk()
669{
670 register struct varent *v;
671 register char **vp;
672 time_t t;
673 int intvl, cnt;
674
675 v = adrof("mail");
676 if (v == 0)
677 return;
678 time(&t);
679 vp = v->vec;
680 cnt = blklen(vp);
681 intvl = (cnt && number(*vp)) ? (--cnt, getn(*vp++)) : MAILINTVL;
682 if (intvl < 1)
683 intvl = 1;
684 if (chktim + intvl > t)
685 return;
686 for (; *vp; vp++) {
687 bool new;
688 struct stat stb;
689
690 if (stat(*vp, &stb) < 0)
691 continue;
692 /*
693 * We assume that a file has been read if the access time is
694 * greater than the mod time.
695 */
696#ifndef CORY
697 if (stb.st_size == 0)
698 continue;
699#endif
700 if (stb.st_atime > stb.st_mtime || stb.st_atime < chktim)
701 continue;
702 new = stb.st_mtime > time0;
703 if (loginsh && !new)
704 continue;
705 if (cnt == 1)
706 printf("You have %smail.\n", new ? "new " : "");
707 else
708 printf("%s in %s.\n", new ? "New mail" : "Mail", *vp);
709 }
710 chktim = t;
711}
712
713#include <pwd.h>
714/*
715 * Extract a home directory from the password file
716 * The argument points to a buffer where the name of the
717 * user whose home directory is sought is currently.
718 * We write the home directory of the user back there.
719 */
720gethdir(home)
721 char *home;
722{
723 register struct passwd *pp = getpwnam(home);
724
725 if (pp == 0)
726 return (1);
727 strcpy(home, pp->pw_dir);
728 return (0);
729}
730
731/*
732 * Move the initial descriptors to their eventual
733 * resting places, closin all other units.
734 */
735initdesc()
736{
737
738 didcch = 0; /* Havent closed for child */
739 didfds = 0; /* 0, 1, 2 aren't set up */
740 SHIN = dcopy(0, FSHIN);
741 SHOUT = dcopy(1, FSHOUT);
742 SHDIAG = dcopy(2, FSHDIAG);
743 OLDSTD = dcopy(SHIN, FOLDSTD);
744 closem();
745}
746
747#ifndef V6
748exit(i)
749 int i;
750{
751
752 _exit(i);
753}
754#endif