1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1982-2012 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                  David Korn <dgk@research.att.com>                   *
18 *                                                                      *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22  * David Korn
23  * AT&T Labs
24  *
25  */
26 
27 #include	"defs.h"
28 #include	<fcin.h>
29 #include	<ls.h>
30 #include	<nval.h>
31 #include	"variables.h"
32 #include	"path.h"
33 #include	"io.h"
34 #include	"jobs.h"
35 #include	"history.h"
36 #include	"test.h"
37 #include	"FEATURE/dynamic"
38 #include	"FEATURE/externs"
39 #if SHOPT_PFSH
40 #   ifdef _hdr_exec_attr
41 #	include	<exec_attr.h>
42 #   endif
43 #   if     _lib_vfork
44 #	include     <ast_vfork.h>
45 #   else
46 #	define vfork()      fork()
47 #   endif
48 #endif
49 
50 #define RW_ALL	(S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH)
51 #define LIBCMD	"cmd"
52 
53 
54 static int		canexecute(Shell_t*,char*,int);
55 static void		funload(Shell_t*,int,const char*);
56 static void		exscript(Shell_t*,char*, char*[], char**);
57 static int		path_chkpaths(Shell_t*,Pathcomp_t*,Pathcomp_t*,Pathcomp_t*,int);
58 static void		path_checkdup(Shell_t *shp,register Pathcomp_t*);
59 
60 static const char	*std_path;
61 
onstdpath(const char * name)62 static int onstdpath(const char *name)
63 {
64 	register const char *cp = std_path, *sp;
65 	if(cp)
66 		while(*cp)
67 		{
68 			for(sp=name; *sp && (*cp == *sp); sp++,cp++);
69 			if(*sp==0 && (*cp==0 || *cp==':'))
70 				return(1);
71 			while(*cp && *cp++!=':');
72 		}
73 	return(0);
74 }
75 
76 #if SHOPT_PFSH
path_xattr(Shell_t * shp,const char * path,char * rpath)77 int path_xattr(Shell_t *shp, const char *path, char *rpath)
78 {
79 	char  resolvedpath[PATH_MAX + 1];
80 	if (shp->gd->user && *shp->gd->user)
81 	{
82 		execattr_t *pf;
83 		if(!rpath)
84 			rpath = resolvedpath;
85 		if (!realpath(path, resolvedpath))
86 			return -1;
87 		if(pf=getexecuser(shp->gd->user, KV_COMMAND, resolvedpath, GET_ONE))
88 		{
89 			if (!pf->attr || pf->attr->length == 0)
90 			{
91 				free_execattr(pf);
92 				return(0);
93 			}
94 			free_execattr(pf);
95 			return(1);
96 		}
97 	}
98 	errno = ENOENT;
99 	return(-1);
100 }
101 #endif /* SHOPT_PFSH */
102 
path_pfexecve(Shell_t * shp,const char * path,char * argv[],char * const envp[],int spawn)103 static pid_t path_pfexecve(Shell_t *shp,const char *path, char *argv[],char *const envp[],int spawn)
104 {
105 #if SHOPT_PFSH
106 	char  resolvedpath[PATH_MAX + 1];
107 	pid_t	pid;
108 	if(spawn)
109 	{
110 		while((pid = vfork()) < 0)
111 			_sh_fork(shp,pid, 0, (int*)0);
112 		if(pid)
113 			return(pid);
114 	}
115 	if(!sh_isoption(SH_PFSH))
116 		return(execve(path, argv, envp));
117 	/* Solaris implements realpath(3C) using the resolvepath(2) */
118 	/* system call so we can save us to call access(2) first */
119 
120 	/* we can exec the command directly instead of via pfexec(1) if */
121 	/* there is a matching entry without attributes in exec_attr(4) */
122 	if(!path_xattr(shp,path,resolvedpath))
123 		return(execve(path, argv, envp));
124 	--argv;
125 	argv[0] = argv[1];
126 	argv[1] = resolvedpath;
127 	return(execve("/usr/bin/pfexec", argv, envp));
128 #else
129 	return(execve(path, argv, envp));
130 #endif
131 }
132 
133 
_spawnveg(Shell_t * shp,const char * path,char * const argv[],char * const envp[],pid_t pgid)134 static pid_t _spawnveg(Shell_t *shp,const char *path, char* const argv[], char* const envp[], pid_t pgid)
135 {
136 	pid_t pid;
137 	while(1)
138 	{
139 		sh_stats(STAT_SPAWN);
140 		pid = spawnveg(path,argv,envp,pgid);
141 		if(pid>=0 || errno!=EAGAIN)
142 			break;
143 	}
144 	return(pid);
145 }
146 
147 /*
148  * used with command -x to run the command in multiple passes
149  * spawn is non-zero when invoked via spawn
150  * the exitval is set to the maximum for each execution
151  */
path_xargs(Shell_t * shp,const char * path,char * argv[],char * const envp[],int spawn)152 static pid_t path_xargs(Shell_t *shp,const char *path, char *argv[],char *const envp[], int spawn)
153 {
154 	register char *cp, **av, **xv;
155 	char **avlast= &argv[shp->xargmax], **saveargs=0;
156 	char *const *ev;
157 	long size, left;
158 	int nlast=1,n,exitval=0;
159 	pid_t pid;
160 	if(shp->xargmin < 0)
161 		return((pid_t)-1);
162 	size = shp->gd->lim.arg_max-1024;
163 	for(ev=envp; cp= *ev; ev++)
164 		size -= strlen(cp)-1;
165 	for(av=argv; (cp= *av) && av< &argv[shp->xargmin]; av++)
166 		size -= strlen(cp)-1;
167 	for(av=avlast; cp= *av; av++,nlast++)
168 		size -= strlen(cp)-1;
169 	av =  &argv[shp->xargmin];
170 	if(!spawn)
171 		job_clear();
172 	shp->exitval = 0;
173 	while(av<avlast)
174 	{
175 		for(xv=av,left=size; left>0 && av<avlast;)
176 			left -= strlen(*av++)+1;
177 		/* leave at least two for last */
178 		if(left<0 && (avlast-av)<2)
179 			av--;
180 		if(xv==&argv[shp->xargmin])
181 		{
182 			n = nlast*sizeof(char*);
183 			saveargs = (char**)malloc(n);
184 			memcpy((void*)saveargs, (void*)av, n);
185 			memcpy((void*)av,(void*)avlast,n);
186 		}
187 		else
188 		{
189 			for(n=shp->xargmin; xv < av; xv++)
190 				argv[n++] = *xv;
191 			for(xv=avlast; cp=  *xv; xv++)
192 				argv[n++] = cp;
193 			argv[n] = 0;
194 		}
195 		if(saveargs || av<avlast || (exitval && !spawn))
196 		{
197 			if((pid=_spawnveg(shp,path,argv,envp,0)) < 0)
198 				return(-1);
199 			job_post(shp,pid,0);
200 			job_wait(pid);
201 			if(shp->exitval>exitval)
202 				exitval = shp->exitval;
203 			if(saveargs)
204 			{
205 				memcpy((void*)av,saveargs,n);
206 				free((void*)saveargs);
207 				saveargs = 0;
208 			}
209 		}
210 		else if(spawn && !sh_isoption(SH_PFSH))
211 		{
212 			shp->xargexit = exitval;
213 			if(saveargs)
214 				free((void*)saveargs);
215 			return(_spawnveg(shp,path,argv,envp,spawn>>1));
216 		}
217 		else
218 		{
219 			if(saveargs)
220 				free((void*)saveargs);
221 			return(path_pfexecve(shp,path,argv,envp,spawn));
222 		}
223 	}
224 	if(!spawn)
225 		exit(exitval);
226 	return((pid_t)-1);
227 }
228 
229 /*
230  * make sure PWD is set up correctly
231  * Return the present working directory
232  * Invokes getcwd() if flag==0 and if necessary
233  * Sets the PWD variable to this value
234  */
path_pwd(Shell_t * shp,int flag)235 char *path_pwd(Shell_t *shp,int flag)
236 {
237 	register char *cp;
238 	register char *dfault = (char*)e_dot;
239 	register int count = 0;
240 	if(shp->pwd)
241 		return((char*)shp->pwd);
242 	while(1)
243 	{
244 		/* try from lowest to highest */
245 		switch(count++)
246 		{
247 			case 0:
248 				cp = nv_getval(PWDNOD);
249 				break;
250 			case 1:
251 				cp = nv_getval(HOME);
252 				break;
253 			case 2:
254 				cp = "/";
255 				break;
256 			case 3:
257 				cp = (char*)e_crondir;
258 				if(flag) /* skip next case when non-zero flag */
259 					++count;
260 				break;
261 			case 4:
262 			{
263 				if(cp=getcwd(NIL(char*),0))
264 				{
265 					nv_offattr(PWDNOD,NV_NOFREE);
266 					_nv_unset(PWDNOD,0);
267 					PWDNOD->nvalue.cp = cp;
268 					goto skip;
269 				}
270 				break;
271 			}
272 			case 5:
273 				return(dfault);
274 		}
275 		if(cp && *cp=='/' && test_inode(cp,e_dot))
276 			break;
277 	}
278 	if(count>1)
279 	{
280 		nv_offattr(PWDNOD,NV_NOFREE);
281 		nv_putval(PWDNOD,cp,NV_RDONLY);
282 	}
283 skip:
284 	nv_onattr(PWDNOD,NV_NOFREE|NV_EXPORT);
285 	shp->pwd = (char*)(PWDNOD->nvalue.cp);
286 	return(cp);
287 }
288 
289 /*
290  * delete current Pathcomp_t structure
291  */
path_delete(Pathcomp_t * first)292 void  path_delete(Pathcomp_t *first)
293 {
294 	register Pathcomp_t *pp=first, *old=0, *ppnext;
295 	while(pp)
296 	{
297 		ppnext = pp->next;
298 		if(--pp->refcount<=0)
299 		{
300 			if(pp->lib)
301 				free((void*)pp->lib);
302 			if(pp->bbuf)
303 				free((void*)pp->bbuf);
304 			free((void*)pp);
305 			if(old)
306 				old->next = ppnext;
307 		}
308 		else
309 			old = pp;
310 		pp = ppnext;
311 	}
312 }
313 
314 /*
315  * returns library variable from .paths
316  * The value might be returned on the stack overwriting path
317  */
path_lib(Shell_t * shp,Pathcomp_t * pp,char * path)318 static char *path_lib(Shell_t *shp,Pathcomp_t *pp, char *path)
319 {
320 	register char *last = strrchr(path,'/');
321 	register int r;
322 	struct stat statb;
323 	if(last)
324 		*last = 0;
325 	else
326 		path = ".";
327 	r = stat(path,&statb);
328 	if(last)
329 		*last = '/';
330 	if(r>=0)
331 	{
332 		Pathcomp_t pcomp;
333 		char save[8];
334 		for( ;pp; pp=pp->next)
335 		{
336 			path_checkdup(shp,pp);
337 			if(pp->ino==statb.st_ino && pp->dev==statb.st_dev && pp->mtime==statb.st_mtime)
338 				return(pp->lib);
339 		}
340 		pcomp.len = 0;
341 		if(last)
342 			pcomp.len = last-path;
343 		memcpy((void*)save, (void*)stakptr(PATH_OFFSET+pcomp.len),sizeof(save));
344 		if(path_chkpaths(shp,(Pathcomp_t*)0,(Pathcomp_t*)0,&pcomp,PATH_OFFSET))
345 			return(stakfreeze(1));
346 		memcpy((void*)stakptr(PATH_OFFSET+pcomp.len),(void*)save,sizeof(save));
347 	}
348 	return(0);
349 }
350 
351 #if 0
352 void path_dump(register Pathcomp_t *pp)
353 {
354 	sfprintf(sfstderr,"dump\n");
355 	while(pp)
356 	{
357 		sfprintf(sfstderr,"pp=%x dev=%d ino=%d len=%d flags=%o name=%.*s\n",
358 			pp,pp->dev,pp->ino,pp->len,pp->flags,pp->len,pp->name);
359 		pp = pp->next;
360 	}
361 }
362 #endif
363 
364 /*
365  * check for duplicate directories on PATH
366  */
path_checkdup(Shell_t * shp,register Pathcomp_t * pp)367 static void path_checkdup(Shell_t *shp,register Pathcomp_t *pp)
368 {
369 	register char		*name = pp->name;
370 	register Pathcomp_t	*oldpp,*first;
371 	register int		flag=0;
372 	struct stat 		statb;
373 	if(stat(name,&statb)<0 || !S_ISDIR(statb.st_mode))
374 	{
375 		pp->flags |= PATH_SKIP;
376 		pp->dev = *name=='/';
377 		return;
378 	}
379 	pp->mtime = statb.st_mtime;
380 	pp->ino = statb.st_ino;
381 	pp->dev = statb.st_dev;
382 	if(*name=='/' && onstdpath(name))
383 		flag = PATH_STD_DIR;
384 	first = (pp->flags&PATH_CDPATH)?(Pathcomp_t*)shp->cdpathlist:path_get(shp,"");
385 	for(oldpp=first; oldpp && oldpp!=pp; oldpp=oldpp->next)
386 	{
387 		if(pp->ino==oldpp->ino && pp->dev==oldpp->dev && pp->mtime==oldpp->mtime)
388 		{
389 			flag |= PATH_SKIP;
390 			break;
391 		}
392 	}
393 	pp->flags |= flag;
394 	if(((pp->flags&(PATH_PATH|PATH_SKIP))==PATH_PATH))
395 	{
396 		int offset = staktell();
397 		stakputs(name);
398 		path_chkpaths(shp,first,0,pp,offset);
399 		stakseek(offset);
400 	}
401 }
402 
403 /*
404  * write the next path to search on the current stack
405  * if last is given, all paths that come before <last> are skipped
406  * the next pathcomp is returned.
407  */
path_nextcomp(Shell_t * shp,register Pathcomp_t * pp,const char * name,Pathcomp_t * last)408 Pathcomp_t *path_nextcomp(Shell_t *shp,register Pathcomp_t *pp, const char *name, Pathcomp_t *last)
409 {
410 	Pathcomp_t	*ppnext;
411 	stakseek(PATH_OFFSET);
412 	if(*name=='/')
413 		pp = 0;
414 	else
415 	{
416 		for(;pp && pp!=last;pp=ppnext)
417 		{
418 			ppnext = pp->next;
419 			if(!pp->dev && !pp->ino)
420 				path_checkdup(shp,pp);
421 			if(pp->flags&PATH_SKIP)
422 				return(ppnext);
423 			if(!last || *pp->name!='/')
424 				break;
425 		}
426 		if(!pp)		/* this should not happen */
427 			pp = last;
428 	}
429 	if(pp && (pp->name[0]!='.' || pp->name[1]))
430 	{
431 		if(*pp->name!='/')
432 		{
433 			stakputs(path_pwd(shp,1));
434 			if(*stakptr(staktell()-1)!='/')
435 				stakputc('/');
436 		}
437 		stakwrite(pp->name,pp->len);
438 		if(pp->name[pp->len-1]!='/')
439 			stakputc('/');
440 	}
441 	stakputs(name);
442 	stakputc(0);
443 	while(pp && pp!=last && (pp=pp->next))
444 	{
445 		if(!(pp->flags&PATH_SKIP))
446 			return(pp);
447 	}
448 	return((Pathcomp_t*)0);
449 }
450 
defpath_init(Shell_t * shp)451 static Pathcomp_t* defpath_init(Shell_t *shp)
452 {
453 	Pathcomp_t *pp = (void*)path_addpath(shp,(Pathcomp_t*)0,(std_path),PATH_PATH);
454 	return(pp);
455 }
456 
path_init(Shell_t * shp)457 static void path_init(Shell_t *shp)
458 {
459 	const char *val;
460 	Pathcomp_t *pp;
461 	if(!std_path && !(std_path=astconf("PATH",NIL(char*),NIL(char*))))
462 		std_path = e_defpath;
463 	if(val=sh_scoped(shp,(PATHNOD))->nvalue.cp)
464 	{
465 		shp->pathlist = pp = (void*)path_addpath(shp,(Pathcomp_t*)shp->pathlist,val,PATH_PATH);
466 	}
467 	else
468 	{
469 		if(!(pp=(Pathcomp_t*)shp->defpathlist))
470 			pp = defpath_init(shp);
471 		shp->pathlist = (void*)path_dup(pp);
472 	}
473 	if(val=sh_scoped(shp,(FPATHNOD))->nvalue.cp)
474 	{
475 		pp = (void*)path_addpath(shp,(Pathcomp_t*)shp->pathlist,val,PATH_FPATH);
476 	}
477 }
478 
479 /*
480  * returns that pathlist to search
481  */
path_get(register Shell_t * shp,register const char * name)482 Pathcomp_t *path_get(register Shell_t *shp,register const char *name)
483 {
484 	register Pathcomp_t *pp=0;
485 	if(*name && strchr(name,'/'))
486 		return(0);
487 	if(!sh_isstate(SH_DEFPATH))
488 	{
489 		if(!shp->pathlist)
490 			path_init(shp);
491 		pp = (Pathcomp_t*)shp->pathlist;
492 	}
493 	if(!pp && (!(sh_scoped(shp,PATHNOD)->nvalue.cp)) || sh_isstate(SH_DEFPATH))
494 	{
495 		if(!(pp=(Pathcomp_t*)shp->defpathlist))
496 			pp = defpath_init(shp);
497 	}
498 	return(pp);
499 }
500 
501 /*
502  * open file corresponding to name using path give by <pp>
503  */
path_opentype(Shell_t * shp,const char * name,register Pathcomp_t * pp,int fun)504 static int	path_opentype(Shell_t *shp,const char *name, register Pathcomp_t *pp, int fun)
505 {
506 	register int fd= -1;
507 	struct stat statb;
508 	Pathcomp_t *oldpp;
509 	if(!pp && !shp->pathlist)
510 		path_init(shp);
511 	if(!fun && strchr(name,'/'))
512 	{
513 		if(sh_isoption(SH_RESTRICTED))
514 			errormsg(SH_DICT,ERROR_exit(1),e_restricted,name);
515 	}
516 	do
517 	{
518 		pp = path_nextcomp(shp,oldpp=pp,name,0);
519 		while(oldpp && (oldpp->flags&PATH_SKIP))
520 			oldpp = oldpp->next;
521 		if(fun && (!oldpp || !(oldpp->flags&PATH_FPATH)))
522 			continue;
523 		if((fd = sh_open(path_relative(shp,stakptr(PATH_OFFSET)),O_RDONLY,0)) >= 0)
524 		{
525 			if(fstat(fd,&statb)<0 || S_ISDIR(statb.st_mode))
526 			{
527 				errno = EISDIR;
528 				sh_close(fd);
529 				fd = -1;
530 			}
531 		}
532 	}
533 	while( fd<0 && pp);
534 	if(fd>=0 && (fd = sh_iomovefd(fd)) > 0)
535 	{
536 		fcntl(fd,F_SETFD,FD_CLOEXEC);
537 		shp->fdstatus[fd] |= IOCLEX;
538 	}
539 	return(fd);
540 }
541 
542 /*
543  * open file corresponding to name using path give by <pp>
544  */
path_open(Shell_t * shp,const char * name,register Pathcomp_t * pp)545 int	path_open(Shell_t *shp,const char *name, register Pathcomp_t *pp)
546 {
547 	return(path_opentype(shp,name,pp,0));
548 }
549 
550 /*
551  * given a pathname return the base name
552  */
553 
path_basename(register const char * name)554 char	*path_basename(register const char *name)
555 {
556 	register const char *start = name;
557 	while (*name)
558 		if ((*name++ == '/') && *name)	/* don't trim trailing / */
559 			start = name;
560 	return ((char*)start);
561 }
562 
path_fullname(Shell_t * shp,const char * name)563 char *path_fullname(Shell_t *shp,const char *name)
564 {
565 	int len=strlen(name)+1,dirlen=0;
566 	char *path,*pwd;
567 	if(*name!='/')
568 	{
569 		pwd = path_pwd(shp,1);
570 		dirlen = strlen(pwd)+1;
571 	}
572 	path = (char*)malloc(len+dirlen);
573 	if(dirlen)
574 	{
575 		memcpy((void*)path,(void*)pwd,dirlen);
576 		path[dirlen-1] = '/';
577 	}
578 	memcpy((void*)&path[dirlen],(void*)name,len);
579 	pathcanon(path,0);
580 	return(path);
581 }
582 
583 /*
584  * load functions from file <fno>
585  */
funload(Shell_t * shp,int fno,const char * name)586 static void funload(Shell_t *shp,int fno, const char *name)
587 {
588 	char		*pname,*oldname=shp->st.filename, buff[IOBSIZE+1];
589 	Namval_t	*np;
590 	struct Ufunction *rp,*rpfirst;
591 	int		 savestates = sh_getstate(), oldload=shp->funload;
592 	pname = path_fullname(shp,stakptr(PATH_OFFSET));
593 	if(shp->fpathdict && (rp = dtmatch(shp->fpathdict,(void*)pname)))
594 	{
595 		Dt_t	*funtree = sh_subfuntree(1);
596 		while(1)
597 		{
598 			rpfirst = dtprev(shp->fpathdict,rp);
599 			if(!rpfirst || strcmp(pname,rpfirst->fname))
600 				break;
601 			rp = rpfirst;
602 		}
603 		do
604 		{
605 			if((np = dtsearch(funtree,rp->np)) && is_afunction(np))
606 			{
607 				if(np->nvalue.rp)
608 					np->nvalue.rp->fdict = 0;
609 				nv_delete(np,funtree,NV_NOFREE);
610 			}
611 			dtinsert(funtree,rp->np);
612 			rp->fdict = funtree;
613 		}
614 		while((rp=dtnext(shp->fpathdict,rp)) && strcmp(pname,rp->fname)==0);
615 		sh_close(fno);
616 		return;
617 	}
618 	sh_onstate(SH_NOLOG);
619 	sh_onstate(SH_NOALIAS);
620 	shp->readscript = (char*)name;
621 	shp->st.filename = pname;
622 	shp->funload = 1;
623 	error_info.line = 0;
624 	sh_eval(sfnew(NIL(Sfio_t*),buff,IOBSIZE,fno,SF_READ),SH_FUNEVAL);
625 	sh_close(fno);
626 	shp->readscript = 0;
627 #if SHOPT_NAMESPACE
628 	if(shp->namespace)
629 		np = sh_fsearch(shp,name,0);
630 	else
631 #endif /* SHOPT_NAMESPACE */
632 		np = nv_search(name,shp->fun_tree,0);
633 	if(!np || !np->nvalue.ip)
634 		pname = stakcopy(shp->st.filename);
635 	else
636 		pname = 0;
637 	free((void*)shp->st.filename);
638 	shp->funload = oldload;
639 	shp->st.filename = oldname;
640 	sh_setstate(savestates);
641 	if(pname)
642 		errormsg(SH_DICT,ERROR_exit(ERROR_NOEXEC),e_funload,name,pname);
643 }
644 
645 /*
646  * do a path search and track alias if requested
647  * if flag is 0, or if name not found, then try autoloading function
648  * if flag==2 or 3, returns 1 if name found on FPATH
649  * if flag==3 no tracked alias will be set
650  * returns 1, if function was autoloaded.
651  * If oldpp is not NULL, it will contain a pointer to the path component
652  *    where it was found.
653  */
654 
path_search(Shell_t * shp,register const char * name,Pathcomp_t ** oldpp,int flag)655 int	path_search(Shell_t *shp,register const char *name,Pathcomp_t **oldpp, int flag)
656 {
657 	register Namval_t *np;
658 	register int fno;
659 	Pathcomp_t *pp=0;
660 	if(name && strchr(name,'/'))
661 	{
662 		stakseek(PATH_OFFSET);
663 		stakputs(name);
664 		if(canexecute(shp,stakptr(PATH_OFFSET),0)<0)
665 		{
666 			*stakptr(PATH_OFFSET) = 0;
667 			return(0);
668 		}
669 		if(*name=='/')
670 			return(1);
671 		stakseek(PATH_OFFSET);
672 		stakputs(path_pwd(shp,1));
673 		stakputc('/');
674 		stakputs(name);
675 		stakputc(0);
676 		return(0);
677 	}
678 	if(sh_isstate(SH_DEFPATH))
679 	{
680 		if(!shp->defpathlist)
681 			defpath_init(shp);
682 	}
683 	else if(!shp->pathlist)
684 		path_init(shp);
685 	if(flag)
686 	{
687 		if(!(flag&1) && (np=nv_search(name,shp->track_tree,0)) && !nv_isattr(np,NV_NOALIAS) && (pp=(Pathcomp_t*)np->nvalue.cp))
688 		{
689 			stakseek(PATH_OFFSET);
690 			path_nextcomp(shp,pp,name,pp);
691 			if(oldpp)
692 				*oldpp = pp;
693 			stakputc(0);
694 			return(0);
695 		}
696 		pp = path_absolute(shp,name,oldpp?*oldpp:NIL(Pathcomp_t*));
697 		if(oldpp)
698 			*oldpp = pp;
699 		if(!pp && (np=nv_search(name,shp->fun_tree,0))&&np->nvalue.ip)
700 			return(1);
701 		if(!pp)
702 			*stakptr(PATH_OFFSET) = 0;
703 	}
704 	if(flag==0 || !pp || (pp->flags&PATH_FPATH))
705 	{
706 		if(!pp)
707 			pp=sh_isstate(SH_DEFPATH)?shp->defpathlist:shp->pathlist;
708 		if(pp && strmatch(name,e_alphanum)  && (fno=path_opentype(shp,name,pp,1))>=0)
709 		{
710 			if(flag==2)
711 			{
712 				sh_close(fno);
713 				return(1);
714 			}
715 			funload(shp,fno,name);
716 			return(1);
717 		}
718 		*stakptr(PATH_OFFSET) = 0;
719 		return(0);
720 	}
721 	else if(pp && !sh_isstate(SH_DEFPATH) && *name!='/' && flag<3)
722 	{
723 		if(np=nv_search(name,shp->track_tree,NV_ADD))
724 			path_alias(np,pp);
725 	}
726 	return(0);
727 }
728 
729 /*
730  * do a path search and find the full pathname of file name
731  */
path_absolute(Shell_t * shp,register const char * name,Pathcomp_t * pp)732 Pathcomp_t *path_absolute(Shell_t *shp,register const char *name, Pathcomp_t *pp)
733 {
734 	register int	f,isfun;
735 	int		noexec=0;
736 	Pathcomp_t	*oldpp;
737 	Namval_t	*np;
738 	char		*cp;
739 	char		*bp;
740 	shp->path_err = ENOENT;
741 	if(!pp && !(pp=path_get(shp,"")))
742 		return(0);
743 	shp->path_err = 0;
744 	while(1)
745 	{
746 		sh_sigcheck(shp);
747 		shp->bltin_dir = 0;
748 		while(oldpp=pp)
749 		{
750 			pp = path_nextcomp(shp,pp,name,0);
751 			if(!(oldpp->flags&PATH_SKIP))
752 				break;
753 		}
754 		if(!oldpp)
755 		{
756 			shp->path_err = ENOENT;
757 			return(0);
758 		}
759 		isfun = (oldpp->flags&PATH_FPATH);
760 		if(!isfun && !sh_isoption(SH_RESTRICTED))
761 		{
762 #if SHOPT_DYNAMIC
763 			Shbltin_f addr;
764 			int n;
765 #endif
766 			if(*stakptr(PATH_OFFSET)=='/' && nv_search(stakptr(PATH_OFFSET),shp->bltin_tree,0))
767 				return(oldpp);
768 #if SHOPT_DYNAMIC
769 			n = staktell();
770 			stakputs("b_");
771 			stakputs(name);
772 			stakputc(0);
773 			if((addr = sh_getlib(shp, stakptr(n), oldpp)) &&
774 			   (np = sh_addbuiltin(stakptr(PATH_OFFSET),addr,NiL)) &&
775 			   nv_isattr(np,NV_BLTINOPT))
776 			{
777 				shp->bltin_dir = 0;
778 				return(oldpp);
779 			}
780 			stakseek(n);
781 			while(bp = oldpp->blib)
782 			{
783 				char *fp;
784 				void *dll;
785 				int m;
786 				if(fp = strchr(bp, ':'))
787 				{
788 					*fp++ = 0;
789 					oldpp->blib = fp;
790 					fp = 0;
791 				}
792 				else
793 				{
794 					fp = oldpp->bbuf;
795 					oldpp->blib = oldpp->bbuf = 0;
796 				}
797 				n = staktell();
798 				stakputs("b_");
799 				stakputs(name);
800 				stakputc(0);
801 				m = staktell();
802 				shp->bltin_dir = oldpp->name;
803 				if(*bp!='/')
804 				{
805 					stakputs(oldpp->name);
806 					stakputc('/');
807 				}
808 				stakputs(bp);
809 				stakputc(0);
810 				if(cp = strrchr(stakptr(m),'/'))
811 					cp++;
812 				else
813 					cp = stakptr(m);
814 				if(!strcmp(cp,LIBCMD) &&
815 				   (addr=(Shbltin_f)dlllook((void*)0,stakptr(n))) &&
816 				   (np = sh_addbuiltin(stakptr(PATH_OFFSET),addr,NiL)) &&
817 				   nv_isattr(np,NV_BLTINOPT))
818 				{
819 				found:
820 					if(fp)
821 						free(fp);
822 					shp->bltin_dir = 0;
823 					return(oldpp);
824 				}
825 #ifdef SH_PLUGIN_VERSION
826 				if (dll = dllplugin(SH_ID, stakptr(m), NiL, SH_PLUGIN_VERSION, NiL, RTLD_LAZY, NiL, 0))
827 					sh_addlib(shp,dll,stakptr(m),oldpp);
828 #else
829 #if (_AST_VERSION>=20040404)
830 				if (dll = dllplug(SH_ID, stakptr(m), NiL, RTLD_LAZY, NiL, 0))
831 #else
832 				if (dll = dllfind(stakptr(m), NiL, RTLD_LAZY, NiL, 0))
833 #endif
834 				{
835 					/*
836 					 * this detects the 2007-05-11 builtin context change and also
837 					 * the 2008-03-30 opt_info.num change that hit libcmd::b_head
838 					 */
839 
840 					if (libcmd && !dlllook(dll, "b_pids"))
841 					{
842 						dlclose(dll);
843 						dll = 0;
844 					}
845 					else
846 						sh_addlib(shp,dll,stakptr(m),oldpp);
847 				}
848 #endif
849 				if(dll &&
850 				   (addr=(Shbltin_f)dlllook(dll,stakptr(n))) &&
851 				   (!(np = sh_addbuiltin(stakptr(PATH_OFFSET),NiL,NiL)) || np->nvalue.bfp!=(Nambfp_f)addr) &&
852 				   (np = sh_addbuiltin(stakptr(PATH_OFFSET),addr,NiL)))
853 				{
854 					np->nvenv = dll;
855 					goto found;
856 				}
857 				if(*stakptr(PATH_OFFSET)=='/' && nv_search(stakptr(PATH_OFFSET),shp->bltin_tree,0))
858 					goto found;
859 				if(fp)
860 					free(fp);
861 				stakseek(n);
862 			}
863 #endif /* SHOPT_DYNAMIC */
864 		}
865 		shp->bltin_dir = 0;
866 		sh_stats(STAT_PATHS);
867 		f = canexecute(shp,stakptr(PATH_OFFSET),isfun);
868 		if(isfun && f>=0 && (cp = strrchr(name,'.')))
869 		{
870 			*cp = 0;
871 			if(nv_open(name,sh_subfuntree(1),NV_NOARRAY|NV_IDENT|NV_NOSCOPE))
872 				f = -1;
873 			*cp = '.';
874 		}
875 		if(isfun && f>=0)
876 		{
877 			nv_onattr(nv_open(name,sh_subfuntree(1),NV_NOARRAY|NV_IDENT|NV_NOSCOPE),NV_LTOU|NV_FUNCTION);
878 			funload(shp,f,name);
879 			close(f);
880 			f = -1;
881 			return(0);
882 		}
883 		else if(f>=0 && (oldpp->flags & PATH_STD_DIR))
884 		{
885 			int n = staktell();
886 			stakputs("/bin/");
887 			stakputs(name);
888 			stakputc(0);
889 			np = nv_search(stakptr(n),shp->bltin_tree,0);
890 			stakseek(n);
891 			if(np)
892 			{
893 				n = np->nvflag;
894 				np = sh_addbuiltin(stakptr(PATH_OFFSET),(Shbltin_f)np->nvalue.bfp,nv_context(np));
895 				np->nvflag = n;
896 			}
897 		}
898 		if(!pp || f>=0)
899 			break;
900 		if(errno!=ENOENT)
901 			noexec = errno;
902 	}
903 	if(f<0)
904 	{
905 		shp->path_err = (noexec?noexec:ENOENT);
906 		return(0);
907 	}
908 	stakputc(0);
909 	return(oldpp);
910 }
911 
912 /*
913  * returns 0 if path can execute
914  * sets exec_err if file is found but can't be executable
915  */
916 #undef S_IXALL
917 #ifdef S_IXUSR
918 #   define S_IXALL	(S_IXUSR|S_IXGRP|S_IXOTH)
919 #else
920 #   ifdef S_IEXEC
921 #	define S_IXALL	(S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6))
922 #   else
923 #	define S_IXALL	0111
924 #   endif /*S_EXEC */
925 #endif /* S_IXUSR */
926 
canexecute(Shell_t * shp,register char * path,int isfun)927 static int canexecute(Shell_t *shp,register char *path, int isfun)
928 {
929 	struct stat statb;
930 	register int fd=0;
931 	path = path_relative(shp,path);
932 	if(isfun)
933 	{
934 		if((fd=open(path,O_RDONLY,0))<0 || fstat(fd,&statb)<0)
935 			goto err;
936 	}
937 	else if(stat(path,&statb) < 0)
938 	{
939 #if _WINIX
940 		/* check for .exe or .bat suffix */
941 		char *cp;
942 		if(errno==ENOENT && (!(cp=strrchr(path,'.')) || strlen(cp)>4 || strchr(cp,'/')))
943 		{
944 			int offset = staktell()-1;
945 			stakseek(offset);
946 			stakputs(".bat");
947 			path = stakptr(PATH_OFFSET);
948 			if(stat(path,&statb) < 0)
949 			{
950 				if(errno!=ENOENT)
951 					goto err;
952 				memcpy(stakptr(offset),".sh",4);
953 				if(stat(path,&statb) < 0)
954 					goto err;
955 			}
956 		}
957 		else
958 #endif /* _WINIX */
959 		goto err;
960 	}
961 	errno = EPERM;
962 	if(S_ISDIR(statb.st_mode))
963 		errno = EISDIR;
964 	else if((statb.st_mode&S_IXALL)==S_IXALL || sh_access(path,X_OK)>=0)
965 		return(fd);
966 	if(isfun && fd>=0)
967 		sh_close(fd);
968 err:
969 	return(-1);
970 }
971 
972 /*
973  * Return path relative to present working directory
974  */
975 
path_relative(Shell_t * shp,register const char * file)976 char *path_relative(Shell_t *shp,register const char* file)
977 {
978 	register const char *pwd;
979 	register const char *fp = file;
980 	/* can't relpath when shp->pwd not set */
981 	if(!(pwd=shp->pwd))
982 		return((char*)fp);
983 	while(*pwd==*fp)
984 	{
985 		if(*pwd++==0)
986 			return((char*)e_dot);
987 		fp++;
988 	}
989 	if(*pwd==0 && *fp == '/')
990 	{
991 		while(*++fp=='/');
992 		if(*fp)
993 			return((char*)fp);
994 		return((char*)e_dot);
995 	}
996 	return((char*)file);
997 }
998 
path_exec(Shell_t * shp,register const char * arg0,register char * argv[],struct argnod * local)999 void	path_exec(Shell_t *shp,register const char *arg0,register char *argv[],struct argnod *local)
1000 {
1001 	char **envp;
1002 	const char *opath;
1003 	Pathcomp_t *libpath, *pp=0;
1004 	int slash=0;
1005 	nv_setlist(local,NV_EXPORT|NV_IDENT|NV_ASSIGN,0);
1006 	envp = sh_envgen();
1007 	if(strchr(arg0,'/'))
1008 	{
1009 		slash=1;
1010 		/* name containing / not allowed for restricted shell */
1011 		if(sh_isoption(SH_RESTRICTED))
1012 			errormsg(SH_DICT,ERROR_exit(1),e_restricted,arg0);
1013 	}
1014 	else
1015 		pp=path_get(shp,arg0);
1016 	shp->path_err= ENOENT;
1017 	sfsync(NIL(Sfio_t*));
1018 	timerdel(NIL(void*));
1019 	/* find first path that has a library component */
1020 	while(pp && (pp->flags&PATH_SKIP))
1021 		pp = pp->next;
1022 	if(pp || slash) do
1023 	{
1024 		sh_sigcheck(shp);
1025 		if(libpath=pp)
1026 		{
1027 			pp = path_nextcomp(shp,pp,arg0,0);
1028 			opath = stakfreeze(1)+PATH_OFFSET;
1029 		}
1030 		else
1031 			opath = arg0;
1032 		path_spawn(shp,opath,argv,envp,libpath,0);
1033 		while(pp && (pp->flags&PATH_FPATH))
1034 			pp = path_nextcomp(shp,pp,arg0,0);
1035 	}
1036 	while(pp);
1037 	/* force an exit */
1038 	((struct checkpt*)shp->jmplist)->mode = SH_JMPEXIT;
1039 	if((errno=shp->path_err)==ENOENT)
1040 		errormsg(SH_DICT,ERROR_exit(ERROR_NOENT),e_found,arg0);
1041 	else
1042 		errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,arg0);
1043 }
1044 
path_spawn(Shell_t * shp,const char * opath,register char ** argv,char ** envp,Pathcomp_t * libpath,int spawn)1045 pid_t path_spawn(Shell_t *shp,const char *opath,register char **argv, char **envp, Pathcomp_t *libpath, int spawn)
1046 {
1047 	register char *path;
1048 	char **xp=0, *xval, *libenv = (libpath?libpath->lib:0);
1049 	Namval_t*	np;
1050 	char		*s, *v;
1051 	int		r, n, pidsize;
1052 	pid_t		pid= -1;
1053 	/* leave room for inserting _= pathname in environment */
1054 	envp--;
1055 #if _lib_readlink
1056 	/* save original pathname */
1057 	stakseek(PATH_OFFSET);
1058 	pidsize = sfprintf(stkstd,"*%d*",spawn?getpid():getppid());
1059 	stakputs(opath);
1060 	opath = stakfreeze(1)+PATH_OFFSET+pidsize;
1061 	np=nv_search(argv[0],shp->track_tree,0);
1062 	while(libpath && !libpath->lib)
1063 		libpath=libpath->next;
1064 	if(libpath && (!np || nv_size(np)>0))
1065 	{
1066 		/* check for symlink and use symlink name */
1067 		char buff[PATH_MAX+1];
1068 		char save[PATH_MAX+1];
1069 		stakseek(PATH_OFFSET);
1070 		stakputs(opath);
1071 		path = stakptr(PATH_OFFSET);
1072 		while((n=readlink(path,buff,PATH_MAX))>0)
1073 		{
1074 			buff[n] = 0;
1075 			n = PATH_OFFSET;
1076 			r = 0;
1077 			if((v=strrchr(path,'/')) && *buff!='/')
1078 			{
1079 				if(buff[0]=='.' && buff[1]=='.' && (r = strlen(path) + 1) <= PATH_MAX)
1080 					memcpy(save, path, r);
1081 				else
1082 					r = 0;
1083 				n += (v+1-path);
1084 			}
1085 			stakseek(n);
1086 			stakputs(buff);
1087 			stakputc(0);
1088 			path = stakptr(PATH_OFFSET);
1089 			if(v && buff[0]=='.' && buff[1]=='.')
1090 			{
1091 				pathcanon(path, 0);
1092 				if(r && access(path,X_OK))
1093 				{
1094 					memcpy(path, save, r);
1095 					break;
1096 				}
1097 			}
1098 			if(libenv = path_lib(shp,libpath,path))
1099 				break;
1100 		}
1101 		stakseek(0);
1102 	}
1103 #endif
1104 	if(libenv && (v = strchr(libenv,'=')))
1105 	{
1106 		n = v - libenv;
1107 		*v = 0;
1108 		np = nv_open(libenv,shp->var_tree,0);
1109 		*v = '=';
1110 		s = nv_getval(np);
1111 		stakputs(libenv);
1112 		if(s)
1113 		{
1114 			stakputc(':');
1115 			stakputs(s);
1116 		}
1117 		v = stakfreeze(1);
1118 		r = 1;
1119 		xp = envp + 1;
1120 		while (s = *xp++)
1121 		{
1122 			if (strneq(s, v, n) && s[n] == '=')
1123 			{
1124 				xval = *--xp;
1125 				*xp = v;
1126 				r = 0;
1127 				break;
1128 			}
1129 		}
1130 		if (r)
1131 		{
1132 			*envp-- = v;
1133 			xp = 0;
1134 		}
1135 	}
1136 	if(!opath)
1137 		opath = stakptr(PATH_OFFSET);
1138 	envp[0] =  (char*)opath-(PATH_OFFSET+pidsize);
1139 	envp[0][0] =  '_';
1140 	envp[0][1] =  '=';
1141 	sfsync(sfstderr);
1142 	sh_sigcheck(shp);
1143 	path = path_relative(shp,opath);
1144 #ifdef SHELLMAGIC
1145 	if(*path!='/' && path!=opath)
1146 	{
1147 		/*
1148 		 * The following code because execv(foo,) and execv(./foo,)
1149 		 * may not yield the same results
1150 		 */
1151 		char *sp = (char*)malloc(strlen(path)+3);
1152 		sp[0] = '.';
1153 		sp[1] = '/';
1154 		strcpy(sp+2,path);
1155 		path = sp;
1156 	}
1157 #endif /* SHELLMAGIC */
1158 	if(spawn && !sh_isoption(SH_PFSH))
1159 		pid = _spawnveg(shp,opath, &argv[0],envp, spawn>>1);
1160 	else
1161 		pid = path_pfexecve(shp,opath, &argv[0] ,envp,spawn);
1162 	if(xp)
1163 		*xp = xval;
1164 #ifdef SHELLMAGIC
1165 	if(*path=='.' && path!=opath)
1166 	{
1167 		free(path);
1168 		path = path_relative(shp,opath);
1169 	}
1170 #endif /* SHELLMAGIC */
1171 	if(pid>0)
1172 		return(pid);
1173 retry:
1174 	switch(shp->path_err = errno)
1175 	{
1176 #ifdef apollo
1177 	    /*
1178   	     * On apollo's execve will fail with eacces when
1179 	     * file has execute but not read permissions. So,
1180 	     * for now we will pretend that EACCES and ENOEXEC
1181  	     * mean the same thing.
1182  	     */
1183 	    case EACCES:
1184 #endif /* apollo */
1185 	    case ENOEXEC:
1186 #if SHOPT_SUID_EXEC
1187 	    case EPERM:
1188 		/* some systems return EPERM if setuid bit is on */
1189 #endif
1190 		errno = ENOEXEC;
1191 		if(spawn)
1192 		{
1193 #ifdef _lib_fork
1194 			if(shp->subshell)
1195 				return(-1);
1196 			do
1197 			{
1198 				if((pid=fork())>0)
1199 					return(pid);
1200 			}
1201 			while(_sh_fork(shp,pid,0,(int*)0) < 0);
1202 			((struct checkpt*)shp->jmplist)->mode = SH_JMPEXIT;
1203 #else
1204 			return(-1);
1205 #endif
1206 		}
1207 		exscript(shp,path,argv,envp);
1208 #ifndef apollo
1209 	    case EACCES:
1210 	    {
1211 		struct stat statb;
1212 		if(stat(path,&statb)>=0)
1213 		{
1214 			if(S_ISDIR(statb.st_mode))
1215 				errno = EISDIR;
1216 #ifdef S_ISSOCK
1217 			if(S_ISSOCK(statb.st_mode))
1218 				exscript(shp,path,argv,envp);
1219 #endif
1220 		}
1221 	    }
1222 		/* FALL THROUGH */
1223 #endif /* !apollo */
1224 #ifdef ENAMETOOLONG
1225 	    case ENAMETOOLONG:
1226 #endif /* ENAMETOOLONG */
1227 #if !SHOPT_SUID_EXEC
1228 	    case EPERM:
1229 #endif
1230 		shp->path_err = errno;
1231 		return(-1);
1232 	    case ENOTDIR:
1233 	    case ENOENT:
1234 	    case EINTR:
1235 #ifdef EMLINK
1236 	    case EMLINK:
1237 #endif /* EMLINK */
1238 		return(-1);
1239 	    case E2BIG:
1240 		if(shp->xargmin)
1241 		{
1242 			pid = path_xargs(shp,opath, &argv[0] ,envp,spawn);
1243 			if(pid<0)
1244 				goto retry;
1245 			return(pid);
1246 		}
1247 	    default:
1248 		errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,path);
1249 	}
1250 	return 0;
1251 }
1252 
1253 /*
1254  * File is executable but not machine code.
1255  * Assume file is a Shell script and execute it.
1256  */
1257 
exscript(Shell_t * shp,register char * path,register char * argv[],char ** envp)1258 static void exscript(Shell_t *shp,register char *path,register char *argv[],char **envp)
1259 {
1260 	register Sfio_t *sp;
1261 	path = path_relative(shp,path);
1262 	shp->comdiv=0;
1263 	shp->bckpid = 0;
1264 	shp->coshell = 0;
1265 	shp->st.ioset=0;
1266 	/* clean up any cooperating processes */
1267 	if(shp->cpipe[0]>0)
1268 		sh_pclose(shp->cpipe);
1269 	if(shp->cpid && shp->outpipe)
1270 		sh_close(*shp->outpipe);
1271 	shp->cpid = 0;
1272 	if(sp=fcfile())
1273 		while(sfstack(sp,SF_POPSTACK));
1274 	job_clear();
1275 	if(shp->infd>0 && (shp->fdstatus[shp->infd]&IOCLEX))
1276 		sh_close(shp->infd);
1277 	sh_setstate(sh_state(SH_FORKED));
1278 	sfsync(sfstderr);
1279 #if SHOPT_SUID_EXEC && !SHOPT_PFSH
1280 	/* check if file cannot open for read or script is setuid/setgid  */
1281 	{
1282 		static char name[] = "/tmp/euidXXXXXXXXXX";
1283 		register int n;
1284 		register uid_t euserid;
1285 		char *savet=0;
1286 		struct stat statb;
1287 		if((n=sh_open(path,O_RDONLY,0)) >= 0)
1288 		{
1289 			/* move <n> if n=0,1,2 */
1290 			n = sh_iomovefd(n);
1291 			if(fstat(n,&statb)>=0 && !(statb.st_mode&(S_ISUID|S_ISGID)))
1292 				goto openok;
1293 			sh_close(n);
1294 		}
1295 		if((euserid=geteuid()) != shp->gd->userid)
1296 		{
1297 			strncpy(name+9,fmtbase((long)getpid(),10,0),sizeof(name)-10);
1298 			/* create a suid open file with owner equal effective uid */
1299 			if((n=open(name,O_CREAT|O_TRUNC|O_WRONLY,S_ISUID|S_IXUSR)) < 0)
1300 				goto fail;
1301 			unlink(name);
1302 			/* make sure that file has right owner */
1303 			if(fstat(n,&statb)<0 || statb.st_uid != euserid)
1304 				goto fail;
1305 			if(n!=10)
1306 			{
1307 				sh_close(10);
1308 				fcntl(n, F_DUPFD, 10);
1309 				sh_close(n);
1310 				n=10;
1311 			}
1312 		}
1313 		savet = *--argv;
1314 		*argv = path;
1315 		path_pfexecve(shp,e_suidexec,argv,envp,0);
1316 	fail:
1317 		/*
1318 		 *  The following code is just for compatibility
1319 		 */
1320 		if((n=open(path,O_RDONLY,0)) < 0)
1321 			errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,path);
1322 		if(savet)
1323 			*argv++ = savet;
1324 	openok:
1325 		shp->infd = n;
1326 	}
1327 #else
1328 	if((shp->infd = sh_open(path,O_RDONLY,0)) < 0)
1329 		errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,path);
1330 #endif
1331 	shp->infd = sh_iomovefd(shp->infd);
1332 #if SHOPT_ACCT
1333 	sh_accbegin(path) ;  /* reset accounting */
1334 #endif	/* SHOPT_ACCT */
1335 	shp->arglist = sh_argcreate(argv);
1336 	shp->lastarg = strdup(path);
1337 	/* save name of calling command */
1338 	shp->readscript = error_info.id;
1339 	/* close history file if name has changed */
1340 	if(shp->gd->hist_ptr && (path=nv_getval(HISTFILE)) && strcmp(path,shp->gd->hist_ptr->histname))
1341 	{
1342 		hist_close(shp->gd->hist_ptr);
1343 		(HISTCUR)->nvalue.lp = 0;
1344 	}
1345 	sh_offstate(SH_FORKED);
1346 	if(shp->sigflag[SIGCHLD]==SH_SIGOFF)
1347 		shp->sigflag[SIGCHLD] = SH_SIGFAULT;
1348 	siglongjmp(*shp->jmplist,SH_JMPSCRIPT);
1349 }
1350 
1351 #if SHOPT_ACCT
1352 #   include <sys/acct.h>
1353 #   include "FEATURE/time"
1354 
1355     static struct acct sabuf;
1356     static struct tms buffer;
1357     static clock_t	before;
1358     static char *SHACCT; /* set to value of SHACCT environment variable */
1359     static shaccton;	/* non-zero causes accounting record to be written */
1360     static int compress(time_t);
1361     /*
1362      *	initialize accounting, i.e., see if SHACCT variable set
1363      */
sh_accinit(void)1364     void sh_accinit(void)
1365     {
1366 	SHACCT = getenv("SHACCT");
1367     }
1368     /*
1369     * suspend accounting until turned on by sh_accbegin()
1370     */
sh_accsusp(void)1371     void sh_accsusp(void)
1372     {
1373 	shaccton=0;
1374 #ifdef AEXPAND
1375 	sabuf.ac_flag |= AEXPND;
1376 #endif /* AEXPAND */
1377     }
1378 
1379     /*
1380      * begin an accounting record by recording start time
1381      */
sh_accbegin(const char * cmdname)1382     void sh_accbegin(const char *cmdname)
1383     {
1384 	if(SHACCT)
1385 	{
1386 		sabuf.ac_btime = time(NIL(time_t *));
1387 		before = times(&buffer);
1388 		sabuf.ac_uid = getuid();
1389 		sabuf.ac_gid = getgid();
1390 		strncpy(sabuf.ac_comm, (char*)path_basename(cmdname),
1391 			sizeof(sabuf.ac_comm));
1392 		shaccton = 1;
1393 	}
1394     }
1395     /*
1396      * terminate an accounting record and append to accounting file
1397      */
sh_accend(void)1398     void	sh_accend(void)
1399     {
1400 	int	fd;
1401 	clock_t	after;
1402 
1403 	if(shaccton)
1404 	{
1405 		after = times(&buffer);
1406 		sabuf.ac_utime = compress(buffer.tms_utime + buffer.tms_cutime);
1407 		sabuf.ac_stime = compress(buffer.tms_stime + buffer.tms_cstime);
1408 		sabuf.ac_etime = compress( (time_t)(after-before));
1409 		fd = open( SHACCT , O_WRONLY | O_APPEND | O_CREAT,RW_ALL);
1410 		write(fd, (const char*)&sabuf, sizeof( sabuf ));
1411 		close( fd);
1412 	}
1413     }
1414 
1415     /*
1416      * Produce a pseudo-floating point representation
1417      * with 3 bits base-8 exponent, 13 bits fraction.
1418      */
compress(register time_t t)1419     static int compress(register time_t t)
1420     {
1421 	register int exp = 0, rund = 0;
1422 
1423 	while (t >= 8192)
1424 	{
1425 		exp++;
1426 		rund = t&04;
1427 		t >>= 3;
1428 	}
1429 	if (rund)
1430 	{
1431 		t++;
1432 		if (t >= 8192)
1433 		{
1434 			t >>= 3;
1435 			exp++;
1436 		}
1437 	}
1438 	return((exp<<13) + t);
1439     }
1440 #endif	/* SHOPT_ACCT */
1441 
1442 
1443 
1444 /*
1445  * add a pathcomponent to the path search list and eliminate duplicates
1446  * and non-existing absolute paths.
1447  */
path_addcomp(Shell_t * shp,Pathcomp_t * first,Pathcomp_t * old,const char * name,int flag)1448 static Pathcomp_t *path_addcomp(Shell_t *shp,Pathcomp_t *first, Pathcomp_t *old,const char *name, int flag)
1449 {
1450 	register Pathcomp_t *pp, *oldpp;
1451 	int len, offset=staktell();
1452 	if(!(flag&PATH_BFPATH))
1453 	{
1454 		register const char *cp = name;
1455 		while(*cp && *cp!=':')
1456 			stakputc(*cp++);
1457 		len = staktell()-offset;
1458 		stakputc(0);
1459 		stakseek(offset);
1460 		name = (const char*)stakptr(offset);
1461 	}
1462 	else
1463 		len = strlen(name);
1464 	for(pp=first; pp; pp=pp->next)
1465 	{
1466 		if(len == pp->len && memcmp(name,pp->name,len)==0)
1467 		{
1468 			pp->flags |= flag;
1469 			return(first);
1470 		}
1471 	}
1472 	for(pp=first, oldpp=0; pp; oldpp=pp, pp=pp->next);
1473 	pp = newof((Pathcomp_t*)0,Pathcomp_t,1,len+1);
1474 	pp->shp = shp;
1475 	pp->refcount = 1;
1476 	memcpy((char*)(pp+1),name,len+1);
1477 	pp->name = (char*)(pp+1);
1478 	pp->len = len;
1479 	if(oldpp)
1480 		oldpp->next = pp;
1481 	else
1482 		first = pp;
1483 	pp->flags = flag;
1484 	if(strcmp(name,SH_CMDLIB_DIR)==0)
1485 	{
1486 		pp->dev = 1;
1487 		pp->flags |= PATH_BUILTIN_LIB;
1488 		pp->blib = pp->bbuf = malloc(sizeof(LIBCMD));
1489 		strcpy(pp->blib,LIBCMD);
1490 		return(first);
1491 	}
1492 	if((old||shp->pathinit) &&  ((flag&(PATH_PATH|PATH_SKIP))==PATH_PATH))
1493 		path_chkpaths(shp,first,old,pp,offset);
1494 	return(first);
1495 }
1496 
1497 /*
1498  * This function checks for the .paths file in directory in <pp>
1499  * it assumes that the directory is on the stack at <offset>
1500  */
path_chkpaths(Shell_t * shp,Pathcomp_t * first,Pathcomp_t * old,Pathcomp_t * pp,int offset)1501 static int path_chkpaths(Shell_t *shp,Pathcomp_t *first, Pathcomp_t* old,Pathcomp_t *pp, int offset)
1502 {
1503 	struct stat statb;
1504 	int k,m,n,fd;
1505 	char *sp,*cp,*ep;
1506 	stakseek(offset+pp->len);
1507 	if(pp->len==1 && *stakptr(offset)=='/')
1508 		stakseek(offset);
1509 	stakputs("/.paths");
1510 	if((fd=open(stakptr(offset),O_RDONLY))>=0)
1511 	{
1512 		fstat(fd,&statb);
1513 		n = statb.st_size;
1514 		stakseek(offset+pp->len+n+2);
1515 		sp = stakptr(offset+pp->len);
1516 		*sp++ = '/';
1517 		n=read(fd,cp=sp,n);
1518 		sp[n] = 0;
1519 		close(fd);
1520 		for(ep=0; n--; cp++)
1521 		{
1522 			if(*cp=='=')
1523 			{
1524 				ep = cp+1;
1525 				continue;
1526 			}
1527 			else if(*cp!='\r' &&  *cp!='\n')
1528 				continue;
1529 			if(*sp=='#' || sp==cp)
1530 			{
1531 				sp = cp+1;
1532 				continue;
1533 			}
1534 			*cp = 0;
1535 			m = ep ? (ep-sp) : 0;
1536 			if(m==0 || m==6 && memcmp((void*)sp,(void*)"FPATH=",m)==0)
1537 			{
1538 				if(first)
1539 				{
1540 					char *ptr = stakptr(offset+pp->len+1);
1541 					if(ep)
1542 						strcpy(ptr,ep);
1543 					path_addcomp(shp,first,old,stakptr(offset),PATH_FPATH|PATH_BFPATH);
1544 				}
1545 			}
1546 			else if(m==11 && memcmp((void*)sp,(void*)"PLUGIN_LIB=",m)==0)
1547 			{
1548 				if(pp->bbuf)
1549 					free(pp->bbuf);
1550 				pp->blib = pp->bbuf = strdup(ep);
1551 			}
1552 			else if(m)
1553 			{
1554 				pp->lib = (char*)malloc(cp-sp+pp->len+2);
1555 				memcpy((void*)pp->lib,(void*)sp,m);
1556 				memcpy((void*)&pp->lib[m],stakptr(offset),pp->len);
1557 				pp->lib[k=m+pp->len] = '/';
1558 				strcpy((void*)&pp->lib[k+1],ep);
1559 				pathcanon(&pp->lib[m],0);
1560 				if(!first)
1561 				{
1562 					stakseek(0);
1563 					stakputs(pp->lib);
1564 					free((void*)pp->lib);
1565 					return(1);
1566 				}
1567 			}
1568 			sp = cp+1;
1569 			ep = 0;
1570 		}
1571 	}
1572 	return(0);
1573 }
1574 
1575 
path_addpath(Shell_t * shp,Pathcomp_t * first,register const char * path,int type)1576 Pathcomp_t *path_addpath(Shell_t *shp,Pathcomp_t *first, register const char *path,int type)
1577 {
1578 	register const char *cp;
1579 	Pathcomp_t *old=0;
1580 	int offset = staktell();
1581 	char *savptr;
1582 
1583 	if(!path && type!=PATH_PATH)
1584 		return(first);
1585 	if(type!=PATH_FPATH)
1586 	{
1587 		old = first;
1588 		first = 0;
1589 	}
1590 	if(offset)
1591 		savptr = stakfreeze(0);
1592 	if(path) while(*(cp=path))
1593 	{
1594 		if(*cp==':')
1595 		{
1596 			if(type!=PATH_FPATH)
1597 				first = path_addcomp(shp,first,old,".",type);
1598 			while(*++path == ':');
1599 		}
1600 		else
1601 		{
1602 			int c;
1603 			while(*path && *path!=':')
1604 				path++;
1605 			c = *path++;
1606 			first = path_addcomp(shp,first,old,cp,type);
1607 			if(c==0)
1608 				break;
1609 			if(*path==0)
1610 				path--;
1611 		}
1612 	}
1613 	if(old)
1614 	{
1615 		if(!first && !path)
1616 		{
1617 			Pathcomp_t *pp = (Pathcomp_t*)shp->defpathlist;
1618 			if(!pp)
1619 				pp = defpath_init(shp);
1620 			first = path_dup(pp);
1621 		}
1622 		if(cp=(sh_scoped(shp,FPATHNOD))->nvalue.cp)
1623 			first = (void*)path_addpath(shp,(Pathcomp_t*)first,cp,PATH_FPATH);
1624 		path_delete(old);
1625 	}
1626 	if(offset)
1627 		stakset(savptr,offset);
1628 	else
1629 		stakseek(0);
1630 	return(first);
1631 }
1632 
1633 /*
1634  * duplicate the path give by <first> by incremented reference counts
1635  */
path_dup(Pathcomp_t * first)1636 Pathcomp_t *path_dup(Pathcomp_t *first)
1637 {
1638 	register Pathcomp_t *pp=first;
1639 	while(pp)
1640 	{
1641 		pp->refcount++;
1642 		pp = pp->next;
1643 	}
1644 	return(first);
1645 }
1646 
1647 /*
1648  * called whenever the directory is changed
1649  */
path_newdir(Shell_t * shp,Pathcomp_t * first)1650 void path_newdir(Shell_t *shp,Pathcomp_t *first)
1651 {
1652 	register Pathcomp_t *pp=first, *next, *pq;
1653 	struct stat statb;
1654 	for(pp=first; pp; pp=pp->next)
1655 	{
1656 		pp->flags &= ~PATH_SKIP;
1657 		if(*pp->name=='/')
1658 			continue;
1659 		/* delete .paths component */
1660 		if((next=pp->next) && (next->flags&PATH_BFPATH))
1661 		{
1662 			pp->next = next->next;
1663 			if(--next->refcount<=0)
1664 				free((void*)next);
1665 		}
1666 		if(stat(pp->name,&statb)<0 || !S_ISDIR(statb.st_mode))
1667 		{
1668 			pp->dev = 0;
1669 			pp->ino = 0;
1670 			continue;
1671 		}
1672 		pp->dev = statb.st_dev;
1673 		pp->ino = statb.st_ino;
1674 		pp->mtime = statb.st_mtime;
1675 		for(pq=first;pq!=pp;pq=pq->next)
1676 		{
1677 			if(pp->ino==pq->ino && pp->dev==pq->dev)
1678 				pp->flags |= PATH_SKIP;
1679 		}
1680 		for(pq=pp;pq=pq->next;)
1681 		{
1682 			if(pp->ino==pq->ino && pp->dev==pq->dev)
1683 				pq->flags |= PATH_SKIP;
1684 		}
1685 		if((pp->flags&(PATH_PATH|PATH_SKIP))==PATH_PATH)
1686 		{
1687 			/* try to insert .paths component */
1688 			int offset = staktell();
1689 			stakputs(pp->name);
1690 			stakseek(offset);
1691 			next = pp->next;
1692 			pp->next = 0;
1693 			path_chkpaths(shp,first,(Pathcomp_t*)0,pp,offset);
1694 			if(pp->next)
1695 				pp = pp->next;
1696 			pp->next = next;
1697 		}
1698 	}
1699 #if 0
1700 	path_dump(first);
1701 #endif
1702 }
1703 
path_unsetfpath(Shell_t * shp)1704 Pathcomp_t *path_unsetfpath(Shell_t *shp)
1705 {
1706 	Pathcomp_t	*first = (Pathcomp_t*)shp->pathlist;
1707 	register Pathcomp_t *pp=first, *old=0;
1708 	if(shp->fpathdict)
1709 	{
1710 		struct Ufunction  *rp, *rpnext;
1711 		for(rp=(struct Ufunction*)dtfirst(shp->fpathdict);rp;rp=rpnext)
1712 		{
1713 			rpnext = (struct Ufunction*)dtnext(shp->fpathdict,rp);
1714 			if(rp->fdict)
1715 				nv_delete(rp->np,rp->fdict,NV_NOFREE);
1716 			rp->fdict = 0;
1717 		}
1718 	}
1719 	while(pp)
1720 	{
1721 		if((pp->flags&PATH_FPATH) && !(pp->flags&PATH_BFPATH))
1722 		{
1723 			if(pp->flags&PATH_PATH)
1724 				pp->flags &= ~PATH_FPATH;
1725 			else
1726 			{
1727 				Pathcomp_t *ppsave=pp;
1728 				if(old)
1729 					old->next = pp->next;
1730 				else
1731 					first = pp->next;
1732 				pp = pp->next;
1733 				if(--ppsave->refcount<=0)
1734 				{
1735 					if(ppsave->lib)
1736 						free((void*)ppsave->lib);
1737 					free((void*)ppsave);
1738 				}
1739 				continue;
1740 			}
1741 
1742 		}
1743 		old = pp;
1744 		pp = pp->next;
1745 	}
1746 	return(first);
1747 }
1748 
path_dirfind(Pathcomp_t * first,const char * name,int c)1749 Pathcomp_t *path_dirfind(Pathcomp_t *first,const char *name,int c)
1750 {
1751 	register Pathcomp_t *pp=first;
1752 	while(pp)
1753 	{
1754 		if(memcmp(name,pp->name,pp->len)==0 && name[pp->len]==c)
1755 			return(pp);
1756 		pp = pp->next;
1757 	}
1758 	return(0);
1759 }
1760 
1761 /*
1762  * get discipline for tracked alias
1763  */
talias_get(Namval_t * np,Namfun_t * nvp)1764 static char *talias_get(Namval_t *np, Namfun_t *nvp)
1765 {
1766 	Pathcomp_t *pp = (Pathcomp_t*)np->nvalue.cp;
1767 	char *ptr;
1768 	if(!pp)
1769 		return(NULL);
1770 	pp->shp->last_table = 0;
1771 	path_nextcomp(pp->shp,pp,nv_name(np),pp);
1772 	ptr = stakfreeze(0);
1773 	return(ptr+PATH_OFFSET);
1774 }
1775 
talias_put(register Namval_t * np,const char * val,int flags,Namfun_t * fp)1776 static void talias_put(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
1777 {
1778 	if(!val && np->nvalue.cp)
1779 	{
1780 		Pathcomp_t *pp = (Pathcomp_t*)np->nvalue.cp;
1781 		if(--pp->refcount<=0)
1782 			free((void*)pp);
1783 	}
1784 	nv_putv(np,val,flags,fp);
1785 }
1786 
1787 static const Namdisc_t talias_disc   = { 0, talias_put, talias_get   };
1788 static Namfun_t  talias_init = { &talias_disc, 1 };
1789 
1790 /*
1791  *  set tracked alias node <np> to value <pp>
1792  */
path_alias(register Namval_t * np,register Pathcomp_t * pp)1793 void path_alias(register Namval_t *np,register Pathcomp_t *pp)
1794 {
1795 	if(pp)
1796 	{
1797 		struct stat statb;
1798 		char *sp;
1799 		nv_offattr(np,NV_NOPRINT);
1800 		nv_stack(np,&talias_init);
1801 		np->nvalue.cp = (char*)pp;
1802 		pp->refcount++;
1803 		nv_setattr(np,NV_TAGGED|NV_NOFREE);
1804 		path_nextcomp(pp->shp,pp,nv_name(np),pp);
1805 		sp = stakptr(PATH_OFFSET);
1806 		if(sp && lstat(sp,&statb)>=0 && S_ISLNK(statb.st_mode))
1807 			nv_setsize(np,statb.st_size+1);
1808 		else
1809 			nv_setsize(np,0);
1810 	}
1811 	else
1812 		_nv_unset(np,0);
1813 }
1814 
1815