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