1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44#include "libbb.h"
45#include "e2fs_lib.h"
46
47#define OPT_ADD 1
48#define OPT_REM 2
49#define OPT_SET 4
50#define OPT_SET_VER 8
51
52struct globals {
53 unsigned long version;
54 unsigned long af;
55 unsigned long rf;
56 int flags;
57 smallint recursive;
58};
59
60static unsigned long get_flag(char c)
61{
62 const char *fp = strchr(e2attr_flags_sname_chattr, c);
63 if (fp)
64 return e2attr_flags_value_chattr[fp - e2attr_flags_sname_chattr];
65 bb_show_usage();
66}
67
68static char** decode_arg(char **argv, struct globals *gp)
69{
70 unsigned long *fl;
71 const char *arg = *argv;
72 char opt = *arg;
73
74 fl = &gp->af;
75 if (opt == '-') {
76 gp->flags |= OPT_REM;
77 fl = &gp->rf;
78 } else if (opt == '+') {
79 gp->flags |= OPT_ADD;
80 } else {
81 gp->flags |= OPT_SET;
82 }
83
84 while (*++arg) {
85 if (opt == '-') {
86
87
88
89
90
91 if (*arg == 'R') {
92 gp->recursive = 1;
93 continue;
94 }
95 if (*arg == 'V') {
96 ;
97 continue;
98 }
99 if (*arg == 'f') {
100 ;
101 continue;
102 }
103 if (*arg == 'v') {
104 if (!*++argv)
105 bb_show_usage();
106 gp->version = xatoul(*argv);
107 gp->flags |= OPT_SET_VER;
108 continue;
109 }
110
111
112 }
113 *fl |= get_flag(*arg);
114 }
115
116 return argv;
117}
118
119static void change_attributes(const char *name, struct globals *gp);
120
121static int FAST_FUNC chattr_dir_proc(const char *dir_name, struct dirent *de, void *gp)
122{
123 char *path = concat_subpath_file(dir_name, de->d_name);
124
125 if (path) {
126 change_attributes(path, gp);
127 free(path);
128 }
129 return 0;
130}
131
132static void change_attributes(const char *name, struct globals *gp)
133{
134 unsigned long fsflags;
135 struct stat st;
136
137 if (lstat(name, &st) != 0) {
138 bb_perror_msg("stat %s", name);
139 return;
140 }
141 if (S_ISLNK(st.st_mode) && gp->recursive)
142 return;
143
144
145
146
147
148 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) && !S_ISDIR(st.st_mode))
149 return;
150
151 if (gp->flags & OPT_SET_VER)
152 if (fsetversion(name, gp->version) != 0)
153 bb_perror_msg("setting version on %s", name);
154
155 if (gp->flags & OPT_SET) {
156 fsflags = gp->af;
157 } else {
158 if (fgetflags(name, &fsflags) != 0) {
159 bb_perror_msg("reading flags on %s", name);
160 goto skip_setflags;
161 }
162
163 fsflags &= ~gp->rf;
164
165 fsflags |= gp->af;
166
167 if (!S_ISDIR(st.st_mode))
168 fsflags &= ~EXT2_DIRSYNC_FL;
169 }
170 if (fsetflags(name, fsflags) != 0)
171 bb_perror_msg("setting flags on %s", name);
172
173 skip_setflags:
174 if (gp->recursive && S_ISDIR(st.st_mode))
175 iterate_on_dir(name, chattr_dir_proc, gp);
176}
177
178int chattr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
179int chattr_main(int argc UNUSED_PARAM, char **argv)
180{
181 struct globals g;
182
183 memset(&g, 0, sizeof(g));
184
185
186 for (;;) {
187 char *arg = *++argv;
188 if (!arg)
189 bb_show_usage();
190 if (arg[0] != '-' && arg[0] != '+' && arg[0] != '=')
191 break;
192
193 argv = decode_arg(argv, &g);
194 }
195
196
197
198 if ((g.flags & OPT_SET) && (g.flags & (OPT_ADD|OPT_REM)))
199 bb_error_msg_and_die("= is incompatible with - and +");
200 if (g.rf & g.af)
201 bb_error_msg_and_die("can't set and unset a flag");
202 if (!g.flags)
203 bb_error_msg_and_die("must use '-v', =, - or +");
204
205
206 do change_attributes(*argv, &g); while (*++argv);
207
208 return EXIT_SUCCESS;
209}
210