]>
Commit | Line | Data |
---|---|---|
2ac030ae | 1 | /* |
da23017d NS |
2 | * Copyright (c) 2003-2005 Silicon Graphics, Inc. |
3 | * All Rights Reserved. | |
2ac030ae | 4 | * |
da23017d NS |
5 | * This program is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU General Public License as | |
2ac030ae NS |
7 | * published by the Free Software Foundation. |
8 | * | |
da23017d NS |
9 | * This program is distributed in the hope that it would be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
2ac030ae | 13 | * |
da23017d NS |
14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program; if not, write the Free Software Foundation, | |
16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
2ac030ae NS |
17 | */ |
18 | ||
897853d5 DC |
19 | #include "xfs/xfs.h" |
20 | #include "xfs/command.h" | |
21 | #include "xfs/input.h" | |
2ac030ae NS |
22 | #include "init.h" |
23 | #include "io.h" | |
24 | ||
25 | static cmdinfo_t chattr_cmd; | |
26 | static cmdinfo_t lsattr_cmd; | |
45532840 NS |
27 | static unsigned int orflags; |
28 | static unsigned int andflags; | |
3d93ccb7 NS |
29 | unsigned int recurse_all; |
30 | unsigned int recurse_dir; | |
2ac030ae | 31 | |
2ac030ae NS |
32 | static struct xflags { |
33 | uint flag; | |
34 | char *shortname; | |
35 | char *longname; | |
36 | } xflags[] = { | |
ae541a2b NS |
37 | { XFS_XFLAG_REALTIME, "r", "realtime" }, |
38 | { XFS_XFLAG_PREALLOC, "p", "prealloc" }, | |
39 | { XFS_XFLAG_IMMUTABLE, "i", "immutable" }, | |
40 | { XFS_XFLAG_APPEND, "a", "append-only" }, | |
41 | { XFS_XFLAG_SYNC, "s", "sync" }, | |
42 | { XFS_XFLAG_NOATIME, "A", "no-atime" }, | |
43 | { XFS_XFLAG_NODUMP, "d", "no-dump" }, | |
44 | { XFS_XFLAG_RTINHERIT, "t", "rt-inherit" }, | |
45 | { XFS_XFLAG_PROJINHERIT, "P", "proj-inherit" }, | |
46 | { XFS_XFLAG_NOSYMLINKS, "n", "nosymlinks" }, | |
47 | { XFS_XFLAG_EXTSIZE, "e", "extsize" }, | |
48 | { XFS_XFLAG_EXTSZINHERIT, "E", "extsz-inherit" }, | |
2d5121ac BN |
49 | { XFS_XFLAG_NODEFRAG, "f", "no-defrag" }, |
50 | { XFS_XFLAG_FILESTREAM, "S", "filestream" }, | |
2ac030ae NS |
51 | { 0, NULL, NULL } |
52 | }; | |
2d5121ac | 53 | #define CHATTR_XFLAG_LIST "r"/*p*/"iasAdtPneEfS" |
2ac030ae NS |
54 | |
55 | static void | |
56 | lsattr_help(void) | |
57 | { | |
58 | printf(_( | |
59 | "\n" | |
60 | " displays the set of extended inode flags associated with the current file\n" | |
61 | "\n" | |
62 | " Each individual flag is displayed as a single character, in this order:\n" | |
63 | " r -- file data is stored in the realtime section\n" | |
64 | " p -- file has preallocated extents (cannot be changed using chattr)\n" | |
65 | " i -- immutable, file cannot be modified\n" | |
66 | " a -- append-only, file can only be appended to\n" | |
67 | " s -- all updates are synchronous\n" | |
68 | " A -- the access time is not updated for this inode\n" | |
69 | " d -- do not include this file in a dump of the filesystem\n" | |
70 | " t -- child created in this directory has realtime bit set by default\n" | |
71 | " P -- child created in this directory has parents project ID by default\n" | |
72 | " n -- symbolic links cannot be created in this directory\n" | |
ae541a2b NS |
73 | " e -- for non-realtime files, observe the inode extent size value\n" |
74 | " E -- children created in this directory inherit the extent size value\n" | |
ed832ad2 | 75 | " f -- do not include this file when defragmenting the filesystem\n" |
2d5121ac | 76 | " S -- enable filestreams allocator for this directory\n" |
2ac030ae NS |
77 | "\n" |
78 | " Options:\n" | |
45532840 NS |
79 | " -R -- recursively descend (useful when current file is a directory)\n" |
80 | " -D -- recursively descend, but only list attributes on directories\n" | |
2ac030ae NS |
81 | " -a -- show all flags which can be set alongside those which are set\n" |
82 | " -v -- verbose mode; show long names of flags, not single characters\n" | |
83 | "\n")); | |
84 | } | |
85 | ||
86 | static void | |
87 | chattr_help(void) | |
88 | { | |
89 | printf(_( | |
90 | "\n" | |
91 | " modifies the set of extended inode flags associated with the current file\n" | |
92 | "\n" | |
93 | " Examples:\n" | |
94 | " 'chattr +a' - sets the append-only flag\n" | |
95 | " 'chattr -a' - clears the append-only flag\n" | |
96 | "\n" | |
45532840 NS |
97 | " -R -- recursively descend (useful when current file is a directory)\n" |
98 | " -D -- recursively descend, only modifying attributes on directories\n" | |
2ac030ae NS |
99 | " +/-r -- set/clear the realtime flag\n" |
100 | " +/-i -- set/clear the immutable flag\n" | |
101 | " +/-a -- set/clear the append-only flag\n" | |
102 | " +/-s -- set/clear the sync flag\n" | |
103 | " +/-A -- set/clear the no-atime flag\n" | |
104 | " +/-d -- set/clear the no-dump flag\n" | |
105 | " +/-t -- set/clear the realtime inheritance flag\n" | |
106 | " +/-P -- set/clear the project ID inheritance flag\n" | |
107 | " +/-n -- set/clear the no-symbolic-links flag\n" | |
ae541a2b NS |
108 | " +/-e -- set/clear the extent-size flag\n" |
109 | " +/-E -- set/clear the extent-size inheritance flag\n" | |
ed832ad2 | 110 | " +/-f -- set/clear the no-defrag flag\n" |
2d5121ac | 111 | " +/-S -- set/clear the filestreams allocator flag\n" |
2ac030ae NS |
112 | " Note1: user must have certain capabilities to modify immutable/append-only.\n" |
113 | " Note2: immutable/append-only files cannot be deleted; removing these files\n" | |
114 | " requires the immutable/append-only flag to be cleared first.\n" | |
115 | " Note3: the realtime flag can only be set if the filesystem has a realtime\n" | |
116 | " section, and the (regular) file must be empty when the flag is set.\n" | |
117 | "\n")); | |
118 | } | |
119 | ||
120 | void | |
121 | printxattr( | |
122 | uint flags, | |
123 | int verbose, | |
124 | int dofname, | |
125 | const char *fname, | |
126 | int dobraces, | |
127 | int doeol) | |
128 | { | |
129 | struct xflags *p; | |
130 | int first = 1; | |
131 | ||
132 | if (dobraces) | |
133 | fputs("[", stdout); | |
134 | for (p = xflags; p->flag; p++) { | |
135 | if (flags & p->flag) { | |
136 | if (verbose) { | |
137 | if (first) | |
138 | first = 0; | |
139 | else | |
140 | fputs(", ", stdout); | |
141 | fputs(p->longname, stdout); | |
142 | } else { | |
143 | fputs(p->shortname, stdout); | |
144 | } | |
145 | } else if (!verbose) { | |
146 | fputs("-", stdout); | |
147 | } | |
148 | } | |
149 | if (dobraces) | |
150 | fputs("]", stdout); | |
151 | if (dofname) | |
152 | printf(" %s ", fname); | |
153 | if (doeol) | |
154 | fputs("\n", stdout); | |
155 | } | |
156 | ||
45532840 NS |
157 | static int |
158 | lsattr_callback( | |
159 | const char *path, | |
160 | const struct stat *stat, | |
161 | int status, | |
162 | struct FTW *data) | |
163 | { | |
164 | struct fsxattr fsx; | |
165 | int fd; | |
166 | ||
167 | if (recurse_dir && !S_ISDIR(stat->st_mode)) | |
168 | return 0; | |
169 | ||
170 | if ((fd = open(path, O_RDONLY)) == -1) | |
171 | fprintf(stderr, _("%s: cannot open %s: %s\n"), | |
172 | progname, path, strerror(errno)); | |
173 | else if ((xfsctl(path, fd, XFS_IOC_FSGETXATTR, &fsx)) < 0) | |
174 | fprintf(stderr, _("%s: cannot get flags on %s: %s\n"), | |
175 | progname, path, strerror(errno)); | |
176 | else | |
177 | printxattr(fsx.fsx_xflags, 0, 1, path, 0, 1); | |
178 | ||
179 | if (fd != -1) | |
180 | close(fd); | |
181 | return 0; | |
182 | } | |
183 | ||
2ac030ae NS |
184 | static int |
185 | lsattr_f( | |
186 | int argc, | |
187 | char **argv) | |
188 | { | |
189 | struct fsxattr fsx; | |
190 | char *name = file->name; | |
191 | int c, aflag = 0, vflag = 0; | |
192 | ||
45532840 NS |
193 | recurse_all = recurse_dir = 0; |
194 | while ((c = getopt(argc, argv, "DRav")) != EOF) { | |
2ac030ae | 195 | switch (c) { |
45532840 NS |
196 | case 'D': |
197 | recurse_all = 0; | |
198 | recurse_dir = 1; | |
199 | break; | |
200 | case 'R': | |
201 | recurse_all = 1; | |
202 | recurse_dir = 0; | |
203 | break; | |
2ac030ae NS |
204 | case 'a': |
205 | aflag = 1; | |
206 | vflag = 0; | |
207 | break; | |
208 | case 'v': | |
209 | aflag = 0; | |
210 | vflag = 1; | |
211 | break; | |
212 | default: | |
45532840 | 213 | return command_usage(&lsattr_cmd); |
2ac030ae NS |
214 | } |
215 | } | |
216 | ||
45532840 NS |
217 | if (recurse_all || recurse_dir) { |
218 | nftw(name, lsattr_callback, | |
219 | 100, FTW_PHYS | FTW_MOUNT | FTW_DEPTH); | |
220 | } else if ((xfsctl(name, file->fd, XFS_IOC_FSGETXATTR, &fsx)) < 0) { | |
221 | fprintf(stderr, _("%s: cannot get flags on %s: %s\n"), | |
222 | progname, name, strerror(errno)); | |
2ac030ae NS |
223 | } else { |
224 | printxattr(fsx.fsx_xflags, vflag, !aflag, name, vflag, !aflag); | |
225 | if (aflag) { | |
226 | fputs("/", stdout); | |
227 | printxattr(-1, 0, 1, name, 0, 1); | |
228 | } | |
229 | } | |
230 | return 0; | |
231 | } | |
232 | ||
45532840 NS |
233 | static int |
234 | chattr_callback( | |
235 | const char *path, | |
236 | const struct stat *stat, | |
237 | int status, | |
238 | struct FTW *data) | |
239 | { | |
240 | struct fsxattr attr; | |
241 | int fd; | |
242 | ||
243 | if (recurse_dir && !S_ISDIR(stat->st_mode)) | |
244 | return 0; | |
245 | ||
246 | if ((fd = open(path, O_RDONLY)) == -1) { | |
247 | fprintf(stderr, _("%s: cannot open %s: %s\n"), | |
248 | progname, path, strerror(errno)); | |
249 | } else if (xfsctl(path, fd, XFS_IOC_FSGETXATTR, &attr) < 0) { | |
250 | fprintf(stderr, _("%s: cannot get flags on %s: %s\n"), | |
251 | progname, path, strerror(errno)); | |
252 | } else { | |
253 | attr.fsx_xflags |= orflags; | |
254 | attr.fsx_xflags &= ~andflags; | |
255 | if (xfsctl(path, fd, XFS_IOC_FSSETXATTR, &attr) < 0) | |
256 | fprintf(stderr, _("%s: cannot set flags on %s: %s\n"), | |
257 | progname, path, strerror(errno)); | |
258 | } | |
259 | ||
260 | if (fd != -1) | |
261 | close(fd); | |
262 | return 0; | |
263 | } | |
264 | ||
2ac030ae NS |
265 | static int |
266 | chattr_f( | |
267 | int argc, | |
268 | char **argv) | |
269 | { | |
270 | struct fsxattr attr; | |
271 | struct xflags *p; | |
272 | unsigned int i = 0; | |
273 | char *c, *name = file->name; | |
274 | ||
45532840 NS |
275 | orflags = andflags = 0; |
276 | recurse_all = recurse_dir = 0; | |
2ac030ae | 277 | while (++i < argc) { |
45532840 NS |
278 | if (argv[i][0] == '-' && argv[i][1] == 'R') { |
279 | recurse_all = 1; | |
280 | } else if (argv[i][0] == '-' && argv[i][1] == 'D') { | |
281 | recurse_dir = 1; | |
282 | } else if (argv[i][0] == '+') { | |
2ac030ae NS |
283 | for (c = &argv[i][1]; *c; c++) { |
284 | for (p = xflags; p->flag; p++) { | |
285 | if (strncmp(p->shortname, c, 1) == 0) { | |
45532840 | 286 | orflags |= p->flag; |
2ac030ae NS |
287 | break; |
288 | } | |
289 | } | |
290 | if (!p->flag) { | |
291 | fprintf(stderr, _("%s: unknown flag\n"), | |
292 | progname); | |
293 | return 0; | |
294 | } | |
295 | } | |
296 | } else if (argv[i][0] == '-') { | |
297 | for (c = &argv[i][1]; *c; c++) { | |
298 | for (p = xflags; p->flag; p++) { | |
299 | if (strncmp(p->shortname, c, 1) == 0) { | |
45532840 | 300 | andflags |= p->flag; |
2ac030ae NS |
301 | break; |
302 | } | |
303 | } | |
304 | if (!p->flag) { | |
305 | fprintf(stderr, _("%s: unknown flag\n"), | |
306 | progname); | |
307 | return 0; | |
308 | } | |
309 | } | |
310 | } else { | |
311 | fprintf(stderr, _("%s: bad chattr command, not +/-X\n"), | |
312 | progname); | |
313 | return 0; | |
314 | } | |
315 | } | |
45532840 NS |
316 | |
317 | if (recurse_all || recurse_dir) { | |
318 | nftw(name, chattr_callback, | |
319 | 100, FTW_PHYS | FTW_MOUNT | FTW_DEPTH); | |
320 | } else if (xfsctl(name, file->fd, XFS_IOC_FSGETXATTR, &attr) < 0) { | |
321 | fprintf(stderr, _("%s: cannot get flags on %s: %s\n"), | |
322 | progname, name, strerror(errno)); | |
323 | } else { | |
324 | attr.fsx_xflags |= orflags; | |
325 | attr.fsx_xflags &= ~andflags; | |
326 | if (xfsctl(name, file->fd, XFS_IOC_FSSETXATTR, &attr) < 0) | |
327 | fprintf(stderr, _("%s: cannot set flags on %s: %s\n"), | |
328 | progname, name, strerror(errno)); | |
329 | } | |
2ac030ae NS |
330 | return 0; |
331 | } | |
332 | ||
333 | void | |
334 | attr_init(void) | |
335 | { | |
ad765595 | 336 | chattr_cmd.name = "chattr"; |
2ac030ae | 337 | chattr_cmd.cfunc = chattr_f; |
45532840 | 338 | chattr_cmd.args = _("[-R|-D] [+/-"CHATTR_XFLAG_LIST"]"); |
2ac030ae NS |
339 | chattr_cmd.argmin = 1; |
340 | chattr_cmd.argmax = -1; | |
341 | chattr_cmd.flags = CMD_NOMAP_OK; | |
342 | chattr_cmd.oneline = | |
343 | _("change extended inode flags on the currently open file"); | |
344 | chattr_cmd.help = chattr_help; | |
345 | ||
ad765595 | 346 | lsattr_cmd.name = "lsattr"; |
2ac030ae | 347 | lsattr_cmd.cfunc = lsattr_f; |
45532840 | 348 | lsattr_cmd.args = _("[-R|-D|-a|-v]"); |
2ac030ae NS |
349 | lsattr_cmd.argmin = 0; |
350 | lsattr_cmd.argmax = 1; | |
351 | lsattr_cmd.flags = CMD_NOMAP_OK; | |
352 | lsattr_cmd.oneline = | |
353 | _("list extended inode flags set on the currently open file"); | |
354 | lsattr_cmd.help = lsattr_help; | |
355 | ||
356 | add_command(&chattr_cmd); | |
357 | add_command(&lsattr_cmd); | |
358 | } |