which.c - sbase - suckless unix tools | |
git clone git://git.suckless.org/sbase | |
Log | |
Files | |
Refs | |
README | |
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 } |