file system reorg
[unix-history] / usr / src / bin / csh / csh.c
CommitLineData
b79f4fa9
DF
1/*
2 * Copyright (c) 1980 Regents of the University of California.
094e80ed 3 * All rights reserved. The Berkeley Software License Agreement
b79f4fa9
DF
4 * specifies the terms and conditions for redistribution.
5 */
6
35371dec 7#ifndef lint
c502712b 8static char *sccsid = "@(#)csh.c 5.10 (Berkeley) %G%";
094e80ed 9#endif
04d3b78c
BJ
10
11#include "sh.h"
12#include <sys/ioctl.h>
5fe577ad 13#include <sys/file.h>
c502712b 14#include "pathnames.h"
5fe577ad 15
04d3b78c
BJ
16/*
17 * C Shell
18 *
19 * Bill Joy, UC Berkeley, California, USA
20 * October 1978, May 1980
21 *
22 * Jim Kulp, IIASA, Laxenburg, Austria
23 * April 1980
24 */
25
37c9c5f3 26char *pathlist[] = { ".", _PATH_UCB, _PATH_BIN, _PATH_USRBIN, 0 };
6ea8dfee 27char *dumphist[] = { "history", "-h", 0, 0 };
d7929fa7 28char *loadhist[] = { "source", "-h", "~/.history", 0 };
04d3b78c
BJ
29char HIST = '!';
30char HISTSUB = '^';
1274df0a 31bool mflag;
04d3b78c
BJ
32bool nofile;
33bool reenter;
34bool nverbose;
35bool nexececho;
36bool quitit;
37bool fast;
f0bb61e3 38bool batch;
04d3b78c 39bool prompt = 1;
63af20f7 40bool enterhist = 0;
04d3b78c 41
00705acc
JL
42extern gid_t getegid(), getgid();
43extern uid_t geteuid(), getuid();
44
04d3b78c
BJ
45main(c, av)
46 int c;
47 char **av;
48{
49 register char **v, *cp;
50 register int f;
d33af40e 51 struct sigvec osv;
04d3b78c
BJ
52
53 settimes(); /* Immed. estab. timing base */
54 v = av;
55 if (eq(v[0], "a.out")) /* A.out's are quittable */
56 quitit = 1;
57 uid = getuid();
d33af40e 58 loginsh = **v == '-' && c == 1;
04d3b78c 59 if (loginsh)
35371dec 60 (void) time(&chktim);
04d3b78c
BJ
61
62 /*
63 * Move the descriptors to safe places.
64 * The variable didfds is 0 while we have only FSH* to work with.
65 * When didfds is true, we have 0,1,2 and prefer to use these.
66 */
67 initdesc();
68
69 /*
70 * Initialize the shell variables.
71 * ARGV and PROMPT are initialized later.
72 * STATUS is also munged in several places.
73 * CHILD is munged when forking/waiting
74 */
75
76 set("status", "0");
77 dinit(cp = getenv("HOME")); /* dinit thinks that HOME == cwd in a
78 * login shell */
79 if (cp == NOSTR)
80 fast++; /* No home -> can't read scripts */
81 else
82 set("home", savestr(cp));
83 /*
84 * Grab other useful things from the environment.
85 * Should we grab everything??
86 */
87 if ((cp = getenv("USER")) != NOSTR)
88 set("user", savestr(cp));
89 if ((cp = getenv("TERM")) != NOSTR)
90 set("term", savestr(cp));
91 /*
92 * Re-initialize path if set in environment
93 */
94 if ((cp = getenv("PATH")) == NOSTR)
95 set1("path", saveblk(pathlist), &shvhed);
35371dec
EW
96 else
97 importpath(cp);
5fe577ad 98 set("shell", _PATH_CSHELL);
04d3b78c
BJ
99
100 doldol = putn(getpid()); /* For $$ */
101 shtemp = strspl("/tmp/sh", doldol); /* For << */
102
103 /*
104 * Record the interrupt states from the parent process.
105 * If the parent is non-interruptible our hand must be forced
106 * or we (and our children) won't be either.
107 * Our children inherit termination from our parent.
108 * We catch it only if we are the login shell.
109 */
35371dec
EW
110 /* parents interruptibility */
111 (void) sigvec(SIGINT, (struct sigvec *)0, &osv);
d33af40e 112 parintr = osv.sv_handler;
35371dec
EW
113 /* parents terminability */
114 (void) sigvec(SIGTERM, (struct sigvec *)0, &osv);
d33af40e 115 parterm = osv.sv_handler;
f66d6be5 116 if (loginsh) {
35371dec
EW
117 (void) signal(SIGHUP, phup); /* exit processing on HUP */
118 (void) signal(SIGXCPU, phup); /* ...and on XCPU */
119 (void) signal(SIGXFSZ, phup); /* ...and on XFSZ */
f66d6be5 120 }
04d3b78c
BJ
121
122 /*
123 * Process the arguments.
124 *
125 * Note that processing of -v/-x is actually delayed till after
126 * script processing.
04d3b78c
BJ
127 */
128 c--, v++;
f0bb61e3 129 while (c > 0 && (cp = v[0])[0] == '-' && *++cp != '\0' && !batch) {
04d3b78c
BJ
130 do switch (*cp++) {
131
f0bb61e3
RC
132 case 'b': /* -b Next arg is input file */
133 batch++;
134 break;
135
04d3b78c
BJ
136 case 'c': /* -c Command input from arg */
137 if (c == 1)
138 exit(0);
139 c--, v++;
140 arginp = v[0];
141 prompt = 0;
142 nofile++;
143 break;
144
145 case 'e': /* -e Exit on any error */
146 exiterr++;
147 break;
148
149 case 'f': /* -f Fast start */
150 fast++;
151 break;
152
153 case 'i': /* -i Interactive, even if !intty */
154 intact++;
155 nofile++;
156 break;
157
1274df0a
KB
158 case 'm': /* -m read .cshrc (from su) */
159 mflag++;
160 break;
161
04d3b78c
BJ
162 case 'n': /* -n Don't execute */
163 noexec++;
164 break;
165
166 case 'q': /* -q (Undoc'd) ... die on quit */
167 quitit = 1;
168 break;
169
170 case 's': /* -s Read from std input */
171 nofile++;
172 break;
173
174 case 't': /* -t Read one line from input */
175 onelflg = 2;
176 prompt = 0;
177 nofile++;
178 break;
179
180 case 'v': /* -v Echo hist expanded input */
181 nverbose = 1; /* ... later */
182 break;
183
184 case 'x': /* -x Echo just before execution */
185 nexececho = 1; /* ... later */
186 break;
187
188 case 'V': /* -V Echo hist expanded input */
189 setNS("verbose"); /* NOW! */
190 break;
191
192 case 'X': /* -X Echo just before execution */
193 setNS("echo"); /* NOW! */
194 break;
195
196 } while (*cp);
197 v++, c--;
198 }
199
200 if (quitit) /* With all due haste, for debugging */
35371dec 201 (void) signal(SIGQUIT, SIG_DFL);
04d3b78c
BJ
202
203 /*
f0bb61e3 204 * Unless prevented by -c, -i, -s, or -t, if there
04d3b78c
BJ
205 * are remaining arguments the first of them is the name
206 * of a shell file from which to read commands.
207 */
208 if (nofile == 0 && c > 0) {
209 nofile = open(v[0], 0);
210 if (nofile < 0) {
211 child++; /* So this ... */
212 Perror(v[0]); /* ... doesn't return */
213 }
214 file = v[0];
215 SHIN = dmove(nofile, FSHIN); /* Replace FSHIN */
35371dec 216 (void) ioctl(SHIN, FIOCLEX, (char *)0);
04d3b78c
BJ
217 prompt = 0;
218 c--, v++;
219 }
dee2e6bb 220 if (!batch && (uid != geteuid() || getgid() != getegid())) {
f0bb61e3
RC
221 errno = EACCES;
222 child++; /* So this ... */
223 Perror("csh"); /* ... doesn't return */
224 }
04d3b78c
BJ
225 /*
226 * Consider input a tty if it really is or we are interactive.
227 */
228 intty = intact || isatty(SHIN);
229 /*
230 * Decide whether we should play with signals or not.
231 * If we are explicitly told (via -i, or -) or we are a login
232 * shell (arg0 starts with -) or the input and output are both
233 * the ttys("csh", or "csh</dev/ttyx>/dev/ttyx")
234 * Note that in only the login shell is it likely that parent
235 * may have set signals to be ignored
236 */
3b1a0a1e 237 if (loginsh || intact || intty && isatty(SHOUT))
04d3b78c
BJ
238 setintr = 1;
239#ifdef TELL
240 settell();
241#endif
242 /*
243 * Save the remaining arguments in argv.
244 */
245 setq("argv", v, &shvhed);
246
247 /*
248 * Set up the prompt.
249 */
250 if (prompt)
251 set("prompt", uid == 0 ? "# " : "% ");
252
253 /*
254 * If we are an interactive shell, then start fiddling
255 * with the signals; this is a tricky game.
256 */
257 shpgrp = getpgrp(0);
258 opgrp = tpgrp = -1;
259 oldisc = -1;
260 if (setintr) {
261 **av = '-';
262 if (!quitit) /* Wary! */
35371dec
EW
263 (void) signal(SIGQUIT, SIG_IGN);
264 (void) signal(SIGINT, pintr);
265 (void) sigblock(sigmask(SIGINT));
266 (void) signal(SIGTERM, SIG_IGN);
04d3b78c 267 if (quitit == 0 && arginp == 0) {
35371dec
EW
268 (void) signal(SIGTSTP, SIG_IGN);
269 (void) signal(SIGTTIN, SIG_IGN);
270 (void) signal(SIGTTOU, SIG_IGN);
04d3b78c
BJ
271 /*
272 * Wait till in foreground, in case someone
273 * stupidly runs
274 * csh &
275 * dont want to try to grab away the tty.
276 */
277 if (isatty(FSHDIAG))
278 f = FSHDIAG;
279 else if (isatty(FSHOUT))
280 f = FSHOUT;
281 else if (isatty(OLDSTD))
282 f = OLDSTD;
283 else
284 f = -1;
285retry:
35371dec
EW
286 if (ioctl(f, TIOCGPGRP, (char *)&tpgrp) == 0 &&
287 tpgrp != -1) {
04d3b78c
BJ
288 int ldisc;
289 if (tpgrp != shpgrp) {
d33af40e 290 int (*old)() = signal(SIGTTIN, SIG_DFL);
35371dec
EW
291 (void) kill(0, SIGTTIN);
292 (void) signal(SIGTTIN, old);
04d3b78c
BJ
293 goto retry;
294 }
35371dec 295 if (ioctl(f, TIOCGETD, (char *)&oldisc) != 0)
04d3b78c
BJ
296 goto notty;
297 if (oldisc != NTTYDISC) {
d7929fa7
KM
298#ifdef DEBUG
299 printf("Switching to new tty driver...\n");
300#endif DEBUG
04d3b78c 301 ldisc = NTTYDISC;
35371dec
EW
302 (void) ioctl(f, TIOCSETD,
303 (char *)&ldisc);
04d3b78c
BJ
304 } else
305 oldisc = -1;
306 opgrp = shpgrp;
307 shpgrp = getpid();
308 tpgrp = shpgrp;
35371dec
EW
309 (void) ioctl(f, TIOCSPGRP, (char *)&shpgrp);
310 (void) setpgrp(0, shpgrp);
311 (void) ioctl(dcopy(f, FSHTTY), FIOCLEX,
312 (char *)0);
04d3b78c
BJ
313 } else {
314notty:
315 printf("Warning: no access to tty; thus no job control in this shell...\n");
316 tpgrp = -1;
317 }
318 }
319 }
3b1a0a1e
KM
320 if (setintr == 0 && parintr == SIG_DFL)
321 setintr++;
35371dec 322 (void) signal(SIGCHLD, pchild); /* while signals not ready */
04d3b78c
BJ
323
324 /*
325 * Set an exit here in case of an interrupt or error reading
326 * the shell start-up scripts.
327 */
328 setexit();
329 haderr = 0; /* In case second time through */
330 if (!fast && reenter == 0) {
331 reenter++;
5fe577ad
KB
332 {
333 int osetintr, omask;
334 osetintr = setintr;
335 omask = sigblock(sigmask(SIGINT));
336 setintr = 0;
337 srcunit(open(_PATH_DOTCSHRC, O_RDONLY), 0, 0);
338 if (!fast && !arginp && !onelflg)
339 dohash();
340 if (loginsh)
341 srcunit(open(_PATH_DOTLOGIN, O_RDONLY), 0, 0);
342 (void)sigsetmask(omask);
343 setintr = osetintr;
344 }
04d3b78c
BJ
345 /* Will have value("home") here because set fast if don't */
346 srccat(value("home"), "/.cshrc");
35371dec 347 if (!fast && !arginp && !onelflg && !havhash)
04d3b78c
BJ
348 dohash();
349 if (loginsh) {
04d3b78c
BJ
350 srccat(value("home"), "/.login");
351 }
5eaf2044 352 dosource(loadhist);
04d3b78c
BJ
353 }
354
355 /*
356 * Now are ready for the -v and -x flags
357 */
358 if (nverbose)
359 setNS("verbose");
360 if (nexececho)
361 setNS("echo");
362
363 /*
364 * All the rest of the world is inside this call.
365 * The argument to process indicates whether it should
366 * catch "error unwinds". Thus if we are a interactive shell
367 * our call here will never return by being blown past on an error.
368 */
369 process(setintr);
370
371 /*
372 * Mop-up.
373 */
374 if (loginsh) {
375 printf("logout\n");
35371dec 376 (void) close(SHIN);
04d3b78c
BJ
377 child++;
378 goodbye();
379 }
d7929fa7 380 rechist();
04d3b78c
BJ
381 exitstat();
382}
383
384untty()
385{
386
387 if (tpgrp > 0) {
35371dec
EW
388 (void) setpgrp(0, opgrp);
389 (void) ioctl(FSHTTY, TIOCSPGRP, (char *)&opgrp);
04d3b78c 390 if (oldisc != -1 && oldisc != NTTYDISC) {
d7929fa7 391#ifdef DEBUG
04d3b78c 392 printf("\nReverting to old tty driver...\n");
d7929fa7 393#endif DEBUG
35371dec 394 (void) ioctl(FSHTTY, TIOCSETD, (char *)&oldisc);
04d3b78c
BJ
395 }
396 }
397}
398
399importpath(cp)
ec1a81af 400 char *cp;
04d3b78c
BJ
401{
402 register int i = 0;
403 register char *dp;
404 register char **pv;
405 int c;
406 static char dot[2] = {'.', 0};
407
408 for (dp = cp; *dp; dp++)
409 if (*dp == ':')
410 i++;
411 /*
412 * i+2 where i is the number of colons in the path.
413 * There are i+1 directories in the path plus we need
414 * room for a zero terminator.
415 */
35371dec 416 pv = (char **) calloc((unsigned) (i + 2), sizeof (char **));
04d3b78c
BJ
417 dp = cp;
418 i = 0;
419 if (*dp)
420 for (;;) {
421 if ((c = *dp) == ':' || c == 0) {
422 *dp = 0;
423 pv[i++] = savestr(*cp ? cp : dot);
424 if (c) {
425 cp = dp + 1;
426 *dp = ':';
427 } else
428 break;
429 }
430 dp++;
431 }
432 pv[i] = 0;
433 set1("path", pv, &shvhed);
434}
435
436/*
437 * Source to the file which is the catenation of the argument names.
438 */
439srccat(cp, dp)
440 char *cp, *dp;
441{
442 register char *ep = strspl(cp, dp);
443 register int unit = dmove(open(ep, 0), -1);
444
35371dec 445 (void) ioctl(unit, FIOCLEX, (char *)0);
04d3b78c 446 xfree(ep);
1274df0a 447 srcunit(unit, mflag ? 0 : 1, 0);
04d3b78c
BJ
448}
449
450/*
1274df0a
KB
451 * Source to a unit.
452 * This occurs on ".cshrc"s and the like.
04d3b78c 453 */
470cb5e7
KB
454int insource;
455static
d7929fa7 456srcunit(unit, onlyown, hflg)
04d3b78c 457 register int unit;
1274df0a 458 bool onlyown, hflg;
04d3b78c
BJ
459{
460 /* We have to push down a lot of state here */
461 /* All this could go into a structure */
462 int oSHIN = -1, oldintty = intty;
463 struct whyle *oldwhyl = whyles;
464 char *ogointr = gointr, *oarginp = arginp;
465 char *oevalp = evalp, **oevalvec = evalvec;
466 int oonelflg = onelflg;
d7929fa7
KM
467 bool oenterhist = enterhist;
468 char OHIST = HIST;
04d3b78c
BJ
469#ifdef TELL
470 bool otell = cantell;
471#endif
472 struct Bin saveB;
473
474 /* The (few) real local variables */
475 jmp_buf oldexit;
1f7b623f
KB
476 int reenter;
477 long omask;
04d3b78c
BJ
478
479 if (unit < 0)
480 return;
481 if (didfds)
482 donefds();
483 if (onlyown) {
484 struct stat stb;
485
ec1a81af
SL
486 if (fstat(unit, &stb) < 0 ||
487 (stb.st_uid != uid && stb.st_gid != getgid())) {
35371dec 488 (void) close(unit);
04d3b78c
BJ
489 return;
490 }
491 }
492
493 /*
494 * There is a critical section here while we are pushing down the
495 * input stream since we have stuff in different structures.
496 * If we weren't careful an interrupt could corrupt SHIN's Bin
497 * structure and kill the shell.
498 *
499 * We could avoid the critical region by grouping all the stuff
500 * in a single structure and pointing at it to move it all at
501 * once. This is less efficient globally on many variable references
502 * however.
503 */
470cb5e7 504 insource = 1;
04d3b78c
BJ
505 getexit(oldexit);
506 reenter = 0;
507 if (setintr)
d33af40e 508 omask = sigblock(sigmask(SIGINT));
04d3b78c
BJ
509 setexit();
510 reenter++;
511 if (reenter == 1) {
512 /* Setup the new values of the state stuff saved above */
513 copy((char *)&saveB, (char *)&B, sizeof saveB);
514 fbuf = (char **) 0;
515 fseekp = feobp = fblocks = 0;
516 oSHIN = SHIN, SHIN = unit, arginp = 0, onelflg = 0;
517 intty = isatty(SHIN), whyles = 0, gointr = 0;
518 evalvec = 0; evalp = 0;
d7929fa7
KM
519 enterhist = hflg;
520 if (enterhist)
521 HIST = '\0';
04d3b78c
BJ
522 /*
523 * Now if we are allowing commands to be interrupted,
524 * we let ourselves be interrupted.
525 */
526 if (setintr)
35371dec 527 (void) sigsetmask(omask);
04d3b78c
BJ
528#ifdef TELL
529 settell();
530#endif
531 process(0); /* 0 -> blow away on errors */
532 }
533 if (setintr)
35371dec 534 (void) sigsetmask(omask);
04d3b78c
BJ
535 if (oSHIN >= 0) {
536 register int i;
537
538 /* We made it to the new state... free up its storage */
539 /* This code could get run twice but xfree doesn't care */
540 for (i = 0; i < fblocks; i++)
541 xfree(fbuf[i]);
542 xfree((char *)fbuf);
543
544 /* Reset input arena */
545 copy((char *)&B, (char *)&saveB, sizeof B);
546
35371dec 547 (void) close(SHIN), SHIN = oSHIN;
04d3b78c
BJ
548 arginp = oarginp, onelflg = oonelflg;
549 evalp = oevalp, evalvec = oevalvec;
550 intty = oldintty, whyles = oldwhyl, gointr = ogointr;
020d9a25
KM
551 if (enterhist)
552 HIST = OHIST;
d7929fa7 553 enterhist = oenterhist;
04d3b78c
BJ
554#ifdef TELL
555 cantell = otell;
556#endif
557 }
558
559 resexit(oldexit);
560 /*
561 * If process reset() (effectively an unwind) then
562 * we must also unwind.
563 */
564 if (reenter >= 2)
565 error(NOSTR);
470cb5e7 566 insource = 0;
04d3b78c
BJ
567}
568
d7929fa7 569rechist()
04d3b78c 570{
63af20f7
KM
571 char buf[BUFSIZ];
572 int fp, ftmp, oldidfds;
04d3b78c 573
d7929fa7 574 if (!fast) {
6ea8dfee
KM
575 if (value("savehist")[0] == '\0')
576 return;
35371dec
EW
577 (void) strcpy(buf, value("home"));
578 (void) strcat(buf, "/.history");
14f52162 579 fp = creat(buf, 0666);
6ea8dfee
KM
580 if (fp == -1)
581 return;
582 oldidfds = didfds;
583 didfds = 0;
584 ftmp = SHOUT;
585 SHOUT = fp;
35371dec 586 (void) strcpy(buf, value("savehist"));
6ea8dfee
KM
587 dumphist[2] = buf;
588 dohist(dumphist);
35371dec 589 (void) close(fp);
6ea8dfee
KM
590 SHOUT = ftmp;
591 didfds = oldidfds;
d7929fa7
KM
592 }
593}
594
595goodbye()
596{
597 if (loginsh) {
35371dec
EW
598 (void) signal(SIGQUIT, SIG_IGN);
599 (void) signal(SIGINT, SIG_IGN);
600 (void) signal(SIGTERM, SIG_IGN);
04d3b78c 601 setintr = 0; /* No interrupts after "logout" */
5fe577ad 602 srcunit(open(_PATH_DOTLOGOUT, O_RDONLY), 0, 0);
04d3b78c
BJ
603 if (adrof("home"))
604 srccat(value("home"), "/.logout");
605 }
d7929fa7 606 rechist();
04d3b78c
BJ
607 exitstat();
608}
609
610exitstat()
611{
612
35371dec
EW
613#ifdef PROF
614 monitor(0);
615#endif
04d3b78c
BJ
616 /*
617 * Note that if STATUS is corrupted (i.e. getn bombs)
618 * then error will exit directly because we poke child here.
619 * Otherwise we might continue unwarrantedly (sic).
620 */
621 child++;
622 exit(getn(value("status")));
623}
624
d7929fa7
KM
625/*
626 * in the event of a HUP we want to save the history
627 */
628phup()
629{
630 rechist();
631 exit(1);
632}
633
04d3b78c
BJ
634char *jobargv[2] = { "jobs", 0 };
635/*
636 * Catch an interrupt, e.g. during lexical input.
637 * If we are an interactive shell, we reset the interrupt catch
638 * immediately. In any case we drain the shell output,
639 * and finally go through the normal error mechanism, which
640 * gets a chance to make the shell go away.
641 */
642pintr()
401149be
BJ
643{
644 pintr1(1);
645}
646
647pintr1(wantnl)
648 bool wantnl;
04d3b78c
BJ
649{
650 register char **v;
1f7b623f 651 long omask;
04d3b78c 652
1f7b623f 653 omask = sigblock(0L);
04d3b78c 654 if (setintr) {
35371dec 655 (void) sigsetmask(omask & ~sigmask(SIGINT));
04d3b78c
BJ
656 if (pjobs) {
657 pjobs = 0;
658 printf("\n");
659 dojobs(jobargv);
660 bferr("Interrupted");
661 }
662 }
35371dec 663 (void) sigsetmask(omask & ~sigmask(SIGCHLD));
04d3b78c
BJ
664 draino();
665
666 /*
667 * If we have an active "onintr" then we search for the label.
668 * Note that if one does "onintr -" then we shan't be interruptible
669 * so we needn't worry about that here.
670 */
671 if (gointr) {
672 search(ZGOTO, 0, gointr);
673 timflg = 0;
674 if (v = pargv)
675 pargv = 0, blkfree(v);
676 if (v = gargv)
677 gargv = 0, blkfree(v);
678 reset();
401149be 679 } else if (intty && wantnl)
04d3b78c
BJ
680 printf("\n"); /* Some like this, others don't */
681 error(NOSTR);
682}
683
684/*
685 * Process is the main driving routine for the shell.
686 * It runs all command processing, except for those within { ... }
687 * in expressions (which is run by a routine evalav in sh.exp.c which
688 * is a stripped down process), and `...` evaluation which is run
689 * also by a subset of this code in sh.glob.c in the routine backeval.
690 *
691 * The code here is a little strange because part of it is interruptible
692 * and hence freeing of structures appears to occur when none is necessary
693 * if this is ignored.
694 *
695 * Note that if catch is not set then we will unwind on any error.
696 * If an end-of-file occurs, we return.
697 */
698process(catch)
699 bool catch;
700{
04d3b78c 701 jmp_buf osetexit;
35371dec 702 register struct command *t;
04d3b78c
BJ
703
704 getexit(osetexit);
705 for (;;) {
706 pendjob();
707 paraml.next = paraml.prev = &paraml;
708 paraml.word = "";
709 t = 0;
710 setexit();
63af20f7 711 justpr = enterhist; /* execute if not entering history */
04d3b78c
BJ
712
713 /*
714 * Interruptible during interactive reads
715 */
716 if (setintr)
1f7b623f 717 (void) sigsetmask(sigblock(0L) & ~sigmask(SIGINT));
04d3b78c
BJ
718
719 /*
720 * For the sake of reset()
721 */
722 freelex(&paraml), freesyn(t), t = 0;
723
724 if (haderr) {
725 if (!catch) {
726 /* unwind */
727 doneinp = 0;
728 resexit(osetexit);
729 reset();
730 }
731 haderr = 0;
732 /*
733 * Every error is eventually caught here or
734 * the shell dies. It is at this
735 * point that we clean up any left-over open
736 * files, by closing all but a fixed number
737 * of pre-defined files. Thus routines don't
738 * have to worry about leaving files open due
739 * to deeper errors... they will get closed here.
740 */
741 closem();
742 continue;
743 }
744 if (doneinp) {
745 doneinp = 0;
746 break;
747 }
748 if (chkstop)
749 chkstop--;
750 if (neednote)
751 pnote();
c9166193 752 if (intty && prompt && evalvec == 0) {
04d3b78c
BJ
753 mailchk();
754 /*
755 * If we are at the end of the input buffer
756 * then we are going to read fresh stuff.
757 * Otherwise, we are rereading input and don't
758 * need or want to prompt.
759 */
760 if (fseekp == feobp)
544d4ed6 761 printprompt();
04d3b78c
BJ
762 }
763 err = 0;
764
765 /*
766 * Echo not only on VERBOSE, but also with history expansion.
767 * If there is a lexical error then we forego history echo.
768 */
d7929fa7
KM
769 if (lex(&paraml) && !err && intty ||
770 adrof("verbose")) {
04d3b78c
BJ
771 haderr = 1;
772 prlex(&paraml);
773 haderr = 0;
774 }
775
776 /*
777 * The parser may lose space if interrupted.
778 */
779 if (setintr)
35371dec 780 (void) sigblock(sigmask(SIGINT));
04d3b78c
BJ
781
782 /*
63af20f7
KM
783 * Save input text on the history list if
784 * reading in old history, or it
04d3b78c
BJ
785 * is from the terminal at the top level and not
786 * in a loop.
787 */
63af20f7 788 if (enterhist || catch && intty && !whyles)
04d3b78c
BJ
789 savehist(&paraml);
790
791 /*
d7929fa7
KM
792 * Print lexical error messages, except when sourcing
793 * history lists.
04d3b78c 794 */
d7929fa7 795 if (!enterhist && err)
04d3b78c
BJ
796 error(err);
797
798 /*
799 * If had a history command :p modifier then
800 * this is as far as we should go
801 */
802 if (justpr)
803 reset();
804
805 alias(&paraml);
806
807 /*
808 * Parse the words of the input into a parse tree.
809 */
810 t = syntax(paraml.next, &paraml, 0);
811 if (err)
812 error(err);
813
814 /*
815 * Execute the parse tree
816 */
817 execute(t, tpgrp);
818
819 /*
820 * Made it!
821 */
822 freelex(&paraml), freesyn(t);
823 }
824 resexit(osetexit);
825}
826
827dosource(t)
828 register char **t;
829{
830 register char *f;
831 register int u;
d7929fa7
KM
832 bool hflg = 0;
833 char buf[BUFSIZ];
04d3b78c
BJ
834
835 t++;
d7929fa7
KM
836 if (*t && eq(*t, "-h")) {
837 t++;
838 hflg++;
839 }
35371dec 840 (void) strcpy(buf, *t);
d7929fa7 841 f = globone(buf);
04d3b78c
BJ
842 u = dmove(open(f, 0), -1);
843 xfree(f);
d7929fa7 844 if (u < 0 && !hflg)
04d3b78c 845 Perror(f);
35371dec 846 (void) ioctl(u, FIOCLEX, (char *)0);
d7929fa7 847 srcunit(u, 0, hflg);
04d3b78c
BJ
848}
849
850/*
851 * Check for mail.
852 * If we are a login shell, then we don't want to tell
853 * about any mail file unless its been modified
854 * after the time we started.
855 * This prevents us from telling the user things he already
856 * knows, since the login program insists on saying
857 * "You have mail."
858 */
859mailchk()
860{
861 register struct varent *v;
862 register char **vp;
863 time_t t;
864 int intvl, cnt;
865 struct stat stb;
866 bool new;
867
868 v = adrof("mail");
869 if (v == 0)
870 return;
35371dec 871 (void) time(&t);
04d3b78c
BJ
872 vp = v->vec;
873 cnt = blklen(vp);
874 intvl = (cnt && number(*vp)) ? (--cnt, getn(*vp++)) : MAILINTVL;
875 if (intvl < 1)
876 intvl = 1;
877 if (chktim + intvl > t)
878 return;
879 for (; *vp; vp++) {
880 if (stat(*vp, &stb) < 0)
881 continue;
ae3d9709 882 new = stb.st_mtime > time0.tv_sec;
04d3b78c
BJ
883 if (stb.st_size == 0 || stb.st_atime > stb.st_mtime ||
884 (stb.st_atime < chktim && stb.st_mtime < chktim) ||
885 loginsh && !new)
886 continue;
887 if (cnt == 1)
888 printf("You have %smail.\n", new ? "new " : "");
889 else
890 printf("%s in %s.\n", new ? "New mail" : "Mail", *vp);
891 }
892 chktim = t;
893}
894
895#include <pwd.h>
896/*
897 * Extract a home directory from the password file
898 * The argument points to a buffer where the name of the
899 * user whose home directory is sought is currently.
900 * We write the home directory of the user back there.
901 */
902gethdir(home)
903 char *home;
904{
905 register struct passwd *pp = getpwnam(home);
906
907 if (pp == 0)
908 return (1);
35371dec 909 (void) strcpy(home, pp->pw_dir);
04d3b78c
BJ
910 return (0);
911}
912
913/*
914 * Move the initial descriptors to their eventual
915 * resting places, closin all other units.
916 */
917initdesc()
918{
919
04d3b78c 920 didfds = 0; /* 0, 1, 2 aren't set up */
35371dec
EW
921 (void) ioctl(SHIN = dcopy(0, FSHIN), FIOCLEX, (char *)0);
922 (void) ioctl(SHOUT = dcopy(1, FSHOUT), FIOCLEX, (char *)0);
923 (void) ioctl(SHDIAG = dcopy(2, FSHDIAG), FIOCLEX, (char *)0);
924 (void) ioctl(OLDSTD = dcopy(SHIN, FOLDSTD), FIOCLEX, (char *)0);
04d3b78c
BJ
925 closem();
926}
927
e31125a2
SL
928#ifdef PROF
929done(i)
930#else
04d3b78c 931exit(i)
e31125a2 932#endif
04d3b78c
BJ
933 int i;
934{
935
936 untty();
04d3b78c 937 _exit(i);
04d3b78c 938}
19d39288 939
544d4ed6 940printprompt()
19d39288 941{
544d4ed6
SL
942 register char *cp;
943
e31125a2 944 if (!whyles) {
544d4ed6
SL
945 for (cp = value("prompt"); *cp; cp++)
946 if (*cp == HIST)
947 printf("%d", eventno + 1);
948 else {
949 if (*cp == '\\' && cp[1] == HIST)
950 cp++;
fad613b5 951 cshputchar(*cp | QUOTE);
544d4ed6
SL
952 }
953 } else
954 /*
955 * Prompt for forward reading loop
956 * body content.
957 */
958 printf("? ");
959 flush();
19d39288 960}