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