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