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