/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1982-2010 AT&T Intellectual Property *
* and is licensed under the *
* Common Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* David Korn <dgk@research.att.com> *
* *
***********************************************************************/
#pragma prototyped
/*
* David Korn
* AT&T Labs
*
*/
#include "defs.h"
#include <fcin.h>
#include <ls.h>
#include <nval.h>
#include "variables.h"
#include "path.h"
#include "io.h"
#include "jobs.h"
#include "history.h"
#include "test.h"
#if SHOPT_PFSH
# ifdef _hdr_exec_attr
# include <exec_attr.h>
# endif
# if _lib_vfork
# include <ast_vfork.h>
# else
# endif
#endif
static int canexecute(char*,int);
static void path_checkdup(register Pathcomp_t*);
static const char *std_path;
{
if(cp)
while(*cp)
{
return(1);
}
return(0);
}
{
#if SHOPT_PFSH
if(spawn)
{
if(pid)
return(pid);
}
if(!sh_isoption(SH_PFSH))
/* Solaris implements realpath(3C) using the resolvepath(2) */
/* system call so we can save us to call access(2) first */
return -1;
/* we can exec the command directly instead of via pfexec(1) if */
/* there is a matching entry without attributes in exec_attr(4) */
{
{
{
return r;
}
}
else
{
return -1;
}
}
--argv;
#else
#endif
}
{
job_lock();
while(1)
{
break;
}
if(pid>0)
else
job_unlock();
return(pid);
}
/*
* used with command -x to run the command in multiple passes
* spawn is non-zero when invoked via spawn
* the exitval is set to the maximum for each execution
*/
{
char *const *ev;
return((pid_t)-1);
if(!spawn)
job_clear();
{
/* leave at least two for last */
av--;
{
n = nlast*sizeof(char*);
}
else
{
argv[n] = 0;
}
{
return(-1);
if(saveargs)
{
saveargs = 0;
}
}
{
}
else
}
if(!spawn)
return((pid_t)-1);
}
/*
* make sure PWD is set up correctly
* Return the present working directory
* Invokes getcwd() if flag==0 and if necessary
* Sets the PWD variable to this value
*/
{
register char *cp;
register int count = 0;
while(1)
{
/* try from lowest to highest */
switch(count++)
{
case 0:
break;
case 1:
break;
case 2:
cp = "/";
break;
case 3:
if(flag) /* skip next case when non-zero flag */
++count;
break;
case 4:
{
{
goto skip;
}
break;
}
case 5:
return(dfault);
}
break;
}
if(count>1)
{
}
skip:
return(cp);
}
{
{
return;
stakputs("/bin");
stakputc(0);
return;
}
}
/*
* delete current Pathcomp_t structure
*/
{
while(pp)
{
{
{
#if SHOPT_DYNAMIC
#endif /* SHOPT_DYNAMIC */
}
if(old)
}
else
}
}
/*
* returns library variable from .paths
* The value might be returned on the stack overwriting path
*/
{
register int r;
if(last)
*last = 0;
else
path = ".";
if(last)
*last = '/';
if(r>=0)
{
{
}
if(last)
return(stakfreeze(1));
}
return(0);
}
#if 0
{
while(pp)
{
}
}
#endif
/*
* check for duplicate directories on PATH
*/
{
register int flag=0;
{
return;
}
flag = PATH_STD_DIR;
{
{
break;
}
}
{
}
}
/*
* write the next path to search on the current stack
* if last is given, all paths that come before <last> are skipped
* the next pathcomp is returned.
*/
{
if(*name=='/')
pp = 0;
else
{
{
continue;
break;
}
if(!pp) /* this should not happen */
}
{
{
stakputc('/');
}
stakputc('/');
}
stakputc(0);
{
return(pp);
}
return((Pathcomp_t*)0);
}
{
return(pp);
}
{
const char *val;
{
}
else
{
}
{
}
}
/*
* returns that pathlist to search
*/
{
return(0);
if(!sh_isstate(SH_DEFPATH))
{
}
{
}
return(pp);
}
/*
* open file corresponding to name using path give by <pp>
*/
{
if(pp)
else
{
shp = sh_getinterp();
}
{
if(sh_isoption(SH_RESTRICTED))
}
do
{
continue;
{
{
fd = -1;
}
}
}
{
if(!shp)
{
shp = sh_getinterp();
#if _UWIN
#endif
}
}
return(fd);
}
/*
* open file corresponding to name using path give by <pp>
*/
{
}
/*
* given a pathname return the base name
*/
{
while (*name)
return ((char*)start);
}
{
if(*name!='/')
{
}
if(dirlen)
{
}
return(path);
}
/*
* load functions from file <fno>
*/
{
{
do
{
{
}
}
return;
}
error_info.line = 0;
shp->readscript = 0;
}
/*
* do a path search and track alias if requested
* if flag is 0, or if name not found, then try autoloading function
* if flag==2 or 3, returns 1 if name found on FPATH
* if flag==3 no tracked alias will be set
* returns 1, if function was autoloaded.
* If oldpp is not NULL, it will contain a pointer to the path component
* where it was found.
*/
{
register int fno;
{
{
*stakptr(PATH_OFFSET) = 0;
return(0);
}
if(*name=='/')
return(1);
stakputc('/');
stakputc(0);
return(0);
}
if(sh_isstate(SH_DEFPATH))
{
if(!shp->defpathlist)
}
if(flag)
{
if((np=nv_search(name,shp->track_tree,0)) && !nv_isattr(np,NV_NOALIAS) && (pp=(Pathcomp_t*)np->nvalue.cp))
{
stakputc(0);
return(0);
}
if(oldpp)
return(1);
if(!pp)
*stakptr(PATH_OFFSET) = 0;
}
{
if(!pp)
{
if(flag==2)
{
return(1);
}
return(1);
}
*stakptr(PATH_OFFSET) = 0;
return(0);
}
{
}
return(0);
}
/*
* do a path search and find the full pathname of file name
*/
{
register int f,isfun;
int noexec=0;
return(0);
while(1)
{
sh_sigcheck();
{
{
{
return(0);
}
}
}
{
return(oldpp);
#if SHOPT_DYNAMIC
{
typedef int (*Fptr_t)(int, char*[], void*);
int n = staktell();
int libcmd;
char *cp;
stakputs("b_");
stakputc(0);
{
cp++;
else
{
return(oldpp);
}
#if (_AST_VERSION>=20040404)
#else
#endif
{
/*
* this detects the 2007-05-11 builtin context change and also
* the 2008-03-30 opt_info.num change that hit libcmd::b_head
*/
{
}
else
}
}
{
return(oldpp);
}
}
#endif /* SHOPT_DYNAMIC */
}
if(isfun && f>=0)
{
close(f);
f = -1;
return(0);
}
{
int n = staktell();
stakputs("/bin/");
stakputc(0);
stakseek(n);
if(np)
{
}
}
if(!pp || f>=0)
break;
}
if(f<0)
{
return(0);
}
stakputc(0);
return(oldpp);
}
/*
* returns 0 if path can execute
* sets exec_err if file is found but can't be executable
*/
#ifdef S_IXUSR
#else
# ifdef S_IEXEC
# else
# endif /*S_EXEC */
#endif /* S_IXUSR */
{
register int fd=0;
if(isfun)
{
goto err;
}
{
#if _WINIX
/* check for .exe or .bat suffix */
char *cp;
{
stakputs(".bat");
{
goto err;
goto err;
}
}
else
#endif /* _WINIX */
goto err;
}
return(fd);
err:
return(-1);
}
/*
* Return path relative to present working directory
*/
{
register const char *pwd;
/* can't relpath when sh.pwd not set */
return((char*)fp);
{
if(*pwd++==0)
return((char*)e_dot);
fp++;
}
{
while(*++fp=='/');
if(*fp)
return((char*)fp);
return((char*)e_dot);
}
return((char*)file);
}
{
char **envp;
const char *opath;
int slash=0;
{
slash=1;
/* name containing / not allowed for restricted shell */
if(sh_isoption(SH_RESTRICTED))
}
else
/* find first path that has a library component */
{
sh_sigcheck();
{
}
else
}
while(pp);
/* force an exit */
else
}
pid_t path_spawn(const char *opath,register char **argv, char **envp, Pathcomp_t *libpath, int spawn)
{
register char *path;
char *s, *v;
int r, n, pidsize;
/* leave room for inserting _= pathname in environment */
envp--;
#if _lib_readlink
/* save original pathname */
{
/* check for symlink and use symlink name */
{
buff[n] = 0;
n = PATH_OFFSET;
r = 0;
{
else
r = 0;
n += (v+1-path);
}
stakseek(n);
stakputc(0);
{
{
break;
}
}
break;
}
stakseek(0);
}
#endif
{
n = v - libenv;
*v = 0;
*v = '=';
if(s)
{
stakputc(':');
stakputs(s);
}
v = stakfreeze(1);
r = 1;
while (s = *xp++)
{
if (strneq(s, v, n) && s[n] == '=')
{
*xp = v;
r = 0;
break;
}
}
if (r)
{
*envp-- = v;
xp = 0;
}
}
if(!opath)
envp[0][0] = '_';
sh_sigcheck();
#ifdef SHELLMAGIC
{
/*
* The following code because execv(foo,) and execv(./foo,)
* may not yield the same results
*/
sp[0] = '.';
}
#endif /* SHELLMAGIC */
else
if(xp)
#ifdef SHELLMAGIC
{
}
#endif /* SHELLMAGIC */
if(pid>0)
return(pid);
{
#ifdef apollo
/*
* On apollo's execve will fail with eacces when
* file has execute but not read permissions. So,
* for now we will pretend that EACCES and ENOEXEC
* mean the same thing.
*/
case EACCES:
#endif /* apollo */
case ENOEXEC:
#if SHOPT_SUID_EXEC
case EPERM:
/* some systems return EPERM if setuid bit is on */
#endif
if(spawn)
{
#ifdef _lib_fork
return(-1);
do
{
return(pid);
}
#else
return(-1);
#endif
}
#ifndef apollo
case EACCES:
{
{
#ifdef S_ISSOCK
#endif
}
}
/* FALL THROUGH */
#endif /* !apollo */
#ifdef ENAMETOOLONG
case ENAMETOOLONG:
#endif /* ENAMETOOLONG */
#if !SHOPT_SUID_EXEC
case EPERM:
#endif
return(-1);
case ENOTDIR:
case ENOENT:
case EINTR:
#ifdef EMLINK
case EMLINK:
#endif /* EMLINK */
return(-1);
case E2BIG:
{
if(pid<0)
goto retry;
return(pid);
}
default:
}
return 0;
}
/*
* File is executable but not machine code.
* Assume file is a Shell script and execute it.
*/
{
/* clean up any cooperating processes */
job_clear();
#if SHOPT_SUID_EXEC && !SHOPT_PFSH
{
register int n;
char *savet=0;
{
/* move <n> if n=0,1,2 */
n = sh_iomovefd(n);
goto openok;
sh_close(n);
}
{
/* create a suid open file with owner equal effective uid */
goto fail;
/* make sure that file has right owner */
goto fail;
if(n!=10)
{
sh_close(10);
sh_close(n);
n=10;
}
}
fail:
/*
* The following code is just for compatibility
*/
if(savet)
}
#else
#endif
#if SHOPT_ACCT
#endif /* SHOPT_ACCT */
/* save name of calling command */
/* close history file if name has changed */
{
}
}
#if SHOPT_ACCT
/*
* initialize accounting, i.e., see if SHACCT variable set
*/
void sh_accinit(void)
{
}
/*
* suspend accounting until turned on by sh_accbegin()
*/
void sh_accsusp(void)
{
shaccton=0;
#ifdef AEXPAND
#endif /* AEXPAND */
}
/*
* begin an accounting record by recording start time
*/
{
if(SHACCT)
{
shaccton = 1;
}
}
/*
* terminate an accounting record and append to accounting file
*/
void sh_accend(void)
{
int fd;
if(shaccton)
{
}
}
/*
* Produce a pseudo-floating point representation
* with 3 bits base-8 exponent, 13 bits fraction.
*/
{
while (t >= 8192)
{
exp++;
rund = t&04;
t >>= 3;
}
if (rund)
{
t++;
if (t >= 8192)
{
t >>= 3;
exp++;
}
}
return((exp<<13) + t);
}
#endif /* SHOPT_ACCT */
/*
* add a pathcomponent to the path search list and eliminate duplicates
* and non-existing absolute paths.
*/
{
if(!(flag&PATH_BFPATH))
{
stakputc(0);
}
else
{
{
return(first);
}
}
if(oldpp)
else
{
return(first);
}
return(first);
}
/*
* This function checks for the .paths file in directory in <pp>
* it assumes that the directory is on the stack at <offset>
*/
{
int k,m,n,fd;
stakputs("/.paths");
{
*sp++ = '/';
sp[n] = 0;
{
if(*cp=='=')
{
continue;
}
continue;
{
continue;
}
*cp = 0;
{
if(first)
{
if(ep)
}
}
{
{
{
}
else
{
if (*ep != '/')
if (*ep != '/')
{
*sp++ = '/';
}
}
}
}
else if(m)
{
if(!first)
{
stakseek(0);
return(1);
}
}
ep = 0;
}
}
return(0);
}
{
register const char *cp;
char *savptr;
return(first);
if(type!=PATH_FPATH)
{
first = 0;
}
if(offset)
savptr = stakfreeze(0);
{
if(*cp==':')
{
if(type!=PATH_FPATH)
while(*++path == ':');
}
else
{
int c;
path++;
c = *path++;
if(c==0)
break;
if(*path==0)
path--;
}
}
if(old)
{
{
if(!pp)
}
}
if(offset)
else
stakseek(0);
return(first);
}
/*
* duplicate the path give by <first> by incremented reference counts
*/
{
while(pp)
{
}
return(first);
}
/*
* called whenever the directory is changed
*/
{
{
continue;
/* delete .paths component */
{
}
{
continue;
}
{
}
{
}
{
/* try to insert .paths component */
}
}
#if 0
#endif
}
{
{
{
}
}
while(pp)
{
{
else
{
if(old)
else
{
}
continue;
}
}
}
return(first);
}
{
while(pp)
{
return(pp);
}
return(0);
}
/*
* get discipline for tracked alias
*/
{
char *ptr;
if(!pp)
return(NULL);
ptr = stakfreeze(0);
return(ptr+PATH_OFFSET);
}
{
{
}
}
/*
* set tracked alias node <np> to value <pp>
*/
{
if(pp)
{
char *sp;
else
nv_setsize(np,0);
}
else
}