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