|
|
1.1 ! root 1: /* ! 2: * locate a program file along the user's PATH. ! 3: * try to mimic output of the BSD version. ! 4: */ ! 5: #include <stdio.h> ! 6: #include <sys/stat.h> ! 7: #include <access.h> ! 8: ! 9: char *getenv(); ! 10: char *index(); ! 11: char **parsepath(); /* parse PATH into argv-like structure */ ! 12: void fatal(); /* display error message and die */ ! 13: void usage(); /* display usage message and die */ ! 14: char *calloc(); ! 15: char *index(); ! 16: ! 17: #define TRUE (0 == 0) ! 18: #define FALSE (0 != 0) ! 19: #define EXEC_BITS (S_IEXEC | (S_IEXEC >> 3) | (S_IEXEC >> 6)) ! 20: ! 21: main(argc, argv) ! 22: int argc; ! 23: char *argv[]; ! 24: { ! 25: char *pathp; /* pointer to PATH string */ ! 26: char **pathpp; /* pointer to path entries */ ! 27: char **pathlist; /* pointer to path list */ ! 28: static char pathbuf[BUFSIZ]; /* expanded file names */ ! 29: static char path[BUFSIZ]; /* saved copy for error msgs */ ! 30: ! 31: if ((pathp = getenv("PATH")) == NULL) ! 32: fatal("PATH not found in environment"); ! 33: strcpy(path, pathp); ! 34: if (--argc < 1) ! 35: usage(); ! 36: pathlist = parsepath(pathp); ! 37: ! 38: for (++argv; argc-- > 0; ++argv) { ! 39: pathpp = pathlist; ! 40: for ( ; *pathpp != NULL; ++pathpp) { ! 41: if (**pathpp != '\0') { ! 42: strcpy(pathbuf, *pathpp); ! 43: strcat(pathbuf, "/"); ! 44: strcat(pathbuf, *argv); ! 45: } else ! 46: strcpy(pathbuf, *argv); ! 47: if (is_exec(pathbuf)) { ! 48: puts(pathbuf); ! 49: break; ! 50: } ! 51: } ! 52: if (*pathpp == NULL) ! 53: if (index(*argv, '/') != NULL) ! 54: printf("%s not found\n", *argv); ! 55: else ! 56: printf("no %s in %s\n", *argv, path); ! 57: } ! 58: exit(0); ! 59: } ! 60: ! 61: /* ! 62: * check to see if the given name is executable. ! 63: * this isn't as trivial as it may seem since access() says ! 64: * that root (UID 0) can execute anything, even if the ! 65: * execute mode bits are not set. ! 66: */ ! 67: is_exec(name) ! 68: char *name; ! 69: { ! 70: static struct stat statbuf; ! 71: ! 72: if (access(name, AEXEC) != 0) ! 73: return FALSE; ! 74: if (stat(name, &statbuf) == -1) { ! 75: fprintf(stderr, "%s: Unable to stat\n", name); ! 76: return FALSE; ! 77: } ! 78: if ((statbuf.st_mode & S_IFMT) != S_IFREG) ! 79: return FALSE; ! 80: return (getuid() != 0 || (statbuf.st_mode & EXEC_BITS)); ! 81: } ! 82: ! 83: /* ! 84: * parse a path of the form dir1:dir2:dir3 into an array of pointers to ! 85: * the individual directory entries. Note that this null terminates each ! 86: * directory entry by replacing all ':' characters in "path" with NUL's. ! 87: * take special care of leading and trailing ':' which imply the current ! 88: * directory. ! 89: */ ! 90: char ** ! 91: parsepath(path) ! 92: char *path; ! 93: { ! 94: register char *cp; ! 95: register int i = 1; ! 96: char **patharray, **pp; ! 97: ! 98: for (cp = path; *cp != '\0'; ) /* calculate number of entries */ ! 99: if (*cp++ == ':') ! 100: ++i; ! 101: if ((patharray = (char **)calloc(i + 1, sizeof (char *))) == NULL) ! 102: fatal("Out of memory for PATH list"); ! 103: for (cp = path, pp = patharray; *cp != '\0' || pp == patharray; ) { ! 104: *pp++ = cp; ! 105: while (*cp != '\0') { ! 106: if (*cp == ':') { ! 107: *cp++ = '\0'; ! 108: break; ! 109: } ! 110: ++cp; ! 111: } ! 112: if ((pp - patharray) < i) ! 113: *pp = cp; ! 114: } ! 115: return (patharray); ! 116: } ! 117: ! 118: void ! 119: usage() ! 120: { ! 121: fatal("usage: which name ...."); ! 122: } ! 123: ! 124: void ! 125: fatal(info) ! 126: char *info; ! 127: { ! 128: fprintf(stderr, "which: %r\n", &info); ! 129: exit(1); ! 130: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.