blob: c8c92453a6e266e2a7995d193675cf54cee125c9 [file] [log] [blame]
Theodore Ts'o3839e651997-04-26 13:21:57 +00001/*
2 * chattr.c - Change file attributes on an ext2 file system
3 *
4 * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
5 * Laboratoire MASI, Institut Blaise Pascal
6 * Universite Pierre et Marie Curie (Paris VI)
7 *
8 * This file can be redistributed under the terms of the GNU General
9 * Public License
10 */
11
12/*
13 * History:
14 * 93/10/30 - Creation
15 * 93/11/13 - Replace stat() calls by lstat() to avoid loops
16 * 94/02/27 - Integrated in Ted's distribution
17 */
18
Theodore Ts'oa418d3a1997-04-26 14:00:26 +000019#include <sys/types.h>
Theodore Ts'o3839e651997-04-26 13:21:57 +000020#include <dirent.h>
21#include <fcntl.h>
Theodore Ts'o3839e651997-04-26 13:21:57 +000022#include <stdio.h>
23#include <stdlib.h>
24#include <unistd.h>
Theodore Ts'o19c78dc1997-04-29 16:17:09 +000025#include <string.h>
Theodore Ts'oa418d3a1997-04-26 14:00:26 +000026#ifdef HAVE_ERRNO_H
27#include <errno.h>
28#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +000029#include <sys/param.h>
30#include <sys/stat.h>
31#include <linux/ext2_fs.h>
32
33#include "et/com_err.h"
34#include "e2p/e2p.h"
35
36#include "../version.h"
37
38const char * program_name = "chattr";
39
40int add = 0;
41int rem = 0;
42int set = 0;
43int set_version = 0;
44
45unsigned long version;
46
47int recursive = 0;
48int verbose = 0;
49
50unsigned long af;
51unsigned long rf;
52unsigned long sf;
53
Theodore Ts'o818180c1998-06-27 05:11:14 +000054static void fatal_error(const char * fmt_string, int errcode)
Theodore Ts'o3839e651997-04-26 13:21:57 +000055{
56 fprintf (stderr, fmt_string, program_name);
57 exit (errcode);
58}
59
Theodore Ts'o818180c1998-06-27 05:11:14 +000060#define usage() fatal_error("usage: %s [-RV] [-+=AacdisSu] [-v version] files...\n", \
Theodore Ts'o3839e651997-04-26 13:21:57 +000061 1)
62
63static int decode_arg (int * i, int argc, char ** argv)
64{
65 char * p;
66 char * tmp;
67
68 switch (argv[*i][0])
69 {
70 case '-':
71 for (p = &argv[*i][1]; *p; p++)
72 switch (*p)
73 {
74 case 'R':
75 recursive = 1;
76 break;
77 case 'S':
78 rf |= EXT2_SYNC_FL;
79 rem = 1;
80 break;
81 case 'V':
82 verbose = 1;
83 break;
Theodore Ts'of3db3561997-04-26 13:34:30 +000084#ifdef EXT2_APPEND_FL
85 case 'a':
86 rf |= EXT2_APPEND_FL;
87 rem = 1;
88 break;
89#endif
Theodore Ts'o5c576471997-04-29 15:29:49 +000090#ifdef EXT2_NOATIME_FL
91 case 'A':
92 rf |= EXT2_NOATIME_FL;
93 rem = 1;
94 break;
95#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +000096 case 'c':
97 rf |= EXT2_COMPR_FL;
98 rem = 1;
99 break;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000100#ifdef EXT2_NODUMP_FL
101 case 'd':
102 rf |= EXT2_NODUMP_FL;
103 rem = 1;
104 break;
105#endif
106#ifdef EXT2_IMMUTABLE_FL
107 case 'i':
108 rf |= EXT2_IMMUTABLE_FL;
109 rem = 1;
110 break;
111#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000112 case 's':
113 rf |= EXT2_SECRM_FL;
114 rem = 1;
115 break;
116 case 'u':
117 rf |= EXT2_UNRM_FL;
118 rem = 1;
119 break;
120 case 'v':
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000121 (*i)++;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000122 if (*i >= argc)
123 usage ();
Theodore Ts'o3839e651997-04-26 13:21:57 +0000124 version = strtol (argv[*i], &tmp, 0);
125 if (*tmp)
126 {
127 com_err (program_name, 0,
128 "bad version - %s\n", argv[*i]);
129 usage ();
130 }
131 set_version = 1;
132 break;
133 default:
134 fprintf (stderr, "%s: Unrecognized argument: %c\n",
135 program_name, *p);
136 usage ();
137 }
138 break;
139 case '+':
140 add = 1;
141 for (p = &argv[*i][1]; *p; p++)
142 switch (*p)
143 {
144 case 'S':
145 af |= EXT2_SYNC_FL;
146 break;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000147#ifdef EXT2_APPEND_FL
148 case 'a':
149 af |= EXT2_APPEND_FL;
150 break;
151#endif
Theodore Ts'o5c576471997-04-29 15:29:49 +0000152#ifdef EXT2_NOATIME_FL
153 case 'A':
154 af |= EXT2_NOATIME_FL;
155 break;
156#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000157 case 'c':
158 af |= EXT2_COMPR_FL;
159 break;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000160#ifdef EXT2_NODUMP_FL
161 case 'd':
162 af |= EXT2_NODUMP_FL;
163 break;
164#endif
165#ifdef EXT2_IMMUTABLE_FL
166 case 'i':
167 af |= EXT2_IMMUTABLE_FL;
168 break;
169#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000170 case 's':
171 af |= EXT2_SECRM_FL;
172 break;
173 case 'u':
174 af |= EXT2_UNRM_FL;
175 break;
176 default:
177 usage ();
178 }
179 break;
180 case '=':
181 set = 1;
182 for (p = &argv[*i][1]; *p; p++)
183 switch (*p)
184 {
185 case 'S':
186 sf |= EXT2_SYNC_FL;
187 break;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000188#ifdef EXT2_APPEND_FL
189 case 'a':
190 sf |= EXT2_APPEND_FL;
191 break;
192#endif
Theodore Ts'o5c576471997-04-29 15:29:49 +0000193#ifdef EXT2_NOATIME_FL
194 case 'A':
195 sf |= EXT2_NOATIME_FL;
196 break;
197#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000198 case 'c':
199 sf |= EXT2_COMPR_FL;
200 break;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000201#ifdef EXT2_NODUMP_FL
202 case 'd':
203 sf |= EXT2_NODUMP_FL;
204 break;
205#endif
206#ifdef EXT2_IMMUTABLE_FL
207 case 'i':
208 sf |= EXT2_IMMUTABLE_FL;
209 break;
210#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000211 case 's':
212 sf |= EXT2_SECRM_FL;
213 break;
214 case 'u':
215 sf |= EXT2_UNRM_FL;
216 break;
217 default:
218 usage ();
219 }
220 break;
221 default:
222 return EOF;
223 break;
224 }
225 return 1;
226}
227
228static int chattr_dir_proc (const char *, struct dirent *, void *);
229
230static void change_attributes (const char * name)
231{
232 unsigned long flags;
233 struct stat st;
234
235 if (lstat (name, &st) == -1)
236 {
237 com_err (program_name, errno, "while stating %s", name);
238 return;
239 }
240 if (set)
241 {
242 if (verbose)
243 {
244 printf ("Flags of %s set as ", name);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000245 print_flags (stdout, sf, 0);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000246 printf ("\n");
247 }
248 if (fsetflags (name, sf) == -1)
249 perror (name);
250 }
251 else
252 {
253 if (fgetflags (name, &flags) == -1)
254 com_err (program_name, errno,
255 "while reading flags on %s", name);
256 else
257 {
258 if (rem)
259 flags &= ~rf;
260 if (add)
261 flags |= af;
262 if (verbose)
263 {
264 printf ("Flags of %s set as ", name);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000265 print_flags (stdout, flags, 0);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000266 printf ("\n");
267 }
268 if (fsetflags (name, flags) == -1)
269 com_err (program_name, errno,
270 "while setting flags on %s", name);
271 }
272 }
273 if (set_version)
274 {
275 if (verbose)
276 printf ("Version of %s set as %lu\n", name, version);
277 if (fsetversion (name, version) == -1)
278 com_err (program_name, errno,
279 "while setting version on %s", name);
280 }
281 if (S_ISDIR(st.st_mode) && recursive)
282 iterate_on_dir (name, chattr_dir_proc, (void *) NULL);
283}
284
285static int chattr_dir_proc (const char * dir_name, struct dirent * de, void * private)
286{
Theodore Ts'o3839e651997-04-26 13:21:57 +0000287 if (strcmp (de->d_name, ".") && strcmp (de->d_name, ".."))
288 {
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000289 char *path;
290
291 path = malloc(strlen (dir_name) + 1 + strlen (de->d_name) + 1);
292 if (!path)
293 fatal_error("Couldn't allocate path variable "
294 "in chattr_dir_proc", 1);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000295 sprintf (path, "%s/%s", dir_name, de->d_name);
296 change_attributes (path);
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000297 free(path);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000298 }
299 return 0;
300}
301
Theodore Ts'o00e54331997-09-16 02:13:52 +0000302int main (int argc, char ** argv)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000303{
304 int i, j;
305 int end_arg = 0;
306
307 fprintf (stderr, "chattr %s, %s for EXT2 FS %s, %s\n",
308 E2FSPROGS_VERSION, E2FSPROGS_DATE,
309 EXT2FS_VERSION, EXT2FS_DATE);
310 if (argc && *argv)
311 program_name = *argv;
312 i = 1;
313 while (i < argc && !end_arg)
314 {
315 if (decode_arg (&i, argc, argv) == EOF)
316 end_arg = 1;
317 else
318 i++;
319 }
320 if (i >= argc)
321 usage ();
322 if (set && (add || rem))
323 {
324 fprintf (stderr, "= is incompatible with - and +\n");
325 exit (1);
326 }
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000327 if (!(add || rem || set || set_version))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000328 {
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000329 fprintf (stderr, "Must use '-v', =, - or +\n");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000330 exit (1);
331 }
332 for (j = i; j < argc; j++)
333 change_attributes (argv[j]);
Theodore Ts'o00e54331997-09-16 02:13:52 +0000334 exit(0);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000335}