diff options
Diffstat (limited to 'stest.c')
-rw-r--r-- | stest.c | 84 |
1 files changed, 84 insertions, 0 deletions
@@ -0,0 +1,84 @@ | |||
1 | /* See LICENSE file for copyright and license details. */ | ||
2 | #include <dirent.h> | ||
3 | #include <stdbool.h> | ||
4 | #include <stdio.h> | ||
5 | #include <stdlib.h> | ||
6 | #include <string.h> | ||
7 | #include <unistd.h> | ||
8 | #include <sys/stat.h> | ||
9 | |||
10 | #define FLAG(x) (flag[(x)-'a']) | ||
11 | |||
12 | static void test(const char *, const char *); | ||
13 | |||
14 | static bool match = false; | ||
15 | static bool flag[26]; | ||
16 | static struct stat old, new; | ||
17 | |||
18 | int | ||
19 | main(int argc, char *argv[]) { | ||
20 | struct dirent *d; | ||
21 | char buf[BUFSIZ], *p; | ||
22 | DIR *dir; | ||
23 | int opt; | ||
24 | |||
25 | while((opt = getopt(argc, argv, "abcdefghln:o:pqrsuwx")) != -1) | ||
26 | switch(opt) { | ||
27 | case 'n': /* newer than file */ | ||
28 | case 'o': /* older than file */ | ||
29 | if(!(FLAG(opt) = !stat(optarg, (opt == 'n' ? &new : &old)))) | ||
30 | perror(optarg); | ||
31 | break; | ||
32 | default: /* miscellaneous operators */ | ||
33 | FLAG(opt) = true; | ||
34 | break; | ||
35 | case '?': /* error: unknown flag */ | ||
36 | fprintf(stderr, "usage: %s [-abcdefghlpqrsuwx] [-n file] [-o file] [file...]\n", argv[0]); | ||
37 | exit(2); | ||
38 | } | ||
39 | if(optind == argc) | ||
40 | while(fgets(buf, sizeof buf, stdin)) { | ||
41 | if((p = strchr(buf, '\n'))) | ||
42 | *p = '\0'; | ||
43 | test(buf, buf); | ||
44 | } | ||
45 | for(; optind < argc; optind++) | ||
46 | if(FLAG('l') && (dir = opendir(argv[optind]))) { | ||
47 | /* test directory contents */ | ||
48 | while((d = readdir(dir))) | ||
49 | if(snprintf(buf, sizeof buf, "%s/%s", argv[optind], d->d_name) < sizeof buf) | ||
50 | test(buf, d->d_name); | ||
51 | closedir(dir); | ||
52 | } | ||
53 | else | ||
54 | test(argv[optind], argv[optind]); | ||
55 | |||
56 | return match ? 0 : 1; | ||
57 | } | ||
58 | |||
59 | void | ||
60 | test(const char *path, const char *name) { | ||
61 | struct stat st, ln; | ||
62 | |||
63 | if(!stat(path, &st) && (FLAG('a') || name[0] != '.') /* hidden files */ | ||
64 | && (!FLAG('b') || S_ISBLK(st.st_mode)) /* block special */ | ||
65 | && (!FLAG('c') || S_ISCHR(st.st_mode)) /* character special */ | ||
66 | && (!FLAG('d') || S_ISDIR(st.st_mode)) /* directory */ | ||
67 | && (!FLAG('e') || access(path, F_OK) == 0) /* exists */ | ||
68 | && (!FLAG('f') || S_ISREG(st.st_mode)) /* regular file */ | ||
69 | && (!FLAG('g') || st.st_mode & S_ISGID) /* set-group-id flag */ | ||
70 | && (!FLAG('h') || (!lstat(path, &ln) && S_ISLNK(ln.st_mode))) /* symbolic link */ | ||
71 | && (!FLAG('n') || st.st_mtime > new.st_mtime) /* newer than file */ | ||
72 | && (!FLAG('o') || st.st_mtime < old.st_mtime) /* older than file */ | ||
73 | && (!FLAG('p') || S_ISFIFO(st.st_mode)) /* named pipe */ | ||
74 | && (!FLAG('r') || access(path, R_OK) == 0) /* readable */ | ||
75 | && (!FLAG('s') || st.st_size > 0) /* not empty */ | ||
76 | && (!FLAG('u') || st.st_mode & S_ISUID) /* set-user-id flag */ | ||
77 | && (!FLAG('w') || access(path, W_OK) == 0) /* writable */ | ||
78 | && (!FLAG('x') || access(path, X_OK) == 0)) { /* executable */ | ||
79 | if(FLAG('q')) | ||
80 | exit(0); | ||
81 | match = true; | ||
82 | puts(name); | ||
83 | } | ||
84 | } | ||