1 | #include <ftw.h> |
2 | #include <getopt.h> |
3 | #include <mcheck.h> |
4 | #include <stdio.h> |
5 | #include <stdlib.h> |
6 | #include <string.h> |
7 | #include <unistd.h> |
8 | #include <sys/stat.h> |
9 | |
10 | |
11 | int do_depth; |
12 | int do_chdir; |
13 | int do_phys; |
14 | int do_exit; |
15 | char *skip_subtree; |
16 | char *skip_siblings; |
17 | |
18 | struct option options[] = |
19 | { |
20 | { "depth" , no_argument, &do_depth, 1 }, |
21 | { "chdir" , no_argument, &do_chdir, 1 }, |
22 | { "phys" , no_argument, &do_phys, 1 }, |
23 | { "skip-subtree" , required_argument, NULL, 't' }, |
24 | { "skip-siblings" , required_argument, NULL, 's' }, |
25 | { "early-exit" , no_argument, &do_exit, 1 }, |
26 | { NULL, 0, NULL, 0 } |
27 | }; |
28 | |
29 | const char *flag2name[] = |
30 | { |
31 | [FTW_F] = "FTW_F" , |
32 | [FTW_D] = "FTW_D" , |
33 | [FTW_DNR] = "FTW_DNR" , |
34 | [FTW_NS] = "FTW_NS" , |
35 | [FTW_SL] = "FTW_SL" , |
36 | [FTW_DP] = "FTW_DP" , |
37 | [FTW_SLN] = "FTW_SLN" |
38 | }; |
39 | |
40 | |
41 | static int |
42 | cb (const char *name, const struct stat *st, int flag, struct FTW *f) |
43 | { |
44 | if (do_exit && strcmp (name + f->base, "file@2" )) |
45 | return FTW_CONTINUE; |
46 | |
47 | printf (format: "base = \"%.*s\", file = \"%s\", flag = %s" , |
48 | f->base, name, name + f->base, flag2name[flag]); |
49 | if (do_chdir) |
50 | { |
51 | char *cwd = getcwd (NULL, size: 0); |
52 | printf (format: ", cwd = %s" , cwd); |
53 | free (ptr: cwd); |
54 | } |
55 | printf (format: ", level = %d\n" , f->level); |
56 | |
57 | if (skip_siblings && strcmp (name + f->base, skip_siblings) == 0) |
58 | return FTW_SKIP_SIBLINGS; |
59 | |
60 | if (skip_subtree && strcmp (name + f->base, skip_subtree) == 0) |
61 | return FTW_SKIP_SUBTREE; |
62 | |
63 | return do_exit ? 26 : FTW_CONTINUE; |
64 | } |
65 | |
66 | int |
67 | main (int argc, char *argv[]) |
68 | { |
69 | int opt; |
70 | int r; |
71 | int flag = 0; |
72 | mtrace (); |
73 | |
74 | while ((opt = getopt_long_only (argc: argc, argv: argv, shortopts: "" , longopts: options, NULL)) != -1) |
75 | { |
76 | if (opt == 't') |
77 | skip_subtree = optarg; |
78 | else if (opt == 's') |
79 | skip_siblings = optarg; |
80 | } |
81 | |
82 | if (do_chdir) |
83 | flag |= FTW_CHDIR; |
84 | if (do_depth) |
85 | flag |= FTW_DEPTH; |
86 | if (do_phys) |
87 | flag |= FTW_PHYS; |
88 | if (skip_subtree || skip_siblings) |
89 | { |
90 | flag |= FTW_ACTIONRETVAL; |
91 | if (do_exit) |
92 | { |
93 | printf (format: "--early-exit cannot be used together with --skip-{siblings,subtree}" ); |
94 | exit (1); |
95 | } |
96 | } |
97 | |
98 | char *cw1 = getcwd (NULL, size: 0); |
99 | |
100 | r = nftw (dir: optind < argc ? argv[optind] : "." , func: cb, descriptors: do_exit ? 1 : 3, flag: flag); |
101 | if (r < 0) |
102 | perror ("nftw" ); |
103 | |
104 | char *cw2 = getcwd (NULL, size: 0); |
105 | |
106 | if (strcmp (cw1, cw2) != 0) |
107 | { |
108 | printf (format: "current working directory before and after nftw call differ:\n" |
109 | "before: %s\n" |
110 | "after: %s\n" , cw1, cw2); |
111 | exit (1); |
112 | } |
113 | |
114 | if (do_exit) |
115 | { |
116 | puts (s: r == 26 ? "succeeded" : "failed" ); |
117 | return r == 26 ? 0 : 1; |
118 | } |
119 | return r; |
120 | } |
121 | |