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