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