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