xref: /titanic_50/usr/src/cmd/csh/sh.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
3*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
4*7c478bd9Sstevel@tonic-gate  */
5*7c478bd9Sstevel@tonic-gate 
6*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
7*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
8*7c478bd9Sstevel@tonic-gate 
9*7c478bd9Sstevel@tonic-gate /*
10*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1980 Regents of the University of California.
11*7c478bd9Sstevel@tonic-gate  * All rights reserved.  The Berkeley Software License Agreement
12*7c478bd9Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
13*7c478bd9Sstevel@tonic-gate  */
14*7c478bd9Sstevel@tonic-gate 
15*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
16*7c478bd9Sstevel@tonic-gate 
17*7c478bd9Sstevel@tonic-gate #include <locale.h>
18*7c478bd9Sstevel@tonic-gate #include "sh.h"
19*7c478bd9Sstevel@tonic-gate /* #include <sys/ioctl.h> */
20*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
21*7c478bd9Sstevel@tonic-gate #include <sys/filio.h>
22*7c478bd9Sstevel@tonic-gate #include "sh.tconst.h"
23*7c478bd9Sstevel@tonic-gate #include <pwd.h>
24*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
25*7c478bd9Sstevel@tonic-gate #include "sh_policy.h"		/* for pfcsh */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /*
28*7c478bd9Sstevel@tonic-gate  * We use these csh(1) private versions of the select macros, (see select(3C))
29*7c478bd9Sstevel@tonic-gate  * so as not to be limited by the size of struct fd_set (ie 1024).
30*7c478bd9Sstevel@tonic-gate  */
31*7c478bd9Sstevel@tonic-gate #define CSH_FD_SET(n, p)    ((*((p) + ((n)/NFDBITS))) |= (1 << ((n) % NFDBITS)))
32*7c478bd9Sstevel@tonic-gate #define CSH_FD_CLR(n, p)    ((*((p) + ((n)/NFDBITS))) &= ~(1 << ((n) % NFDBITS)))
33*7c478bd9Sstevel@tonic-gate #define CSH_FD_ISSET(n, p)  ((*((p) + ((n)/NFDBITS))) & (1 << ((n) % NFDBITS)))
34*7c478bd9Sstevel@tonic-gate #define CSH_FD_ZERO(p, n)      memset((void *)(p), 0,  (n))
35*7c478bd9Sstevel@tonic-gate 
36*7c478bd9Sstevel@tonic-gate tchar *pathlist[] =	{ S_usrbin/*"/usr/bin"*/, S_DOT /*"."*/, 0 };
37*7c478bd9Sstevel@tonic-gate tchar *dumphist[] =	{ S_history /*"history"*/, S_h /*"-h"*/, 0, 0 };
38*7c478bd9Sstevel@tonic-gate tchar *loadhist[] =	{ S_source /*"source"*/, S_h /*"-h"*/, S_NDOThistory /*"~/.history"*/, 0 };
39*7c478bd9Sstevel@tonic-gate tchar HIST = '!';
40*7c478bd9Sstevel@tonic-gate tchar HISTSUB = '^';
41*7c478bd9Sstevel@tonic-gate int	nofile;
42*7c478bd9Sstevel@tonic-gate bool	reenter;
43*7c478bd9Sstevel@tonic-gate bool	nverbose;
44*7c478bd9Sstevel@tonic-gate bool	nexececho;
45*7c478bd9Sstevel@tonic-gate bool	quitit;
46*7c478bd9Sstevel@tonic-gate bool	fast;
47*7c478bd9Sstevel@tonic-gate bool	batch;
48*7c478bd9Sstevel@tonic-gate bool	prompt = 1;
49*7c478bd9Sstevel@tonic-gate bool	enterhist = 0;
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate extern	gid_t getegid(), getgid();
52*7c478bd9Sstevel@tonic-gate extern	uid_t geteuid(), getuid();
53*7c478bd9Sstevel@tonic-gate extern tchar **strblktotsblk(/* char **, int */);
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate int siglwp();
56*7c478bd9Sstevel@tonic-gate int sigwaiting();
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate main(c, av)
59*7c478bd9Sstevel@tonic-gate 	int c;
60*7c478bd9Sstevel@tonic-gate 	char **av;
61*7c478bd9Sstevel@tonic-gate {
62*7c478bd9Sstevel@tonic-gate 	register tchar **v, *cp, *p, *q, *r;
63*7c478bd9Sstevel@tonic-gate 	register int f;
64*7c478bd9Sstevel@tonic-gate 	struct sigvec osv;
65*7c478bd9Sstevel@tonic-gate 	struct sigaction sa;
66*7c478bd9Sstevel@tonic-gate 	tchar s_prompt[MAXHOSTNAMELEN+3];
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate 	pfcshflag = 0;
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate 	/*
71*7c478bd9Sstevel@tonic-gate 	 * set up the error exit, if there is an error before
72*7c478bd9Sstevel@tonic-gate 	 * this is done, it will core dump, and we don't
73*7c478bd9Sstevel@tonic-gate 	 * tolerate core dumps
74*7c478bd9Sstevel@tonic-gate 	 */
75*7c478bd9Sstevel@tonic-gate 	haderr = 0;
76*7c478bd9Sstevel@tonic-gate 	setexit();
77*7c478bd9Sstevel@tonic-gate 	if ( haderr ) {
78*7c478bd9Sstevel@tonic-gate 		/*
79*7c478bd9Sstevel@tonic-gate 		 *  if were here, there was an error in the csh
80*7c478bd9Sstevel@tonic-gate 		 *  startup so just punt
81*7c478bd9Sstevel@tonic-gate 		 */
82*7c478bd9Sstevel@tonic-gate 		printf("csh startup error, csh exiting...\n");
83*7c478bd9Sstevel@tonic-gate 		flush();
84*7c478bd9Sstevel@tonic-gate 		exitstat();
85*7c478bd9Sstevel@tonic-gate 	}
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
89*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
90*7c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
91*7c478bd9Sstevel@tonic-gate #endif
92*7c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate 	/*
95*7c478bd9Sstevel@tonic-gate 	 * This is a profile shell if the simple name of argv[0] is
96*7c478bd9Sstevel@tonic-gate 	 * pfcsh or -pfcsh
97*7c478bd9Sstevel@tonic-gate 	 */
98*7c478bd9Sstevel@tonic-gate 	p = strtots(NOSTR, "pfcsh");
99*7c478bd9Sstevel@tonic-gate 	r = strtots(NOSTR, "-pfcsh");
100*7c478bd9Sstevel@tonic-gate 	if ((p != NOSTR) && (r != NOSTR) &&
101*7c478bd9Sstevel@tonic-gate 	    ((q = strtots(NOSTR, *av)) != NOSTR)) {
102*7c478bd9Sstevel@tonic-gate 		if (c > 0 && (eq(p, simple(q)) || eq(r, simple(q)))) {
103*7c478bd9Sstevel@tonic-gate 			pfcshflag = 1;
104*7c478bd9Sstevel@tonic-gate 		}
105*7c478bd9Sstevel@tonic-gate 		XFREE(q);
106*7c478bd9Sstevel@tonic-gate 	}
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate 	if (p != NOSTR)
109*7c478bd9Sstevel@tonic-gate 		XFREE(p);
110*7c478bd9Sstevel@tonic-gate 	if (r != NOSTR)
111*7c478bd9Sstevel@tonic-gate 		XFREE(r);
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate 	if (pfcshflag == 1) {
114*7c478bd9Sstevel@tonic-gate 		secpolicy_init();
115*7c478bd9Sstevel@tonic-gate 	}
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate 	/* Copy arguments */
118*7c478bd9Sstevel@tonic-gate 	v = strblktotsblk(av, c);
119*7c478bd9Sstevel@tonic-gate 
120*7c478bd9Sstevel@tonic-gate 	/*
121*7c478bd9Sstevel@tonic-gate 	 * Initialize paraml list
122*7c478bd9Sstevel@tonic-gate 	 */
123*7c478bd9Sstevel@tonic-gate 	paraml.next = paraml.prev = &paraml;
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate 	settimes();			/* Immed. estab. timing base */
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate 	if (eq(v[0], S_aout/*"a.out"*/))	/* A.out's are quittable */
128*7c478bd9Sstevel@tonic-gate 		quitit = 1;
129*7c478bd9Sstevel@tonic-gate 	uid = getuid();
130*7c478bd9Sstevel@tonic-gate 	loginsh = **v == '-';
131*7c478bd9Sstevel@tonic-gate 	if (loginsh)
132*7c478bd9Sstevel@tonic-gate 		(void) time(&chktim);
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate 	/*
135*7c478bd9Sstevel@tonic-gate 	 * Move the descriptors to safe places.
136*7c478bd9Sstevel@tonic-gate 	 * The variable didfds is 0 while we have only FSH* to work with.
137*7c478bd9Sstevel@tonic-gate 	 * When didfds is true, we have 0,1,2 and prefer to use these.
138*7c478bd9Sstevel@tonic-gate 	 *
139*7c478bd9Sstevel@tonic-gate 	 * Also, setup data for csh internal file descriptor book keeping.
140*7c478bd9Sstevel@tonic-gate 	 */
141*7c478bd9Sstevel@tonic-gate 	initdesc(c, av);
142*7c478bd9Sstevel@tonic-gate 
143*7c478bd9Sstevel@tonic-gate 	/*
144*7c478bd9Sstevel@tonic-gate 	 * Initialize the shell variables.
145*7c478bd9Sstevel@tonic-gate 	 * ARGV and PROMPT are initialized later.
146*7c478bd9Sstevel@tonic-gate 	 * STATUS is also munged in several places.
147*7c478bd9Sstevel@tonic-gate 	 * CHILD is munged when forking/waiting
148*7c478bd9Sstevel@tonic-gate 	 */
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate 	/* don't do globbing here, just set exact copies */
151*7c478bd9Sstevel@tonic-gate 	setNS(S_noglob);
152*7c478bd9Sstevel@tonic-gate 
153*7c478bd9Sstevel@tonic-gate 	set(S_status /* "status" */, S_0 /* "0" */);
154*7c478bd9Sstevel@tonic-gate 	dinit(cp = getenvs_("HOME"));	/* dinit thinks that HOME==cwd in a */
155*7c478bd9Sstevel@tonic-gate 					/* login shell */
156*7c478bd9Sstevel@tonic-gate 	if (cp == NOSTR)
157*7c478bd9Sstevel@tonic-gate 		fast++;			/* No home -> can't read scripts */
158*7c478bd9Sstevel@tonic-gate 	else {
159*7c478bd9Sstevel@tonic-gate 		if (strlen_(cp) >= BUFSIZ - 10) {
160*7c478bd9Sstevel@tonic-gate 			cp = NOSTR;
161*7c478bd9Sstevel@tonic-gate 			fast++;
162*7c478bd9Sstevel@tonic-gate 			printf("%s\n", gettext("Pathname too long"));
163*7c478bd9Sstevel@tonic-gate 			set(S_home /* "home" */, savestr(cp));
164*7c478bd9Sstevel@tonic-gate 			local_setenv(S_HOME, savestr(cp));
165*7c478bd9Sstevel@tonic-gate 		}
166*7c478bd9Sstevel@tonic-gate 		set(S_home /* "home" */, savestr(cp));
167*7c478bd9Sstevel@tonic-gate 	}
168*7c478bd9Sstevel@tonic-gate 	/*
169*7c478bd9Sstevel@tonic-gate 	 * Grab other useful things from the environment.
170*7c478bd9Sstevel@tonic-gate 	 * Should we grab everything??
171*7c478bd9Sstevel@tonic-gate 	 */
172*7c478bd9Sstevel@tonic-gate 	if ((cp = getenvs_("USER")) != NOSTR)
173*7c478bd9Sstevel@tonic-gate 		set(S_user/*"user"*/, savestr(cp));
174*7c478bd9Sstevel@tonic-gate 	else {
175*7c478bd9Sstevel@tonic-gate 		/*
176*7c478bd9Sstevel@tonic-gate 		 * If USER is not defined, set it here.
177*7c478bd9Sstevel@tonic-gate 		 */
178*7c478bd9Sstevel@tonic-gate 		struct passwd *pw;
179*7c478bd9Sstevel@tonic-gate 		pw = getpwuid(getuid());
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 		if (pw != NULL) {
182*7c478bd9Sstevel@tonic-gate 			set(S_user, strtots((tchar *)0, pw->pw_name ));
183*7c478bd9Sstevel@tonic-gate 			local_setenv(S_USER, strtots((tchar *)0, pw->pw_name));
184*7c478bd9Sstevel@tonic-gate 		}
185*7c478bd9Sstevel@tonic-gate 		else if (loginsh) { /* Give up setting USER variable. */
186*7c478bd9Sstevel@tonic-gate 			printf("Warning: USER environment variable could not be set.\n");
187*7c478bd9Sstevel@tonic-gate 		}
188*7c478bd9Sstevel@tonic-gate 	}
189*7c478bd9Sstevel@tonic-gate 	if ((cp = getenvs_("TERM")) != NOSTR)
190*7c478bd9Sstevel@tonic-gate 		set(S_term/*"term"*/, savestr(cp));
191*7c478bd9Sstevel@tonic-gate 	/*
192*7c478bd9Sstevel@tonic-gate 	 * Re-initialize path if set in environment
193*7c478bd9Sstevel@tonic-gate 	 */
194*7c478bd9Sstevel@tonic-gate 	if ((cp = getenvs_("PATH")) == NOSTR)
195*7c478bd9Sstevel@tonic-gate 		set1(S_path/*"path"*/, saveblk(pathlist), &shvhed);
196*7c478bd9Sstevel@tonic-gate 	else
197*7c478bd9Sstevel@tonic-gate 		importpath(cp);
198*7c478bd9Sstevel@tonic-gate 	set(S_shell/*"shell"*/, S_SHELLPATH);
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate 	doldol = putn(getpid());		/* For $$ */
201*7c478bd9Sstevel@tonic-gate 
202*7c478bd9Sstevel@tonic-gate 	/* restore globbing until the user says otherwise */
203*7c478bd9Sstevel@tonic-gate 	unsetv(S_noglob);
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate 	/*
206*7c478bd9Sstevel@tonic-gate 	 * Record the interrupt states from the parent process.
207*7c478bd9Sstevel@tonic-gate 	 * If the parent is non-interruptible our hand must be forced
208*7c478bd9Sstevel@tonic-gate 	 * or we (and our children) won't be either.
209*7c478bd9Sstevel@tonic-gate 	 * Our children inherit termination from our parent.
210*7c478bd9Sstevel@tonic-gate 	 * We catch it only if we are the login shell.
211*7c478bd9Sstevel@tonic-gate 	 */
212*7c478bd9Sstevel@tonic-gate 		/* parents interruptibility */
213*7c478bd9Sstevel@tonic-gate 	(void) sigvec(SIGINT, (struct sigvec *)0, &osv);
214*7c478bd9Sstevel@tonic-gate 	parintr = osv.sv_handler;
215*7c478bd9Sstevel@tonic-gate 		/* parents terminability */
216*7c478bd9Sstevel@tonic-gate 	(void) sigvec(SIGTERM, (struct sigvec *)0, &osv);
217*7c478bd9Sstevel@tonic-gate 	parterm = osv.sv_handler;
218*7c478bd9Sstevel@tonic-gate 
219*7c478bd9Sstevel@tonic-gate 	_signal(SIGLWP, siglwp);
220*7c478bd9Sstevel@tonic-gate 	_signal(SIGWAITING, sigwaiting);
221*7c478bd9Sstevel@tonic-gate 	if (loginsh) {
222*7c478bd9Sstevel@tonic-gate 		(void) signal(SIGHUP, phup);	/* exit processing on HUP */
223*7c478bd9Sstevel@tonic-gate 		(void) signal(SIGXCPU, phup);	/* ...and on XCPU */
224*7c478bd9Sstevel@tonic-gate 		(void) signal(SIGXFSZ, phup);	/* ...and on XFSZ */
225*7c478bd9Sstevel@tonic-gate 	}
226*7c478bd9Sstevel@tonic-gate 
227*7c478bd9Sstevel@tonic-gate 	/*
228*7c478bd9Sstevel@tonic-gate 	 * Process the arguments.
229*7c478bd9Sstevel@tonic-gate 	 *
230*7c478bd9Sstevel@tonic-gate 	 * Note that processing of -v/-x is actually delayed till after
231*7c478bd9Sstevel@tonic-gate 	 * script processing.
232*7c478bd9Sstevel@tonic-gate 	 */
233*7c478bd9Sstevel@tonic-gate 	c--, v++;
234*7c478bd9Sstevel@tonic-gate 	while (c > 0 && (cp = v[0])[0] == '-' && *++cp != '\0' && !batch) {
235*7c478bd9Sstevel@tonic-gate 		do switch (*cp++) {
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate 		case 'b':		/* -b	Next arg is input file */
238*7c478bd9Sstevel@tonic-gate 			batch++;
239*7c478bd9Sstevel@tonic-gate 			break;
240*7c478bd9Sstevel@tonic-gate 
241*7c478bd9Sstevel@tonic-gate 		case 'c':		/* -c	Command input from arg */
242*7c478bd9Sstevel@tonic-gate 			if (c == 1)
243*7c478bd9Sstevel@tonic-gate 				exit(0);
244*7c478bd9Sstevel@tonic-gate 			c--, v++;
245*7c478bd9Sstevel@tonic-gate 			arginp = v[0];
246*7c478bd9Sstevel@tonic-gate 			prompt = 0;
247*7c478bd9Sstevel@tonic-gate 			nofile++;
248*7c478bd9Sstevel@tonic-gate 			cflg++;
249*7c478bd9Sstevel@tonic-gate 			break;
250*7c478bd9Sstevel@tonic-gate 
251*7c478bd9Sstevel@tonic-gate 		case 'e':		/* -e	Exit on any error */
252*7c478bd9Sstevel@tonic-gate 			exiterr++;
253*7c478bd9Sstevel@tonic-gate 			break;
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate 		case 'f':		/* -f	Fast start */
256*7c478bd9Sstevel@tonic-gate 			fast++;
257*7c478bd9Sstevel@tonic-gate 			break;
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate 		case 'i':		/* -i	Interactive, even if !intty */
260*7c478bd9Sstevel@tonic-gate 			intact++;
261*7c478bd9Sstevel@tonic-gate 			nofile++;
262*7c478bd9Sstevel@tonic-gate 			break;
263*7c478bd9Sstevel@tonic-gate 
264*7c478bd9Sstevel@tonic-gate 		case 'n':		/* -n	Don't execute */
265*7c478bd9Sstevel@tonic-gate 			noexec++;
266*7c478bd9Sstevel@tonic-gate 			break;
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate 		case 'q':		/* -q	(Undoc'd) ... die on quit */
269*7c478bd9Sstevel@tonic-gate 			quitit = 1;
270*7c478bd9Sstevel@tonic-gate 			break;
271*7c478bd9Sstevel@tonic-gate 
272*7c478bd9Sstevel@tonic-gate 		case 's':		/* -s	Read from std input */
273*7c478bd9Sstevel@tonic-gate 			nofile++;
274*7c478bd9Sstevel@tonic-gate 			break;
275*7c478bd9Sstevel@tonic-gate 
276*7c478bd9Sstevel@tonic-gate 		case 't':		/* -t	Read one line from input */
277*7c478bd9Sstevel@tonic-gate 			onelflg = 2;
278*7c478bd9Sstevel@tonic-gate 			prompt = 0;
279*7c478bd9Sstevel@tonic-gate 			nofile++;
280*7c478bd9Sstevel@tonic-gate 			break;
281*7c478bd9Sstevel@tonic-gate #ifdef TRACE
282*7c478bd9Sstevel@tonic-gate 		case 'T':		/* -T 	trace switch on */
283*7c478bd9Sstevel@tonic-gate 			trace_init();
284*7c478bd9Sstevel@tonic-gate 			break;
285*7c478bd9Sstevel@tonic-gate #endif
286*7c478bd9Sstevel@tonic-gate 
287*7c478bd9Sstevel@tonic-gate 		case 'v':		/* -v	Echo hist expanded input */
288*7c478bd9Sstevel@tonic-gate 			nverbose = 1;			/* ... later */
289*7c478bd9Sstevel@tonic-gate 			break;
290*7c478bd9Sstevel@tonic-gate 
291*7c478bd9Sstevel@tonic-gate 		case 'x':		/* -x	Echo just before execution */
292*7c478bd9Sstevel@tonic-gate 			nexececho = 1;			/* ... later */
293*7c478bd9Sstevel@tonic-gate 			break;
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate 		case 'V':		/* -V	Echo hist expanded input */
296*7c478bd9Sstevel@tonic-gate 			setNS(S_verbose/*"verbose"*/);		/* NOW! */
297*7c478bd9Sstevel@tonic-gate 			break;
298*7c478bd9Sstevel@tonic-gate 
299*7c478bd9Sstevel@tonic-gate 		case 'X':		/* -X	Echo just before execution */
300*7c478bd9Sstevel@tonic-gate 			setNS(S_echo/*"echo"*/);			/* NOW! */
301*7c478bd9Sstevel@tonic-gate 			break;
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate 		} while (*cp);
304*7c478bd9Sstevel@tonic-gate 		v++, c--;
305*7c478bd9Sstevel@tonic-gate 	}
306*7c478bd9Sstevel@tonic-gate 
307*7c478bd9Sstevel@tonic-gate 	if (quitit)			/* With all due haste, for debugging */
308*7c478bd9Sstevel@tonic-gate 		(void) signal(SIGQUIT, SIG_DFL);
309*7c478bd9Sstevel@tonic-gate 
310*7c478bd9Sstevel@tonic-gate 	/*
311*7c478bd9Sstevel@tonic-gate 	 * Unless prevented by -c, -i, -s, or -t, if there
312*7c478bd9Sstevel@tonic-gate 	 * are remaining arguments the first of them is the name
313*7c478bd9Sstevel@tonic-gate 	 * of a shell file from which to read commands.
314*7c478bd9Sstevel@tonic-gate 	 */
315*7c478bd9Sstevel@tonic-gate 	if (!batch && (uid != geteuid() || getgid() != getegid())) {
316*7c478bd9Sstevel@tonic-gate 		errno = EACCES;
317*7c478bd9Sstevel@tonic-gate 		child++;			/* So this ... */
318*7c478bd9Sstevel@tonic-gate 		Perror(S_csh/*"csh"*/);		/* ... doesn't return */
319*7c478bd9Sstevel@tonic-gate 	}
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate 	if (nofile == 0 && c > 0) {
322*7c478bd9Sstevel@tonic-gate 		nofile = open_(v[0], 0);
323*7c478bd9Sstevel@tonic-gate 		if (nofile < 0) {
324*7c478bd9Sstevel@tonic-gate 			child++;		/* So this ... */
325*7c478bd9Sstevel@tonic-gate 			Perror(v[0]);		/* ... doesn't return */
326*7c478bd9Sstevel@tonic-gate 		}
327*7c478bd9Sstevel@tonic-gate 		file = v[0];
328*7c478bd9Sstevel@tonic-gate 		SHIN = dmove(nofile, FSHIN);	/* Replace FSHIN */
329*7c478bd9Sstevel@tonic-gate 		(void) fcntl(SHIN, F_SETFD, 1);
330*7c478bd9Sstevel@tonic-gate 		prompt = 0;
331*7c478bd9Sstevel@tonic-gate 		c--, v++;
332*7c478bd9Sstevel@tonic-gate 	}
333*7c478bd9Sstevel@tonic-gate 
334*7c478bd9Sstevel@tonic-gate 	/*
335*7c478bd9Sstevel@tonic-gate 	 * Consider input a tty if it really is or we are interactive.
336*7c478bd9Sstevel@tonic-gate 	 */
337*7c478bd9Sstevel@tonic-gate 	intty = intact || isatty(SHIN);
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 	/*
340*7c478bd9Sstevel@tonic-gate 	 * Decide whether we should play with signals or not.
341*7c478bd9Sstevel@tonic-gate 	 * If we are explicitly told (via -i, or -) or we are a login
342*7c478bd9Sstevel@tonic-gate 	 * shell (arg0 starts with -) or the input and output are both
343*7c478bd9Sstevel@tonic-gate 	 * the ttys("csh", or "csh</dev/ttyx>/dev/ttyx")
344*7c478bd9Sstevel@tonic-gate 	 * Note that in only the login shell is it likely that parent
345*7c478bd9Sstevel@tonic-gate 	 * may have set signals to be ignored
346*7c478bd9Sstevel@tonic-gate 	 */
347*7c478bd9Sstevel@tonic-gate 	if (loginsh || intact || intty && isatty(SHOUT))
348*7c478bd9Sstevel@tonic-gate 		setintr = 1;
349*7c478bd9Sstevel@tonic-gate #ifdef TELL
350*7c478bd9Sstevel@tonic-gate 	settell();
351*7c478bd9Sstevel@tonic-gate #endif
352*7c478bd9Sstevel@tonic-gate 	/*
353*7c478bd9Sstevel@tonic-gate 	 * Save the remaining arguments in argv.
354*7c478bd9Sstevel@tonic-gate 	 */
355*7c478bd9Sstevel@tonic-gate 	setq(S_argv/*"argv"*/, v, &shvhed);
356*7c478bd9Sstevel@tonic-gate 
357*7c478bd9Sstevel@tonic-gate 	/*
358*7c478bd9Sstevel@tonic-gate 	 * Set up the prompt.
359*7c478bd9Sstevel@tonic-gate 	 */
360*7c478bd9Sstevel@tonic-gate 	if (prompt) {
361*7c478bd9Sstevel@tonic-gate 		gethostname_(s_prompt, MAXHOSTNAMELEN);
362*7c478bd9Sstevel@tonic-gate 		strcat_(s_prompt, uid == 0 ? S_SHARPSP/*"# "*/ : S_PERSENTSP/*"% "*/);
363*7c478bd9Sstevel@tonic-gate 		set(S_prompt/*"prompt"*/, s_prompt);
364*7c478bd9Sstevel@tonic-gate 	}
365*7c478bd9Sstevel@tonic-gate 
366*7c478bd9Sstevel@tonic-gate 	/*
367*7c478bd9Sstevel@tonic-gate 	 * If we are an interactive shell, then start fiddling
368*7c478bd9Sstevel@tonic-gate 	 * with the signals; this is a tricky game.
369*7c478bd9Sstevel@tonic-gate 	 */
370*7c478bd9Sstevel@tonic-gate 	shpgrp = getpgid(0);
371*7c478bd9Sstevel@tonic-gate 	opgrp = tpgrp = -1;
372*7c478bd9Sstevel@tonic-gate 	if (setintr) {
373*7c478bd9Sstevel@tonic-gate 		**av = '-';
374*7c478bd9Sstevel@tonic-gate 		if (!quitit)		/* Wary! */
375*7c478bd9Sstevel@tonic-gate 			(void) signal(SIGQUIT, SIG_IGN);
376*7c478bd9Sstevel@tonic-gate 		(void) signal(SIGINT, pintr);
377*7c478bd9Sstevel@tonic-gate 		(void) sigblock(sigmask(SIGINT));
378*7c478bd9Sstevel@tonic-gate 		(void) signal(SIGTERM, SIG_IGN);
379*7c478bd9Sstevel@tonic-gate 		if (quitit == 0 && arginp == 0) {
380*7c478bd9Sstevel@tonic-gate 			(void) signal(SIGTSTP, SIG_IGN);
381*7c478bd9Sstevel@tonic-gate 			(void) signal(SIGTTIN, SIG_IGN);
382*7c478bd9Sstevel@tonic-gate 			(void) signal(SIGTTOU, SIG_IGN);
383*7c478bd9Sstevel@tonic-gate 			/*
384*7c478bd9Sstevel@tonic-gate 			 * Wait till in foreground, in case someone
385*7c478bd9Sstevel@tonic-gate 			 * stupidly runs
386*7c478bd9Sstevel@tonic-gate 			 *	csh &
387*7c478bd9Sstevel@tonic-gate 			 * dont want to try to grab away the tty.
388*7c478bd9Sstevel@tonic-gate 			 */
389*7c478bd9Sstevel@tonic-gate 			if (isatty(FSHDIAG))
390*7c478bd9Sstevel@tonic-gate 				f = FSHDIAG;
391*7c478bd9Sstevel@tonic-gate 			else if (isatty(FSHOUT))
392*7c478bd9Sstevel@tonic-gate 				f = FSHOUT;
393*7c478bd9Sstevel@tonic-gate 			else if (isatty(OLDSTD))
394*7c478bd9Sstevel@tonic-gate 				f = OLDSTD;
395*7c478bd9Sstevel@tonic-gate 			else
396*7c478bd9Sstevel@tonic-gate 				f = -1;
397*7c478bd9Sstevel@tonic-gate retry:
398*7c478bd9Sstevel@tonic-gate 			if (ioctl(f, TIOCGPGRP,  (char *)&tpgrp) == 0 &&
399*7c478bd9Sstevel@tonic-gate 			    tpgrp != -1) {
400*7c478bd9Sstevel@tonic-gate 				if (tpgrp != shpgrp) {
401*7c478bd9Sstevel@tonic-gate 					void (*old)() = (void (*)())signal(SIGTTIN, SIG_DFL);
402*7c478bd9Sstevel@tonic-gate 					(void) kill(0, SIGTTIN);
403*7c478bd9Sstevel@tonic-gate 					(void) signal(SIGTTIN, old);
404*7c478bd9Sstevel@tonic-gate 					goto retry;
405*7c478bd9Sstevel@tonic-gate 				}
406*7c478bd9Sstevel@tonic-gate 				opgrp = shpgrp;
407*7c478bd9Sstevel@tonic-gate 				shpgrp = getpid();
408*7c478bd9Sstevel@tonic-gate 				tpgrp = shpgrp;
409*7c478bd9Sstevel@tonic-gate 				(void) setpgid(0, shpgrp);
410*7c478bd9Sstevel@tonic-gate 				(void) ioctl(f, TIOCSPGRP,  (char *)&shpgrp);
411*7c478bd9Sstevel@tonic-gate 				(void) fcntl(dcopy(f, FSHTTY), F_SETFD, 1);
412*7c478bd9Sstevel@tonic-gate 			} else {
413*7c478bd9Sstevel@tonic-gate notty:
414*7c478bd9Sstevel@tonic-gate   printf("Warning: no access to tty; thus no job control in this shell...\n");
415*7c478bd9Sstevel@tonic-gate 				tpgrp = -1;
416*7c478bd9Sstevel@tonic-gate 			}
417*7c478bd9Sstevel@tonic-gate 		}
418*7c478bd9Sstevel@tonic-gate 	}
419*7c478bd9Sstevel@tonic-gate 	if (setintr == 0 && parintr == SIG_DFL)
420*7c478bd9Sstevel@tonic-gate 		setintr++;
421*7c478bd9Sstevel@tonic-gate 
422*7c478bd9Sstevel@tonic-gate 	/*
423*7c478bd9Sstevel@tonic-gate 	 * Set SIGCHLD handler, making sure that reads restart after it runs.
424*7c478bd9Sstevel@tonic-gate 	 */
425*7c478bd9Sstevel@tonic-gate 	sigemptyset(&sa.sa_mask);
426*7c478bd9Sstevel@tonic-gate 	sa.sa_handler = pchild;
427*7c478bd9Sstevel@tonic-gate 	sa.sa_flags = SA_RESTART;
428*7c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGCHLD, &sa, (struct sigaction *) NULL);
429*7c478bd9Sstevel@tonic-gate 
430*7c478bd9Sstevel@tonic-gate 	/*
431*7c478bd9Sstevel@tonic-gate 	 * Set an exit here in case of an interrupt or error reading
432*7c478bd9Sstevel@tonic-gate 	 * the shell start-up scripts.
433*7c478bd9Sstevel@tonic-gate 	 */
434*7c478bd9Sstevel@tonic-gate 	setexit();
435*7c478bd9Sstevel@tonic-gate 	haderr = 0;		/* In case second time through */
436*7c478bd9Sstevel@tonic-gate 	if (!fast && reenter == 0) {
437*7c478bd9Sstevel@tonic-gate 		reenter++;
438*7c478bd9Sstevel@tonic-gate 
439*7c478bd9Sstevel@tonic-gate                 /*
440*7c478bd9Sstevel@tonic-gate                  * If this is a login csh, and /etc/.login exists,
441*7c478bd9Sstevel@tonic-gate                  * source /etc/.login first.
442*7c478bd9Sstevel@tonic-gate                  */
443*7c478bd9Sstevel@tonic-gate                 if (loginsh) {
444*7c478bd9Sstevel@tonic-gate 			tchar tmp_etc[4+1];	/*strlen("/etc")+1 */
445*7c478bd9Sstevel@tonic-gate 			tchar tmp_login[7+1];	/*strlen("/.login")+1*/
446*7c478bd9Sstevel@tonic-gate 
447*7c478bd9Sstevel@tonic-gate 			strtots(tmp_etc, "/etc");
448*7c478bd9Sstevel@tonic-gate 			strtots(tmp_login, "/.login");
449*7c478bd9Sstevel@tonic-gate                         srccat_inlogin(tmp_etc, tmp_login);
450*7c478bd9Sstevel@tonic-gate                 }
451*7c478bd9Sstevel@tonic-gate 
452*7c478bd9Sstevel@tonic-gate 		/* Will have value("home") here because set fast if don't */
453*7c478bd9Sstevel@tonic-gate 		srccat(value(S_home/*"home"*/), S_SLADOTcshrc/*"/.cshrc"*/);
454*7c478bd9Sstevel@tonic-gate 
455*7c478bd9Sstevel@tonic-gate 		/*Hash path*/
456*7c478bd9Sstevel@tonic-gate 		if (!fast && !arginp && !onelflg && !havhash)
457*7c478bd9Sstevel@tonic-gate 			dohash(xhash);
458*7c478bd9Sstevel@tonic-gate 
459*7c478bd9Sstevel@tonic-gate 
460*7c478bd9Sstevel@tonic-gate 		/*
461*7c478bd9Sstevel@tonic-gate 		 * Reconstruct the history list now, so that it's
462*7c478bd9Sstevel@tonic-gate 		 * available from within .login.
463*7c478bd9Sstevel@tonic-gate 		 */
464*7c478bd9Sstevel@tonic-gate 		dosource(loadhist);
465*7c478bd9Sstevel@tonic-gate 		if (loginsh) {
466*7c478bd9Sstevel@tonic-gate 			srccat_inlogin(value(S_home/*"home"*/), S_SLADOTlogin/*"/.login"*/);
467*7c478bd9Sstevel@tonic-gate 		}
468*7c478bd9Sstevel@tonic-gate 
469*7c478bd9Sstevel@tonic-gate 		/*
470*7c478bd9Sstevel@tonic-gate 		 * To get cdpath hashing $cdpath must have a
471*7c478bd9Sstevel@tonic-gate 		 * value, not $CDPATH.  So if after reading
472*7c478bd9Sstevel@tonic-gate 		 * the startup files ( .cshrc ), and
473*7c478bd9Sstevel@tonic-gate 		 * user has specified a value for cdpath, then
474*7c478bd9Sstevel@tonic-gate 		 * cache $cdpath paths. xhash2 is global array
475*7c478bd9Sstevel@tonic-gate 		 * for $cdpath caching.
476*7c478bd9Sstevel@tonic-gate 		 */
477*7c478bd9Sstevel@tonic-gate 		if (!fast && !arginp && !onelflg && !havhash2 )
478*7c478bd9Sstevel@tonic-gate 				dohash(xhash2);
479*7c478bd9Sstevel@tonic-gate 	}
480*7c478bd9Sstevel@tonic-gate 
481*7c478bd9Sstevel@tonic-gate 	/*
482*7c478bd9Sstevel@tonic-gate 	 * Now are ready for the -v and -x flags
483*7c478bd9Sstevel@tonic-gate 	 */
484*7c478bd9Sstevel@tonic-gate 	if (nverbose)
485*7c478bd9Sstevel@tonic-gate 		setNS(S_verbose/*"verbose"*/);
486*7c478bd9Sstevel@tonic-gate 	if (nexececho)
487*7c478bd9Sstevel@tonic-gate 		setNS(S_echo/*"echo"*/);
488*7c478bd9Sstevel@tonic-gate 
489*7c478bd9Sstevel@tonic-gate 	/*
490*7c478bd9Sstevel@tonic-gate 	 * All the rest of the world is inside this call.
491*7c478bd9Sstevel@tonic-gate 	 * The argument to process indicates whether it should
492*7c478bd9Sstevel@tonic-gate 	 * catch "error unwinds".  Thus if we are a interactive shell
493*7c478bd9Sstevel@tonic-gate 	 * our call here will never return by being blown past on an error.
494*7c478bd9Sstevel@tonic-gate 	 */
495*7c478bd9Sstevel@tonic-gate 	process(setintr);
496*7c478bd9Sstevel@tonic-gate 
497*7c478bd9Sstevel@tonic-gate 	/*
498*7c478bd9Sstevel@tonic-gate 	 * Mop-up.
499*7c478bd9Sstevel@tonic-gate 	 */
500*7c478bd9Sstevel@tonic-gate 	if (loginsh) {
501*7c478bd9Sstevel@tonic-gate 		printf("logout\n");
502*7c478bd9Sstevel@tonic-gate 		(void) close(SHIN);	/* No need for unsetfd(). */
503*7c478bd9Sstevel@tonic-gate 		child++;
504*7c478bd9Sstevel@tonic-gate 		goodbye();
505*7c478bd9Sstevel@tonic-gate 	}
506*7c478bd9Sstevel@tonic-gate 	rechist();
507*7c478bd9Sstevel@tonic-gate 	exitstat();
508*7c478bd9Sstevel@tonic-gate }
509*7c478bd9Sstevel@tonic-gate 
510*7c478bd9Sstevel@tonic-gate untty()
511*7c478bd9Sstevel@tonic-gate {
512*7c478bd9Sstevel@tonic-gate 
513*7c478bd9Sstevel@tonic-gate 	if (tpgrp > 0) {
514*7c478bd9Sstevel@tonic-gate 		(void) setpgid(0, opgrp);
515*7c478bd9Sstevel@tonic-gate 		(void) ioctl(FSHTTY, TIOCSPGRP,  (char *)&opgrp);
516*7c478bd9Sstevel@tonic-gate 	}
517*7c478bd9Sstevel@tonic-gate }
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate importpath(cp)
520*7c478bd9Sstevel@tonic-gate 	tchar *cp;
521*7c478bd9Sstevel@tonic-gate {
522*7c478bd9Sstevel@tonic-gate 	register int i = 0;
523*7c478bd9Sstevel@tonic-gate 	register tchar *dp;
524*7c478bd9Sstevel@tonic-gate 	register tchar **pv;
525*7c478bd9Sstevel@tonic-gate 	int c;
526*7c478bd9Sstevel@tonic-gate 	static tchar dot[2] = {'.', 0};
527*7c478bd9Sstevel@tonic-gate 
528*7c478bd9Sstevel@tonic-gate 	for (dp = cp; *dp; dp++)
529*7c478bd9Sstevel@tonic-gate 		if (*dp == ':')
530*7c478bd9Sstevel@tonic-gate 			i++;
531*7c478bd9Sstevel@tonic-gate 	/*
532*7c478bd9Sstevel@tonic-gate 	 * i+2 where i is the number of colons in the path.
533*7c478bd9Sstevel@tonic-gate 	 * There are i+1 directories in the path plus we need
534*7c478bd9Sstevel@tonic-gate 	 * room for a zero terminator.
535*7c478bd9Sstevel@tonic-gate 	 */
536*7c478bd9Sstevel@tonic-gate 	pv =  (tchar **) calloc((unsigned) (i + 2), sizeof  (tchar **));
537*7c478bd9Sstevel@tonic-gate 	dp = cp;
538*7c478bd9Sstevel@tonic-gate 	i = 0;
539*7c478bd9Sstevel@tonic-gate 	if (*dp)
540*7c478bd9Sstevel@tonic-gate 	for (;;) {
541*7c478bd9Sstevel@tonic-gate 		if ((c = *dp) == ':' || c == 0) {
542*7c478bd9Sstevel@tonic-gate 			*dp = 0;
543*7c478bd9Sstevel@tonic-gate 			pv[i++] = savestr(*cp ? cp : dot);
544*7c478bd9Sstevel@tonic-gate 			if (c) {
545*7c478bd9Sstevel@tonic-gate 				cp = dp + 1;
546*7c478bd9Sstevel@tonic-gate 				*dp = ':';
547*7c478bd9Sstevel@tonic-gate 			} else
548*7c478bd9Sstevel@tonic-gate 				break;
549*7c478bd9Sstevel@tonic-gate 		}
550*7c478bd9Sstevel@tonic-gate 		dp++;
551*7c478bd9Sstevel@tonic-gate 	}
552*7c478bd9Sstevel@tonic-gate 	pv[i] = 0;
553*7c478bd9Sstevel@tonic-gate 	set1(S_path /*"path"*/, pv, &shvhed);
554*7c478bd9Sstevel@tonic-gate }
555*7c478bd9Sstevel@tonic-gate 
556*7c478bd9Sstevel@tonic-gate /*
557*7c478bd9Sstevel@tonic-gate  * Source to the file which is the catenation of the argument names.
558*7c478bd9Sstevel@tonic-gate  */
559*7c478bd9Sstevel@tonic-gate srccat(cp, dp)
560*7c478bd9Sstevel@tonic-gate 	tchar *cp, *dp;
561*7c478bd9Sstevel@tonic-gate {
562*7c478bd9Sstevel@tonic-gate 	register tchar *ep = strspl(cp, dp);
563*7c478bd9Sstevel@tonic-gate 	register int unit = dmove(open_(ep, 0), -1);
564*7c478bd9Sstevel@tonic-gate 
565*7c478bd9Sstevel@tonic-gate 	(void) fcntl(unit, F_SETFD, 1);
566*7c478bd9Sstevel@tonic-gate 	xfree(ep);
567*7c478bd9Sstevel@tonic-gate #ifdef INGRES
568*7c478bd9Sstevel@tonic-gate 	srcunit(unit, 0, 0);
569*7c478bd9Sstevel@tonic-gate #else
570*7c478bd9Sstevel@tonic-gate 	srcunit(unit, 1, 0);
571*7c478bd9Sstevel@tonic-gate #endif
572*7c478bd9Sstevel@tonic-gate }
573*7c478bd9Sstevel@tonic-gate 
574*7c478bd9Sstevel@tonic-gate /*
575*7c478bd9Sstevel@tonic-gate  * Source to the file which is the catenation of the argument names.
576*7c478bd9Sstevel@tonic-gate  * 	This one does not check the ownership.
577*7c478bd9Sstevel@tonic-gate  */
578*7c478bd9Sstevel@tonic-gate srccat_inlogin(cp, dp)
579*7c478bd9Sstevel@tonic-gate 	tchar *cp, *dp;
580*7c478bd9Sstevel@tonic-gate {
581*7c478bd9Sstevel@tonic-gate 	register tchar *ep = strspl(cp, dp);
582*7c478bd9Sstevel@tonic-gate 	register int unit = dmove(open_(ep, 0), -1);
583*7c478bd9Sstevel@tonic-gate 
584*7c478bd9Sstevel@tonic-gate 	(void) fcntl(unit, F_SETFD, 1);
585*7c478bd9Sstevel@tonic-gate 	xfree(ep);
586*7c478bd9Sstevel@tonic-gate 	srcunit(unit, 0, 0);
587*7c478bd9Sstevel@tonic-gate }
588*7c478bd9Sstevel@tonic-gate 
589*7c478bd9Sstevel@tonic-gate /*
590*7c478bd9Sstevel@tonic-gate  * Source to a unit.  If onlyown it must be our file or our group or
591*7c478bd9Sstevel@tonic-gate  * we don't chance it.	This occurs on ".cshrc"s and the like.
592*7c478bd9Sstevel@tonic-gate  */
593*7c478bd9Sstevel@tonic-gate srcunit(unit, onlyown, hflg)
594*7c478bd9Sstevel@tonic-gate 	register int unit;
595*7c478bd9Sstevel@tonic-gate 	bool onlyown;
596*7c478bd9Sstevel@tonic-gate 	bool hflg;
597*7c478bd9Sstevel@tonic-gate {
598*7c478bd9Sstevel@tonic-gate 	/* We have to push down a lot of state here */
599*7c478bd9Sstevel@tonic-gate 	/* All this could go into a structure */
600*7c478bd9Sstevel@tonic-gate 	int oSHIN = -1, oldintty = intty;
601*7c478bd9Sstevel@tonic-gate 	struct whyle *oldwhyl = whyles;
602*7c478bd9Sstevel@tonic-gate 	tchar *ogointr = gointr, *oarginp = arginp;
603*7c478bd9Sstevel@tonic-gate 	tchar *oevalp = evalp, **oevalvec = evalvec;
604*7c478bd9Sstevel@tonic-gate 	int oonelflg = onelflg;
605*7c478bd9Sstevel@tonic-gate 	bool oenterhist = enterhist;
606*7c478bd9Sstevel@tonic-gate 	tchar OHIST = HIST;
607*7c478bd9Sstevel@tonic-gate #ifdef TELL
608*7c478bd9Sstevel@tonic-gate 	bool otell = cantell;
609*7c478bd9Sstevel@tonic-gate #endif
610*7c478bd9Sstevel@tonic-gate 	struct Bin saveB;
611*7c478bd9Sstevel@tonic-gate 
612*7c478bd9Sstevel@tonic-gate 	/* The (few) real local variables */
613*7c478bd9Sstevel@tonic-gate 	jmp_buf oldexit;
614*7c478bd9Sstevel@tonic-gate 	int reenter, omask;
615*7c478bd9Sstevel@tonic-gate 
616*7c478bd9Sstevel@tonic-gate 	if (unit < 0)
617*7c478bd9Sstevel@tonic-gate 		return;
618*7c478bd9Sstevel@tonic-gate 	if (didfds)
619*7c478bd9Sstevel@tonic-gate 		donefds();
620*7c478bd9Sstevel@tonic-gate 	if (onlyown) {
621*7c478bd9Sstevel@tonic-gate 		struct stat stb;
622*7c478bd9Sstevel@tonic-gate 
623*7c478bd9Sstevel@tonic-gate 		if (fstat(unit, &stb) < 0 ||
624*7c478bd9Sstevel@tonic-gate 		    (stb.st_uid != uid && stb.st_gid != getgid())) {
625*7c478bd9Sstevel@tonic-gate 			(void) close(unit);
626*7c478bd9Sstevel@tonic-gate 			unsetfd(unit);
627*7c478bd9Sstevel@tonic-gate 			return;
628*7c478bd9Sstevel@tonic-gate 		}
629*7c478bd9Sstevel@tonic-gate 	}
630*7c478bd9Sstevel@tonic-gate 
631*7c478bd9Sstevel@tonic-gate 	/*
632*7c478bd9Sstevel@tonic-gate 	 * There is a critical section here while we are pushing down the
633*7c478bd9Sstevel@tonic-gate 	 * input stream since we have stuff in different structures.
634*7c478bd9Sstevel@tonic-gate 	 * If we weren't careful an interrupt could corrupt SHIN's Bin
635*7c478bd9Sstevel@tonic-gate 	 * structure and kill the shell.
636*7c478bd9Sstevel@tonic-gate 	 *
637*7c478bd9Sstevel@tonic-gate 	 * We could avoid the critical region by grouping all the stuff
638*7c478bd9Sstevel@tonic-gate 	 * in a single structure and pointing at it to move it all at
639*7c478bd9Sstevel@tonic-gate 	 * once.  This is less efficient globally on many variable references
640*7c478bd9Sstevel@tonic-gate 	 * however.
641*7c478bd9Sstevel@tonic-gate 	 */
642*7c478bd9Sstevel@tonic-gate 	getexit(oldexit);
643*7c478bd9Sstevel@tonic-gate 	reenter = 0;
644*7c478bd9Sstevel@tonic-gate 	if (setintr)
645*7c478bd9Sstevel@tonic-gate 		omask = sigblock(sigmask(SIGINT));
646*7c478bd9Sstevel@tonic-gate 	setexit();
647*7c478bd9Sstevel@tonic-gate 	reenter++;
648*7c478bd9Sstevel@tonic-gate 	if (reenter == 1) {
649*7c478bd9Sstevel@tonic-gate 		/* Setup the new values of the state stuff saved above */
650*7c478bd9Sstevel@tonic-gate 		copy( (char *)&saveB,  (char *)&B, sizeof saveB);
651*7c478bd9Sstevel@tonic-gate 		fbuf =  (tchar **) 0;
652*7c478bd9Sstevel@tonic-gate 		fseekp = feobp = fblocks = 0;
653*7c478bd9Sstevel@tonic-gate 		oSHIN = SHIN, SHIN = unit, arginp = 0, onelflg = 0;
654*7c478bd9Sstevel@tonic-gate 		intty = isatty(SHIN), whyles = 0, gointr = 0;
655*7c478bd9Sstevel@tonic-gate 		evalvec = 0; evalp = 0;
656*7c478bd9Sstevel@tonic-gate 		enterhist = hflg;
657*7c478bd9Sstevel@tonic-gate 		if (enterhist)
658*7c478bd9Sstevel@tonic-gate 			HIST = '\0';
659*7c478bd9Sstevel@tonic-gate 		/*
660*7c478bd9Sstevel@tonic-gate 		 * Now if we are allowing commands to be interrupted,
661*7c478bd9Sstevel@tonic-gate 		 * we let ourselves be interrupted.
662*7c478bd9Sstevel@tonic-gate 		 */
663*7c478bd9Sstevel@tonic-gate 		if (setintr)
664*7c478bd9Sstevel@tonic-gate 			(void) sigsetmask(omask);
665*7c478bd9Sstevel@tonic-gate #ifdef TELL
666*7c478bd9Sstevel@tonic-gate 		settell();
667*7c478bd9Sstevel@tonic-gate #endif
668*7c478bd9Sstevel@tonic-gate 		process(0);		/* 0 -> blow away on errors */
669*7c478bd9Sstevel@tonic-gate 	}
670*7c478bd9Sstevel@tonic-gate 	if (setintr)
671*7c478bd9Sstevel@tonic-gate 		(void) sigsetmask(omask);
672*7c478bd9Sstevel@tonic-gate 	if (oSHIN >= 0) {
673*7c478bd9Sstevel@tonic-gate 		register int i;
674*7c478bd9Sstevel@tonic-gate 
675*7c478bd9Sstevel@tonic-gate 		/* We made it to the new state... free up its storage */
676*7c478bd9Sstevel@tonic-gate 		/* This code could get run twice but xfree doesn't care */
677*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < fblocks; i++)
678*7c478bd9Sstevel@tonic-gate 			xfree(fbuf[i]);
679*7c478bd9Sstevel@tonic-gate 		xfree( (char *)fbuf);
680*7c478bd9Sstevel@tonic-gate 
681*7c478bd9Sstevel@tonic-gate 		/* Reset input arena */
682*7c478bd9Sstevel@tonic-gate 		copy( (char *)&B,  (char *)&saveB, sizeof B);
683*7c478bd9Sstevel@tonic-gate 
684*7c478bd9Sstevel@tonic-gate 		(void) close(SHIN), SHIN = oSHIN;
685*7c478bd9Sstevel@tonic-gate 		unsetfd(SHIN);
686*7c478bd9Sstevel@tonic-gate 		arginp = oarginp, onelflg = oonelflg;
687*7c478bd9Sstevel@tonic-gate 		evalp = oevalp, evalvec = oevalvec;
688*7c478bd9Sstevel@tonic-gate 		intty = oldintty, whyles = oldwhyl, gointr = ogointr;
689*7c478bd9Sstevel@tonic-gate 		if (enterhist)
690*7c478bd9Sstevel@tonic-gate 			HIST = OHIST;
691*7c478bd9Sstevel@tonic-gate 		enterhist = oenterhist;
692*7c478bd9Sstevel@tonic-gate #ifdef TELL
693*7c478bd9Sstevel@tonic-gate 		cantell = otell;
694*7c478bd9Sstevel@tonic-gate #endif
695*7c478bd9Sstevel@tonic-gate 	}
696*7c478bd9Sstevel@tonic-gate 
697*7c478bd9Sstevel@tonic-gate 	resexit(oldexit);
698*7c478bd9Sstevel@tonic-gate 	/*
699*7c478bd9Sstevel@tonic-gate 	 * If process reset() (effectively an unwind) then
700*7c478bd9Sstevel@tonic-gate 	 * we must also unwind.
701*7c478bd9Sstevel@tonic-gate 	 */
702*7c478bd9Sstevel@tonic-gate 	if (reenter >= 2)
703*7c478bd9Sstevel@tonic-gate 		error(NULL);
704*7c478bd9Sstevel@tonic-gate }
705*7c478bd9Sstevel@tonic-gate 
706*7c478bd9Sstevel@tonic-gate rechist()
707*7c478bd9Sstevel@tonic-gate {
708*7c478bd9Sstevel@tonic-gate 	tchar buf[BUFSIZ];
709*7c478bd9Sstevel@tonic-gate 	int fp, ftmp, oldidfds;
710*7c478bd9Sstevel@tonic-gate 
711*7c478bd9Sstevel@tonic-gate 	if (!fast) {
712*7c478bd9Sstevel@tonic-gate 		if (value(S_savehist/*"savehist"*/)[0] == '\0')
713*7c478bd9Sstevel@tonic-gate 			return;
714*7c478bd9Sstevel@tonic-gate 		(void) strcpy_(buf, value(S_home/*"home"*/));
715*7c478bd9Sstevel@tonic-gate 		(void) strcat_(buf, S_SLADOThistory/*"/.history"*/);
716*7c478bd9Sstevel@tonic-gate 		fp = creat_(buf, 0666);
717*7c478bd9Sstevel@tonic-gate 		if (fp == -1)
718*7c478bd9Sstevel@tonic-gate 			return;
719*7c478bd9Sstevel@tonic-gate 		oldidfds = didfds;
720*7c478bd9Sstevel@tonic-gate 		didfds = 0;
721*7c478bd9Sstevel@tonic-gate 		ftmp = SHOUT;
722*7c478bd9Sstevel@tonic-gate 		SHOUT = fp;
723*7c478bd9Sstevel@tonic-gate 		(void) strcpy_(buf, value(S_savehist/*"savehist"*/));
724*7c478bd9Sstevel@tonic-gate 		dumphist[2] = buf;
725*7c478bd9Sstevel@tonic-gate 		dohist(dumphist);
726*7c478bd9Sstevel@tonic-gate 		(void) close(fp);
727*7c478bd9Sstevel@tonic-gate 		unsetfd(fp);
728*7c478bd9Sstevel@tonic-gate 		SHOUT = ftmp;
729*7c478bd9Sstevel@tonic-gate 		didfds = oldidfds;
730*7c478bd9Sstevel@tonic-gate 	}
731*7c478bd9Sstevel@tonic-gate }
732*7c478bd9Sstevel@tonic-gate 
733*7c478bd9Sstevel@tonic-gate goodbye()
734*7c478bd9Sstevel@tonic-gate {
735*7c478bd9Sstevel@tonic-gate 	if (loginsh) {
736*7c478bd9Sstevel@tonic-gate 		(void) signal(SIGQUIT, SIG_IGN);
737*7c478bd9Sstevel@tonic-gate 		(void) signal(SIGINT, SIG_IGN);
738*7c478bd9Sstevel@tonic-gate 		(void) signal(SIGTERM, SIG_IGN);
739*7c478bd9Sstevel@tonic-gate 		setintr = 0;		/* No interrupts after "logout" */
740*7c478bd9Sstevel@tonic-gate 		if (adrof(S_home/*"home"*/))
741*7c478bd9Sstevel@tonic-gate 			srccat(value(S_home/*"home"*/), S_SLADOTlogout/*"/.logout"*/);
742*7c478bd9Sstevel@tonic-gate 	}
743*7c478bd9Sstevel@tonic-gate 	rechist();
744*7c478bd9Sstevel@tonic-gate 	exitstat();
745*7c478bd9Sstevel@tonic-gate }
746*7c478bd9Sstevel@tonic-gate 
747*7c478bd9Sstevel@tonic-gate exitstat()
748*7c478bd9Sstevel@tonic-gate {
749*7c478bd9Sstevel@tonic-gate 
750*7c478bd9Sstevel@tonic-gate #ifdef PROF
751*7c478bd9Sstevel@tonic-gate 	monitor(0);
752*7c478bd9Sstevel@tonic-gate #endif
753*7c478bd9Sstevel@tonic-gate 	/*
754*7c478bd9Sstevel@tonic-gate 	 * Note that if STATUS is corrupted (i.e. getn bombs)
755*7c478bd9Sstevel@tonic-gate 	 * then error will exit directly because we poke child here.
756*7c478bd9Sstevel@tonic-gate 	 * Otherwise we might continue unwarrantedly (sic).
757*7c478bd9Sstevel@tonic-gate 	 */
758*7c478bd9Sstevel@tonic-gate 	child++;
759*7c478bd9Sstevel@tonic-gate 	untty();
760*7c478bd9Sstevel@tonic-gate 	exit(getn(value(S_status/*"status"*/)));
761*7c478bd9Sstevel@tonic-gate }
762*7c478bd9Sstevel@tonic-gate 
763*7c478bd9Sstevel@tonic-gate /*
764*7c478bd9Sstevel@tonic-gate  * in the event of a HUP we want to save the history
765*7c478bd9Sstevel@tonic-gate  */
766*7c478bd9Sstevel@tonic-gate void
767*7c478bd9Sstevel@tonic-gate phup()
768*7c478bd9Sstevel@tonic-gate {
769*7c478bd9Sstevel@tonic-gate 	rechist();
770*7c478bd9Sstevel@tonic-gate 	exit(1);
771*7c478bd9Sstevel@tonic-gate }
772*7c478bd9Sstevel@tonic-gate 
773*7c478bd9Sstevel@tonic-gate tchar *jobargv[2] = { S_jobs/*"jobs"*/, 0 };
774*7c478bd9Sstevel@tonic-gate /*
775*7c478bd9Sstevel@tonic-gate  * Catch an interrupt, e.g. during lexical input.
776*7c478bd9Sstevel@tonic-gate  * If we are an interactive shell, we reset the interrupt catch
777*7c478bd9Sstevel@tonic-gate  * immediately.  In any case we drain the shell output,
778*7c478bd9Sstevel@tonic-gate  * and finally go through the normal error mechanism, which
779*7c478bd9Sstevel@tonic-gate  * gets a chance to make the shell go away.
780*7c478bd9Sstevel@tonic-gate  */
781*7c478bd9Sstevel@tonic-gate void
782*7c478bd9Sstevel@tonic-gate pintr()
783*7c478bd9Sstevel@tonic-gate {
784*7c478bd9Sstevel@tonic-gate 	pintr1(1);
785*7c478bd9Sstevel@tonic-gate }
786*7c478bd9Sstevel@tonic-gate 
787*7c478bd9Sstevel@tonic-gate pintr1(wantnl)
788*7c478bd9Sstevel@tonic-gate 	bool wantnl;
789*7c478bd9Sstevel@tonic-gate {
790*7c478bd9Sstevel@tonic-gate 	register tchar **v;
791*7c478bd9Sstevel@tonic-gate 	int omask;
792*7c478bd9Sstevel@tonic-gate 
793*7c478bd9Sstevel@tonic-gate 	omask = sigblock(0);
794*7c478bd9Sstevel@tonic-gate 	if (setintr) {
795*7c478bd9Sstevel@tonic-gate 		(void) sigsetmask(omask & ~sigmask(SIGINT));
796*7c478bd9Sstevel@tonic-gate 		if (pjobs) {
797*7c478bd9Sstevel@tonic-gate 			pjobs = 0;
798*7c478bd9Sstevel@tonic-gate 			printf("\n");
799*7c478bd9Sstevel@tonic-gate 			dojobs(jobargv);
800*7c478bd9Sstevel@tonic-gate 			bferr("Interrupted");
801*7c478bd9Sstevel@tonic-gate 		}
802*7c478bd9Sstevel@tonic-gate 	}
803*7c478bd9Sstevel@tonic-gate 	(void) sigsetmask(omask & ~sigmask(SIGCHLD));
804*7c478bd9Sstevel@tonic-gate 	draino();
805*7c478bd9Sstevel@tonic-gate 
806*7c478bd9Sstevel@tonic-gate 	/*
807*7c478bd9Sstevel@tonic-gate 	 * If we have an active "onintr" then we search for the label.
808*7c478bd9Sstevel@tonic-gate 	 * Note that if one does "onintr -" then we shan't be interruptible
809*7c478bd9Sstevel@tonic-gate 	 * so we needn't worry about that here.
810*7c478bd9Sstevel@tonic-gate 	 */
811*7c478bd9Sstevel@tonic-gate 	if (gointr) {
812*7c478bd9Sstevel@tonic-gate 		search(ZGOTO, 0, gointr);
813*7c478bd9Sstevel@tonic-gate 		timflg = 0;
814*7c478bd9Sstevel@tonic-gate 		if (v = pargv)
815*7c478bd9Sstevel@tonic-gate 			pargv = 0, blkfree(v);
816*7c478bd9Sstevel@tonic-gate 		if (v = gargv)
817*7c478bd9Sstevel@tonic-gate 			gargv = 0, blkfree(v);
818*7c478bd9Sstevel@tonic-gate 		reset();
819*7c478bd9Sstevel@tonic-gate 	} else if (intty && wantnl)
820*7c478bd9Sstevel@tonic-gate 		printf("\n");		/* Some like this, others don't */
821*7c478bd9Sstevel@tonic-gate 	error(NULL);
822*7c478bd9Sstevel@tonic-gate }
823*7c478bd9Sstevel@tonic-gate 
824*7c478bd9Sstevel@tonic-gate /*
825*7c478bd9Sstevel@tonic-gate  * Process is the main driving routine for the shell.
826*7c478bd9Sstevel@tonic-gate  * It runs all command processing, except for those within { ... }
827*7c478bd9Sstevel@tonic-gate  * in expressions (which is run by a routine evalav in sh.exp.c which
828*7c478bd9Sstevel@tonic-gate  * is a stripped down process), and `...` evaluation which is run
829*7c478bd9Sstevel@tonic-gate  * also by a subset of this code in sh.glob.c in the routine backeval.
830*7c478bd9Sstevel@tonic-gate  *
831*7c478bd9Sstevel@tonic-gate  * The code here is a little strange because part of it is interruptible
832*7c478bd9Sstevel@tonic-gate  * and hence freeing of structures appears to occur when none is necessary
833*7c478bd9Sstevel@tonic-gate  * if this is ignored.
834*7c478bd9Sstevel@tonic-gate  *
835*7c478bd9Sstevel@tonic-gate  * Note that if catch is not set then we will unwind on any error.
836*7c478bd9Sstevel@tonic-gate  * If an end-of-file occurs, we return.
837*7c478bd9Sstevel@tonic-gate  */
838*7c478bd9Sstevel@tonic-gate process(catch)
839*7c478bd9Sstevel@tonic-gate 	bool catch;
840*7c478bd9Sstevel@tonic-gate {
841*7c478bd9Sstevel@tonic-gate 	jmp_buf osetexit;
842*7c478bd9Sstevel@tonic-gate 	register struct command *t;
843*7c478bd9Sstevel@tonic-gate 
844*7c478bd9Sstevel@tonic-gate 	getexit(osetexit);
845*7c478bd9Sstevel@tonic-gate 	for (;;) {
846*7c478bd9Sstevel@tonic-gate 		pendjob();
847*7c478bd9Sstevel@tonic-gate 		paraml.next = paraml.prev = &paraml;
848*7c478bd9Sstevel@tonic-gate 		paraml.word = S_ /*""*/;
849*7c478bd9Sstevel@tonic-gate 		t = 0;
850*7c478bd9Sstevel@tonic-gate 		setexit();
851*7c478bd9Sstevel@tonic-gate 		justpr = enterhist;	/* execute if not entering history */
852*7c478bd9Sstevel@tonic-gate 
853*7c478bd9Sstevel@tonic-gate 		/*
854*7c478bd9Sstevel@tonic-gate 		 * Interruptible during interactive reads
855*7c478bd9Sstevel@tonic-gate 		 */
856*7c478bd9Sstevel@tonic-gate 		if (setintr)
857*7c478bd9Sstevel@tonic-gate 			(void) sigsetmask(sigblock(0) & ~sigmask(SIGINT));
858*7c478bd9Sstevel@tonic-gate 
859*7c478bd9Sstevel@tonic-gate 		/*
860*7c478bd9Sstevel@tonic-gate 		 * For the sake of reset()
861*7c478bd9Sstevel@tonic-gate 		 */
862*7c478bd9Sstevel@tonic-gate 		freelex(&paraml), freesyn(t), t = 0;
863*7c478bd9Sstevel@tonic-gate 
864*7c478bd9Sstevel@tonic-gate 		if (haderr) {
865*7c478bd9Sstevel@tonic-gate 			if (!catch) {
866*7c478bd9Sstevel@tonic-gate 				/* unwind */
867*7c478bd9Sstevel@tonic-gate 				doneinp = 0;
868*7c478bd9Sstevel@tonic-gate 				resexit(osetexit);
869*7c478bd9Sstevel@tonic-gate 				reset();
870*7c478bd9Sstevel@tonic-gate 			}
871*7c478bd9Sstevel@tonic-gate 			haderr = 0;
872*7c478bd9Sstevel@tonic-gate 			/*
873*7c478bd9Sstevel@tonic-gate 			 * Every error is eventually caught here or
874*7c478bd9Sstevel@tonic-gate 			 * the shell dies.  It is at this
875*7c478bd9Sstevel@tonic-gate 			 * point that we clean up any left-over open
876*7c478bd9Sstevel@tonic-gate 			 * files, by closing all but a fixed number
877*7c478bd9Sstevel@tonic-gate 			 * of pre-defined files.  Thus routines don't
878*7c478bd9Sstevel@tonic-gate 			 * have to worry about leaving files open due
879*7c478bd9Sstevel@tonic-gate 			 * to deeper errors... they will get closed here.
880*7c478bd9Sstevel@tonic-gate 			 */
881*7c478bd9Sstevel@tonic-gate 			closem();
882*7c478bd9Sstevel@tonic-gate 			continue;
883*7c478bd9Sstevel@tonic-gate 		}
884*7c478bd9Sstevel@tonic-gate 		if (doneinp) {
885*7c478bd9Sstevel@tonic-gate 			doneinp = 0;
886*7c478bd9Sstevel@tonic-gate 			break;
887*7c478bd9Sstevel@tonic-gate 		}
888*7c478bd9Sstevel@tonic-gate 		if (chkstop)
889*7c478bd9Sstevel@tonic-gate 			chkstop--;
890*7c478bd9Sstevel@tonic-gate 		if (neednote)
891*7c478bd9Sstevel@tonic-gate 			pnote();
892*7c478bd9Sstevel@tonic-gate 		if (intty && prompt && evalvec == 0) {
893*7c478bd9Sstevel@tonic-gate 			mailchk();
894*7c478bd9Sstevel@tonic-gate 			/*
895*7c478bd9Sstevel@tonic-gate 			 * If we are at the end of the input buffer
896*7c478bd9Sstevel@tonic-gate 			 * then we are going to read fresh stuff.
897*7c478bd9Sstevel@tonic-gate 			 * Otherwise, we are rereading input and don't
898*7c478bd9Sstevel@tonic-gate 			 * need or want to prompt.
899*7c478bd9Sstevel@tonic-gate 			 */
900*7c478bd9Sstevel@tonic-gate 			if (fseekp == feobp)
901*7c478bd9Sstevel@tonic-gate 				printprompt();
902*7c478bd9Sstevel@tonic-gate 		}
903*7c478bd9Sstevel@tonic-gate 		err = 0;
904*7c478bd9Sstevel@tonic-gate 
905*7c478bd9Sstevel@tonic-gate 		/*
906*7c478bd9Sstevel@tonic-gate 		 * Echo not only on VERBOSE, but also with history expansion.
907*7c478bd9Sstevel@tonic-gate 		 */
908*7c478bd9Sstevel@tonic-gate 		if (lex(&paraml) && intty ||
909*7c478bd9Sstevel@tonic-gate 		    adrof(S_verbose /*"verbose"*/)) {
910*7c478bd9Sstevel@tonic-gate 			haderr = 1;
911*7c478bd9Sstevel@tonic-gate 			prlex(&paraml);
912*7c478bd9Sstevel@tonic-gate 			haderr = 0;
913*7c478bd9Sstevel@tonic-gate 		}
914*7c478bd9Sstevel@tonic-gate 
915*7c478bd9Sstevel@tonic-gate 		/*
916*7c478bd9Sstevel@tonic-gate 		 * The parser may lose space if interrupted.
917*7c478bd9Sstevel@tonic-gate 		 */
918*7c478bd9Sstevel@tonic-gate 		if (setintr)
919*7c478bd9Sstevel@tonic-gate 			(void) sigblock(sigmask(SIGINT));
920*7c478bd9Sstevel@tonic-gate 
921*7c478bd9Sstevel@tonic-gate 		/*
922*7c478bd9Sstevel@tonic-gate 		 * Save input text on the history list if
923*7c478bd9Sstevel@tonic-gate 		 * reading in old history, or it
924*7c478bd9Sstevel@tonic-gate 		 * is from the terminal at the top level and not
925*7c478bd9Sstevel@tonic-gate 		 * in a loop.
926*7c478bd9Sstevel@tonic-gate 		 */
927*7c478bd9Sstevel@tonic-gate 		if (enterhist || catch && intty && !whyles)
928*7c478bd9Sstevel@tonic-gate 			savehist(&paraml);
929*7c478bd9Sstevel@tonic-gate 
930*7c478bd9Sstevel@tonic-gate 		/*
931*7c478bd9Sstevel@tonic-gate 		 * Print lexical error messages, except when sourcing
932*7c478bd9Sstevel@tonic-gate 		 * history lists.
933*7c478bd9Sstevel@tonic-gate 		 */
934*7c478bd9Sstevel@tonic-gate 		if (!enterhist && err)
935*7c478bd9Sstevel@tonic-gate 			error("%s", gettext(err));
936*7c478bd9Sstevel@tonic-gate 
937*7c478bd9Sstevel@tonic-gate 		/*
938*7c478bd9Sstevel@tonic-gate 		 * If had a history command :p modifier then
939*7c478bd9Sstevel@tonic-gate 		 * this is as far as we should go
940*7c478bd9Sstevel@tonic-gate 		 */
941*7c478bd9Sstevel@tonic-gate 		if (justpr)
942*7c478bd9Sstevel@tonic-gate 			reset();
943*7c478bd9Sstevel@tonic-gate 
944*7c478bd9Sstevel@tonic-gate 		alias(&paraml);
945*7c478bd9Sstevel@tonic-gate 
946*7c478bd9Sstevel@tonic-gate 		/*
947*7c478bd9Sstevel@tonic-gate 		 * Parse the words of the input into a parse tree.
948*7c478bd9Sstevel@tonic-gate 		 */
949*7c478bd9Sstevel@tonic-gate 		t = syntax(paraml.next, &paraml, 0);
950*7c478bd9Sstevel@tonic-gate 		if (err)
951*7c478bd9Sstevel@tonic-gate 			error("%s", gettext(err));
952*7c478bd9Sstevel@tonic-gate 
953*7c478bd9Sstevel@tonic-gate 		/*
954*7c478bd9Sstevel@tonic-gate 		 * Execute the parse tree
955*7c478bd9Sstevel@tonic-gate 		 */
956*7c478bd9Sstevel@tonic-gate 		{
957*7c478bd9Sstevel@tonic-gate 			/*
958*7c478bd9Sstevel@tonic-gate 			 * POSIX requires SIGCHLD to be held
959*7c478bd9Sstevel@tonic-gate 			 * until all processes have joined the
960*7c478bd9Sstevel@tonic-gate 			 * process group in order to avoid race
961*7c478bd9Sstevel@tonic-gate 			 * condition.
962*7c478bd9Sstevel@tonic-gate 			 */
963*7c478bd9Sstevel@tonic-gate 			int omask;
964*7c478bd9Sstevel@tonic-gate 
965*7c478bd9Sstevel@tonic-gate 			omask = sigblock(sigmask(SIGCHLD));
966*7c478bd9Sstevel@tonic-gate 			execute(t, tpgrp);
967*7c478bd9Sstevel@tonic-gate 			(void)sigsetmask(omask &~ sigmask(SIGCHLD));
968*7c478bd9Sstevel@tonic-gate 		}
969*7c478bd9Sstevel@tonic-gate 
970*7c478bd9Sstevel@tonic-gate 		if (err)
971*7c478bd9Sstevel@tonic-gate 			error("%s", gettext(err));
972*7c478bd9Sstevel@tonic-gate 		/*
973*7c478bd9Sstevel@tonic-gate 		 * Made it!
974*7c478bd9Sstevel@tonic-gate 		 */
975*7c478bd9Sstevel@tonic-gate 		freelex(&paraml), freesyn(t);
976*7c478bd9Sstevel@tonic-gate 	}
977*7c478bd9Sstevel@tonic-gate 	resexit(osetexit);
978*7c478bd9Sstevel@tonic-gate }
979*7c478bd9Sstevel@tonic-gate 
980*7c478bd9Sstevel@tonic-gate dosource(t)
981*7c478bd9Sstevel@tonic-gate 	register tchar **t;
982*7c478bd9Sstevel@tonic-gate {
983*7c478bd9Sstevel@tonic-gate 	register tchar *f;
984*7c478bd9Sstevel@tonic-gate 	register int u;
985*7c478bd9Sstevel@tonic-gate 	bool hflg = 0;
986*7c478bd9Sstevel@tonic-gate 	tchar buf[BUFSIZ];
987*7c478bd9Sstevel@tonic-gate 
988*7c478bd9Sstevel@tonic-gate 	t++;
989*7c478bd9Sstevel@tonic-gate 	if (*t && eq(*t, S_h /*"-h"*/)) {
990*7c478bd9Sstevel@tonic-gate 		if (*++t == NOSTR)
991*7c478bd9Sstevel@tonic-gate 			bferr("Too few arguments.");
992*7c478bd9Sstevel@tonic-gate 		hflg++;
993*7c478bd9Sstevel@tonic-gate 	}
994*7c478bd9Sstevel@tonic-gate 	(void) strcpy_(buf, *t);
995*7c478bd9Sstevel@tonic-gate 	f = globone(buf);
996*7c478bd9Sstevel@tonic-gate 	u = dmove(open_(f, 0), -1);
997*7c478bd9Sstevel@tonic-gate 	xfree(f);
998*7c478bd9Sstevel@tonic-gate 	freelex(&paraml);
999*7c478bd9Sstevel@tonic-gate 	if (u < 0 && !hflg)
1000*7c478bd9Sstevel@tonic-gate 		Perror(f);
1001*7c478bd9Sstevel@tonic-gate 	(void) fcntl(u, F_SETFD, 1);
1002*7c478bd9Sstevel@tonic-gate 	srcunit(u, 0, hflg);
1003*7c478bd9Sstevel@tonic-gate }
1004*7c478bd9Sstevel@tonic-gate 
1005*7c478bd9Sstevel@tonic-gate /*
1006*7c478bd9Sstevel@tonic-gate  * Check for mail.
1007*7c478bd9Sstevel@tonic-gate  * If we are a login shell, then we don't want to tell
1008*7c478bd9Sstevel@tonic-gate  * about any mail file unless its been modified
1009*7c478bd9Sstevel@tonic-gate  * after the time we started.
1010*7c478bd9Sstevel@tonic-gate  * This prevents us from telling the user things he already
1011*7c478bd9Sstevel@tonic-gate  * knows, since the login program insists on saying
1012*7c478bd9Sstevel@tonic-gate  * "You have mail."
1013*7c478bd9Sstevel@tonic-gate  */
1014*7c478bd9Sstevel@tonic-gate mailchk()
1015*7c478bd9Sstevel@tonic-gate {
1016*7c478bd9Sstevel@tonic-gate 	register struct varent *v;
1017*7c478bd9Sstevel@tonic-gate 	register tchar **vp;
1018*7c478bd9Sstevel@tonic-gate 	time_t t;
1019*7c478bd9Sstevel@tonic-gate 	int intvl, cnt;
1020*7c478bd9Sstevel@tonic-gate 	struct stat stb;
1021*7c478bd9Sstevel@tonic-gate 	bool new;
1022*7c478bd9Sstevel@tonic-gate 
1023*7c478bd9Sstevel@tonic-gate 	v = adrof(S_mail /*"mail"*/);
1024*7c478bd9Sstevel@tonic-gate 	if (v == 0)
1025*7c478bd9Sstevel@tonic-gate 		return;
1026*7c478bd9Sstevel@tonic-gate 	(void) time(&t);
1027*7c478bd9Sstevel@tonic-gate 	vp = v->vec;
1028*7c478bd9Sstevel@tonic-gate 	cnt = blklen(vp);
1029*7c478bd9Sstevel@tonic-gate 	intvl = (cnt && number(*vp)) ? (--cnt, getn(*vp++)) : MAILINTVL;
1030*7c478bd9Sstevel@tonic-gate 	if (intvl < 1)
1031*7c478bd9Sstevel@tonic-gate 		intvl = 1;
1032*7c478bd9Sstevel@tonic-gate 	if (chktim + intvl > t)
1033*7c478bd9Sstevel@tonic-gate 		return;
1034*7c478bd9Sstevel@tonic-gate 	for (; *vp; vp++) {
1035*7c478bd9Sstevel@tonic-gate 		if (stat_(*vp, &stb) < 0)
1036*7c478bd9Sstevel@tonic-gate 			continue;
1037*7c478bd9Sstevel@tonic-gate 		new = stb.st_mtime > time0.tv_sec;
1038*7c478bd9Sstevel@tonic-gate 		if (stb.st_size == 0 || stb.st_atime >= stb.st_mtime ||
1039*7c478bd9Sstevel@tonic-gate 		    (stb.st_atime <= chktim && stb.st_mtime <= chktim) ||
1040*7c478bd9Sstevel@tonic-gate 		    loginsh && !new)
1041*7c478bd9Sstevel@tonic-gate 			continue;
1042*7c478bd9Sstevel@tonic-gate 		if (cnt == 1)
1043*7c478bd9Sstevel@tonic-gate 			printf("You have %smail.\n", new ? "new " : "");
1044*7c478bd9Sstevel@tonic-gate 		else
1045*7c478bd9Sstevel@tonic-gate 			printf("%s in %t.\n", new ? "New mail" : "Mail", *vp);
1046*7c478bd9Sstevel@tonic-gate 	}
1047*7c478bd9Sstevel@tonic-gate 	chktim = t;
1048*7c478bd9Sstevel@tonic-gate }
1049*7c478bd9Sstevel@tonic-gate 
1050*7c478bd9Sstevel@tonic-gate /*
1051*7c478bd9Sstevel@tonic-gate  * Extract a home directory from the password file
1052*7c478bd9Sstevel@tonic-gate  * The argument points to a buffer where the name of the
1053*7c478bd9Sstevel@tonic-gate  * user whose home directory is sought is currently.
1054*7c478bd9Sstevel@tonic-gate  * We write the home directory of the user back there.
1055*7c478bd9Sstevel@tonic-gate  */
1056*7c478bd9Sstevel@tonic-gate gethdir(home)
1057*7c478bd9Sstevel@tonic-gate 	tchar *home;
1058*7c478bd9Sstevel@tonic-gate {
1059*7c478bd9Sstevel@tonic-gate 	/* getpwname will not be modified, so we need temp. buffer */
1060*7c478bd9Sstevel@tonic-gate 	char home_str[BUFSIZ];
1061*7c478bd9Sstevel@tonic-gate 	tchar home_ts[BUFSIZ];
1062*7c478bd9Sstevel@tonic-gate 	register struct passwd *pp /*= getpwnam(home)*/;
1063*7c478bd9Sstevel@tonic-gate 
1064*7c478bd9Sstevel@tonic-gate 	pp = getpwnam(tstostr(home_str, home));
1065*7c478bd9Sstevel@tonic-gate 	if (pp == 0)
1066*7c478bd9Sstevel@tonic-gate 		return (1);
1067*7c478bd9Sstevel@tonic-gate 	(void) strcpy_(home, strtots(home_ts, pp->pw_dir));
1068*7c478bd9Sstevel@tonic-gate 	return (0);
1069*7c478bd9Sstevel@tonic-gate }
1070*7c478bd9Sstevel@tonic-gate 
1071*7c478bd9Sstevel@tonic-gate 
1072*7c478bd9Sstevel@tonic-gate /*
1073*7c478bd9Sstevel@tonic-gate #ifdef PROF
1074*7c478bd9Sstevel@tonic-gate done(i)
1075*7c478bd9Sstevel@tonic-gate #else
1076*7c478bd9Sstevel@tonic-gate exit(i)
1077*7c478bd9Sstevel@tonic-gate #endif
1078*7c478bd9Sstevel@tonic-gate 	int i;
1079*7c478bd9Sstevel@tonic-gate {
1080*7c478bd9Sstevel@tonic-gate 
1081*7c478bd9Sstevel@tonic-gate 	untty();
1082*7c478bd9Sstevel@tonic-gate 	_exit(i);
1083*7c478bd9Sstevel@tonic-gate }
1084*7c478bd9Sstevel@tonic-gate */
1085*7c478bd9Sstevel@tonic-gate 
1086*7c478bd9Sstevel@tonic-gate printprompt()
1087*7c478bd9Sstevel@tonic-gate {
1088*7c478bd9Sstevel@tonic-gate 	register tchar *cp;
1089*7c478bd9Sstevel@tonic-gate 
1090*7c478bd9Sstevel@tonic-gate 	if (!whyles) {
1091*7c478bd9Sstevel@tonic-gate 		/*
1092*7c478bd9Sstevel@tonic-gate 		 * Print the prompt string
1093*7c478bd9Sstevel@tonic-gate 		 */
1094*7c478bd9Sstevel@tonic-gate 		for (cp = value(S_prompt /*"prompt"*/); *cp; cp++)
1095*7c478bd9Sstevel@tonic-gate 			if (*cp == HIST)
1096*7c478bd9Sstevel@tonic-gate 				printf("%d", eventno + 1);
1097*7c478bd9Sstevel@tonic-gate 			else {
1098*7c478bd9Sstevel@tonic-gate 				if (*cp == '\\' && cp[1] == HIST)
1099*7c478bd9Sstevel@tonic-gate 					cp++;
1100*7c478bd9Sstevel@tonic-gate 				Putchar(*cp | QUOTE);
1101*7c478bd9Sstevel@tonic-gate 			}
1102*7c478bd9Sstevel@tonic-gate 	} else
1103*7c478bd9Sstevel@tonic-gate 		/*
1104*7c478bd9Sstevel@tonic-gate 		 * Prompt for forward reading loop
1105*7c478bd9Sstevel@tonic-gate 		 * body content.
1106*7c478bd9Sstevel@tonic-gate 		 */
1107*7c478bd9Sstevel@tonic-gate 		printf("? ");
1108*7c478bd9Sstevel@tonic-gate 	flush();
1109*7c478bd9Sstevel@tonic-gate }
1110*7c478bd9Sstevel@tonic-gate 
1111*7c478bd9Sstevel@tonic-gate /*
1112*7c478bd9Sstevel@tonic-gate  * Save char * block.
1113*7c478bd9Sstevel@tonic-gate  */
1114*7c478bd9Sstevel@tonic-gate tchar **
1115*7c478bd9Sstevel@tonic-gate strblktotsblk(v, num)
1116*7c478bd9Sstevel@tonic-gate 	register char **v;
1117*7c478bd9Sstevel@tonic-gate 	int num;
1118*7c478bd9Sstevel@tonic-gate {
1119*7c478bd9Sstevel@tonic-gate 	register tchar **newv =
1120*7c478bd9Sstevel@tonic-gate 		 (tchar **) calloc((unsigned) (num+ 1), sizeof  (tchar **));
1121*7c478bd9Sstevel@tonic-gate 	tchar **onewv = newv;
1122*7c478bd9Sstevel@tonic-gate 
1123*7c478bd9Sstevel@tonic-gate 	while (*v && num--)
1124*7c478bd9Sstevel@tonic-gate 		*newv++ = strtots(NOSTR,*v++);
1125*7c478bd9Sstevel@tonic-gate 	*newv = 0;
1126*7c478bd9Sstevel@tonic-gate 	return (onewv);
1127*7c478bd9Sstevel@tonic-gate }
1128*7c478bd9Sstevel@tonic-gate 
1129*7c478bd9Sstevel@tonic-gate 
1130*7c478bd9Sstevel@tonic-gate sigwaiting()
1131*7c478bd9Sstevel@tonic-gate {
1132*7c478bd9Sstevel@tonic-gate 	_signal(SIGWAITING, sigwaiting);
1133*7c478bd9Sstevel@tonic-gate }
1134*7c478bd9Sstevel@tonic-gate 
1135*7c478bd9Sstevel@tonic-gate siglwp()
1136*7c478bd9Sstevel@tonic-gate {
1137*7c478bd9Sstevel@tonic-gate 	_signal(SIGLWP, siglwp);
1138*7c478bd9Sstevel@tonic-gate }
1139*7c478bd9Sstevel@tonic-gate 
1140*7c478bd9Sstevel@tonic-gate 
1141*7c478bd9Sstevel@tonic-gate /*
1142*7c478bd9Sstevel@tonic-gate  * Following functions and data are used for csh to do its
1143*7c478bd9Sstevel@tonic-gate  * file descriptors book keeping.
1144*7c478bd9Sstevel@tonic-gate  */
1145*7c478bd9Sstevel@tonic-gate 
1146*7c478bd9Sstevel@tonic-gate static int *fdinuse = NULL;	/* The list of files opened by csh */
1147*7c478bd9Sstevel@tonic-gate static int nbytesused = 0;	/* no of bytes allocated to fdinuse */
1148*7c478bd9Sstevel@tonic-gate static int max_fd = 0;		/* The maximum descriptor in fdinuse */
1149*7c478bd9Sstevel@tonic-gate static int my_pid;		/* The process id set in initdesc() */
1150*7c478bd9Sstevel@tonic-gate static int NoFile = NOFILE;	/* The number of files I can use. */
1151*7c478bd9Sstevel@tonic-gate 
1152*7c478bd9Sstevel@tonic-gate /*
1153*7c478bd9Sstevel@tonic-gate  * Get the number of files this csh can use.
1154*7c478bd9Sstevel@tonic-gate  *
1155*7c478bd9Sstevel@tonic-gate  * Move the initial descriptors to their eventual
1156*7c478bd9Sstevel@tonic-gate  * resting places, closing all other units.
1157*7c478bd9Sstevel@tonic-gate  *
1158*7c478bd9Sstevel@tonic-gate  * Also, reserve 0/1/2, so NIS+ routines do not get
1159*7c478bd9Sstevel@tonic-gate  * hold of them. And initialize fdinuse list and set
1160*7c478bd9Sstevel@tonic-gate  * the current process id.
1161*7c478bd9Sstevel@tonic-gate  *
1162*7c478bd9Sstevel@tonic-gate  * If this csh was invoked from setuid'ed script file,
1163*7c478bd9Sstevel@tonic-gate  * do not close the third argument passed. The file
1164*7c478bd9Sstevel@tonic-gate  * must be one of /dev/fd/0,1,2,,,
1165*7c478bd9Sstevel@tonic-gate  *	(execv() always passes three arguments when it execs a script
1166*7c478bd9Sstevel@tonic-gate  *	 file in a form of #! /bin/csh -b.)
1167*7c478bd9Sstevel@tonic-gate  *
1168*7c478bd9Sstevel@tonic-gate  * If is_reinit is set in initdesc_x(), then we only close the file
1169*7c478bd9Sstevel@tonic-gate  * descriptors that we actually opened (as recorded in fdinuse).
1170*7c478bd9Sstevel@tonic-gate  */
1171*7c478bd9Sstevel@tonic-gate initdesc(argc, argv)
1172*7c478bd9Sstevel@tonic-gate 	int argc;
1173*7c478bd9Sstevel@tonic-gate 	char *argv[];
1174*7c478bd9Sstevel@tonic-gate {
1175*7c478bd9Sstevel@tonic-gate 	initdesc_x(argc, argv, 0);
1176*7c478bd9Sstevel@tonic-gate }
1177*7c478bd9Sstevel@tonic-gate 
1178*7c478bd9Sstevel@tonic-gate reinitdesc(argc, argv)
1179*7c478bd9Sstevel@tonic-gate 	int argc;
1180*7c478bd9Sstevel@tonic-gate 	char *argv[];
1181*7c478bd9Sstevel@tonic-gate {
1182*7c478bd9Sstevel@tonic-gate 	initdesc_x(argc, argv, 1);
1183*7c478bd9Sstevel@tonic-gate }
1184*7c478bd9Sstevel@tonic-gate 
1185*7c478bd9Sstevel@tonic-gate /*
1186*7c478bd9Sstevel@tonic-gate  * Callback functions for closing all file descriptors.
1187*7c478bd9Sstevel@tonic-gate  */
1188*7c478bd9Sstevel@tonic-gate static int
1189*7c478bd9Sstevel@tonic-gate close_except(void *cd, int fd)
1190*7c478bd9Sstevel@tonic-gate {
1191*7c478bd9Sstevel@tonic-gate 	int script_fd = *(int *)cd;
1192*7c478bd9Sstevel@tonic-gate 
1193*7c478bd9Sstevel@tonic-gate 	if (fd >= 3 && fd < NoFile && fd != script_fd)
1194*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
1195*7c478bd9Sstevel@tonic-gate 	return (0);
1196*7c478bd9Sstevel@tonic-gate }
1197*7c478bd9Sstevel@tonic-gate 
1198*7c478bd9Sstevel@tonic-gate static int
1199*7c478bd9Sstevel@tonic-gate close_inuse(void *cd, int fd)
1200*7c478bd9Sstevel@tonic-gate {
1201*7c478bd9Sstevel@tonic-gate 	int script_fd = *(int *)cd;
1202*7c478bd9Sstevel@tonic-gate 
1203*7c478bd9Sstevel@tonic-gate 	if (fd >= 3 && fd < NoFile && fd != script_fd &&
1204*7c478bd9Sstevel@tonic-gate 	    CSH_FD_ISSET(fd, fdinuse)) {
1205*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
1206*7c478bd9Sstevel@tonic-gate 		unsetfd(fd);
1207*7c478bd9Sstevel@tonic-gate 	}
1208*7c478bd9Sstevel@tonic-gate 	return (0);
1209*7c478bd9Sstevel@tonic-gate }
1210*7c478bd9Sstevel@tonic-gate 
1211*7c478bd9Sstevel@tonic-gate initdesc_x(argc, argv, is_reinit)
1212*7c478bd9Sstevel@tonic-gate 	int argc;
1213*7c478bd9Sstevel@tonic-gate 	char *argv[];
1214*7c478bd9Sstevel@tonic-gate 	int is_reinit;
1215*7c478bd9Sstevel@tonic-gate {
1216*7c478bd9Sstevel@tonic-gate 
1217*7c478bd9Sstevel@tonic-gate 	int script_fd = -1;
1218*7c478bd9Sstevel@tonic-gate 	struct stat buf;
1219*7c478bd9Sstevel@tonic-gate 	struct rlimit rlp;
1220*7c478bd9Sstevel@tonic-gate 
1221*7c478bd9Sstevel@tonic-gate 	 /*
1222*7c478bd9Sstevel@tonic-gate 	  * Get pid of this shell
1223*7c478bd9Sstevel@tonic-gate 	  */
1224*7c478bd9Sstevel@tonic-gate 	my_pid = getpid();
1225*7c478bd9Sstevel@tonic-gate 
1226*7c478bd9Sstevel@tonic-gate 	/*
1227*7c478bd9Sstevel@tonic-gate 	 * Get the hard limit numbers of descriptors
1228*7c478bd9Sstevel@tonic-gate 	 * this csh can use.
1229*7c478bd9Sstevel@tonic-gate 	 */
1230*7c478bd9Sstevel@tonic-gate 	if (getrlimit(RLIMIT_NOFILE, &rlp) == 0)
1231*7c478bd9Sstevel@tonic-gate 		NoFile = rlp.rlim_cur;
1232*7c478bd9Sstevel@tonic-gate 
1233*7c478bd9Sstevel@tonic-gate 	/*
1234*7c478bd9Sstevel@tonic-gate 	 * If this csh was invoked for executing setuid script file,
1235*7c478bd9Sstevel@tonic-gate 	 * the third argument passed is the special file name
1236*7c478bd9Sstevel@tonic-gate 	 * which should not be closed.  This special file name is
1237*7c478bd9Sstevel@tonic-gate 	 * in the form /dev/fd/X.
1238*7c478bd9Sstevel@tonic-gate 	 */
1239*7c478bd9Sstevel@tonic-gate 	if (argc >= 3)
1240*7c478bd9Sstevel@tonic-gate 	    if (sscanf(argv[2], "/dev/fd/%d", &script_fd) != 1)
1241*7c478bd9Sstevel@tonic-gate 		script_fd = -1;
1242*7c478bd9Sstevel@tonic-gate 	    else
1243*7c478bd9Sstevel@tonic-gate 		fcntl(script_fd, F_SETFD, 1);	/* Make sure to close
1244*7c478bd9Sstevel@tonic-gate 						 *  this file on exec.
1245*7c478bd9Sstevel@tonic-gate 						 */
1246*7c478bd9Sstevel@tonic-gate 
1247*7c478bd9Sstevel@tonic-gate 	if (fdinuse == NULL) {
1248*7c478bd9Sstevel@tonic-gate 		nbytesused = sizeof(int) * howmany(NoFile, sizeof(int) * NBBY);
1249*7c478bd9Sstevel@tonic-gate 		fdinuse = (int *) xalloc(nbytesused);
1250*7c478bd9Sstevel@tonic-gate 	}
1251*7c478bd9Sstevel@tonic-gate 
1252*7c478bd9Sstevel@tonic-gate 	/*
1253*7c478bd9Sstevel@tonic-gate 	 * Close all files except 0/1/2 to get a clean
1254*7c478bd9Sstevel@tonic-gate 	 * file descritor space.
1255*7c478bd9Sstevel@tonic-gate 	 */
1256*7c478bd9Sstevel@tonic-gate 	if (!is_reinit)
1257*7c478bd9Sstevel@tonic-gate 		(void) fdwalk(close_except, &script_fd);
1258*7c478bd9Sstevel@tonic-gate 	else
1259*7c478bd9Sstevel@tonic-gate 		(void) fdwalk(close_inuse, &script_fd);
1260*7c478bd9Sstevel@tonic-gate 
1261*7c478bd9Sstevel@tonic-gate 	didfds = 0;			/* 0, 1, 2 aren't set up */
1262*7c478bd9Sstevel@tonic-gate 
1263*7c478bd9Sstevel@tonic-gate 	if (fstat(0, &buf) < 0)
1264*7c478bd9Sstevel@tonic-gate 		open("/dev/null", 0);
1265*7c478bd9Sstevel@tonic-gate 
1266*7c478bd9Sstevel@tonic-gate 	(void) fcntl(SHIN = dcopy(0, FSHIN), F_SETFD,  1);
1267*7c478bd9Sstevel@tonic-gate 	(void) fcntl(SHOUT = dcopy(1, FSHOUT), F_SETFD,  1);
1268*7c478bd9Sstevel@tonic-gate 	(void) fcntl(SHDIAG = dcopy(2, FSHDIAG), F_SETFD,  1);
1269*7c478bd9Sstevel@tonic-gate 	(void) fcntl(OLDSTD = dcopy(SHIN, FOLDSTD), F_SETFD,  1);
1270*7c478bd9Sstevel@tonic-gate 
1271*7c478bd9Sstevel@tonic-gate 	/*
1272*7c478bd9Sstevel@tonic-gate 	 * Open 0/1/2 to avoid Nis+ functions to pick them up.
1273*7c478bd9Sstevel@tonic-gate 	 *	Now, 0/1/2 are saved, close them and open them.
1274*7c478bd9Sstevel@tonic-gate 	 */
1275*7c478bd9Sstevel@tonic-gate 	close(0); close(1); close(2);
1276*7c478bd9Sstevel@tonic-gate 	open("/dev/null", 0);
1277*7c478bd9Sstevel@tonic-gate 	dup(0);
1278*7c478bd9Sstevel@tonic-gate 	dup(0);
1279*7c478bd9Sstevel@tonic-gate 
1280*7c478bd9Sstevel@tonic-gate 	/*
1281*7c478bd9Sstevel@tonic-gate 	 * Clear fd_set mask
1282*7c478bd9Sstevel@tonic-gate 	 */
1283*7c478bd9Sstevel@tonic-gate 	if ( ! is_reinit)
1284*7c478bd9Sstevel@tonic-gate 		CSH_FD_ZERO(fdinuse, nbytesused);
1285*7c478bd9Sstevel@tonic-gate }
1286*7c478bd9Sstevel@tonic-gate 
1287*7c478bd9Sstevel@tonic-gate /*
1288*7c478bd9Sstevel@tonic-gate  * This routine is called after an error to close up
1289*7c478bd9Sstevel@tonic-gate  * any units which may have been left open accidentally.
1290*7c478bd9Sstevel@tonic-gate  *
1291*7c478bd9Sstevel@tonic-gate  * You only need to remove files in fdinuse list.
1292*7c478bd9Sstevel@tonic-gate  * After you have removed the files, you can clear the
1293*7c478bd9Sstevel@tonic-gate  * list and max_fd.
1294*7c478bd9Sstevel@tonic-gate  */
1295*7c478bd9Sstevel@tonic-gate closem()
1296*7c478bd9Sstevel@tonic-gate {
1297*7c478bd9Sstevel@tonic-gate 	register int f;
1298*7c478bd9Sstevel@tonic-gate 
1299*7c478bd9Sstevel@tonic-gate 	for (f = 3; f <= max_fd; f++) {
1300*7c478bd9Sstevel@tonic-gate 		if (CSH_FD_ISSET(f, fdinuse) &&
1301*7c478bd9Sstevel@tonic-gate 		    f != SHIN && f != SHOUT && f != SHDIAG &&
1302*7c478bd9Sstevel@tonic-gate 		    f != OLDSTD && f != FSHTTY)
1303*7c478bd9Sstevel@tonic-gate 			close(f);
1304*7c478bd9Sstevel@tonic-gate 	}
1305*7c478bd9Sstevel@tonic-gate 	CSH_FD_ZERO(fdinuse, nbytesused);
1306*7c478bd9Sstevel@tonic-gate 	max_fd = 0;
1307*7c478bd9Sstevel@tonic-gate }
1308*7c478bd9Sstevel@tonic-gate 
1309*7c478bd9Sstevel@tonic-gate /*
1310*7c478bd9Sstevel@tonic-gate  * Reset my_pid when a new process is created.  Only call this
1311*7c478bd9Sstevel@tonic-gate  * if you want the process to affect fdinuse (e.g., fork, but
1312*7c478bd9Sstevel@tonic-gate  * not vfork).
1313*7c478bd9Sstevel@tonic-gate  */
1314*7c478bd9Sstevel@tonic-gate new_process()
1315*7c478bd9Sstevel@tonic-gate {
1316*7c478bd9Sstevel@tonic-gate 	my_pid = getpid();
1317*7c478bd9Sstevel@tonic-gate }
1318*7c478bd9Sstevel@tonic-gate 
1319*7c478bd9Sstevel@tonic-gate 
1320*7c478bd9Sstevel@tonic-gate /*
1321*7c478bd9Sstevel@tonic-gate  * Whenever Csh open/create/dup/pipe a file or files,
1322*7c478bd9Sstevel@tonic-gate  * Csh keeps track of its open files. The open files
1323*7c478bd9Sstevel@tonic-gate  * are kept in "fdinuse, Fd In Use" list.
1324*7c478bd9Sstevel@tonic-gate  *
1325*7c478bd9Sstevel@tonic-gate  * When a file descriptor is newly allocated, setfd() is
1326*7c478bd9Sstevel@tonic-gate  * used to mark the fact in "fdinuse" list.
1327*7c478bd9Sstevel@tonic-gate  *	For example,
1328*7c478bd9Sstevel@tonic-gate  *		fd = open("newfile", 0);
1329*7c478bd9Sstevel@tonic-gate  *		setfd(fd);
1330*7c478bd9Sstevel@tonic-gate  *
1331*7c478bd9Sstevel@tonic-gate  * When a file is freed by close() function, unsetfd() is
1332*7c478bd9Sstevel@tonic-gate  * used to remove the fd from "fdinuse" list.
1333*7c478bd9Sstevel@tonic-gate  *	For example,
1334*7c478bd9Sstevel@tonic-gate  *		close(fd);
1335*7c478bd9Sstevel@tonic-gate  *		unsetfd(fd);
1336*7c478bd9Sstevel@tonic-gate  */
1337*7c478bd9Sstevel@tonic-gate setfd(fd)
1338*7c478bd9Sstevel@tonic-gate 	int fd;
1339*7c478bd9Sstevel@tonic-gate {
1340*7c478bd9Sstevel@tonic-gate 	/*
1341*7c478bd9Sstevel@tonic-gate 	 * Because you want to avoid
1342*7c478bd9Sstevel@tonic-gate 	 * conflict due to vfork().
1343*7c478bd9Sstevel@tonic-gate 	 */
1344*7c478bd9Sstevel@tonic-gate 	if (my_pid != getpid())
1345*7c478bd9Sstevel@tonic-gate 		return;
1346*7c478bd9Sstevel@tonic-gate 
1347*7c478bd9Sstevel@tonic-gate 	if (fd >= NoFile || fd < 0)
1348*7c478bd9Sstevel@tonic-gate 		return;
1349*7c478bd9Sstevel@tonic-gate 
1350*7c478bd9Sstevel@tonic-gate 	if (fd > max_fd)
1351*7c478bd9Sstevel@tonic-gate 		max_fd = fd;
1352*7c478bd9Sstevel@tonic-gate 	CSH_FD_SET(fd, fdinuse);
1353*7c478bd9Sstevel@tonic-gate }
1354*7c478bd9Sstevel@tonic-gate 
1355*7c478bd9Sstevel@tonic-gate unsetfd(fd)
1356*7c478bd9Sstevel@tonic-gate 	int fd;
1357*7c478bd9Sstevel@tonic-gate {
1358*7c478bd9Sstevel@tonic-gate 	register int i;
1359*7c478bd9Sstevel@tonic-gate 
1360*7c478bd9Sstevel@tonic-gate 	/*
1361*7c478bd9Sstevel@tonic-gate 	 * Because you want to avoid
1362*7c478bd9Sstevel@tonic-gate 	 * conflict due to vfork().
1363*7c478bd9Sstevel@tonic-gate 	 */
1364*7c478bd9Sstevel@tonic-gate 	if (my_pid != getpid())
1365*7c478bd9Sstevel@tonic-gate 		return;
1366*7c478bd9Sstevel@tonic-gate 
1367*7c478bd9Sstevel@tonic-gate 	if (fd >= NoFile || fd < 0)
1368*7c478bd9Sstevel@tonic-gate 		return;
1369*7c478bd9Sstevel@tonic-gate 
1370*7c478bd9Sstevel@tonic-gate 	CSH_FD_CLR(fd, fdinuse);
1371*7c478bd9Sstevel@tonic-gate 	if (fd == max_fd) {
1372*7c478bd9Sstevel@tonic-gate 		for (i = max_fd-1; i >= 3; i--)
1373*7c478bd9Sstevel@tonic-gate 			if (CSH_FD_ISSET(i, fdinuse)) {
1374*7c478bd9Sstevel@tonic-gate 				max_fd = i;
1375*7c478bd9Sstevel@tonic-gate 				return;
1376*7c478bd9Sstevel@tonic-gate 			}
1377*7c478bd9Sstevel@tonic-gate 		max_fd = 0;
1378*7c478bd9Sstevel@tonic-gate 	}
1379*7c478bd9Sstevel@tonic-gate }
1380*7c478bd9Sstevel@tonic-gate 
1381*7c478bd9Sstevel@tonic-gate /*
1382*7c478bd9Sstevel@tonic-gate  * A generic call back routine to output error messages from the
1383*7c478bd9Sstevel@tonic-gate  * policy backing functions called by pfcsh.
1384*7c478bd9Sstevel@tonic-gate  */
1385*7c478bd9Sstevel@tonic-gate void
1386*7c478bd9Sstevel@tonic-gate secpolicy_print(int level, const char *msg)
1387*7c478bd9Sstevel@tonic-gate {
1388*7c478bd9Sstevel@tonic-gate 	switch (level) {
1389*7c478bd9Sstevel@tonic-gate 	case SECPOLICY_WARN:
1390*7c478bd9Sstevel@tonic-gate 	default:
1391*7c478bd9Sstevel@tonic-gate 		haderr = 1;
1392*7c478bd9Sstevel@tonic-gate 		printf("%s: ", msg);	/* printf() does gettext() */
1393*7c478bd9Sstevel@tonic-gate 		break;
1394*7c478bd9Sstevel@tonic-gate 	case SECPOLICY_ERROR:
1395*7c478bd9Sstevel@tonic-gate 		bferr(msg);		/* bferr() does gettext() */
1396*7c478bd9Sstevel@tonic-gate 		break;
1397*7c478bd9Sstevel@tonic-gate 	}
1398*7c478bd9Sstevel@tonic-gate }
1399