14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*8462SApril.Chin@Sun.COM *          Copyright (c) 1982-2008 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
7*8462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                  David Korn <dgk@research.att.com>                   *
184887Schin *                                                                      *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin /*
224887Schin  * UNIX shell
234887Schin  *
244887Schin  * S. R. Bourne
254887Schin  * Rewritten By David Korn
264887Schin  * AT&T Labs
274887Schin  *
284887Schin  */
294887Schin 
304887Schin #include	<ast.h>
314887Schin #include	<sfio.h>
324887Schin #include	<stak.h>
334887Schin #include	<ls.h>
344887Schin #include	<fcin.h>
354887Schin #include	"defs.h"
364887Schin #include	"variables.h"
374887Schin #include	"path.h"
384887Schin #include	"io.h"
394887Schin #include	"jobs.h"
404887Schin #include	"shnodes.h"
414887Schin #include	"history.h"
424887Schin #include	"timeout.h"
434887Schin #include	"FEATURE/time"
444887Schin #include	"FEATURE/pstat"
454887Schin #include	"FEATURE/execargs"
464887Schin #include	"FEATURE/externs"
474887Schin #ifdef	_hdr_nc
484887Schin #   include	<nc.h>
494887Schin #endif	/* _hdr_nc */
504887Schin 
514887Schin #define CMD_LENGTH	64
524887Schin 
534887Schin /* These routines are referenced by this module */
544887Schin static void	exfile(Shell_t*, Sfio_t*,int);
554887Schin static void	chkmail(Shell_t *shp, char*);
564887Schin #if defined(_lib_fork) && !defined(_NEXT_SOURCE)
574887Schin     static void	fixargs(char**,int);
584887Schin #else
594887Schin #   define fixargs(a,b)
604887Schin #endif
614887Schin 
624887Schin #ifndef environ
634887Schin     extern char	**environ;
644887Schin #endif
654887Schin 
664887Schin static struct stat lastmail;
674887Schin static time_t	mailtime;
684887Schin static char	beenhere = 0;
694887Schin 
704887Schin #ifdef _lib_sigvec
714887Schin     void clearsigmask(register int sig)
724887Schin     {
734887Schin 	struct sigvec vec;
744887Schin 	if(sigvec(sig,NIL(struct sigvec*),&vec)>=0 && vec.sv_mask)
754887Schin 	{
764887Schin 		vec.sv_mask = 0;
774887Schin 		sigvec(sig,&vec,NIL(struct sigvec*));
784887Schin 	}
794887Schin     }
804887Schin #endif /* _lib_sigvec */
814887Schin 
824887Schin #ifdef _lib_fts_notify
834887Schin #   include	<fts.h>
844887Schin     /* check for interrupts during tree walks */
854887Schin     static int fts_sigcheck(FTS* fp, FTSENT* ep, void* context)
864887Schin     {
874887Schin 	Shell_t *shp = (Shell_t*)context;
884887Schin 	NOT_USED(fp);
894887Schin 	NOT_USED(ep);
904887Schin 	if(shp->trapnote&SH_SIGSET)
914887Schin 	{
924887Schin 		errno = EINTR;
934887Schin 		return(-1);
944887Schin 	}
954887Schin 	return(0);
964887Schin     }
974887Schin #endif /* _lib_fts_notify */
984887Schin 
994887Schin #ifdef PATH_BFPATH
1004887Schin #define PATHCOMP	NIL(Pathcomp_t*)
1014887Schin #else
1024887Schin #define PATHCOMP	""
1034887Schin #endif
1044887Schin 
1054887Schin /*
1064887Schin  * search for file and exfile() it if it exists
1074887Schin  * 1 returned if file found, 0 otherwise
1084887Schin  */
1094887Schin 
1104887Schin int sh_source(Shell_t *shp, Sfio_t *iop, const char *file)
1114887Schin {
1124887Schin 	char*	oid;
1134887Schin 	char*	nid;
1144887Schin 	int	fd;
1154887Schin 
1164887Schin 	if (!file || !*file || (fd = path_open(file, PATHCOMP)) < 0)
1174887Schin 		return 0;
1184887Schin 	oid = error_info.id;
1194887Schin 	nid = error_info.id = strdup(file);
1204887Schin 	shp->st.filename = path_fullname(stakptr(PATH_OFFSET));
1214887Schin 	exfile(shp, iop, fd);
1224887Schin 	error_info.id = oid;
1234887Schin 	free(nid);
1244887Schin 	return 1;
1254887Schin }
1264887Schin 
1274887Schin #ifdef S_ISSOCK
1284887Schin #define REMOTE(m)	(S_ISSOCK(m)||!(m))
1294887Schin #else
1304887Schin #define REMOTE(m)	!(m)
1314887Schin #endif
1324887Schin 
133*8462SApril.Chin@Sun.COM int sh_main(int ac, char *av[], Shinit_f userinit)
1344887Schin {
1354887Schin 	register char	*name;
1364887Schin 	register int	fdin;
1374887Schin 	register Sfio_t  *iop;
1384887Schin 	register Shell_t *shp;
1394887Schin 	struct stat	statb;
1404887Schin 	int i, rshflag;		/* set for restricted shell */
1414887Schin 	char *command;
1424887Schin #ifdef _lib_sigvec
143*8462SApril.Chin@Sun.COM 	/* This is to clear mask that may be left on by rlogin */
1444887Schin 	clearsigmask(SIGALRM);
1454887Schin 	clearsigmask(SIGHUP);
1464887Schin 	clearsigmask(SIGCHLD);
1474887Schin #endif /* _lib_sigvec */
1484887Schin #ifdef	_hdr_nc
1494887Schin 	_NutConf(_NC_SET_SUFFIXED_SEARCHING, 1);
1504887Schin #endif	/* _hdr_nc */
1514887Schin 	fixargs(av,0);
1524887Schin 	shp = sh_init(ac,av,userinit);
1534887Schin 	time(&mailtime);
1544887Schin 	if(rshflag=sh_isoption(SH_RESTRICTED))
1554887Schin 		sh_offoption(SH_RESTRICTED);
1564887Schin #ifdef _lib_fts_notify
1574887Schin 	fts_notify(fts_sigcheck,(void*)shp);
1584887Schin #endif /* _lib_fts_notify */
1594887Schin 	if(sigsetjmp(*((sigjmp_buf*)shp->jmpbuffer),0))
1604887Schin 	{
1614887Schin 		/* begin script execution here */
1624887Schin 		sh_reinit((char**)0);
1634887Schin 	}
1644887Schin 	shp->fn_depth = shp->dot_depth = 0;
1654887Schin 	command = error_info.id;
1664887Schin 	/* set pidname '$$' */
1674887Schin 	shp->pid = getpid();
1684887Schin 	srand(shp->pid&0x7fff);
1694887Schin 	shp->ppid = getppid();
1704887Schin 	if(nv_isnull(PS4NOD))
1714887Schin 		nv_putval(PS4NOD,e_traceprompt,NV_RDONLY);
1724887Schin 	path_pwd(1);
1734887Schin 	iop = (Sfio_t*)0;
1744887Schin #if SHOPT_BRACEPAT
1754887Schin 	sh_onoption(SH_BRACEEXPAND);
1764887Schin #endif
1774887Schin 	if((beenhere++)==0)
1784887Schin 	{
1794887Schin 		sh_onstate(SH_PROFILE);
1804887Schin 		if(shp->ppid==1)
1814887Schin 			shp->login_sh++;
1824887Schin 		if(shp->login_sh >= 2)
1834887Schin 			sh_onoption(SH_LOGIN_SHELL);
1844887Schin 		/* decide whether shell is interactive */
185*8462SApril.Chin@Sun.COM 		if(!sh_isoption(SH_INTERACTIVE) && !sh_isoption(SH_TFLAG) && !sh_isoption(SH_CFLAG) &&
186*8462SApril.Chin@Sun.COM 		   sh_isoption(SH_SFLAG) && tty_check(0) && tty_check(ERRIO))
187*8462SApril.Chin@Sun.COM 			sh_onoption(SH_INTERACTIVE);
188*8462SApril.Chin@Sun.COM 		if(sh_isoption(SH_INTERACTIVE))
1894887Schin 		{
1904887Schin 			sh_onoption(SH_BGNICE);
1914887Schin 			sh_onoption(SH_RC);
1924887Schin 		}
1934887Schin 		if(!sh_isoption(SH_RC) && (sh_isoption(SH_BASH) && !sh_isoption(SH_POSIX)
1944887Schin #if SHOPT_REMOTE
1954887Schin 		   || !fstat(0, &statb) && REMOTE(statb.st_mode)
1964887Schin #endif
1974887Schin 		  ))
1984887Schin 			sh_onoption(SH_RC);
199*8462SApril.Chin@Sun.COM 		for(i=0; i<elementsof(shp->offoptions.v); i++)
200*8462SApril.Chin@Sun.COM 			shp->options.v[i] &= ~shp->offoptions.v[i];
2014887Schin 		if(sh_isoption(SH_INTERACTIVE))
2024887Schin 		{
2034887Schin #ifdef SIGXCPU
2044887Schin 			signal(SIGXCPU,SIG_DFL);
2054887Schin #endif /* SIGXCPU */
2064887Schin #ifdef SIGXFSZ
2074887Schin 			signal(SIGXFSZ,SIG_DFL);
2084887Schin #endif /* SIGXFSZ */
2094887Schin 			sh_onoption(SH_MONITOR);
2104887Schin 		}
211*8462SApril.Chin@Sun.COM 		job_init(shp,sh_isoption(SH_LOGIN_SHELL));
212*8462SApril.Chin@Sun.COM 		if(sh_isoption(SH_LOGIN_SHELL))
2134887Schin 		{
2144887Schin 			/*	system profile	*/
2154887Schin 			sh_source(shp, iop, e_sysprofile);
2164887Schin 			if(!sh_isoption(SH_NOUSRPROFILE) && !sh_isoption(SH_PRIVILEGED))
2174887Schin 			{
2184887Schin 				char **files = shp->login_files;
219*8462SApril.Chin@Sun.COM 				while ((name = *files++) && !sh_source(shp, iop, sh_mactry(shp,name)));
2204887Schin 			}
2214887Schin 		}
2224887Schin 		/* make sure PWD is set up correctly */
2234887Schin 		path_pwd(1);
2244887Schin 		if(!sh_isoption(SH_NOEXEC))
2254887Schin 		{
2264887Schin 			if(!sh_isoption(SH_NOUSRPROFILE) && !sh_isoption(SH_PRIVILEGED) && sh_isoption(SH_RC))
2274887Schin 			{
2284887Schin #if SHOPT_BASH
2294887Schin 				if(sh_isoption(SH_BASH) && !sh_isoption(SH_POSIX))
2304887Schin 				{
2314887Schin #if SHOPT_SYSRC
2324887Schin 					sh_source(shp, iop, e_bash_sysrc);
2334887Schin #endif
234*8462SApril.Chin@Sun.COM 					sh_source(shp, iop, shp->rcfile ? shp->rcfile : sh_mactry(shp,(char*)e_bash_rc));
2354887Schin 				}
2364887Schin 				else
2374887Schin #endif
2384887Schin 				{
239*8462SApril.Chin@Sun.COM 					if(name = sh_mactry(shp,nv_getval(ENVNOD)))
240*8462SApril.Chin@Sun.COM 						name = *name ? strdup(name) : (char*)0;
2414887Schin #if SHOPT_SYSRC
242*8462SApril.Chin@Sun.COM 					if(!strmatch(name, "?(.)/./*"))
243*8462SApril.Chin@Sun.COM 						sh_source(shp, iop, e_sysrc);
2444887Schin #endif
245*8462SApril.Chin@Sun.COM 					if(name)
246*8462SApril.Chin@Sun.COM 					{
247*8462SApril.Chin@Sun.COM 						sh_source(shp, iop, name);
248*8462SApril.Chin@Sun.COM 						free(name);
249*8462SApril.Chin@Sun.COM 					}
2504887Schin 				}
2514887Schin 			}
2524887Schin 			else if(sh_isoption(SH_INTERACTIVE) && sh_isoption(SH_PRIVILEGED))
2534887Schin 				sh_source(shp, iop, e_suidprofile);
2544887Schin 		}
2554887Schin 		shp->st.cmdname = error_info.id = command;
2564887Schin 		sh_offstate(SH_PROFILE);
2574887Schin 		if(rshflag)
2584887Schin 			sh_onoption(SH_RESTRICTED);
2594887Schin 		/* open input file if specified */
2604887Schin 		if(shp->comdiv)
2614887Schin 		{
2624887Schin 		shell_c:
2634887Schin 			iop = sfnew(NIL(Sfio_t*),shp->comdiv,strlen(shp->comdiv),0,SF_STRING|SF_READ);
2644887Schin 		}
2654887Schin 		else
2664887Schin 		{
2674887Schin 			name = error_info.id;
2684887Schin 			error_info.id = shp->shname;
2694887Schin 			if(sh_isoption(SH_SFLAG))
2704887Schin 				fdin = 0;
2714887Schin 			else
2724887Schin 			{
2734887Schin 				char *sp;
2744887Schin 				/* open stream should have been passed into shell */
2754887Schin 				if(strmatch(name,e_devfdNN))
2764887Schin 				{
2774887Schin 					char *cp;
2784887Schin 					int type;
2794887Schin 					fdin = (int)strtol(name+8, (char**)0, 10);
2804887Schin 					if(fstat(fdin,&statb)<0)
281*8462SApril.Chin@Sun.COM 						errormsg(SH_DICT,ERROR_system(1),e_open,name);
2824887Schin #if !_WINIX
2834887Schin 					/*
2844887Schin 					 * try to undo effect of solaris 2.5+
2854887Schin 					 * change for argv for setuid scripts
2864887Schin 					 */
2874887Schin 					if(((type = sh_type(cp = av[0])) & SH_TYPE_SH) && (!(name = nv_getval(L_ARGNOD)) || !((type = sh_type(cp = name)) & SH_TYPE_SH)))
2884887Schin 					{
2894887Schin 						av[0] = (type & SH_TYPE_LOGIN) ? cp : path_basename(cp);
2904887Schin 						/*  exec to change $0 for ps */
2914887Schin 						execv(pathshell(),av);
2924887Schin 						/* exec fails */
2934887Schin 						shp->st.dolv[0] = av[0];
2944887Schin 						fixargs(shp->st.dolv,1);
2954887Schin 					}
2964887Schin #endif
2974887Schin 					name = av[0];
2984887Schin 					sh_offoption(SH_VERBOSE);
2994887Schin 					sh_offoption(SH_XTRACE);
3004887Schin 				}
3014887Schin 				else
3024887Schin 				{
3034887Schin 					int isdir = 0;
3044887Schin 					if((fdin=sh_open(name,O_RDONLY,0))>=0 &&(fstat(fdin,&statb)<0 || S_ISDIR(statb.st_mode)))
3054887Schin 					{
3064887Schin 						close(fdin);
3074887Schin 						isdir = 1;
3084887Schin 						fdin = -1;
3094887Schin 					}
3104887Schin 					else
3114887Schin 						shp->st.filename = path_fullname(name);
3124887Schin 					sp = 0;
3134887Schin 					if(fdin < 0 && !strchr(name,'/'))
3144887Schin 					{
3154887Schin #ifdef PATH_BFPATH
3164887Schin 						if(path_absolute(name,NIL(Pathcomp_t*)))
3174887Schin 							sp = stakptr(PATH_OFFSET);
3184887Schin #else
3194887Schin 							sp = path_absolute(name,NIL(char*));
3204887Schin #endif
3214887Schin 						if(sp)
3224887Schin 						{
3234887Schin 							if((fdin=sh_open(sp,O_RDONLY,0))>=0)
3244887Schin 								shp->st.filename = path_fullname(sp);
3254887Schin 						}
3264887Schin 					}
3274887Schin 					if(fdin<0)
3284887Schin 					{
3294887Schin 						if(isdir)
3304887Schin 							errno = EISDIR;
3314887Schin 						 error_info.id = av[0];
3324887Schin 						if(sp || errno!=ENOENT)
3334887Schin 							errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_open,name);
3344887Schin 						/* try sh -c 'name "$@"' */
3354887Schin 						sh_onoption(SH_CFLAG);
3364887Schin 						shp->comdiv = (char*)malloc(strlen(name)+7);
3374887Schin 						name = strcopy(shp->comdiv,name);
3384887Schin 						if(shp->st.dolc)
3394887Schin 							strcopy(name," \"$@\"");
3404887Schin 						goto shell_c;
3414887Schin 					}
3424887Schin 					if(fdin==0)
3434887Schin 						fdin = sh_iomovefd(fdin);
3444887Schin 				}
3454887Schin 				shp->readscript = shp->shname;
3464887Schin 			}
3474887Schin 			error_info.id = name;
3484887Schin 			shp->comdiv--;
3494887Schin #if SHOPT_ACCT
3504887Schin 			sh_accinit();
3514887Schin 			if(fdin != 0)
3524887Schin 				sh_accbegin(error_info.id);
3534887Schin #endif	/* SHOPT_ACCT */
3544887Schin 		}
3554887Schin 	}
3564887Schin 	else
3574887Schin 	{
3584887Schin 		fdin = shp->infd;
3594887Schin 		fixargs(shp->st.dolv,1);
3604887Schin 	}
3614887Schin 	if(sh_isoption(SH_INTERACTIVE))
3624887Schin 		sh_onstate(SH_INTERACTIVE);
3634887Schin 	nv_putval(IFSNOD,(char*)e_sptbnl,NV_RDONLY);
3644887Schin 	exfile(shp,iop,fdin);
365*8462SApril.Chin@Sun.COM 	sh_done(shp,0);
3664887Schin 	/* NOTREACHED */
3674887Schin 	return(0);
3684887Schin }
3694887Schin 
3704887Schin /*
3714887Schin  * iop is not null when the input is a string
3724887Schin  * fdin is the input file descriptor
3734887Schin  */
3744887Schin 
3754887Schin static void	exfile(register Shell_t *shp, register Sfio_t *iop,register int fno)
3764887Schin {
3774887Schin 	time_t curtime;
3784887Schin 	Shnode_t *t;
3794887Schin 	int maxtry=IOMAXTRY, tdone=0, execflags;
3804887Schin 	int states,jmpval;
3814887Schin 	struct checkpt buff;
3824887Schin 	sh_pushcontext(&buff,SH_JMPERREXIT);
3834887Schin 	/* open input stream */
3844887Schin 	nv_putval(SH_PATHNAMENOD, shp->st.filename ,NV_NOFREE);
3854887Schin 	if(!iop)
3864887Schin 	{
3874887Schin 		if(fno > 0)
3884887Schin 		{
3894887Schin 			int r;
3904887Schin 			if(fno < 10 && ((r=sh_fcntl(fno,F_DUPFD,10))>=10))
3914887Schin 			{
3924887Schin 				shp->fdstatus[r] = shp->fdstatus[fno];
3934887Schin 				sh_close(fno);
3944887Schin 				fno = r;
3954887Schin 			}
3964887Schin 			fcntl(fno,F_SETFD,FD_CLOEXEC);
3974887Schin 			shp->fdstatus[fno] |= IOCLEX;
398*8462SApril.Chin@Sun.COM 			iop = sh_iostream((void*)shp,fno);
3994887Schin 		}
4004887Schin 		else
4014887Schin 			iop = sfstdin;
4024887Schin 	}
4034887Schin 	else
4044887Schin 		fno = -1;
4054887Schin 	shp->infd = fno;
4064887Schin 	if(sh_isstate(SH_INTERACTIVE))
4074887Schin 	{
4084887Schin 		if(nv_isnull(PS1NOD))
4094887Schin 			nv_putval(PS1NOD,(shp->euserid?e_stdprompt:e_supprompt),NV_RDONLY);
4104887Schin 		sh_sigdone();
411*8462SApril.Chin@Sun.COM 		if(sh_histinit((void*)shp))
4124887Schin 			sh_onoption(SH_HISTORY);
4134887Schin 	}
4144887Schin 	else
4154887Schin 	{
4164887Schin 		if(!sh_isstate(SH_PROFILE))
4174887Schin 		{
4184887Schin 			buff.mode = SH_JMPEXIT;
4194887Schin 			sh_onoption(SH_TRACKALL);
4204887Schin 			sh_offoption(SH_MONITOR);
4214887Schin 		}
4224887Schin 		sh_offstate(SH_INTERACTIVE);
4234887Schin 		sh_offstate(SH_MONITOR);
4244887Schin 		sh_offstate(SH_HISTORY);
4254887Schin 		sh_offoption(SH_HISTORY);
4264887Schin 	}
4274887Schin 	states = sh_getstate();
4284887Schin 	jmpval = sigsetjmp(buff.buff,0);
4294887Schin 	if(jmpval)
4304887Schin 	{
4314887Schin 		Sfio_t *top;
432*8462SApril.Chin@Sun.COM 		sh_iorestore((void*)shp,0,jmpval);
4334887Schin 		hist_flush(shp->hist_ptr);
4344887Schin 		sfsync(shp->outpool);
4354887Schin 		shp->st.execbrk = shp->st.breakcnt = 0;
4364887Schin 		/* check for return from profile or env file */
4374887Schin 		if(sh_isstate(SH_PROFILE) && (jmpval==SH_JMPFUN || jmpval==SH_JMPEXIT))
4384887Schin 			goto done;
439*8462SApril.Chin@Sun.COM 		if(!sh_isoption(SH_INTERACTIVE) || sh_isstate(SH_FORKED) || (jmpval > SH_JMPERREXIT && job_close(shp) >=0))
4404887Schin 		{
4414887Schin 			sh_offstate(SH_INTERACTIVE);
4424887Schin 			sh_offstate(SH_MONITOR);
4434887Schin 			goto done;
4444887Schin 		}
4454887Schin 		/* skip over remaining input */
4464887Schin 		if(top = fcfile())
4474887Schin 		{
4484887Schin 			while(fcget()>0);
4494887Schin 			fcclose();
4504887Schin 			while(top=sfstack(iop,SF_POPSTACK))
4514887Schin 				sfclose(top);
4524887Schin 		}
4534887Schin 		/* make sure that we own the terminal */
4544887Schin #ifdef SIGTSTP
4554887Schin 		tcsetpgrp(job.fd,shp->pid);
4564887Schin #endif /* SIGTSTP */
4574887Schin 	}
4584887Schin 	/* error return here */
4594887Schin 	sfclrerr(iop);
4604887Schin 	sh_setstate(states);
4614887Schin 	shp->st.optindex = 1;
4624887Schin 	opt_info.offset = 0;
4634887Schin 	shp->st.loopcnt = 0;
4644887Schin 	shp->trapnote = 0;
4654887Schin 	shp->intrap = 0;
4664887Schin 	error_info.line = 1;
4674887Schin 	shp->inlineno = 1;
4684887Schin 	shp->binscript = 0;
4694887Schin 	if(sfeof(iop))
4704887Schin 		goto eof_or_error;
4714887Schin 	/* command loop */
4724887Schin 	while(1)
4734887Schin 	{
4744887Schin 		shp->nextprompt = 1;
475*8462SApril.Chin@Sun.COM 		sh_freeup(shp);
4764887Schin 		stakset(NIL(char*),0);
4774887Schin 		exitset();
4784887Schin 		sh_offstate(SH_STOPOK);
4794887Schin 		sh_offstate(SH_ERREXIT);
4804887Schin 		sh_offstate(SH_VERBOSE);
4814887Schin 		sh_offstate(SH_TIMING);
4824887Schin 		sh_offstate(SH_GRACE);
4834887Schin 		sh_offstate(SH_TTYWAIT);
4844887Schin 		if(sh_isoption(SH_VERBOSE))
4854887Schin 			sh_onstate(SH_VERBOSE);
4864887Schin 		sh_onstate(SH_ERREXIT);
4874887Schin 		/* -eim  flags don't apply to profiles */
4884887Schin 		if(sh_isstate(SH_PROFILE))
4894887Schin 		{
4904887Schin 			sh_offstate(SH_INTERACTIVE);
4914887Schin 			sh_offstate(SH_ERREXIT);
4924887Schin 			sh_offstate(SH_MONITOR);
4934887Schin 		}
4944887Schin 		if(sh_isstate(SH_INTERACTIVE) && !tdone)
4954887Schin 		{
4964887Schin 			register char *mail;
4974887Schin #ifdef JOBS
4984887Schin 			sh_offstate(SH_MONITOR);
4994887Schin 			if(sh_isoption(SH_MONITOR))
5004887Schin 				sh_onstate(SH_MONITOR);
5014887Schin 			if(job.pwlist)
5024887Schin 			{
5034887Schin 				job_walk(sfstderr,job_list,JOB_NFLAG,(char**)0);
5044887Schin 				job_wait((pid_t)0);
5054887Schin 			}
5064887Schin #endif	/* JOBS */
5074887Schin 			if((mail=nv_getval(MAILPNOD)) || (mail=nv_getval(MAILNOD)))
5084887Schin 			{
5094887Schin 				time(&curtime);
5104887Schin 				if ((curtime - mailtime) >= sh_mailchk)
5114887Schin 				{
5124887Schin 					chkmail(shp,mail);
5134887Schin 					mailtime = curtime;
5144887Schin 				}
5154887Schin 			}
5164887Schin 			if(shp->hist_ptr)
5174887Schin 				hist_eof(shp->hist_ptr);
5184887Schin 			/* sets timeout for command entry */
5194887Schin 			shp->timeout = shp->st.tmout;
5204887Schin #if SHOPT_TIMEOUT
5214887Schin 			if(shp->timeout <= 0 || shp->timeout > SHOPT_TIMEOUT)
5224887Schin 				shp->timeout = SHOPT_TIMEOUT;
5234887Schin #endif /* SHOPT_TIMEOUT */
5244887Schin 			shp->inlineno = 1;
5254887Schin 			error_info.line = 1;
5264887Schin 			shp->exitval = 0;
5274887Schin 			shp->trapnote = 0;
5284887Schin 			if(buff.mode == SH_JMPEXIT)
5294887Schin 			{
5304887Schin 				buff.mode = SH_JMPERREXIT;
5314887Schin #ifdef DEBUG
5324887Schin 				errormsg(SH_DICT,ERROR_warn(0),"%d: mode changed to JMP_EXIT",getpid());
5334887Schin #endif
5344887Schin 			}
5354887Schin 		}
5364887Schin 		errno = 0;
5374887Schin 		if(tdone || !sfreserve(iop,0,0))
5384887Schin 		{
5394887Schin 		eof_or_error:
5404887Schin 			if(sh_isstate(SH_INTERACTIVE) && !sferror(iop))
5414887Schin 			{
5424887Schin 				if(--maxtry>0 && sh_isoption(SH_IGNOREEOF) &&
5434887Schin 					 !sferror(sfstderr) && (shp->fdstatus[fno]&IOTTY))
5444887Schin 				{
5454887Schin 					sfclrerr(iop);
5464887Schin 					errormsg(SH_DICT,0,e_logout);
5474887Schin 					continue;
5484887Schin 				}
549*8462SApril.Chin@Sun.COM 				else if(job_close(shp)<0)
5504887Schin 					continue;
5514887Schin 			}
5524887Schin 			if(errno==0 && sferror(iop) && --maxtry>0)
5534887Schin 			{
5544887Schin 				sfclrlock(iop);
5554887Schin 				sfclrerr(iop);
5564887Schin 				continue;
5574887Schin 			}
5584887Schin 			goto done;
5594887Schin 		}
5604887Schin 		maxtry = IOMAXTRY;
5614887Schin 		if(sh_isstate(SH_INTERACTIVE) && shp->hist_ptr)
5624887Schin 		{
5634887Schin 			job_wait((pid_t)0);
5644887Schin 			hist_eof(shp->hist_ptr);
5654887Schin 			sfsync(sfstderr);
5664887Schin 		}
5674887Schin 		if(sh_isoption(SH_HISTORY))
5684887Schin 			sh_onstate(SH_HISTORY);
5694887Schin 		job.waitall = job.curpgid = 0;
5704887Schin 		error_info.flags |= ERROR_INTERACTIVE;
5714887Schin 		t = (Shnode_t*)sh_parse(shp,iop,0);
5724887Schin 		if(!sh_isstate(SH_INTERACTIVE) && !sh_isstate(SH_CFLAG))
5734887Schin 			error_info.flags &= ~ERROR_INTERACTIVE;
5744887Schin 		shp->readscript = 0;
5754887Schin 		if(sh_isstate(SH_INTERACTIVE) && shp->hist_ptr)
5764887Schin 			hist_flush(shp->hist_ptr);
5774887Schin 		sh_offstate(SH_HISTORY);
5784887Schin 		if(t)
5794887Schin 		{
5804887Schin 			execflags = sh_state(SH_ERREXIT)|sh_state(SH_INTERACTIVE);
5814887Schin 			/* The last command may not have to fork */
5824887Schin 			if(!sh_isstate(SH_PROFILE) && !sh_isstate(SH_INTERACTIVE) &&
5834887Schin 				(fno<0 || !(shp->fdstatus[fno]&(IOTTY|IONOSEEK)))
5844887Schin 				&& !sfreserve(iop,0,0))
5854887Schin 			{
5864887Schin 					execflags |= sh_state(SH_NOFORK);
5874887Schin 			}
5884887Schin 			shp->st.execbrk = 0;
5894887Schin 			sh_exec(t,execflags);
5904887Schin 			if(shp->forked)
5914887Schin 			{
5924887Schin 				sh_offstate(SH_INTERACTIVE);
5934887Schin 				goto done;
5944887Schin 			}
5954887Schin 			/* This is for sh -t */
5964887Schin 			if(sh_isoption(SH_TFLAG) && !sh_isstate(SH_PROFILE))
5974887Schin 				tdone++;
5984887Schin 		}
5994887Schin 	}
6004887Schin done:
6014887Schin 	sh_popcontext(&buff);
6024887Schin 	if(sh_isstate(SH_INTERACTIVE))
6034887Schin 	{
6044887Schin 		sfputc(sfstderr,'\n');
605*8462SApril.Chin@Sun.COM 		job_close(shp);
6064887Schin 	}
6074887Schin 	if(jmpval == SH_JMPSCRIPT)
6084887Schin 		siglongjmp(*shp->jmplist,jmpval);
6094887Schin 	else if(jmpval == SH_JMPEXIT)
610*8462SApril.Chin@Sun.COM 		sh_done(shp,0);
6114887Schin 	if(fno>0)
6124887Schin 		sh_close(fno);
6134887Schin 	if(shp->st.filename)
6144887Schin 		free((void*)shp->st.filename);
6154887Schin 	shp->st.filename = 0;
6164887Schin }
6174887Schin 
6184887Schin 
6194887Schin /* prints out messages if files in list have been modified since last call */
6204887Schin static void chkmail(Shell_t *shp, char *files)
6214887Schin {
6224887Schin 	register char *cp,*sp,*qp;
6234887Schin 	register char save;
6244887Schin 	struct argnod *arglist=0;
6254887Schin 	int	offset = staktell();
6264887Schin 	char 	*savstak=stakptr(0);
6274887Schin 	struct stat	statb;
6284887Schin 	if(*(cp=files) == 0)
6294887Schin 		return;
6304887Schin 	sp = cp;
6314887Schin 	do
6324887Schin 	{
6334887Schin 		/* skip to : or end of string saving first '?' */
6344887Schin 		for(qp=0;*sp && *sp != ':';sp++)
6354887Schin 			if((*sp == '?' || *sp=='%') && qp == 0)
6364887Schin 				qp = sp;
6374887Schin 		save = *sp;
6384887Schin 		*sp = 0;
6394887Schin 		/* change '?' to end-of-string */
6404887Schin 		if(qp)
6414887Schin 			*qp = 0;
6424887Schin 		do
6434887Schin 		{
6444887Schin 			/* see if time has been modified since last checked
6454887Schin 			 * and the access time <= the modification time
6464887Schin 			 */
6474887Schin 			if(stat(cp,&statb) >= 0 && statb.st_mtime >= mailtime
6484887Schin 				&& statb.st_atime <= statb.st_mtime)
6494887Schin 			{
6504887Schin 				/* check for directory */
6514887Schin 				if(!arglist && S_ISDIR(statb.st_mode))
6524887Schin 				{
6534887Schin 					/* generate list of directory entries */
6544887Schin 					path_complete(cp,"/*",&arglist);
6554887Schin 				}
6564887Schin 				else
6574887Schin 				{
6584887Schin 					/*
6594887Schin 					 * If the file has shrunk,
6604887Schin 					 * or if the size is zero
6614887Schin 					 * then don't print anything
6624887Schin 					 */
6634887Schin 					if(statb.st_size &&
6644887Schin 						(  statb.st_ino != lastmail.st_ino
6654887Schin 						|| statb.st_dev != lastmail.st_dev
6664887Schin 						|| statb.st_size > lastmail.st_size))
6674887Schin 					{
6684887Schin 						/* save and restore $_ */
6694887Schin 						char *save = shp->lastarg;
6704887Schin 						shp->lastarg = cp;
671*8462SApril.Chin@Sun.COM 						errormsg(SH_DICT,0,sh_mactry(shp,qp?qp+1:(char*)e_mailmsg));
6724887Schin 						shp->lastarg = save;
6734887Schin 					}
6744887Schin 					lastmail = statb;
6754887Schin 					break;
6764887Schin 				}
6774887Schin 			}
6784887Schin 			if(arglist)
6794887Schin 			{
6804887Schin 				cp = arglist->argval;
6814887Schin 				arglist = arglist->argchn.ap;
6824887Schin 			}
6834887Schin 			else
6844887Schin 				cp = 0;
6854887Schin 		}
6864887Schin 		while(cp);
6874887Schin 		if(qp)
6884887Schin 			*qp = '?';
6894887Schin 		*sp++ = save;
6904887Schin 		cp = sp;
6914887Schin 	}
6924887Schin 	while(save);
6934887Schin 	stakset(savstak,offset);
6944887Schin }
6954887Schin 
6964887Schin #undef EXECARGS
6974887Schin #undef PSTAT
6984887Schin #if defined(_hdr_execargs) && defined(pdp11)
6994887Schin #   include	<execargs.h>
7004887Schin #   define EXECARGS	1
7014887Schin #endif
7024887Schin 
7034887Schin #if defined(_lib_pstat) && defined(_sys_pstat)
7044887Schin #   include	<sys/pstat.h>
7054887Schin #   define PSTAT	1
7064887Schin #endif
7074887Schin 
7084887Schin #if defined(_lib_fork) && !defined(_NEXT_SOURCE)
7094887Schin /*
7104887Schin  * fix up command line for ps command
7114887Schin  * mode is 0 for initialization
7124887Schin  */
7134887Schin static void fixargs(char **argv, int mode)
7144887Schin {
7154887Schin #if EXECARGS
7164887Schin 	*execargs=(char *)argv;
7174887Schin #else
7184887Schin 	static char *buff;
7194887Schin 	static int command_len;
7204887Schin 	register char *cp;
7214887Schin 	int offset=0,size;
7224887Schin #   ifdef PSTAT
7234887Schin 	union pstun un;
7244887Schin 	if(mode==0)
7254887Schin 	{
7264887Schin 		struct pst_static st;
7274887Schin 		un.pst_static = &st;
7284887Schin 		if(pstat(PSTAT_STATIC, un, sizeof(struct pst_static), 1, 0)<0)
7294887Schin 			return;
7304887Schin 		command_len = st.command_length;
7314887Schin 		return;
7324887Schin 	}
7334887Schin 	stakseek(command_len+2);
7344887Schin 	buff = stakseek(0);
7354887Schin #   else
7364887Schin 	if(mode==0)
7374887Schin 	{
7384887Schin 		buff = argv[0];
7394887Schin 		while(cp = *argv++)
7404887Schin 			command_len += strlen(cp)+1;
7414887Schin 		if(environ && *environ==buff+command_len)
7424887Schin 		{
7434887Schin 			for(argv=environ; cp = *argv; cp++)
7444887Schin 			{
7454887Schin 				if(command_len > CMD_LENGTH)
7464887Schin 				{
7474887Schin 					command_len = CMD_LENGTH;
7484887Schin 					break;
7494887Schin 				}
7504887Schin 				*argv++ = strdup(cp);
7514887Schin 				command_len += strlen(cp)+1;
7524887Schin 			}
7534887Schin 		}
7544887Schin 		command_len -= 1;
7554887Schin 		return;
7564887Schin 	}
7574887Schin #   endif /* PSTAT */
7584887Schin 	if(command_len==0)
7594887Schin 		return;
7604887Schin 	while((cp = *argv++) && offset < command_len)
7614887Schin 	{
7624887Schin 		if(offset + (size=strlen(cp)) >= command_len)
7634887Schin 			size = command_len - offset;
7644887Schin 		memcpy(buff+offset,cp,size);
7654887Schin 		offset += size;
7664887Schin 		buff[offset++] = ' ';
7674887Schin 	}
7684887Schin 	buff[offset-1] = 0;
7694887Schin #   ifdef PSTAT
7704887Schin 	un.pst_command = stakptr(0);
7714887Schin 	pstat(PSTAT_SETCMD,un,0,0,0);
7724887Schin #   endif /* PSTAT */
7734887Schin #endif /* EXECARGS */
7744887Schin }
7754887Schin #endif /* _lib_fork */
776