Whamcloud - gitweb
ChangeLog, debugfs.c:
[tools/e2fsprogs.git] / misc / chattr.c
1 /*
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
19 #include <sys/types.h>
20 #include <dirent.h>
21 #include <fcntl.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <string.h>
26 #ifdef HAVE_ERRNO_H
27 #include <errno.h>
28 #endif
29 #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
38 const char * program_name = "chattr";
39
40 int add = 0;
41 int rem = 0;
42 int set = 0;
43 int set_version = 0;
44
45 unsigned long version;
46
47 int recursive = 0;
48 int verbose = 0;
49
50 unsigned long af;
51 unsigned long rf;
52 unsigned long sf;
53
54 static void fatal_error(const char * fmt_string, int errcode)
55 {
56         fprintf (stderr, fmt_string, program_name);
57         exit (errcode);
58 }
59
60 #define usage() fatal_error("usage: %s [-RV] [-+=AacdisSu] [-v version] files...\n", \
61                              1)
62
63 static 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;
84 #ifdef  EXT2_APPEND_FL
85                         case 'a':
86                                 rf |= EXT2_APPEND_FL;
87                                 rem = 1;
88                                 break;
89 #endif
90 #ifdef EXT2_NOATIME_FL
91                         case 'A':
92                                 rf |= EXT2_NOATIME_FL;
93                                 rem = 1;
94                                 break;
95 #endif
96                         case 'c':
97                                 rf |= EXT2_COMPR_FL;
98                                 rem = 1;
99                                 break;
100 #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
112                         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':
121                                 (*i)++;
122                                 if (*i >= argc)
123                                         usage ();
124                                 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;
147 #ifdef  EXT2_APPEND_FL
148                         case 'a':
149                                 af |= EXT2_APPEND_FL;
150                                 break;
151 #endif
152 #ifdef EXT2_NOATIME_FL
153                         case 'A':
154                                 af |= EXT2_NOATIME_FL;
155                                 break;
156 #endif
157                         case 'c':
158                                 af |= EXT2_COMPR_FL;
159                                 break;
160 #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
170                         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;
188 #ifdef  EXT2_APPEND_FL
189                         case 'a':
190                                 sf |= EXT2_APPEND_FL;
191                                 break;
192 #endif
193 #ifdef EXT2_NOATIME_FL
194                         case 'A':
195                                 sf |= EXT2_NOATIME_FL;
196                                 break;
197 #endif
198                         case 'c':
199                                 sf |= EXT2_COMPR_FL;
200                                 break;
201 #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
211                         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
228 static int chattr_dir_proc (const char *, struct dirent *, void *);
229
230 static 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);
245                         print_flags (stdout, sf, 0);
246                         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);
265                                 print_flags (stdout, flags, 0);
266                                 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
285 static int chattr_dir_proc (const char * dir_name, struct dirent * de, void * private)
286 {
287         if (strcmp (de->d_name, ".") && strcmp (de->d_name, ".."))
288         {
289                 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);
295                 sprintf (path, "%s/%s", dir_name, de->d_name);
296                 change_attributes (path);
297                 free(path);
298         }
299         return 0;
300 }
301
302 int main (int argc, char ** argv)
303 {
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         }
327         if (!(add || rem || set || set_version))
328         {
329                 fprintf (stderr, "Must use '-v', =, - or +\n");
330                 exit (1);
331         }
332         for (j = i; j < argc; j++)
333                 change_attributes (argv[j]);
334         exit(0);
335 }