/* See LICENSE file for copyright and license details. */ #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> #include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "util.h" static int aflag; static int which(const char *path, const char *name) { char *ptr, *p; size_t i, len; struct stat st; int dirfd, found = 0; ptr = p = enstrdup(3, path); len = strlen(p); for (i = 0; i < len + 1; i++) { if (ptr[i] != ':' && ptr[i] != '\0') continue; ptr[i] = '\0'; if ((dirfd = open(p, O_RDONLY, 0)) >= 0) { if (!fstatat(dirfd, name, &st, 0) && S_ISREG(st.st_mode) && !faccessat(dirfd, name, X_OK, 0)) { found = 1; fputs(p, stdout); if (i && ptr[i - 1] != '/') fputc('/', stdout); puts(name); if (!aflag) { close(dirfd); break; } } close(dirfd); } p = ptr + i + 1; } free(ptr); return found; } static void usage(void) { eprintf("usage: %s [-a] name ...\n", argv0); } int main(int argc, char *argv[]) { char *path; int found = 0, foundall = 1; ARGBEGIN { case 'a': aflag = 1; break; default: usage(); } ARGEND if (!argc) usage(); if (!(path = getenv("PATH"))) enprintf(3, "$PATH is not set\n"); for (; *argv; argc--, argv++) { if (which(path, *argv)) { found = 1; } else { weprintf("%s: command not found.\n", *argv); foundall = 0; } } return found ? foundall ? 0 : 1 : 2; }