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