which.c - sbase - suckless unix tools
 (HTM) git clone git://git.suckless.org/sbase
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       which.c (1648B)
       ---
            1 /* See LICENSE file for copyright and license details. */
            2 #include <sys/stat.h>
            3 #include <sys/types.h>
            4 
            5 #include <fcntl.h>
            6 #include <limits.h>
            7 #include <stdio.h>
            8 #include <stdlib.h>
            9 #include <string.h>
           10 #include <unistd.h>
           11 
           12 #include "util.h"
           13 
           14 static int aflag;
           15 
           16 static int
           17 canexec(int fd, const char *name)
           18 {
           19         struct stat st;
           20 
           21         if (fstatat(fd, name, &st, 0) < 0 || !S_ISREG(st.st_mode))
           22                 return 0;
           23         return faccessat(fd, name, X_OK, AT_EACCESS) == 0;
           24 }
           25 
           26 static int
           27 which(const char *path, const char *name)
           28 {
           29         char *ptr, *p;
           30         size_t i, len;
           31         int dirfd, found = 0;
           32 
           33         if (strchr(name, '/')) {
           34                 found = canexec(AT_FDCWD, name);
           35                 if (found)
           36                         puts(name);
           37                 return found;
           38         }
           39 
           40         ptr = p = enstrdup(3, path);
           41         len = strlen(p);
           42         for (i = 0; i < len + 1; i++) {
           43                 if (ptr[i] != ':' && ptr[i] != '\0')
           44                         continue;
           45                 ptr[i] = '\0';
           46                 if ((dirfd = open(p, O_RDONLY)) >= 0) {
           47                         if (canexec(dirfd, name)) {
           48                                 found = 1;
           49                                 fputs(p, stdout);
           50                                 if (i && ptr[i - 1] != '/')
           51                                         fputc('/', stdout);
           52                                 puts(name);
           53                         }
           54                         close(dirfd);
           55                         if (!aflag && found)
           56                                 break;
           57                 }
           58                 p = ptr + i + 1;
           59         }
           60         free(ptr);
           61 
           62         return found;
           63 }
           64 
           65 static void
           66 usage(void)
           67 {
           68         eprintf("usage: %s [-a] name ...\n", argv0);
           69 }
           70 
           71 int
           72 main(int argc, char *argv[])
           73 {
           74         char *path;
           75         int found = 0, foundall = 1;
           76 
           77         ARGBEGIN {
           78         case 'a':
           79                 aflag = 1;
           80                 break;
           81         default:
           82                 usage();
           83         } ARGEND
           84 
           85         if (!argc)
           86                 usage();
           87 
           88         if (!(path = getenv("PATH")))
           89                 enprintf(3, "$PATH is not set\n");
           90 
           91         for (; *argv; argc--, argv++) {
           92                 if (which(path, *argv)) {
           93                         found = 1;
           94                 } else {
           95                         weprintf("%s: not an external command\n", *argv);
           96                         foundall = 0;
           97                 }
           98         }
           99 
          100         return found ? foundall ? 0 : 1 : 2;
          101 }