1*4887Schin /***********************************************************************
2*4887Schin *                                                                      *
3*4887Schin *               This software is part of the ast package               *
4*4887Schin *           Copyright (c) 1982-2007 AT&T Knowledge Ventures            *
5*4887Schin *                      and is licensed under the                       *
6*4887Schin *                  Common Public License, Version 1.0                  *
7*4887Schin *                      by AT&T Knowledge Ventures                      *
8*4887Schin *                                                                      *
9*4887Schin *                A copy of the License is available at                 *
10*4887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*4887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*4887Schin *                                                                      *
13*4887Schin *              Information and Software Systems Research               *
14*4887Schin *                            AT&T Research                             *
15*4887Schin *                           Florham Park NJ                            *
16*4887Schin *                                                                      *
17*4887Schin *                  David Korn <dgk@research.att.com>                   *
18*4887Schin *                                                                      *
19*4887Schin ***********************************************************************/
20*4887Schin #pragma prototyped
21*4887Schin /*
22*4887Schin  * UNIX shell
23*4887Schin  *
24*4887Schin  * S. R. Bourne
25*4887Schin  * Rewritten By David Korn
26*4887Schin  * AT&T Labs
27*4887Schin  *
28*4887Schin  */
29*4887Schin 
30*4887Schin #include	<ast.h>
31*4887Schin #include	<sfio.h>
32*4887Schin #include	<stak.h>
33*4887Schin #include	<ls.h>
34*4887Schin #include	<fcin.h>
35*4887Schin #include	"defs.h"
36*4887Schin #include	"variables.h"
37*4887Schin #include	"path.h"
38*4887Schin #include	"io.h"
39*4887Schin #include	"jobs.h"
40*4887Schin #include	"shnodes.h"
41*4887Schin #include	"history.h"
42*4887Schin #include	"timeout.h"
43*4887Schin #include	"FEATURE/time"
44*4887Schin #include	"FEATURE/pstat"
45*4887Schin #include	"FEATURE/execargs"
46*4887Schin #include	"FEATURE/externs"
47*4887Schin #ifdef	_hdr_nc
48*4887Schin #   include	<nc.h>
49*4887Schin #endif	/* _hdr_nc */
50*4887Schin 
51*4887Schin #define CMD_LENGTH	64
52*4887Schin 
53*4887Schin /* These routines are referenced by this module */
54*4887Schin static void	exfile(Shell_t*, Sfio_t*,int);
55*4887Schin static void	chkmail(Shell_t *shp, char*);
56*4887Schin #if defined(_lib_fork) && !defined(_NEXT_SOURCE)
57*4887Schin     static void	fixargs(char**,int);
58*4887Schin #else
59*4887Schin #   define fixargs(a,b)
60*4887Schin #endif
61*4887Schin 
62*4887Schin #ifndef environ
63*4887Schin     extern char	**environ;
64*4887Schin #endif
65*4887Schin 
66*4887Schin static struct stat lastmail;
67*4887Schin static time_t	mailtime;
68*4887Schin static char	beenhere = 0;
69*4887Schin 
70*4887Schin #ifdef _lib_sigvec
71*4887Schin     void clearsigmask(register int sig)
72*4887Schin     {
73*4887Schin 	struct sigvec vec;
74*4887Schin 	if(sigvec(sig,NIL(struct sigvec*),&vec)>=0 && vec.sv_mask)
75*4887Schin 	{
76*4887Schin 		vec.sv_mask = 0;
77*4887Schin 		sigvec(sig,&vec,NIL(struct sigvec*));
78*4887Schin 	}
79*4887Schin     }
80*4887Schin #endif /* _lib_sigvec */
81*4887Schin 
82*4887Schin #ifdef _lib_fts_notify
83*4887Schin #   include	<fts.h>
84*4887Schin     /* check for interrupts during tree walks */
85*4887Schin     static int fts_sigcheck(FTS* fp, FTSENT* ep, void* context)
86*4887Schin     {
87*4887Schin 	Shell_t *shp = (Shell_t*)context;
88*4887Schin 	NOT_USED(fp);
89*4887Schin 	NOT_USED(ep);
90*4887Schin 	if(shp->trapnote&SH_SIGSET)
91*4887Schin 	{
92*4887Schin 		errno = EINTR;
93*4887Schin 		return(-1);
94*4887Schin 	}
95*4887Schin 	return(0);
96*4887Schin     }
97*4887Schin #endif /* _lib_fts_notify */
98*4887Schin 
99*4887Schin #ifdef PATH_BFPATH
100*4887Schin #define PATHCOMP	NIL(Pathcomp_t*)
101*4887Schin #else
102*4887Schin #define PATHCOMP	""
103*4887Schin #endif
104*4887Schin 
105*4887Schin /*
106*4887Schin  * search for file and exfile() it if it exists
107*4887Schin  * 1 returned if file found, 0 otherwise
108*4887Schin  */
109*4887Schin 
110*4887Schin int sh_source(Shell_t *shp, Sfio_t *iop, const char *file)
111*4887Schin {
112*4887Schin 	char*	oid;
113*4887Schin 	char*	nid;
114*4887Schin 	int	fd;
115*4887Schin 
116*4887Schin 	if (!file || !*file || (fd = path_open(file, PATHCOMP)) < 0)
117*4887Schin 		return 0;
118*4887Schin 	oid = error_info.id;
119*4887Schin 	nid = error_info.id = strdup(file);
120*4887Schin 	shp->st.filename = path_fullname(stakptr(PATH_OFFSET));
121*4887Schin 	exfile(shp, iop, fd);
122*4887Schin 	error_info.id = oid;
123*4887Schin 	free(nid);
124*4887Schin 	return 1;
125*4887Schin }
126*4887Schin 
127*4887Schin #ifdef S_ISSOCK
128*4887Schin #define REMOTE(m)	(S_ISSOCK(m)||!(m))
129*4887Schin #else
130*4887Schin #define REMOTE(m)	!(m)
131*4887Schin #endif
132*4887Schin 
133*4887Schin int sh_main(int ac, char *av[], void (*userinit)(int))
134*4887Schin {
135*4887Schin 	register char	*name;
136*4887Schin 	register int	fdin;
137*4887Schin 	register Sfio_t  *iop;
138*4887Schin 	register Shell_t *shp;
139*4887Schin 	struct stat	statb;
140*4887Schin 	int i, rshflag;		/* set for restricted shell */
141*4887Schin 	char *command;
142*4887Schin #ifdef _lib_sigvec
143*4887Schin 	/* This is to clear mask that my be left on by rlogin */
144*4887Schin 	clearsigmask(SIGALRM);
145*4887Schin 	clearsigmask(SIGHUP);
146*4887Schin 	clearsigmask(SIGCHLD);
147*4887Schin #endif /* _lib_sigvec */
148*4887Schin #ifdef	_hdr_nc
149*4887Schin 	_NutConf(_NC_SET_SUFFIXED_SEARCHING, 1);
150*4887Schin #endif	/* _hdr_nc */
151*4887Schin 	fixargs(av,0);
152*4887Schin 	shp = sh_init(ac,av,userinit);
153*4887Schin 	time(&mailtime);
154*4887Schin 	if(rshflag=sh_isoption(SH_RESTRICTED))
155*4887Schin 		sh_offoption(SH_RESTRICTED);
156*4887Schin #ifdef _lib_fts_notify
157*4887Schin 	fts_notify(fts_sigcheck,(void*)shp);
158*4887Schin #endif /* _lib_fts_notify */
159*4887Schin 	if(sigsetjmp(*((sigjmp_buf*)shp->jmpbuffer),0))
160*4887Schin 	{
161*4887Schin 		/* begin script execution here */
162*4887Schin 		sh_reinit((char**)0);
163*4887Schin 		if(rshflag)
164*4887Schin 			sh_onoption(SH_RESTRICTED);
165*4887Schin 	}
166*4887Schin 	shp->fn_depth = shp->dot_depth = 0;
167*4887Schin 	command = error_info.id;
168*4887Schin 	/* set pidname '$$' */
169*4887Schin 	shp->pid = getpid();
170*4887Schin 	srand(shp->pid&0x7fff);
171*4887Schin 	shp->ppid = getppid();
172*4887Schin 	if(nv_isnull(PS4NOD))
173*4887Schin 		nv_putval(PS4NOD,e_traceprompt,NV_RDONLY);
174*4887Schin 	path_pwd(1);
175*4887Schin 	iop = (Sfio_t*)0;
176*4887Schin #if SHOPT_BRACEPAT
177*4887Schin 	sh_onoption(SH_BRACEEXPAND);
178*4887Schin #endif
179*4887Schin 	if((beenhere++)==0)
180*4887Schin 	{
181*4887Schin 		sh_onstate(SH_PROFILE);
182*4887Schin 		if(shp->ppid==1)
183*4887Schin 			shp->login_sh++;
184*4887Schin 		if(shp->login_sh >= 2)
185*4887Schin 			sh_onoption(SH_LOGIN_SHELL);
186*4887Schin 		/* decide whether shell is interactive */
187*4887Schin 		if(!sh_isoption(SH_TFLAG) && !sh_isoption(SH_CFLAG) && sh_isoption(SH_SFLAG) &&
188*4887Schin 			tty_check(0) && tty_check(ERRIO))
189*4887Schin 		{
190*4887Schin 			sh_onoption(SH_INTERACTIVE);
191*4887Schin 			sh_onoption(SH_BGNICE);
192*4887Schin 			sh_onoption(SH_RC);
193*4887Schin 		}
194*4887Schin 		if(!sh_isoption(SH_RC) && (sh_isoption(SH_BASH) && !sh_isoption(SH_POSIX)
195*4887Schin #if SHOPT_REMOTE
196*4887Schin 		   || !fstat(0, &statb) && REMOTE(statb.st_mode)
197*4887Schin #endif
198*4887Schin 		  ))
199*4887Schin 			sh_onoption(SH_RC);
200*4887Schin 		for(i=0; i<elementsof(sh.offoptions.v); i++)
201*4887Schin 			sh.options.v[i] &= ~sh.offoptions.v[i];
202*4887Schin 		if(sh_isoption(SH_INTERACTIVE))
203*4887Schin 		{
204*4887Schin #ifdef SIGXCPU
205*4887Schin 			signal(SIGXCPU,SIG_DFL);
206*4887Schin #endif /* SIGXCPU */
207*4887Schin #ifdef SIGXFSZ
208*4887Schin 			signal(SIGXFSZ,SIG_DFL);
209*4887Schin #endif /* SIGXFSZ */
210*4887Schin 			sh_onoption(SH_MONITOR);
211*4887Schin 		}
212*4887Schin 		job_init(sh_isoption(SH_LOGIN_SHELL));
213*4887Schin 		if(sh_isoption(SH_LOGIN_SHELL) && !sh_isoption(SH_NOPROFILE))
214*4887Schin 		{
215*4887Schin 			/*	system profile	*/
216*4887Schin 			sh_source(shp, iop, e_sysprofile);
217*4887Schin 			if(!sh_isoption(SH_NOUSRPROFILE) && !sh_isoption(SH_PRIVILEGED))
218*4887Schin 			{
219*4887Schin 				char **files = shp->login_files;
220*4887Schin 				while ((name = *files++) && !sh_source(shp, iop, sh_mactry(name)));
221*4887Schin 			}
222*4887Schin 		}
223*4887Schin 		/* make sure PWD is set up correctly */
224*4887Schin 		path_pwd(1);
225*4887Schin 		if(!sh_isoption(SH_NOEXEC))
226*4887Schin 		{
227*4887Schin 			if(!sh_isoption(SH_NOUSRPROFILE) && !sh_isoption(SH_PRIVILEGED) && sh_isoption(SH_RC))
228*4887Schin 			{
229*4887Schin #if SHOPT_BASH
230*4887Schin 				if(sh_isoption(SH_BASH) && !sh_isoption(SH_POSIX))
231*4887Schin 				{
232*4887Schin #if SHOPT_SYSRC
233*4887Schin 					sh_source(shp, iop, e_bash_sysrc);
234*4887Schin #endif
235*4887Schin 					sh_source(shp, iop, shp->rcfile ? shp->rcfile : sh_mactry((char*)e_bash_rc));
236*4887Schin 				}
237*4887Schin 				else
238*4887Schin #endif
239*4887Schin 				{
240*4887Schin #if SHOPT_SYSRC
241*4887Schin 					sh_source(shp, iop, e_sysrc);
242*4887Schin #endif
243*4887Schin 					sh_source(shp, iop, sh_mactry(nv_getval(ENVNOD)));
244*4887Schin 				}
245*4887Schin 			}
246*4887Schin 			else if(sh_isoption(SH_INTERACTIVE) && sh_isoption(SH_PRIVILEGED))
247*4887Schin 				sh_source(shp, iop, e_suidprofile);
248*4887Schin 		}
249*4887Schin 		shp->st.cmdname = error_info.id = command;
250*4887Schin 		sh_offstate(SH_PROFILE);
251*4887Schin 		if(rshflag)
252*4887Schin 			sh_onoption(SH_RESTRICTED);
253*4887Schin 		/* open input file if specified */
254*4887Schin 		if(shp->comdiv)
255*4887Schin 		{
256*4887Schin 		shell_c:
257*4887Schin 			iop = sfnew(NIL(Sfio_t*),shp->comdiv,strlen(shp->comdiv),0,SF_STRING|SF_READ);
258*4887Schin 		}
259*4887Schin 		else
260*4887Schin 		{
261*4887Schin 			name = error_info.id;
262*4887Schin 			error_info.id = shp->shname;
263*4887Schin 			if(sh_isoption(SH_SFLAG))
264*4887Schin 				fdin = 0;
265*4887Schin 			else
266*4887Schin 			{
267*4887Schin 				char *sp;
268*4887Schin 				/* open stream should have been passed into shell */
269*4887Schin 				if(strmatch(name,e_devfdNN))
270*4887Schin 				{
271*4887Schin 					char *cp;
272*4887Schin 					int type;
273*4887Schin 					fdin = (int)strtol(name+8, (char**)0, 10);
274*4887Schin 					if(fstat(fdin,&statb)<0)
275*4887Schin 						errormsg(SH_DICT,ERROR_system(1),e_open,error_info.id);
276*4887Schin #if !_WINIX
277*4887Schin 					/*
278*4887Schin 					 * try to undo effect of solaris 2.5+
279*4887Schin 					 * change for argv for setuid scripts
280*4887Schin 					 */
281*4887Schin 					if(((type = sh_type(cp = av[0])) & SH_TYPE_SH) && (!(name = nv_getval(L_ARGNOD)) || !((type = sh_type(cp = name)) & SH_TYPE_SH)))
282*4887Schin 					{
283*4887Schin 						av[0] = (type & SH_TYPE_LOGIN) ? cp : path_basename(cp);
284*4887Schin 						/*  exec to change $0 for ps */
285*4887Schin 						execv(pathshell(),av);
286*4887Schin 						/* exec fails */
287*4887Schin 						shp->st.dolv[0] = av[0];
288*4887Schin 						fixargs(shp->st.dolv,1);
289*4887Schin 					}
290*4887Schin #endif
291*4887Schin 					name = av[0];
292*4887Schin 					sh_offoption(SH_VERBOSE);
293*4887Schin 					sh_offoption(SH_XTRACE);
294*4887Schin 				}
295*4887Schin 				else
296*4887Schin 				{
297*4887Schin 					int isdir = 0;
298*4887Schin 					if((fdin=sh_open(name,O_RDONLY,0))>=0 &&(fstat(fdin,&statb)<0 || S_ISDIR(statb.st_mode)))
299*4887Schin 					{
300*4887Schin 						close(fdin);
301*4887Schin 						isdir = 1;
302*4887Schin 						fdin = -1;
303*4887Schin 					}
304*4887Schin 					else
305*4887Schin 						shp->st.filename = path_fullname(name);
306*4887Schin 					sp = 0;
307*4887Schin 					if(fdin < 0 && !strchr(name,'/'))
308*4887Schin 					{
309*4887Schin #ifdef PATH_BFPATH
310*4887Schin 						if(path_absolute(name,NIL(Pathcomp_t*)))
311*4887Schin 							sp = stakptr(PATH_OFFSET);
312*4887Schin #else
313*4887Schin 							sp = path_absolute(name,NIL(char*));
314*4887Schin #endif
315*4887Schin 						if(sp)
316*4887Schin 						{
317*4887Schin 							if((fdin=sh_open(sp,O_RDONLY,0))>=0)
318*4887Schin 								shp->st.filename = path_fullname(sp);
319*4887Schin 						}
320*4887Schin 					}
321*4887Schin 					if(fdin<0)
322*4887Schin 					{
323*4887Schin 						if(isdir)
324*4887Schin 							errno = EISDIR;
325*4887Schin 						 error_info.id = av[0];
326*4887Schin 						if(sp || errno!=ENOENT)
327*4887Schin 							errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_open,name);
328*4887Schin 						/* try sh -c 'name "$@"' */
329*4887Schin 						sh_onoption(SH_CFLAG);
330*4887Schin 						shp->comdiv = (char*)malloc(strlen(name)+7);
331*4887Schin 						name = strcopy(shp->comdiv,name);
332*4887Schin 						if(shp->st.dolc)
333*4887Schin 							strcopy(name," \"$@\"");
334*4887Schin 						goto shell_c;
335*4887Schin 					}
336*4887Schin 					if(fdin==0)
337*4887Schin 						fdin = sh_iomovefd(fdin);
338*4887Schin 				}
339*4887Schin 				shp->readscript = shp->shname;
340*4887Schin 			}
341*4887Schin 			error_info.id = name;
342*4887Schin 			shp->comdiv--;
343*4887Schin #if SHOPT_ACCT
344*4887Schin 			sh_accinit();
345*4887Schin 			if(fdin != 0)
346*4887Schin 				sh_accbegin(error_info.id);
347*4887Schin #endif	/* SHOPT_ACCT */
348*4887Schin 		}
349*4887Schin 	}
350*4887Schin 	else
351*4887Schin 	{
352*4887Schin 		fdin = shp->infd;
353*4887Schin 		fixargs(shp->st.dolv,1);
354*4887Schin 	}
355*4887Schin 	if(sh_isoption(SH_INTERACTIVE))
356*4887Schin 		sh_onstate(SH_INTERACTIVE);
357*4887Schin 	nv_putval(IFSNOD,(char*)e_sptbnl,NV_RDONLY);
358*4887Schin 	exfile(shp,iop,fdin);
359*4887Schin 	sh_done(0);
360*4887Schin 	/* NOTREACHED */
361*4887Schin 	return(0);
362*4887Schin }
363*4887Schin 
364*4887Schin /*
365*4887Schin  * iop is not null when the input is a string
366*4887Schin  * fdin is the input file descriptor
367*4887Schin  */
368*4887Schin 
369*4887Schin static void	exfile(register Shell_t *shp, register Sfio_t *iop,register int fno)
370*4887Schin {
371*4887Schin 	time_t curtime;
372*4887Schin 	Shnode_t *t;
373*4887Schin 	int maxtry=IOMAXTRY, tdone=0, execflags;
374*4887Schin 	int states,jmpval;
375*4887Schin 	struct checkpt buff;
376*4887Schin 	sh_pushcontext(&buff,SH_JMPERREXIT);
377*4887Schin 	/* open input stream */
378*4887Schin 	nv_putval(SH_PATHNAMENOD, shp->st.filename ,NV_NOFREE);
379*4887Schin 	if(!iop)
380*4887Schin 	{
381*4887Schin 		if(fno > 0)
382*4887Schin 		{
383*4887Schin 			int r;
384*4887Schin 			if(fno < 10 && ((r=sh_fcntl(fno,F_DUPFD,10))>=10))
385*4887Schin 			{
386*4887Schin 				shp->fdstatus[r] = shp->fdstatus[fno];
387*4887Schin 				sh_close(fno);
388*4887Schin 				fno = r;
389*4887Schin 			}
390*4887Schin 			fcntl(fno,F_SETFD,FD_CLOEXEC);
391*4887Schin 			shp->fdstatus[fno] |= IOCLEX;
392*4887Schin 			iop = sh_iostream(fno);
393*4887Schin 		}
394*4887Schin 		else
395*4887Schin 			iop = sfstdin;
396*4887Schin 	}
397*4887Schin 	else
398*4887Schin 		fno = -1;
399*4887Schin 	shp->infd = fno;
400*4887Schin 	if(sh_isstate(SH_INTERACTIVE))
401*4887Schin 	{
402*4887Schin 		if(nv_isnull(PS1NOD))
403*4887Schin 			nv_putval(PS1NOD,(shp->euserid?e_stdprompt:e_supprompt),NV_RDONLY);
404*4887Schin 		sh_sigdone();
405*4887Schin 		if(sh_histinit())
406*4887Schin 			sh_onoption(SH_HISTORY);
407*4887Schin 	}
408*4887Schin 	else
409*4887Schin 	{
410*4887Schin 		if(!sh_isstate(SH_PROFILE))
411*4887Schin 		{
412*4887Schin 			buff.mode = SH_JMPEXIT;
413*4887Schin 			sh_onoption(SH_TRACKALL);
414*4887Schin 			sh_offoption(SH_MONITOR);
415*4887Schin 		}
416*4887Schin 		sh_offstate(SH_INTERACTIVE);
417*4887Schin 		sh_offstate(SH_MONITOR);
418*4887Schin 		sh_offstate(SH_HISTORY);
419*4887Schin 		sh_offoption(SH_HISTORY);
420*4887Schin 	}
421*4887Schin 	states = sh_getstate();
422*4887Schin 	jmpval = sigsetjmp(buff.buff,0);
423*4887Schin 	if(jmpval)
424*4887Schin 	{
425*4887Schin 		Sfio_t *top;
426*4887Schin 		sh_iorestore(0,jmpval);
427*4887Schin 		hist_flush(shp->hist_ptr);
428*4887Schin 		sfsync(shp->outpool);
429*4887Schin 		shp->st.execbrk = shp->st.breakcnt = 0;
430*4887Schin 		/* check for return from profile or env file */
431*4887Schin 		if(sh_isstate(SH_PROFILE) && (jmpval==SH_JMPFUN || jmpval==SH_JMPEXIT))
432*4887Schin 			goto done;
433*4887Schin 		if(!sh_isoption(SH_INTERACTIVE) || sh_isstate(SH_FORKED) || (jmpval > SH_JMPERREXIT && job_close() >=0))
434*4887Schin 		{
435*4887Schin 			sh_offstate(SH_INTERACTIVE);
436*4887Schin 			sh_offstate(SH_MONITOR);
437*4887Schin 			goto done;
438*4887Schin 		}
439*4887Schin 		/* skip over remaining input */
440*4887Schin 		if(top = fcfile())
441*4887Schin 		{
442*4887Schin 			while(fcget()>0);
443*4887Schin 			fcclose();
444*4887Schin 			while(top=sfstack(iop,SF_POPSTACK))
445*4887Schin 				sfclose(top);
446*4887Schin 		}
447*4887Schin 		/* make sure that we own the terminal */
448*4887Schin #ifdef SIGTSTP
449*4887Schin 		tcsetpgrp(job.fd,shp->pid);
450*4887Schin #endif /* SIGTSTP */
451*4887Schin 	}
452*4887Schin 	/* error return here */
453*4887Schin 	sfclrerr(iop);
454*4887Schin 	sh_setstate(states);
455*4887Schin 	shp->st.optindex = 1;
456*4887Schin 	opt_info.offset = 0;
457*4887Schin 	shp->st.loopcnt = 0;
458*4887Schin 	shp->trapnote = 0;
459*4887Schin 	shp->intrap = 0;
460*4887Schin 	error_info.line = 1;
461*4887Schin 	shp->inlineno = 1;
462*4887Schin 	shp->binscript = 0;
463*4887Schin 	if(sfeof(iop))
464*4887Schin 		goto eof_or_error;
465*4887Schin 	/* command loop */
466*4887Schin 	while(1)
467*4887Schin 	{
468*4887Schin 		shp->nextprompt = 1;
469*4887Schin 		sh_freeup();
470*4887Schin 		stakset(NIL(char*),0);
471*4887Schin 		exitset();
472*4887Schin 		sh_offstate(SH_STOPOK);
473*4887Schin 		sh_offstate(SH_ERREXIT);
474*4887Schin 		sh_offstate(SH_VERBOSE);
475*4887Schin 		sh_offstate(SH_TIMING);
476*4887Schin 		sh_offstate(SH_GRACE);
477*4887Schin 		sh_offstate(SH_TTYWAIT);
478*4887Schin 		if(sh_isoption(SH_VERBOSE))
479*4887Schin 			sh_onstate(SH_VERBOSE);
480*4887Schin 		sh_onstate(SH_ERREXIT);
481*4887Schin 		/* -eim  flags don't apply to profiles */
482*4887Schin 		if(sh_isstate(SH_PROFILE))
483*4887Schin 		{
484*4887Schin 			sh_offstate(SH_INTERACTIVE);
485*4887Schin 			sh_offstate(SH_ERREXIT);
486*4887Schin 			sh_offstate(SH_MONITOR);
487*4887Schin 		}
488*4887Schin 		if(sh_isstate(SH_INTERACTIVE) && !tdone)
489*4887Schin 		{
490*4887Schin 			register char *mail;
491*4887Schin #ifdef JOBS
492*4887Schin 			sh_offstate(SH_MONITOR);
493*4887Schin 			if(sh_isoption(SH_MONITOR))
494*4887Schin 				sh_onstate(SH_MONITOR);
495*4887Schin 			if(job.pwlist)
496*4887Schin 			{
497*4887Schin 				job_walk(sfstderr,job_list,JOB_NFLAG,(char**)0);
498*4887Schin 				job_wait((pid_t)0);
499*4887Schin 			}
500*4887Schin #endif	/* JOBS */
501*4887Schin 			if((mail=nv_getval(MAILPNOD)) || (mail=nv_getval(MAILNOD)))
502*4887Schin 			{
503*4887Schin 				time(&curtime);
504*4887Schin 				if ((curtime - mailtime) >= sh_mailchk)
505*4887Schin 				{
506*4887Schin 					chkmail(shp,mail);
507*4887Schin 					mailtime = curtime;
508*4887Schin 				}
509*4887Schin 			}
510*4887Schin 			if(shp->hist_ptr)
511*4887Schin 				hist_eof(shp->hist_ptr);
512*4887Schin 			/* sets timeout for command entry */
513*4887Schin 			shp->timeout = shp->st.tmout;
514*4887Schin #if SHOPT_TIMEOUT
515*4887Schin 			if(shp->timeout <= 0 || shp->timeout > SHOPT_TIMEOUT)
516*4887Schin 				shp->timeout = SHOPT_TIMEOUT;
517*4887Schin #endif /* SHOPT_TIMEOUT */
518*4887Schin 			shp->inlineno = 1;
519*4887Schin 			error_info.line = 1;
520*4887Schin 			shp->exitval = 0;
521*4887Schin 			shp->trapnote = 0;
522*4887Schin 			if(buff.mode == SH_JMPEXIT)
523*4887Schin 			{
524*4887Schin 				buff.mode = SH_JMPERREXIT;
525*4887Schin #ifdef DEBUG
526*4887Schin 				errormsg(SH_DICT,ERROR_warn(0),"%d: mode changed to JMP_EXIT",getpid());
527*4887Schin #endif
528*4887Schin 			}
529*4887Schin 		}
530*4887Schin 		errno = 0;
531*4887Schin 		if(tdone || !sfreserve(iop,0,0))
532*4887Schin 		{
533*4887Schin 		eof_or_error:
534*4887Schin 			if(sh_isstate(SH_INTERACTIVE) && !sferror(iop))
535*4887Schin 			{
536*4887Schin 				if(--maxtry>0 && sh_isoption(SH_IGNOREEOF) &&
537*4887Schin 					 !sferror(sfstderr) && (shp->fdstatus[fno]&IOTTY))
538*4887Schin 				{
539*4887Schin 					sfclrerr(iop);
540*4887Schin 					errormsg(SH_DICT,0,e_logout);
541*4887Schin 					continue;
542*4887Schin 				}
543*4887Schin 				else if(job_close()<0)
544*4887Schin 					continue;
545*4887Schin 			}
546*4887Schin 			if(errno==0 && sferror(iop) && --maxtry>0)
547*4887Schin 			{
548*4887Schin 				sfclrlock(iop);
549*4887Schin 				sfclrerr(iop);
550*4887Schin 				continue;
551*4887Schin 			}
552*4887Schin 			goto done;
553*4887Schin 		}
554*4887Schin 		maxtry = IOMAXTRY;
555*4887Schin 		if(sh_isstate(SH_INTERACTIVE) && shp->hist_ptr)
556*4887Schin 		{
557*4887Schin 			job_wait((pid_t)0);
558*4887Schin 			hist_eof(shp->hist_ptr);
559*4887Schin 			sfsync(sfstderr);
560*4887Schin 		}
561*4887Schin 		if(sh_isoption(SH_HISTORY))
562*4887Schin 			sh_onstate(SH_HISTORY);
563*4887Schin 		job.waitall = job.curpgid = 0;
564*4887Schin 		error_info.flags |= ERROR_INTERACTIVE;
565*4887Schin 		t = (Shnode_t*)sh_parse(shp,iop,0);
566*4887Schin 		if(!sh_isstate(SH_INTERACTIVE) && !sh_isstate(SH_CFLAG))
567*4887Schin 			error_info.flags &= ~ERROR_INTERACTIVE;
568*4887Schin 		shp->readscript = 0;
569*4887Schin 		if(sh_isstate(SH_INTERACTIVE) && shp->hist_ptr)
570*4887Schin 			hist_flush(shp->hist_ptr);
571*4887Schin 		sh_offstate(SH_HISTORY);
572*4887Schin 		if(t)
573*4887Schin 		{
574*4887Schin 			execflags = sh_state(SH_ERREXIT)|sh_state(SH_INTERACTIVE);
575*4887Schin 			/* The last command may not have to fork */
576*4887Schin 			if(!sh_isstate(SH_PROFILE) && !sh_isstate(SH_INTERACTIVE) &&
577*4887Schin 				(fno<0 || !(shp->fdstatus[fno]&(IOTTY|IONOSEEK)))
578*4887Schin 				&& !sfreserve(iop,0,0))
579*4887Schin 			{
580*4887Schin 					execflags |= sh_state(SH_NOFORK);
581*4887Schin 			}
582*4887Schin 			shp->st.execbrk = 0;
583*4887Schin 			sh_exec(t,execflags);
584*4887Schin 			if(shp->forked)
585*4887Schin 			{
586*4887Schin 				sh_offstate(SH_INTERACTIVE);
587*4887Schin 				goto done;
588*4887Schin 			}
589*4887Schin 			/* This is for sh -t */
590*4887Schin 			if(sh_isoption(SH_TFLAG) && !sh_isstate(SH_PROFILE))
591*4887Schin 				tdone++;
592*4887Schin 		}
593*4887Schin 	}
594*4887Schin done:
595*4887Schin 	sh_popcontext(&buff);
596*4887Schin 	if(sh_isstate(SH_INTERACTIVE))
597*4887Schin 	{
598*4887Schin 		sfputc(sfstderr,'\n');
599*4887Schin 		job_close();
600*4887Schin 	}
601*4887Schin 	if(jmpval == SH_JMPSCRIPT)
602*4887Schin 		siglongjmp(*shp->jmplist,jmpval);
603*4887Schin 	else if(jmpval == SH_JMPEXIT)
604*4887Schin 		sh_done(0);
605*4887Schin 	if(fno>0)
606*4887Schin 		sh_close(fno);
607*4887Schin 	if(shp->st.filename)
608*4887Schin 		free((void*)shp->st.filename);
609*4887Schin 	shp->st.filename = 0;
610*4887Schin }
611*4887Schin 
612*4887Schin 
613*4887Schin /* prints out messages if files in list have been modified since last call */
614*4887Schin static void chkmail(Shell_t *shp, char *files)
615*4887Schin {
616*4887Schin 	register char *cp,*sp,*qp;
617*4887Schin 	register char save;
618*4887Schin 	struct argnod *arglist=0;
619*4887Schin 	int	offset = staktell();
620*4887Schin 	char 	*savstak=stakptr(0);
621*4887Schin 	struct stat	statb;
622*4887Schin 	if(*(cp=files) == 0)
623*4887Schin 		return;
624*4887Schin 	sp = cp;
625*4887Schin 	do
626*4887Schin 	{
627*4887Schin 		/* skip to : or end of string saving first '?' */
628*4887Schin 		for(qp=0;*sp && *sp != ':';sp++)
629*4887Schin 			if((*sp == '?' || *sp=='%') && qp == 0)
630*4887Schin 				qp = sp;
631*4887Schin 		save = *sp;
632*4887Schin 		*sp = 0;
633*4887Schin 		/* change '?' to end-of-string */
634*4887Schin 		if(qp)
635*4887Schin 			*qp = 0;
636*4887Schin 		do
637*4887Schin 		{
638*4887Schin 			/* see if time has been modified since last checked
639*4887Schin 			 * and the access time <= the modification time
640*4887Schin 			 */
641*4887Schin 			if(stat(cp,&statb) >= 0 && statb.st_mtime >= mailtime
642*4887Schin 				&& statb.st_atime <= statb.st_mtime)
643*4887Schin 			{
644*4887Schin 				/* check for directory */
645*4887Schin 				if(!arglist && S_ISDIR(statb.st_mode))
646*4887Schin 				{
647*4887Schin 					/* generate list of directory entries */
648*4887Schin 					path_complete(cp,"/*",&arglist);
649*4887Schin 				}
650*4887Schin 				else
651*4887Schin 				{
652*4887Schin 					/*
653*4887Schin 					 * If the file has shrunk,
654*4887Schin 					 * or if the size is zero
655*4887Schin 					 * then don't print anything
656*4887Schin 					 */
657*4887Schin 					if(statb.st_size &&
658*4887Schin 						(  statb.st_ino != lastmail.st_ino
659*4887Schin 						|| statb.st_dev != lastmail.st_dev
660*4887Schin 						|| statb.st_size > lastmail.st_size))
661*4887Schin 					{
662*4887Schin 						/* save and restore $_ */
663*4887Schin 						char *save = shp->lastarg;
664*4887Schin 						shp->lastarg = cp;
665*4887Schin 						errormsg(SH_DICT,0,sh_mactry(qp?qp+1:(char*)e_mailmsg));
666*4887Schin 						shp->lastarg = save;
667*4887Schin 					}
668*4887Schin 					lastmail = statb;
669*4887Schin 					break;
670*4887Schin 				}
671*4887Schin 			}
672*4887Schin 			if(arglist)
673*4887Schin 			{
674*4887Schin 				cp = arglist->argval;
675*4887Schin 				arglist = arglist->argchn.ap;
676*4887Schin 			}
677*4887Schin 			else
678*4887Schin 				cp = 0;
679*4887Schin 		}
680*4887Schin 		while(cp);
681*4887Schin 		if(qp)
682*4887Schin 			*qp = '?';
683*4887Schin 		*sp++ = save;
684*4887Schin 		cp = sp;
685*4887Schin 	}
686*4887Schin 	while(save);
687*4887Schin 	stakset(savstak,offset);
688*4887Schin }
689*4887Schin 
690*4887Schin #undef EXECARGS
691*4887Schin #undef PSTAT
692*4887Schin #if defined(_hdr_execargs) && defined(pdp11)
693*4887Schin #   include	<execargs.h>
694*4887Schin #   define EXECARGS	1
695*4887Schin #endif
696*4887Schin 
697*4887Schin #if defined(_lib_pstat) && defined(_sys_pstat)
698*4887Schin #   include	<sys/pstat.h>
699*4887Schin #   define PSTAT	1
700*4887Schin #endif
701*4887Schin 
702*4887Schin #if defined(_lib_fork) && !defined(_NEXT_SOURCE)
703*4887Schin /*
704*4887Schin  * fix up command line for ps command
705*4887Schin  * mode is 0 for initialization
706*4887Schin  */
707*4887Schin static void fixargs(char **argv, int mode)
708*4887Schin {
709*4887Schin #if EXECARGS
710*4887Schin 	*execargs=(char *)argv;
711*4887Schin #else
712*4887Schin 	static char *buff;
713*4887Schin 	static int command_len;
714*4887Schin 	register char *cp;
715*4887Schin 	int offset=0,size;
716*4887Schin #   ifdef PSTAT
717*4887Schin 	union pstun un;
718*4887Schin 	if(mode==0)
719*4887Schin 	{
720*4887Schin 		struct pst_static st;
721*4887Schin 		un.pst_static = &st;
722*4887Schin 		if(pstat(PSTAT_STATIC, un, sizeof(struct pst_static), 1, 0)<0)
723*4887Schin 			return;
724*4887Schin 		command_len = st.command_length;
725*4887Schin 		return;
726*4887Schin 	}
727*4887Schin 	stakseek(command_len+2);
728*4887Schin 	buff = stakseek(0);
729*4887Schin #   else
730*4887Schin 	if(mode==0)
731*4887Schin 	{
732*4887Schin 		buff = argv[0];
733*4887Schin 		while(cp = *argv++)
734*4887Schin 			command_len += strlen(cp)+1;
735*4887Schin 		if(environ && *environ==buff+command_len)
736*4887Schin 		{
737*4887Schin 			for(argv=environ; cp = *argv; cp++)
738*4887Schin 			{
739*4887Schin 				if(command_len > CMD_LENGTH)
740*4887Schin 				{
741*4887Schin 					command_len = CMD_LENGTH;
742*4887Schin 					break;
743*4887Schin 				}
744*4887Schin 				*argv++ = strdup(cp);
745*4887Schin 				command_len += strlen(cp)+1;
746*4887Schin 			}
747*4887Schin 		}
748*4887Schin 		command_len -= 1;
749*4887Schin 		return;
750*4887Schin 	}
751*4887Schin #   endif /* PSTAT */
752*4887Schin 	if(command_len==0)
753*4887Schin 		return;
754*4887Schin 	while((cp = *argv++) && offset < command_len)
755*4887Schin 	{
756*4887Schin 		if(offset + (size=strlen(cp)) >= command_len)
757*4887Schin 			size = command_len - offset;
758*4887Schin 		memcpy(buff+offset,cp,size);
759*4887Schin 		offset += size;
760*4887Schin 		buff[offset++] = ' ';
761*4887Schin 	}
762*4887Schin 	buff[offset-1] = 0;
763*4887Schin #   ifdef PSTAT
764*4887Schin 	un.pst_command = stakptr(0);
765*4887Schin 	pstat(PSTAT_SETCMD,un,0,0,0);
766*4887Schin #   endif /* PSTAT */
767*4887Schin #endif /* EXECARGS */
768*4887Schin }
769*4887Schin #endif /* _lib_fork */
770