|
0
|
1 /* See LICENSE file for copyright and license details. */ |
|
|
2 #include <sys/stat.h> |
|
|
3 |
|
|
4 #include <dirent.h> |
|
|
5 #include <limits.h> |
|
|
6 #include <stdio.h> |
|
|
7 #include <stdlib.h> |
|
|
8 #include <string.h> |
|
|
9 #include <unistd.h> |
|
|
10 |
|
|
11 #include "arg.h" |
|
|
12 char *argv0; |
|
|
13 |
|
|
14 #define FLAG(x) (flag[(x)-'a']) |
|
|
15 |
|
|
16 static void test(const char *, const char *); |
|
|
17 static void usage(void); |
|
|
18 |
|
|
19 static int match = 0; |
|
|
20 static int flag[26]; |
|
|
21 static struct stat old, new; |
|
|
22 |
|
|
23 static void |
|
|
24 test(const char *path, const char *name) |
|
|
25 { |
|
|
26 struct stat st, ln; |
|
|
27 |
|
|
28 if ((!stat(path, &st) && (FLAG('a') || name[0] != '.') /* hidden files */ |
|
|
29 && (!FLAG('b') || S_ISBLK(st.st_mode)) /* block special */ |
|
|
30 && (!FLAG('c') || S_ISCHR(st.st_mode)) /* character special */ |
|
|
31 && (!FLAG('d') || S_ISDIR(st.st_mode)) /* directory */ |
|
|
32 && (!FLAG('e') || access(path, F_OK) == 0) /* exists */ |
|
|
33 && (!FLAG('f') || S_ISREG(st.st_mode)) /* regular file */ |
|
|
34 && (!FLAG('g') || st.st_mode & S_ISGID) /* set-group-id flag */ |
|
|
35 && (!FLAG('h') || (!lstat(path, &ln) && S_ISLNK(ln.st_mode))) /* symbolic link */ |
|
|
36 && (!FLAG('n') || st.st_mtime > new.st_mtime) /* newer than file */ |
|
|
37 && (!FLAG('o') || st.st_mtime < old.st_mtime) /* older than file */ |
|
|
38 && (!FLAG('p') || S_ISFIFO(st.st_mode)) /* named pipe */ |
|
|
39 && (!FLAG('r') || access(path, R_OK) == 0) /* readable */ |
|
|
40 && (!FLAG('s') || st.st_size > 0) /* not empty */ |
|
|
41 && (!FLAG('u') || st.st_mode & S_ISUID) /* set-user-id flag */ |
|
|
42 && (!FLAG('w') || access(path, W_OK) == 0) /* writable */ |
|
|
43 && (!FLAG('x') || access(path, X_OK) == 0)) != FLAG('v')) { /* executable */ |
|
|
44 if (FLAG('q')) |
|
|
45 exit(0); |
|
|
46 match = 1; |
|
|
47 puts(name); |
|
|
48 } |
|
|
49 } |
|
|
50 |
|
|
51 static void |
|
|
52 usage(void) |
|
|
53 { |
|
|
54 fprintf(stderr, "usage: %s [-abcdefghlpqrsuvwx] " |
|
|
55 "[-n file] [-o file] [file...]\n", argv0); |
|
|
56 exit(2); /* like test(1) return > 1 on error */ |
|
|
57 } |
|
|
58 |
|
|
59 int |
|
|
60 main(int argc, char *argv[]) |
|
|
61 { |
|
|
62 struct dirent *d; |
|
|
63 char path[PATH_MAX], *line = NULL, *file; |
|
|
64 size_t linesiz = 0; |
|
|
65 ssize_t n; |
|
|
66 DIR *dir; |
|
|
67 int r; |
|
|
68 |
|
|
69 ARGBEGIN { |
|
|
70 case 'n': /* newer than file */ |
|
|
71 case 'o': /* older than file */ |
|
|
72 file = EARGF(usage()); |
|
|
73 if (!(FLAG(ARGC()) = !stat(file, (ARGC() == 'n' ? &new : &old)))) |
|
|
74 perror(file); |
|
|
75 break; |
|
|
76 default: |
|
|
77 /* miscellaneous operators */ |
|
|
78 if (strchr("abcdefghlpqrsuvwx", ARGC())) |
|
|
79 FLAG(ARGC()) = 1; |
|
|
80 else |
|
|
81 usage(); /* unknown flag */ |
|
|
82 } ARGEND; |
|
|
83 |
|
|
84 if (!argc) { |
|
|
85 /* read list from stdin */ |
|
|
86 while ((n = getline(&line, &linesiz, stdin)) > 0) { |
|
|
87 if (line[n - 1] == '\n') |
|
|
88 line[n - 1] = '\0'; |
|
|
89 test(line, line); |
|
|
90 } |
|
|
91 free(line); |
|
|
92 } else { |
|
|
93 for (; argc; argc--, argv++) { |
|
|
94 if (FLAG('l') && (dir = opendir(*argv))) { |
|
|
95 /* test directory contents */ |
|
|
96 while ((d = readdir(dir))) { |
|
|
97 r = snprintf(path, sizeof path, "%s/%s", |
|
|
98 *argv, d->d_name); |
|
|
99 if (r >= 0 && (size_t)r < sizeof path) |
|
|
100 test(path, d->d_name); |
|
|
101 } |
|
|
102 closedir(dir); |
|
|
103 } else { |
|
|
104 test(*argv, *argv); |
|
|
105 } |
|
|
106 } |
|
|
107 } |
|
|
108 return match ? 0 : 1; |
|
|
109 } |