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