Whamcloud - gitweb
8ea4d0352f1cf055ccd307d9de156f9cbb0546bb
[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 #ifdef HAVE_GETOPT_H
23 #include <getopt.h>
24 #endif
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <string.h>
29 #ifdef HAVE_ERRNO_H
30 #include <errno.h>
31 #endif
32 #include <sys/param.h>
33 #include <sys/stat.h>
34 #include <linux/ext2_fs.h>
35
36 #include "et/com_err.h"
37 #include "e2p/e2p.h"
38
39 #include "../version.h"
40
41 const char * program_name = "chattr";
42
43 int add = 0;
44 int rem = 0;
45 int set = 0;
46 int set_version = 0;
47
48 unsigned long version;
49
50 int recursive = 0;
51 int verbose = 0;
52
53 unsigned long af;
54 unsigned long rf;
55 unsigned long sf;
56
57 static void volatile fatal_error (const char * fmt_string, int errcode)
58 {
59         fprintf (stderr, fmt_string, program_name);
60         exit (errcode);
61 }
62
63 #define usage() fatal_error ("usage: %s [-RV] [-+=AacdisSu] [-v version] files...\n", \
64                              1)
65
66 static int decode_arg (int * i, int argc, char ** argv)
67 {
68         char * p;
69         char * tmp;
70
71         switch (argv[*i][0])
72         {
73         case '-':
74                 for (p = &argv[*i][1]; *p; p++)
75                         switch (*p)
76                         {
77                         case 'R':
78                                 recursive = 1;
79                                 break;
80                         case 'S':
81                                 rf |= EXT2_SYNC_FL;
82                                 rem = 1;
83                                 break;
84                         case 'V':
85                                 verbose = 1;
86                                 break;
87 #ifdef  EXT2_APPEND_FL
88                         case 'a':
89                                 rf |= EXT2_APPEND_FL;
90                                 rem = 1;
91                                 break;
92 #endif
93 #ifdef EXT2_NOATIME_FL
94                         case 'A':
95                                 rf |= EXT2_NOATIME_FL;
96                                 rem = 1;
97                                 break;
98 #endif
99                         case 'c':
100                                 rf |= EXT2_COMPR_FL;
101                                 rem = 1;
102                                 break;
103 #ifdef  EXT2_NODUMP_FL
104                         case 'd':
105                                 rf |= EXT2_NODUMP_FL;
106                                 rem = 1;
107                                 break;
108 #endif
109 #ifdef  EXT2_IMMUTABLE_FL
110                         case 'i':
111                                 rf |= EXT2_IMMUTABLE_FL;
112                                 rem = 1;
113                                 break;
114 #endif
115                         case 's':
116                                 rf |= EXT2_SECRM_FL;
117                                 rem = 1;
118                                 break;
119                         case 'u':
120                                 rf |= EXT2_UNRM_FL;
121                                 rem = 1;
122                                 break;
123                         case 'v':
124                                 (*i)++;
125                                 if (*i >= argc)
126                                         usage ();
127                                 version = strtol (argv[*i], &tmp, 0);
128                                 if (*tmp)
129                                 {
130                                         com_err (program_name, 0,
131                                                  "bad version - %s\n", argv[*i]);
132                                         usage ();
133                                 }
134                                 set_version = 1;
135                                 break;
136                         default:
137                                 fprintf (stderr, "%s: Unrecognized argument: %c\n",
138                                          program_name, *p);
139                                 usage ();
140                         }
141                 break;
142         case '+':
143                 add = 1;
144                 for (p = &argv[*i][1]; *p; p++)
145                         switch (*p)
146                         {
147                         case 'S':
148                                 af |= EXT2_SYNC_FL;
149                                 break;
150 #ifdef  EXT2_APPEND_FL
151                         case 'a':
152                                 af |= EXT2_APPEND_FL;
153                                 break;
154 #endif
155 #ifdef EXT2_NOATIME_FL
156                         case 'A':
157                                 af |= EXT2_NOATIME_FL;
158                                 break;
159 #endif
160                         case 'c':
161                                 af |= EXT2_COMPR_FL;
162                                 break;
163 #ifdef  EXT2_NODUMP_FL
164                         case 'd':
165                                 af |= EXT2_NODUMP_FL;
166                                 break;
167 #endif
168 #ifdef  EXT2_IMMUTABLE_FL
169                         case 'i':
170                                 af |= EXT2_IMMUTABLE_FL;
171                                 break;
172 #endif
173                         case 's':
174                                 af |= EXT2_SECRM_FL;
175                                 break;
176                         case 'u':
177                                 af |= EXT2_UNRM_FL;
178                                 break;
179                         default:
180                                 usage ();
181                         }
182                 break;
183         case '=':
184                 set = 1;
185                 for (p = &argv[*i][1]; *p; p++)
186                         switch (*p)
187                         {
188                         case 'S':
189                                 sf |= EXT2_SYNC_FL;
190                                 break;
191 #ifdef  EXT2_APPEND_FL
192                         case 'a':
193                                 sf |= EXT2_APPEND_FL;
194                                 break;
195 #endif
196 #ifdef EXT2_NOATIME_FL
197                         case 'A':
198                                 sf |= EXT2_NOATIME_FL;
199                                 break;
200 #endif
201                         case 'c':
202                                 sf |= EXT2_COMPR_FL;
203                                 break;
204 #ifdef  EXT2_NODUMP_FL
205                         case 'd':
206                                 sf |= EXT2_NODUMP_FL;
207                                 break;
208 #endif
209 #ifdef  EXT2_IMMUTABLE_FL
210                         case 'i':
211                                 sf |= EXT2_IMMUTABLE_FL;
212                                 break;
213 #endif
214                         case 's':
215                                 sf |= EXT2_SECRM_FL;
216                                 break;
217                         case 'u':
218                                 sf |= EXT2_UNRM_FL;
219                                 break;
220                         default:
221                                 usage ();
222                         }
223                 break;
224         default:
225                 return EOF;
226                 break;
227         }
228         return 1;
229 }
230
231 static int chattr_dir_proc (const char *, struct dirent *, void *);
232
233 static void change_attributes (const char * name)
234 {
235         unsigned long flags;
236         struct stat st;
237
238         if (lstat (name, &st) == -1)
239         {
240                 com_err (program_name, errno, "while stating %s", name);
241                 return;
242         }
243         if (set)
244         {
245                 if (verbose)
246                 {
247                         printf ("Flags of %s set as ", name);
248                         print_flags (stdout, sf, 0);
249                         printf ("\n");
250                 }
251                 if (fsetflags (name, sf) == -1)
252                         perror (name);
253         }
254         else
255         {
256                 if (fgetflags (name, &flags) == -1)
257                         com_err (program_name, errno,
258                                  "while reading flags on %s", name);
259                 else
260                 {
261                         if (rem)
262                                 flags &= ~rf;
263                         if (add)
264                                 flags |= af;
265                         if (verbose)
266                         {
267                                 printf ("Flags of %s set as ", name);
268                                 print_flags (stdout, flags, 0);
269                                 printf ("\n");
270                         }
271                         if (fsetflags (name, flags) == -1)
272                                 com_err (program_name, errno,
273                                          "while setting flags on %s", name);
274                 }
275         }
276         if (set_version)
277         {
278                 if (verbose)
279                         printf ("Version of %s set as %lu\n", name, version);
280                 if (fsetversion (name, version) == -1)
281                         com_err (program_name, errno,
282                                  "while setting version on %s", name);
283         }
284         if (S_ISDIR(st.st_mode) && recursive)
285                 iterate_on_dir (name, chattr_dir_proc, (void *) NULL);
286 }
287
288 static int chattr_dir_proc (const char * dir_name, struct dirent * de, void * private)
289 {
290         if (strcmp (de->d_name, ".") && strcmp (de->d_name, ".."))
291         {
292                 char *path;
293
294                 path = malloc(strlen (dir_name) + 1 + strlen (de->d_name) + 1);
295                 if (!path)
296                         fatal_error("Couldn't allocate path variable "
297                                     "in chattr_dir_proc", 1);
298                 sprintf (path, "%s/%s", dir_name, de->d_name);
299                 change_attributes (path);
300                 free(path);
301         }
302         return 0;
303 }
304
305 int main (int argc, char ** argv)
306 {
307         int i, j;
308         int end_arg = 0;
309
310         fprintf (stderr, "chattr %s, %s for EXT2 FS %s, %s\n",
311                  E2FSPROGS_VERSION, E2FSPROGS_DATE,
312                  EXT2FS_VERSION, EXT2FS_DATE);
313         if (argc && *argv)
314                 program_name = *argv;
315         i = 1;
316         while (i < argc && !end_arg)
317         {
318                 if (decode_arg (&i, argc, argv) == EOF)
319                         end_arg = 1;
320                 else
321                         i++;
322         }
323         if (i >= argc)
324                 usage ();
325         if (set && (add || rem))
326         {
327                 fprintf (stderr, "= is incompatible with - and +\n");
328                 exit (1);
329         }
330         if (!(add || rem || set || set_version))
331         {
332                 fprintf (stderr, "Must use '-v', =, - or +\n");
333                 exit (1);
334         }
335         for (j = i; j < argc; j++)
336                 change_attributes (argv[j]);
337         exit(0);
338 }