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