1 /* $NetBSD: csh.c,v 1.56 2022/09/15 11:35:06 martin Exp $ */
2
3 /*-
4 * Copyright (c) 1980, 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __COPYRIGHT("@(#) Copyright (c) 1980, 1991, 1993\
35 The Regents of the University of California. All rights reserved.");
36 #endif /* not lint */
37
38 #ifndef lint
39 #if 0
40 static char sccsid[] = "@(#)csh.c 8.2 (Berkeley) 10/12/93";
41 #else
42 __RCSID("$NetBSD: csh.c,v 1.56 2022/09/15 11:35:06 martin Exp $");
43 #endif
44 #endif /* not lint */
45
46 #include <sys/types.h>
47 #include <sys/ioctl.h>
48 #include <sys/stat.h>
49
50 #include <errno.h>
51 #include <fcntl.h>
52 #include <locale.h>
53 #include <paths.h> /* should this be included in pathnames.h instead? */
54 #include <pwd.h>
55 #include <stdarg.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <time.h>
59 #include <unistd.h>
60 #include <vis.h>
61
62 #include "csh.h"
63 #include "extern.h"
64 #include "pathnames.h"
65 #include "proc.h"
66
67 /*
68 * C Shell
69 *
70 * Bill Joy, UC Berkeley, California, USA
71 * October 1978, May 1980
72 *
73 * Jim Kulp, IIASA, Laxenburg, Austria
74 * April 1980
75 *
76 * Christos Zoulas, Cornell University
77 * June, 1991
78 */
79
80 FILE *cshin, *cshout, *csherr;
81 struct timespec time0;
82 struct rusage ru0;
83 struct varent shvhed, aliases;
84 Char HISTSUB;
85 int editing;
86
87 int child;
88 int chkstop;
89 int didfds;
90 int doneinp;
91 int exiterr;
92 int haderr;
93 int havhash;
94 int intact;
95 int intty;
96 int justpr;
97 int loginsh;
98 int neednote;
99 int noexec;
100 int pjobs;
101 int setintr;
102 int timflg;
103
104 Char *arginp;
105 Char *ffile;
106 int onelflg;
107 Char *shtemp;
108
109 time_t chktim;
110 Char *doldol;
111 pid_t backpid;
112 gid_t egid, gid;
113 uid_t euid, uid;
114 int shpgrp;
115 int tpgrp;
116
117 int opgrp;
118
119 int SHIN;
120 int SHOUT;
121 int SHERR;
122 int OLDSTD;
123
124 jmp_buf reslab;
125
126 Char *gointr;
127
128 sig_t parintr;
129 sig_t parterm;
130
131 struct Bin B;
132
133 struct Ain lineloc;
134 int cantell;
135 Char *lap;
136 struct whyle *whyles;
137
138 struct wordent *alhistp,*alhistt;
139
140 int AsciiOnly;
141 int gflag;
142 long pnleft;
143 Char *pargs;
144 Char *pargcp;
145 struct Hist Histlist;
146 struct wordent paraml;
147 int eventno;
148 int lastev;
149 Char HIST;
150 Char HISTSUB;
151 const char *bname;
152 Char *Vsav;
153 Char *Vdp;
154 Char *Vexpath;
155 char **Vt;
156 Char **evalvec;
157 Char *evalp;
158 Char *word_chars;
159 Char *STR_SHELLPATH;
160 #ifdef _PATH_BSHELL
161 Char *STR_BSHELL;
162 #endif
163 Char *STR_WORD_CHARS;
164 Char **STR_environ;
165 #ifdef EDIT
166 EditLine *el;
167 History *hi;
168 #endif
169 int editing;
170
171 Char *dumphist[] = {STRhistory, STRmh, 0, 0};
172 Char *tildehist[] = {STRsource, STRmh, STRtildothist, 0};
173
174 int nofile = 0;
175 int batch = 0;
176 int enterhist = 0;
177 int fast = 0;
178 int mflag = 0;
179 int nexececho = 0;
180 int nverbose = 0;
181 int prompt = 1;
182 int quitit = 0;
183 int reenter = 0;
184
185 extern char **environ;
186
187 static ssize_t readf(void *, void *, size_t);
188 static off_t seekf(void *, off_t, int);
189 static ssize_t writef(void *, const void *, size_t);
190 static int closef(void *);
191 static int srccat(Char *, Char *);
192 static int srcfile(const char *, int, int);
193 __dead static void phup(int);
194 static void srcunit(int, int, int);
195 static void mailchk(void);
196 #ifndef _PATH_DEFPATH
197 static Char **defaultpath(void);
198 #endif
199
200 int
main(int argc,char * argv[])201 main(int argc, char *argv[])
202 {
203 struct sigaction oact;
204 Char *cp;
205 char *tcp, **tempv;
206 const char *ecp;
207 sigset_t nsigset;
208 int f;
209
210 cshin = stdin;
211 cshout = stdout;
212 csherr = stderr;
213
214 setprogname(argv[0]);
215 settimes(); /* Immed. estab. timing base */
216
217 /*
218 * Initialize non constant strings
219 */
220 #ifdef _PATH_BSHELL
221 STR_BSHELL = SAVE(_PATH_BSHELL);
222 #endif
223 #ifdef _PATH_CSHELL
224 STR_SHELLPATH = SAVE(_PATH_CSHELL);
225 #endif
226 STR_environ = blk2short(environ);
227 environ = short2blk(STR_environ); /* So that we can free it */
228 STR_WORD_CHARS = SAVE(WORD_CHARS);
229
230 HIST = '!';
231 HISTSUB = '^';
232 word_chars = STR_WORD_CHARS;
233
234 tempv = argv;
235 if (eq(str2short(tempv[0]), STRaout)) /* A.out's are quittable */
236 quitit = 1;
237 uid = getuid();
238 gid = getgid();
239 euid = geteuid();
240 egid = getegid();
241 /*
242 * We are a login shell if: 1. we were invoked as -<something> and we had
243 * no arguments 2. or we were invoked only with the -l flag
244 */
245 loginsh = (**tempv == '-' && argc == 1) ||
246 (argc == 2 && tempv[1][0] == '-' && tempv[1][1] == 'l' &&
247 tempv[1][2] == '\0');
248
249 if (loginsh && **tempv != '-') {
250 /*
251 * Mangle the argv space
252 */
253 tempv[1][0] = '\0';
254 tempv[1][1] = '\0';
255 tempv[1] = NULL;
256 for (tcp = *tempv; *tcp++;)
257 continue;
258 for (tcp--; tcp >= *tempv; tcp--)
259 tcp[1] = tcp[0];
260 *++tcp = '-';
261 argc--;
262 }
263 if (loginsh)
264 (void)time(&chktim);
265
266 AsciiOnly = 1;
267 #ifdef NLS
268 (void)setlocale(LC_ALL, "");
269 {
270 int k;
271
272 for (k = 0200; k <= 0377 && !Isprint(k); k++)
273 continue;
274 AsciiOnly = k > 0377;
275 }
276 #else
277 AsciiOnly = getenv("LANG") == NULL && getenv("LC_CTYPE") == NULL;
278 #endif /* NLS */
279
280 /*
281 * Move the descriptors to safe places. The variable didfds is 0 while we
282 * have only FSH* to work with. When didfds is true, we have 0,1,2 and
283 * prefer to use these.
284 */
285 initdesc();
286 /*
287 * XXX: This is to keep programs that use stdio happy.
288 * what we really want is freunopen() ....
289 * Closing cshin cshout and csherr (which are really stdin stdout
290 * and stderr at this point and then reopening them in the same order
291 * gives us again stdin == cshin stdout == cshout and stderr == csherr.
292 * If that was not the case builtins like printf that use stdio
293 * would break. But in any case we could fix that with memcpy and
294 * a bit of pointer manipulation...
295 * Fortunately this is not needed under the current implementation
296 * of stdio.
297 */
298 (void)fclose(cshin);
299 (void)fclose(cshout);
300 (void)fclose(csherr);
301 if (!(cshin = funopen2((void *) &SHIN, readf, writef, seekf, NULL,
302 closef)))
303 exit(1);
304 if (!(cshout = funopen2((void *) &SHOUT, readf, writef, seekf, NULL,
305 closef)))
306 exit(1);
307 if (!(csherr = funopen2((void *) &SHERR, readf, writef, seekf, NULL,
308 closef)))
309 exit(1);
310 (void)setvbuf(cshin, NULL, _IOLBF, 0);
311 (void)setvbuf(cshout, NULL, _IOLBF, 0);
312 (void)setvbuf(csherr, NULL, _IOLBF, 0);
313
314 /*
315 * Initialize the shell variables. ARGV and PROMPT are initialized later.
316 * STATUS is also munged in several places. CHILD is munged when
317 * forking/waiting
318 */
319 set(STRstatus, Strsave(STR0));
320
321 if ((ecp = getenv("HOME")) != NULL)
322 cp = quote(SAVE(ecp));
323 else
324 cp = NULL;
325
326 if (cp == NULL)
327 fast = 1; /* No home -> can't read scripts */
328 else
329 set(STRhome, cp);
330 dinit(cp); /* dinit thinks that HOME == cwd in a login
331 * shell */
332 /*
333 * Grab other useful things from the environment. Should we grab
334 * everything??
335 */
336 if ((ecp = getenv("LOGNAME")) != NULL ||
337 (ecp = getenv("USER")) != NULL)
338 set(STRuser, quote(SAVE(ecp)));
339 if ((ecp = getenv("TERM")) != NULL)
340 set(STRterm, quote(SAVE(ecp)));
341
342 /*
343 * Re-initialize path if set in environment
344 */
345 if ((ecp = getenv("PATH")) == NULL) {
346 #ifdef _PATH_DEFPATH
347 importpath(str2short(_PATH_DEFPATH));
348 #else
349 setq(STRpath, defaultpath(), &shvhed);
350 #endif
351 } else {
352 importpath(str2short(ecp));
353 }
354
355 set(STRshell, Strsave(STR_SHELLPATH));
356
357 doldol = putn((int) getpid()); /* For $$ */
358 shtemp = Strspl(STRtmpsh, doldol); /* For << */
359
360 /*
361 * Record the interrupt states from the parent process. If the parent is
362 * non-interruptible our hand must be forced or we (and our children) won't
363 * be either. Our children inherit termination from our parent. We catch it
364 * only if we are the login shell.
365 */
366 /* parents interruptibility */
367 (void)sigaction(SIGINT, NULL, &oact);
368 parintr = oact.sa_handler;
369 (void)sigaction(SIGTERM, NULL, &oact);
370 parterm = oact.sa_handler;
371
372 /* catch these all, login shell or not */
373 (void)signal(SIGHUP, phup); /* exit processing on HUP */
374 (void)signal(SIGXCPU, phup); /* ...and on XCPU */
375 (void)signal(SIGXFSZ, phup); /* ...and on XFSZ */
376
377 /*
378 * Process the arguments.
379 *
380 * Note that processing of -v/-x is actually delayed till after script
381 * processing.
382 *
383 * We set the first character of our name to be '-' if we are a shell
384 * running interruptible commands. Many programs which examine ps'es
385 * use this to filter such shells out.
386 */
387 argc--, tempv++;
388 while (argc > 0 && (tcp = tempv[0])[0] == '-' && *++tcp != '\0' && !batch) {
389 do
390 switch (*tcp++) {
391 case 0: /* - Interruptible, no prompt */
392 prompt = 0;
393 setintr = 1;
394 nofile = 1;
395 break;
396 case 'b': /* -b Next arg is input file */
397 batch = 1;
398 break;
399 case 'c': /* -c Command input from arg */
400 if (argc == 1)
401 xexit(0);
402 argc--, tempv++;
403 arginp = SAVE(tempv[0]);
404 prompt = 0;
405 nofile = 1;
406 break;
407 case 'e': /* -e Exit on any error */
408 exiterr = 1;
409 break;
410 case 'f': /* -f Fast start */
411 fast = 1;
412 break;
413 case 'i': /* -i Interactive, even if !intty */
414 intact = 1;
415 nofile = 1;
416 break;
417 case 'm': /* -m read .cshrc (from su) */
418 mflag = 1;
419 break;
420 case 'n': /* -n Don't execute */
421 noexec = 1;
422 break;
423 case 'q': /* -q (Undoc'd) ... die on quit */
424 quitit = 1;
425 break;
426 case 's': /* -s Read from std input */
427 nofile = 1;
428 break;
429 case 't': /* -t Read one line from input */
430 onelflg = 2;
431 prompt = 0;
432 nofile = 1;
433 break;
434 case 'v': /* -v Echo hist expanded input */
435 nverbose = 1; /* ... later */
436 break;
437 case 'x': /* -x Echo just before execution */
438 nexececho = 1; /* ... later */
439 break;
440 case 'V': /* -V Echo hist expanded input */
441 setNS(STRverbose); /* NOW! */
442 break;
443 case 'X': /* -X Echo just before execution */
444 setNS(STRecho); /* NOW! */
445 break;
446
447 } while (*tcp);
448 tempv++, argc--;
449 }
450
451 if (quitit) /* With all due haste, for debugging */
452 (void)signal(SIGQUIT, SIG_DFL);
453
454 /*
455 * Unless prevented by -, -c, -i, -s, or -t, if there are remaining
456 * arguments the first of them is the name of a shell file from which to
457 * read commands.
458 */
459 if (nofile == 0 && argc > 0) {
460 nofile = open(tempv[0], O_RDONLY);
461 if (nofile < 0) {
462 child = 1; /* So this doesn't return */
463 stderror(ERR_SYSTEM, tempv[0], strerror(errno));
464 }
465 ffile = SAVE(tempv[0]);
466 /*
467 * Replace FSHIN. Handle /dev/std{in,out,err} specially
468 * since once they are closed we cannot open them again.
469 * In that case we use our own saved descriptors
470 */
471 if ((SHIN = dmove(nofile, FSHIN)) < 0)
472 switch(nofile) {
473 case 0:
474 SHIN = FSHIN;
475 break;
476 case 1:
477 SHIN = FSHOUT;
478 break;
479 case 2:
480 SHIN = FSHERR;
481 break;
482 default:
483 stderror(ERR_SYSTEM, tempv[0], strerror(errno));
484 /* NOTREACHED */
485 }
486 (void)ioctl(SHIN, FIOCLEX, NULL);
487 prompt = 0;
488 /* argc not used any more */ tempv++;
489 }
490
491 intty = isatty(SHIN);
492 intty |= intact;
493 if (intty || (intact && isatty(SHOUT))) {
494 if (!batch && (uid != euid || gid != egid)) {
495 errno = EACCES;
496 child = 1; /* So this doesn't return */
497 stderror(ERR_SYSTEM, "csh", strerror(errno));
498 }
499 }
500 /*
501 * Decide whether we should play with signals or not. If we are explicitly
502 * told (via -i, or -) or we are a login shell (arg0 starts with -) or the
503 * input and output are both the ttys("csh", or "csh</dev/ttyx>/dev/ttyx")
504 * Note that in only the login shell is it likely that parent may have set
505 * signals to be ignored
506 */
507 if (loginsh || intact || (intty && isatty(SHOUT)))
508 setintr = 1;
509 settell();
510 /*
511 * Save the remaining arguments in argv.
512 */
513 setq(STRargv, blk2short(tempv), &shvhed);
514
515 /*
516 * Set up the prompt.
517 */
518 if (prompt) {
519 set(STRprompt, Strsave(uid == 0 ? STRsymhash : STRsymcent));
520 /* that's a meta-questionmark */
521 set(STRprompt2, Strsave(STRmquestion));
522 }
523
524 /*
525 * If we are an interactive shell, then start fiddling with the signals;
526 * this is a tricky game.
527 */
528 shpgrp = getpgrp();
529 opgrp = tpgrp = -1;
530 if (setintr) {
531 **argv = '-';
532 if (!quitit) /* Wary! */
533 (void)signal(SIGQUIT, SIG_IGN);
534 (void)signal(SIGINT, pintr);
535 sigemptyset(&nsigset);
536 (void)sigaddset(&nsigset, SIGINT);
537 (void)sigprocmask(SIG_BLOCK, &nsigset, NULL);
538 (void)signal(SIGTERM, SIG_IGN);
539 if (quitit == 0 && arginp == 0) {
540 (void)signal(SIGTSTP, SIG_IGN);
541 (void)signal(SIGTTIN, SIG_IGN);
542 (void)signal(SIGTTOU, SIG_IGN);
543 /*
544 * Wait till in foreground, in case someone stupidly runs csh &
545 * dont want to try to grab away the tty.
546 */
547 if (isatty(FSHERR))
548 f = FSHERR;
549 else if (isatty(FSHOUT))
550 f = FSHOUT;
551 else if (isatty(OLDSTD))
552 f = OLDSTD;
553 else
554 f = -1;
555 retry:
556 if ((tpgrp = tcgetpgrp(f)) != -1) {
557 if (tpgrp != shpgrp) {
558 sig_t old = signal(SIGTTIN, SIG_DFL);
559 (void)kill(0, SIGTTIN);
560 (void)signal(SIGTTIN, old);
561 goto retry;
562 }
563 opgrp = shpgrp;
564 shpgrp = getpid();
565 tpgrp = shpgrp;
566 /*
567 * Setpgid will fail if we are a session leader and
568 * mypid == mypgrp (POSIX 4.3.3)
569 */
570 if (opgrp != shpgrp)
571 if (setpgid(0, shpgrp) == -1)
572 goto notty;
573 /*
574 * We do that after we set our process group, to make sure
575 * that the process group belongs to a process in the same
576 * session as the tty (our process and our group) (POSIX 7.2.4)
577 */
578 if (tcsetpgrp(f, shpgrp) == -1)
579 goto notty;
580 (void)ioctl(dcopy(f, FSHTTY), FIOCLEX, NULL);
581 }
582 if (tpgrp == -1) {
583 notty:
584 (void)fprintf(csherr, "Warning: no access to tty (%s).\n",
585 strerror(errno));
586 (void)fprintf(csherr, "Thus no job control in this shell.\n");
587 }
588 }
589 }
590 if ((setintr == 0) && (parintr == SIG_DFL))
591 setintr = 1;
592 (void)signal(SIGCHLD, pchild); /* while signals not ready */
593
594 /*
595 * Set an exit here in case of an interrupt or error reading the shell
596 * start-up scripts.
597 */
598 reenter = setexit(); /* PWP */
599 haderr = 0; /* In case second time through */
600 if (!fast && reenter == 0) {
601 /* Will have value(STRhome) here because set fast if don't */
602 {
603 sig_t oparintr;
604 sigset_t osigset;
605 int osetintr;
606
607 oparintr = parintr;
608 osetintr = setintr;
609 sigemptyset(&nsigset);
610 (void)sigaddset(&nsigset, SIGINT);
611 (void)sigprocmask(SIG_BLOCK, &nsigset, &osigset);
612
613 setintr = 0;
614 parintr = SIG_IGN; /* Disable onintr */
615 #ifdef _PATH_DOTCSHRC
616 (void)srcfile(_PATH_DOTCSHRC, 0, 0);
617 #endif
618 if (!fast && !arginp && !onelflg)
619 dohash(NULL, NULL);
620 #ifdef _PATH_DOTLOGIN
621 if (loginsh)
622 (void)srcfile(_PATH_DOTLOGIN, 0, 0);
623 #endif
624 (void)sigprocmask(SIG_SETMASK, &osigset, NULL);
625 setintr = osetintr;
626 parintr = oparintr;
627 }
628 (void)srccat(value(STRhome), STRsldotcshrc);
629
630 if (!fast && !arginp && !onelflg && !havhash)
631 dohash(NULL, NULL);
632 /*
633 * Source history before .login so that it is available in .login
634 */
635 if ((cp = value(STRhistfile)) != STRNULL)
636 tildehist[2] = cp;
637 dosource(tildehist, NULL);
638 if (loginsh)
639 (void)srccat(value(STRhome), STRsldotlogin);
640 }
641
642 /*
643 * Now are ready for the -v and -x flags
644 */
645 if (nverbose)
646 setNS(STRverbose);
647 if (nexececho)
648 setNS(STRecho);
649
650 /*
651 * All the rest of the world is inside this call. The argument to process
652 * indicates whether it should catch "error unwinds". Thus if we are a
653 * interactive shell our call here will never return by being blown past on
654 * an error.
655 */
656 process(setintr);
657
658 /*
659 * Mop-up.
660 */
661 if (intty) {
662 if (loginsh) {
663 (void)fprintf(cshout, "logout\n");
664 (void)close(SHIN);
665 child = 1;
666 goodbye();
667 }
668 else {
669 (void)fprintf(cshout, "exit\n");
670 }
671 }
672 rechist();
673 exitstat();
674 /* NOTREACHED */
675 }
676
677 void
untty(void)678 untty(void)
679 {
680 if (tpgrp > 0) {
681 (void)setpgid(0, opgrp);
682 (void)tcsetpgrp(FSHTTY, opgrp);
683 }
684 }
685
686 void
importpath(Char * cp)687 importpath(Char *cp)
688 {
689 Char *dp, **pv;
690 int c, i;
691
692 i = 0;
693 for (dp = cp; *dp; dp++)
694 if (*dp == ':')
695 i++;
696 /*
697 * i+2 where i is the number of colons in the path. There are i+1
698 * directories in the path plus we need room for a zero terminator.
699 */
700 pv = xcalloc((size_t) (i + 2), sizeof(*pv));
701 dp = cp;
702 i = 0;
703 if (*dp)
704 for (;;) {
705 if ((c = *dp) == ':' || c == 0) {
706 *dp = 0;
707 pv[i++] = Strsave(*cp ? cp : STRdot);
708 if (c) {
709 cp = dp + 1;
710 *dp = ':';
711 }
712 else
713 break;
714 }
715 dp++;
716 }
717 pv[i] = 0;
718 setq(STRpath, pv, &shvhed);
719 }
720
721 /*
722 * Source to the file which is the catenation of the argument names.
723 */
724 static int
srccat(Char * cp,Char * dp)725 srccat(Char *cp, Char *dp)
726 {
727 Char *ep;
728 char *ptr;
729
730 ep = Strspl(cp, dp);
731 ptr = short2str(ep);
732 free(ep);
733 return srcfile(ptr, mflag ? 0 : 1, 0);
734 }
735
736 /*
737 * Source to a file putting the file descriptor in a safe place (> 2).
738 */
739 static int
srcfile(const char * f,int onlyown,int flag)740 srcfile(const char *f, int onlyown, int flag)
741 {
742 int unit;
743
744 if ((unit = open(f, O_RDONLY)) == -1)
745 return 0;
746 unit = dmove(unit, -1);
747
748 (void) ioctl(unit, FIOCLEX, NULL);
749 srcunit(unit, onlyown, flag);
750 return 1;
751 }
752
753 /*
754 * Source to a unit. If onlyown it must be our file or our group or
755 * we don't chance it. This occurs on ".cshrc"s and the like.
756 */
757 int insource;
758
759 static void
srcunit(int unit,int onlyown,int hflg)760 srcunit(int unit, int onlyown, int hflg)
761 {
762 /* We have to push down a lot of state here */
763 /* All this could go into a structure */
764 struct whyle *oldwhyl;
765 struct Bin saveB;
766 sigset_t nsigset, osigset;
767 jmp_buf oldexit;
768 Char *oarginp, *oevalp, **oevalvec, *ogointr;
769 Char OHIST;
770 int oSHIN, oinsource, oldintty, oonelflg;
771 int oenterhist, otell;
772 /* The (few) real local variables */
773 int my_reenter;
774
775 oSHIN = -1;
776 oldintty = intty;
777 oinsource = insource;
778 oldwhyl = whyles;
779 ogointr = gointr;
780 oarginp = arginp;
781 oevalp = evalp;
782 oevalvec = evalvec;
783 oonelflg = onelflg;
784 oenterhist = enterhist;
785 OHIST = HIST;
786 otell = cantell;
787
788 if (unit < 0)
789 return;
790 if (didfds)
791 donefds();
792 if (onlyown) {
793 struct stat stb;
794
795 if (fstat(unit, &stb) < 0) {
796 (void)close(unit);
797 return;
798 }
799 }
800
801 /*
802 * There is a critical section here while we are pushing down the input
803 * stream since we have stuff in different structures. If we weren't
804 * careful an interrupt could corrupt SHIN's Bin structure and kill the
805 * shell.
806 *
807 * We could avoid the critical region by grouping all the stuff in a single
808 * structure and pointing at it to move it all at once. This is less
809 * efficient globally on many variable references however.
810 */
811 insource = 1;
812 getexit(oldexit);
813
814 if (setintr) {
815 sigemptyset(&nsigset);
816 (void)sigaddset(&nsigset, SIGINT);
817 (void)sigprocmask(SIG_BLOCK, &nsigset, &osigset);
818 }
819 /* Setup the new values of the state stuff saved above */
820 (void)memcpy(&saveB, &B, sizeof(B));
821 fbuf = NULL;
822 fseekp = feobp = fblocks = 0;
823 oSHIN = SHIN, SHIN = unit, arginp = 0, onelflg = 0;
824 intty = isatty(SHIN), whyles = 0, gointr = 0;
825 evalvec = 0;
826 evalp = 0;
827 enterhist = hflg;
828 if (enterhist)
829 HIST = '\0';
830
831 /*
832 * Now if we are allowing commands to be interrupted, we let ourselves be
833 * interrupted.
834 */
835 if (setintr)
836 (void)sigprocmask(SIG_SETMASK, &osigset, NULL);
837 settell();
838
839 if ((my_reenter = setexit()) == 0)
840 process(0); /* 0 -> blow away on errors */
841
842 if (setintr)
843 (void)sigprocmask(SIG_SETMASK, &osigset, NULL);
844 if (oSHIN >= 0) {
845 int i;
846
847 /* We made it to the new state... free up its storage */
848 for (i = 0; i < fblocks; i++)
849 free(fbuf[i]);
850 free(fbuf);
851
852 /* Reset input arena */
853 /* (note that this clears fbuf and fblocks) */
854 (void)memcpy(&B, &saveB, sizeof(B));
855
856 (void)close(SHIN), SHIN = oSHIN;
857 arginp = oarginp, onelflg = oonelflg;
858 evalp = oevalp, evalvec = oevalvec;
859 intty = oldintty, whyles = oldwhyl, gointr = ogointr;
860 if (enterhist)
861 HIST = OHIST;
862 enterhist = oenterhist;
863 cantell = otell;
864 }
865
866 resexit(oldexit);
867 /*
868 * If process reset() (effectively an unwind) then we must also unwind.
869 */
870 if (my_reenter)
871 stderror(ERR_SILENT);
872 insource = oinsource;
873 }
874
875 void
rechist(void)876 rechist(void)
877 {
878 Char buf[BUFSIZE], hbuf[BUFSIZE], *hfile;
879 int fp, ftmp, oldidfds;
880 struct varent *shist;
881
882 if (!fast) {
883 /*
884 * If $savehist is just set, we use the value of $history
885 * else we use the value in $savehist
886 */
887 if ((shist = adrof(STRsavehist)) != NULL) {
888 if (shist->vec[0][0] != '\0')
889 (void)Strcpy(hbuf, shist->vec[0]);
890 else if ((shist = adrof(STRhistory)) && shist->vec[0][0] != '\0')
891 (void)Strcpy(hbuf, shist->vec[0]);
892 else
893 return;
894 }
895 else
896 return;
897
898 if ((hfile = value(STRhistfile)) == STRNULL) {
899 hfile = Strcpy(buf, value(STRhome));
900 (void) Strcat(buf, STRsldthist);
901 }
902
903 if ((fp = open(short2str(hfile), O_WRONLY | O_CREAT | O_TRUNC,
904 0600)) == -1)
905 return;
906
907 oldidfds = didfds;
908 didfds = 0;
909 ftmp = SHOUT;
910 SHOUT = fp;
911 dumphist[2] = hbuf;
912 dohist(dumphist, NULL);
913 SHOUT = ftmp;
914 (void)close(fp);
915 didfds = oldidfds;
916 }
917 }
918
919 void
goodbye(void)920 goodbye(void)
921 {
922 rechist();
923
924 if (loginsh) {
925 (void)signal(SIGQUIT, SIG_IGN);
926 (void)signal(SIGINT, SIG_IGN);
927 (void)signal(SIGTERM, SIG_IGN);
928 setintr = 0; /* No interrupts after "logout" */
929 if (!(adrof(STRlogout)))
930 set(STRlogout, STRnormal);
931 #ifdef _PATH_DOTLOGOUT
932 (void)srcfile(_PATH_DOTLOGOUT, 0, 0);
933 #endif
934 if (adrof(STRhome))
935 (void)srccat(value(STRhome), STRsldtlogout);
936 }
937 exitstat();
938 /* NOTREACHED */
939 }
940
941 __dead void
exitstat(void)942 exitstat(void)
943 {
944 Char *s;
945 #ifdef PROF
946 monitor(0);
947 #endif
948 /*
949 * Note that if STATUS is corrupted (i.e. getn bombs) then error will exit
950 * directly because we poke child here. Otherwise we might continue
951 * unwarrantedly (sic).
952 */
953 child = 1;
954 s = value(STRstatus);
955 xexit(s ? getn(s) : 0);
956 /* NOTREACHED */
957 }
958
959 /*
960 * in the event of a HUP we want to save the history
961 */
962 static void
phup(int sig)963 phup(int sig)
964 {
965 rechist();
966
967 /*
968 * We kill the last foreground process group. It then becomes
969 * responsible to propagate the SIGHUP to its progeny.
970 */
971 {
972 struct process *pp, *np;
973
974 for (pp = proclist.p_next; pp; pp = pp->p_next) {
975 np = pp;
976 /*
977 * Find if this job is in the foreground. It could be that
978 * the process leader has exited and the foreground flag
979 * is cleared for it.
980 */
981 do
982 /*
983 * If a process is in the foreground; we try to kill
984 * its process group. If we succeed, then the
985 * whole job is gone. Otherwise we keep going...
986 * But avoid sending HUP to the shell again.
987 */
988 if ((np->p_flags & PFOREGND) != 0 && np->p_jobid != shpgrp &&
989 kill(-np->p_jobid, SIGHUP) != -1) {
990 /* In case the job was suspended... */
991 (void)kill(-np->p_jobid, SIGCONT);
992 break;
993 }
994 while ((np = np->p_friends) != pp);
995 }
996 }
997 xexit(sig);
998 /* NOTREACHED */
999 }
1000
1001 Char *jobargv[2] = {STRjobs, 0};
1002
1003 /*
1004 * Catch an interrupt, e.g. during lexical input.
1005 * If we are an interactive shell, we reset the interrupt catch
1006 * immediately. In any case we drain the shell output,
1007 * and finally go through the normal error mechanism, which
1008 * gets a chance to make the shell go away.
1009 */
1010 /* ARGSUSED */
1011 void
pintr(int notused)1012 pintr(int notused)
1013 {
1014 pintr1(1);
1015 /* NOTREACHED */
1016 }
1017
1018 void
pintr1(int wantnl)1019 pintr1(int wantnl)
1020 {
1021 Char **v;
1022 sigset_t nsigset, osigset;
1023
1024 sigemptyset(&nsigset);
1025 (void)sigprocmask(SIG_BLOCK, &nsigset, &osigset);
1026 if (setintr) {
1027 nsigset = osigset;
1028 (void)sigdelset(&nsigset, SIGINT);
1029 (void)sigprocmask(SIG_SETMASK, &nsigset, NULL);
1030 if (pjobs) {
1031 pjobs = 0;
1032 (void)fprintf(cshout, "\n");
1033 dojobs(jobargv, NULL);
1034 stderror(ERR_NAME | ERR_INTR);
1035 }
1036 }
1037 (void)sigdelset(&osigset, SIGCHLD);
1038 (void)sigprocmask(SIG_SETMASK, &osigset, NULL);
1039 (void)fpurge(cshout);
1040 (void)endpwent();
1041
1042 /*
1043 * If we have an active "onintr" then we search for the label. Note that if
1044 * one does "onintr -" then we shan't be interruptible so we needn't worry
1045 * about that here.
1046 */
1047 if (gointr) {
1048 gotolab(gointr);
1049 timflg = 0;
1050 if ((v = pargv) != NULL)
1051 pargv = 0, blkfree(v);
1052 if ((v = gargv) != NULL)
1053 gargv = 0, blkfree(v);
1054 reset();
1055 }
1056 else if (intty && wantnl) {
1057 (void)fputc('\r', cshout);
1058 (void)fputc('\n', cshout);
1059 }
1060 stderror(ERR_SILENT);
1061 /* NOTREACHED */
1062 }
1063
1064 /*
1065 * Process is the main driving routine for the shell.
1066 * It runs all command processing, except for those within { ... }
1067 * in expressions (which is run by a routine evalav in sh.exp.c which
1068 * is a stripped down process), and `...` evaluation which is run
1069 * also by a subset of this code in sh.glob.c in the routine backeval.
1070 *
1071 * The code here is a little strange because part of it is interruptible
1072 * and hence freeing of structures appears to occur when none is necessary
1073 * if this is ignored.
1074 *
1075 * Note that if catch is not set then we will unwind on any error.
1076 * If an end-of-file occurs, we return.
1077 */
1078 static struct command *savet = NULL;
1079
1080 void
process(int catch)1081 process(int catch)
1082 {
1083 struct command *t;
1084 jmp_buf osetexit;
1085 sigset_t nsigset;
1086
1087 t = savet;
1088 savet = NULL;
1089 getexit(osetexit);
1090 for (;;) {
1091 pendjob();
1092 paraml.next = paraml.prev = ¶ml;
1093 paraml.word = STRNULL;
1094 (void)setexit();
1095 justpr = enterhist; /* execute if not entering history */
1096
1097 /*
1098 * Interruptible during interactive reads
1099 */
1100 if (setintr) {
1101 sigemptyset(&nsigset);
1102 (void)sigaddset(&nsigset, SIGINT);
1103 (void)sigprocmask(SIG_UNBLOCK, &nsigset, NULL);
1104 }
1105
1106 /*
1107 * For the sake of reset()
1108 */
1109 freelex(¶ml);
1110 if (savet)
1111 freesyn(savet), savet = NULL;
1112
1113 if (haderr) {
1114 if (!catch) {
1115 /* unwind */
1116 doneinp = 0;
1117 resexit(osetexit);
1118 savet = t;
1119 reset();
1120 }
1121 haderr = 0;
1122 /*
1123 * Every error is eventually caught here or the shell dies. It is
1124 * at this point that we clean up any left-over open files, by
1125 * closing all but a fixed number of pre-defined files. Thus
1126 * routines don't have to worry about leaving files open due to
1127 * deeper errors... they will get closed here.
1128 */
1129 closem();
1130 continue;
1131 }
1132 if (doneinp) {
1133 doneinp = 0;
1134 break;
1135 }
1136 if (chkstop)
1137 chkstop--;
1138 if (neednote)
1139 pnote();
1140 if (intty && prompt && evalvec == 0) {
1141 mailchk();
1142 #ifdef EDIT
1143 updateediting();
1144 #endif
1145 /*
1146 * If we are at the end of the input buffer then we are going to
1147 * read fresh stuff. Otherwise, we are rereading input and don't
1148 * need or want to prompt.
1149 */
1150 if (aret == F_SEEK && fseekp == feobp)
1151 printprompt();
1152 (void)fflush(cshout);
1153 }
1154 if (seterr) {
1155 free(seterr);
1156 seterr = NULL;
1157 }
1158
1159
1160 /*
1161 * Echo not only on VERBOSE, but also with history expansion. If there
1162 * is a lexical error then we forego history echo.
1163 */
1164 if ((lex(¶ml) && !seterr && intty) || adrof(STRverbose)) {
1165 int odidfds = didfds;
1166 fflush(csherr);
1167 didfds = 0;
1168 prlex(csherr, ¶ml);
1169 fflush(csherr);
1170 didfds = odidfds;
1171 }
1172
1173 /*
1174 * The parser may lose space if interrupted.
1175 */
1176 if (setintr)
1177 (void)sigprocmask(SIG_BLOCK, &nsigset, NULL);
1178
1179 /*
1180 * Save input text on the history list if reading in old history, or it
1181 * is from the terminal at the top level and not in a loop.
1182 *
1183 * PWP: entry of items in the history list while in a while loop is done
1184 * elsewhere...
1185 */
1186 if (enterhist || (catch && intty && !whyles))
1187 savehist(¶ml);
1188
1189 /*
1190 * Print lexical error messages, except when sourcing history lists.
1191 */
1192 if (!enterhist && seterr)
1193 stderror(ERR_OLD);
1194
1195 /*
1196 * If had a history command :p modifier then this is as far as we
1197 * should go
1198 */
1199 if (justpr)
1200 reset();
1201
1202 alias(¶ml);
1203
1204 /*
1205 * Parse the words of the input into a parse tree.
1206 */
1207 savet = syntax(paraml.next, ¶ml, 0);
1208 if (seterr)
1209 stderror(ERR_OLD);
1210
1211 execute(savet, (tpgrp > 0 ? tpgrp : -1), NULL, NULL);
1212
1213 /*
1214 * Made it!
1215 */
1216 freelex(¶ml);
1217 freesyn(savet), savet = NULL;
1218 }
1219 resexit(osetexit);
1220 savet = t;
1221 }
1222
1223 void
1224 /*ARGSUSED*/
dosource(Char ** v,struct command * t)1225 dosource(Char **v, struct command *t)
1226 {
1227 Char buf[BUFSIZE], *f;
1228 int hflg;
1229
1230 hflg = 0;
1231 v++;
1232 if (*v && eq(*v, STRmh)) {
1233 if (*++v == NULL)
1234 stderror(ERR_NAME | ERR_HFLAG);
1235 hflg++;
1236 }
1237 (void)Strcpy(buf, *v);
1238 f = globone(buf, G_ERROR);
1239 (void)strcpy((char *)buf, short2str(f));
1240 free(f);
1241 if (!srcfile((char *)buf, 0, hflg) && !hflg)
1242 stderror(ERR_SYSTEM, (char *)buf, strerror(errno));
1243 }
1244
1245 /*
1246 * Check for mail.
1247 * If we are a login shell, then we don't want to tell
1248 * about any mail file unless its been modified
1249 * after the time we started.
1250 * This prevents us from telling the user things he already
1251 * knows, since the login program insists on saying
1252 * "You have mail."
1253 */
1254 static void
mailchk(void)1255 mailchk(void)
1256 {
1257 struct stat stb;
1258 struct varent *v;
1259 Char **vp;
1260 time_t t;
1261 int cnt, intvl;
1262 int new;
1263
1264 v = adrof(STRmail);
1265 if (v == 0)
1266 return;
1267 (void)time(&t);
1268 vp = v->vec;
1269 cnt = blklen(vp);
1270 intvl = (cnt && number(*vp)) ? (--cnt, getn(*vp++)) : MAILINTVL;
1271 if (intvl < 1)
1272 intvl = 1;
1273 if (chktim + intvl > t)
1274 return;
1275 for (; *vp; vp++) {
1276 if (stat(short2str(*vp), &stb) < 0)
1277 continue;
1278 new = stb.st_mtime > time0.tv_sec;
1279 if (stb.st_size == 0 || stb.st_atime > stb.st_mtime ||
1280 (stb.st_atime < chktim && stb.st_mtime < chktim) ||
1281 (loginsh && !new))
1282 continue;
1283 if (cnt == 1)
1284 (void)fprintf(cshout, "You have %smail.\n", new ? "new " : "");
1285 else
1286 (void)fprintf(cshout, "%s in %s.\n", new ? "New mail" : "Mail",
1287 vis_str(*vp));
1288 }
1289 chktim = t;
1290 }
1291
1292 /*
1293 * Extract a home directory from the password file
1294 * The argument points to a buffer where the name of the
1295 * user whose home directory is sought is currently.
1296 * We write the home directory of the user back there.
1297 */
1298 int
gethdir(Char * home)1299 gethdir(Char *home)
1300 {
1301 struct passwd *pw;
1302 Char *h;
1303
1304 /*
1305 * Is it us?
1306 */
1307 if (*home == '\0') {
1308 if ((h = value(STRhome)) != NULL) {
1309 (void)Strcpy(home, h);
1310 return 0;
1311 }
1312 else
1313 return 1;
1314 }
1315
1316 if ((pw = getpwnam(short2str(home))) != NULL) {
1317 (void)Strcpy(home, str2short(pw->pw_dir));
1318 return 0;
1319 }
1320 else
1321 return 1;
1322 }
1323
1324 /*
1325 * When didfds is set, we do I/O from 0, 1, 2 otherwise from 15, 16, 17
1326 * We also check if the shell has already changed the descriptor to point to
1327 * 0, 1, 2 when didfds is set.
1328 */
1329 #define DESC(a) (*((int *) (a)) - (didfds && *((int *) a) >= FSHIN ? FSHIN : 0))
1330
1331 static ssize_t
readf(void * oreo,void * buf,size_t siz)1332 readf(void *oreo, void *buf, size_t siz)
1333 {
1334 return read(DESC(oreo), buf, siz);
1335 }
1336
1337
1338 static ssize_t
writef(void * oreo,const void * buf,size_t siz)1339 writef(void *oreo, const void *buf, size_t siz)
1340 {
1341 return write(DESC(oreo), buf, siz);
1342 }
1343
1344 static off_t
seekf(void * oreo,off_t off,int whence)1345 seekf(void *oreo, off_t off, int whence)
1346 {
1347 return lseek(DESC(oreo), off, whence);
1348 }
1349
1350
1351 static int
closef(void * oreo)1352 closef(void *oreo)
1353 {
1354 return close(DESC(oreo));
1355 }
1356
1357
1358 /*
1359 * Print the visible version of a string.
1360 */
1361 int
vis_fputc(int ch,FILE * fp)1362 vis_fputc(int ch, FILE *fp)
1363 {
1364 char uenc[5]; /* 4 + NULL */
1365
1366 if (ch & QUOTE)
1367 return fputc(ch & TRIM, fp);
1368 /*
1369 * XXX: When we are in AsciiOnly we want all characters >= 0200 to
1370 * be encoded, but currently there is no way in vis to do that.
1371 */
1372 (void)vis(uenc, ch & TRIM, VIS_NOSLASH, 0);
1373 return (fputs(uenc, fp));
1374 }
1375
1376 /*
1377 * Move the initial descriptors to their eventual
1378 * resting places, closing all other units.
1379 */
1380 void
initdesc(void)1381 initdesc(void)
1382 {
1383 didfds = 0; /* 0, 1, 2 aren't set up */
1384 (void)ioctl(SHIN = dcopy(0, FSHIN), FIOCLEX, NULL);
1385 (void)ioctl(SHOUT = dcopy(1, FSHOUT), FIOCLEX, NULL);
1386 (void)ioctl(SHERR = dcopy(2, FSHERR), FIOCLEX, NULL);
1387 (void)ioctl(OLDSTD = dcopy(SHIN, FOLDSTD), FIOCLEX, NULL);
1388 closem();
1389 }
1390
1391
1392 __dead void
1393 #ifdef PROF
done(int i)1394 done(int i)
1395 #else
1396 xexit(int i)
1397 #endif
1398 {
1399 untty();
1400 _exit(i);
1401 /* NOTREACHED */
1402 }
1403
1404 #ifndef _PATH_DEFPATH
1405 static Char **
defaultpath(void)1406 defaultpath(void)
1407 {
1408 struct stat stb;
1409 Char **blk, **blkp;
1410 char *ptr;
1411
1412 blkp = blk = xmalloc((size_t) sizeof(Char *) * 10);
1413
1414 #define DIRAPPEND(a) \
1415 if (stat(ptr = a, &stb) == 0 && S_ISDIR(stb.st_mode)) \
1416 *blkp++ = SAVE(ptr)
1417 #ifdef RESCUEDIR
1418 DIRAPPEND(RESCUEDIR);
1419 #endif
1420 DIRAPPEND(_PATH_BIN);
1421 DIRAPPEND(_PATH_USRBIN);
1422
1423 #undef DIRAPPEND
1424
1425 #if 0
1426 if (euid != 0 && uid != 0)
1427 *blkp++ = Strsave(STRdot);
1428 #endif
1429
1430 *blkp = NULL;
1431 return (blk);
1432 }
1433 #endif /* _PATH_DEFPATH */
1434
1435 void
printprompt(void)1436 printprompt(void)
1437 {
1438 Char *cp;
1439
1440 if (editing)
1441 return;
1442
1443 if (!whyles) {
1444 for (cp = value(STRprompt); *cp; cp++)
1445 if (*cp == HIST)
1446 (void)fprintf(cshout, "%d", eventno + 1);
1447 else {
1448 if (*cp == '\\' && cp[1] == HIST)
1449 cp++;
1450 (void)vis_fputc(*cp | QUOTE, cshout);
1451 }
1452 }
1453 else
1454 /*
1455 * Prompt for forward reading loop body content.
1456 */
1457 (void)fprintf(cshout, "? ");
1458 (void)fflush(cshout);
1459 }
1460
1461 #ifdef EDIT
1462 char *
printpromptstr(EditLine * elx)1463 printpromptstr(EditLine *elx) {
1464 static char pbuf[1024];
1465 static char qspace[] = "? ";
1466 Char *cp;
1467 size_t i;
1468
1469 if (whyles)
1470 return qspace;
1471
1472 i = 0;
1473 for (cp = value(STRprompt); *cp; cp++) {
1474 if (i >= sizeof(pbuf))
1475 break;
1476 if (*cp == HIST) {
1477 int r;
1478 r = snprintf(pbuf + i, sizeof(pbuf) - i, "%d", eventno + 1);
1479 if (r > 0)
1480 i += (size_t)r;
1481 } else
1482 pbuf[i++] = (char)*cp;
1483 }
1484 if (i >= sizeof(pbuf))
1485 i = sizeof(pbuf) - 1;
1486 pbuf[i] = '\0';
1487 return pbuf;
1488 }
1489 #endif
1490