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
45
46
47
48
49
50
51
52
53
54#include "libbb.h"
55#include "e2fs_lib.h"
56
57#define OPT_ADD (1 << 0)
58#define OPT_REM (1 << 1)
59#define OPT_SET (1 << 2)
60#define OPT_SET_VER (1 << 3)
61#define OPT_SET_PROJ (1 << 4)
62
63struct globals {
64 unsigned version;
65 unsigned af;
66 unsigned rf;
67 int flags;
68 uint32_t projid;
69 smallint recursive;
70};
71
72static unsigned long get_flag(char c)
73{
74 const char *fp = strchr(e2attr_flags_sname_chattr, c);
75 if (fp)
76 return e2attr_flags_value_chattr[fp - e2attr_flags_sname_chattr];
77 bb_show_usage();
78}
79
80static char** decode_arg(char **argv, struct globals *gp)
81{
82 unsigned *fl;
83 const char *arg = *argv;
84 char opt = *arg;
85
86 fl = &gp->af;
87 if (opt == '-') {
88
89
90
91 fl = &gp->rf;
92 } else if (opt == '+') {
93 gp->flags |= OPT_ADD;
94 } else {
95 gp->flags |= OPT_SET;
96 }
97
98 while (*++arg) {
99 if (opt == '-') {
100
101
102
103
104
105 if (*arg == 'R') {
106 gp->recursive = 1;
107 continue;
108 }
109 if (*arg == 'V') {
110 ;
111 continue;
112 }
113 if (*arg == 'f') {
114 ;
115 continue;
116 }
117 if (*arg == 'v') {
118 if (!*++argv)
119 bb_show_usage();
120 gp->version = xatou(*argv);
121 gp->flags |= OPT_SET_VER;
122 continue;
123 }
124 if (*arg == 'p') {
125 if (!*++argv)
126 bb_show_usage();
127 gp->projid = xatou32(*argv);
128 gp->flags |= OPT_SET_PROJ;
129 continue;
130 }
131
132 gp->flags |= OPT_REM;
133 }
134 *fl |= get_flag(*arg);
135 }
136
137 return argv;
138}
139
140static void change_attributes(const char *name, struct globals *gp);
141
142static int FAST_FUNC chattr_dir_proc(const char *dir_name, struct dirent *de, void *gp)
143{
144
145
146 char *path = concat_subpath_file(dir_name, de->d_name);
147
148 if (path) {
149 change_attributes(path, gp);
150 free(path);
151 }
152 return 0;
153}
154
155static void change_attributes(const char *name, struct globals *gp)
156{
157 unsigned fsflags;
158 int fd;
159 struct stat st;
160
161 if (lstat(name, &st) != 0) {
162 bb_perror_msg("can't stat '%s'", name);
163 return;
164 }
165
166
167
168
169
170 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) && !S_ISDIR(st.st_mode))
171 return;
172
173
174
175
176
177
178 fd = open_or_warn(name, O_RDONLY | O_NONBLOCK | O_NOCTTY | O_NOFOLLOW);
179 if (fd >= 0) {
180 int r;
181
182 if (gp->flags & OPT_SET_VER) {
183 r = ioctl(fd, EXT2_IOC_SETVERSION, &gp->version);
184 if (r != 0)
185 bb_perror_msg("setting %s on %s", "version", name);
186 }
187
188 if (gp->flags & OPT_SET_PROJ) {
189 struct ext2_fsxattr fsxattr;
190 r = ioctl(fd, EXT2_IOC_FSGETXATTR, &fsxattr);
191
192 if (r != 0) {
193 bb_perror_msg("getting %s on %s", "project ID", name);
194 } else {
195 fsxattr.fsx_projid = gp->projid;
196 r = ioctl(fd, EXT2_IOC_FSSETXATTR, &fsxattr);
197 if (r != 0)
198 bb_perror_msg("setting %s on %s", "project ID", name);
199 }
200 }
201
202 if (gp->flags & OPT_SET) {
203 fsflags = gp->af;
204 } else {
205 r = ioctl(fd, EXT2_IOC_GETFLAGS, &fsflags);
206 if (r != 0) {
207 bb_perror_msg("getting %s on %s", "flags", name);
208 goto skip_setflags;
209 }
210
211 fsflags &= ~gp->rf;
212
213 fsflags |= gp->af;
214
215 if (!S_ISDIR(st.st_mode))
216 fsflags &= ~EXT2_DIRSYNC_FL;
217 }
218 r = ioctl(fd, EXT2_IOC_SETFLAGS, &fsflags);
219 if (r != 0)
220 bb_perror_msg("setting %s on %s", "flags", name);
221 skip_setflags:
222 close(fd);
223 }
224
225 if (gp->recursive && S_ISDIR(st.st_mode))
226 iterate_on_dir(name, chattr_dir_proc, gp);
227}
228
229int chattr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
230int chattr_main(int argc UNUSED_PARAM, char **argv)
231{
232 struct globals g;
233
234 memset(&g, 0, sizeof(g));
235
236
237 for (;;) {
238 char *arg = *++argv;
239 if (!arg)
240 bb_show_usage();
241 if (arg[0] != '-' && arg[0] != '+' && arg[0] != '=')
242 break;
243
244 argv = decode_arg(argv, &g);
245 }
246
247
248
249 if ((g.flags & OPT_SET) && (g.flags & (OPT_ADD|OPT_REM)))
250 bb_simple_error_msg_and_die("= is incompatible with - and +");
251 if (g.rf & g.af)
252 bb_simple_error_msg_and_die("can't set and unset a flag");
253 if (!g.flags)
254 bb_simple_error_msg_and_die("must use -v, -p, =, - or +");
255
256
257 do change_attributes(*argv, &g); while (*++argv);
258
259 return EXIT_SUCCESS;
260}
261