GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: bin/csh/csh.c Lines: 0 525 0.0 %
Date: 2016-12-06 Branches: 0 398 0.0 %

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