#ifdef _REENTRANT
#include <thread.h>
#include <pthread.h>
#endif
#include <sys/types.h>
#include <libgen.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#define FFLAG S_IFREG
#define BFLAG S_IFBLK
#define CFLAG S_IFCHR
#define DFLAG S_IFDIR
#define PFLAG S_IFIFO
#define UFLAG S_ISUID
#define GFLAG S_ISGID
#define KFLAG S_ISVTX
#define RFLAG 04
#define WFLAG 02
#define XFLAG 01
static int fullck(char *, mode_t, int);
#ifdef _REENTRANT
static char *
_get_cpath(thread_key_t *keyp)
{
char *str;
if (thr_keycreate_once(keyp, free) != 0)
return (NULL);
str = pthread_getspecific(*keyp);
if (str == NULL) {
str = calloc(PATH_MAX, sizeof (char));
if (thr_setspecific(*keyp, str) != 0) {
if (str)
(void) free(str);
str = NULL;
}
}
return (str);
}
#endif
char *
pathfind(const char *path, const char *name, const char *mode)
{
#ifdef _REENTRANT
static thread_key_t key = THR_ONCE_KEY;
char *cpath = _get_cpath(&key);
#else
static char cpath[PATH_MAX];
#endif
char *cp;
mode_t imode;
int nzflag;
imode = 0; nzflag = 0;
if (mode == ((char *)0))
mode = "";
for (cp = (char *)mode; *cp; cp++) {
switch (*cp) {
case 'r':
imode |= RFLAG;
break;
case 'w':
imode |= WFLAG;
break;
case 'x':
imode |= XFLAG;
break;
case 'b':
imode |= BFLAG;
break;
case 'c':
imode |= CFLAG;
break;
case 'd':
imode |= DFLAG;
break;
case 'f':
imode |= FFLAG;
break;
case 'p':
imode |= PFLAG;
break;
case 'u':
imode |= UFLAG;
break;
case 'g':
imode |= GFLAG;
break;
case 'k':
imode |= KFLAG;
break;
case 's':
nzflag = 1;
break;
default:
return ((char *)0);
}
}
if (name[0] == '/' || path == ((char *)0) || *path == '\0')
path = ":";
while (*path) {
for (cp = cpath; ( char *) cp <
&cpath[PATH_MAX] && (*cp = *path); cp++) {
path++;
if (*cp == ':')
break;
}
if (( char *) cp + strlen(name) + 2 >=
&cpath[PATH_MAX])
continue;
if (cp != cpath)
*cp++ = '/';
*cp = '\0';
(void) strcat(cp, name);
if (access(cpath, imode&07) == 0 &&
fullck(cpath, imode, nzflag))
return (cpath);
}
return ((char *)0);
}
static int
fullck(char *name, mode_t mode, int nzflag)
{
struct stat64 sbuf;
int xor;
if ((mode & 0177000) == 0 && nzflag == 0)
return (1);
if (stat64(name, &sbuf) == -1)
return (0);
xor = (sbuf.st_mode ^ mode) & 077000;
if ((mode & 0170000) == 0)
xor &= ~070000;
if ((mode & 07000) == 0)
xor &= ~07000;
if (xor)
return (0);
if (nzflag && sbuf.st_size == 0)
return (0);
return (1);
}