OSDN Git Service

Code drop from //branches/cupcake/...@124589
[android-x86/external-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 #define _LARGEFILE64_SOURCE
22
23 #include <sys/types.h>
24 #include <dirent.h>
25 #include <fcntl.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <string.h>
30 #ifdef HAVE_ERRNO_H
31 #include <errno.h>
32 #endif
33 #include <sys/param.h>
34 #include <sys/stat.h>
35 #include "ext2fs/ext2_fs.h"
36
37 #ifdef __GNUC__
38 #define EXT2FS_ATTR(x) __attribute__(x)
39 #else
40 #define EXT2FS_ATTR(x)
41 #endif
42
43 #ifndef S_ISLNK                 /* So we can compile even with gcc-warn */
44 # ifdef __S_IFLNK
45 #  define S_ISLNK(mode)  __S_ISTYPE((mode), __S_IFLNK)
46 # else
47 #  define S_ISLNK(mode)  0
48 # endif
49 #endif
50
51 #include "et/com_err.h"
52 #include "e2p/e2p.h"
53
54 #include "../version.h"
55 #include "nls-enable.h"
56
57 static const char * program_name = "chattr";
58
59 static int add;
60 static int rem;
61 static int set;
62 static int set_version;
63
64 static unsigned long version;
65
66 static int recursive;
67 static int verbose;
68
69 static unsigned long af;
70 static unsigned long rf;
71 static unsigned long sf;
72
73 #ifdef _LFS64_LARGEFILE
74 #define LSTAT           lstat64
75 #define STRUCT_STAT     struct stat64
76 #else
77 #define LSTAT           lstat
78 #define STRUCT_STAT     struct stat
79 #endif
80
81 static void usage(void)
82 {
83         fprintf(stderr, 
84                 _("Usage: %s [-RV] [-+=AacDdijsSu] [-v version] files...\n"),
85                 program_name);
86         exit(1);
87 }
88
89 struct flags_char {
90         unsigned long   flag;
91         char            optchar;
92 };
93
94 static const struct flags_char flags_array[] = {
95         { EXT2_NOATIME_FL, 'A' },
96         { EXT2_SYNC_FL, 'S' },
97         { EXT2_DIRSYNC_FL, 'D' },
98         { EXT2_APPEND_FL, 'a' },
99         { EXT2_COMPR_FL, 'c' },
100         { EXT2_NODUMP_FL, 'd' },
101         { EXT2_IMMUTABLE_FL, 'i' },
102         { EXT3_JOURNAL_DATA_FL, 'j' },
103         { EXT2_SECRM_FL, 's' },
104         { EXT2_UNRM_FL, 'u' },
105         { EXT2_NOTAIL_FL, 't' },
106         { EXT2_TOPDIR_FL, 'T' },
107         { 0, 0 }
108 };
109
110 static unsigned long get_flag(char c)
111 {
112         const struct flags_char *fp;
113         
114         for (fp = flags_array; fp->flag != 0; fp++) {
115                 if (fp->optchar == c)
116                         return fp->flag;
117         }
118         return 0;
119 }
120
121
122 static int decode_arg (int * i, int argc, char ** argv)
123 {
124         char * p;
125         char * tmp;
126         unsigned long fl;
127
128         switch (argv[*i][0])
129         {
130         case '-':
131                 for (p = &argv[*i][1]; *p; p++) {
132                         if (*p == 'R') {
133                                 recursive = 1;
134                                 continue;
135                         }
136                         if (*p == 'V') {
137                                 verbose = 1;
138                                 continue;
139                         }
140                         if (*p == 'v') {
141                                 (*i)++;
142                                 if (*i >= argc)
143                                         usage ();
144                                 version = strtol (argv[*i], &tmp, 0);
145                                 if (*tmp) {
146                                         com_err (program_name, 0,
147                                                  _("bad version - %s\n"), 
148                                                  argv[*i]);
149                                         usage ();
150                                 }
151                                 set_version = 1;
152                                 continue;
153                         }
154                         if ((fl = get_flag(*p)) == 0)
155                                 usage();
156                         rf |= fl;
157                         rem = 1;
158                 }
159                 break;
160         case '+':
161                 add = 1;
162                 for (p = &argv[*i][1]; *p; p++) {
163                         if ((fl = get_flag(*p)) == 0)
164                                 usage();
165                         af |= fl;
166                 }
167                 break;
168         case '=':
169                 set = 1;
170                 for (p = &argv[*i][1]; *p; p++) {
171                         if ((fl = get_flag(*p)) == 0)
172                                 usage();
173                         sf |= fl;
174                 }
175                 break;
176         default:
177                 return EOF;
178                 break;
179         }
180         return 1;
181 }
182
183 static int chattr_dir_proc (const char *, struct dirent *, void *);
184
185 static void change_attributes (const char * name)
186 {
187         unsigned long flags;
188         STRUCT_STAT     st;
189
190         if (LSTAT (name, &st) == -1) {
191                 com_err (program_name, errno, _("while trying to stat %s"), 
192                          name);
193                 return;
194         }
195         if (S_ISLNK(st.st_mode) && recursive)
196                 return;
197
198         /* Don't try to open device files, fifos etc.  We probably
199            ought to display an error if the file was explicitly given
200            on the command line (whether or not recursive was
201            requested).  */
202         if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) &&
203             !S_ISDIR(st.st_mode))
204                 return;
205
206         if (set) {
207                 if (verbose) {
208                         printf (_("Flags of %s set as "), name);
209                         print_flags (stdout, sf, 0);
210                         printf ("\n");
211                 }
212                 if (fsetflags (name, sf) == -1)
213                         perror (name);
214         } else {
215                 if (fgetflags (name, &flags) == -1)
216                         com_err (program_name, errno,
217                                  _("while reading flags on %s"), name);
218                 else {
219                         if (rem)
220                                 flags &= ~rf;
221                         if (add)
222                                 flags |= af;
223                         if (verbose) {
224                                 printf (_("Flags of %s set as "), name);
225                                 print_flags (stdout, flags, 0);
226                                 printf ("\n");
227                         }
228                         if (!S_ISDIR(st.st_mode))
229                                 flags &= ~EXT2_DIRSYNC_FL;
230                         if (fsetflags (name, flags) == -1)
231                                 com_err (program_name, errno,
232                                          _("while setting flags on %s"), name);
233                 }
234         }
235         if (set_version) {
236                 if (verbose)
237                         printf (_("Version of %s set as %lu\n"), name, version);
238                 if (fsetversion (name, version) == -1)
239                         com_err (program_name, errno,
240                                  _("while setting version on %s"), name);
241         }
242         if (S_ISDIR(st.st_mode) && recursive)
243                 iterate_on_dir (name, chattr_dir_proc, NULL);
244 }
245
246 static int chattr_dir_proc (const char * dir_name, struct dirent * de,
247                             void * private EXT2FS_ATTR((unused)))
248 {
249         if (strcmp (de->d_name, ".") && strcmp (de->d_name, "..")) {
250                 char *path;
251
252                 path = malloc(strlen (dir_name) + 1 + strlen (de->d_name) + 1);
253                 if (!path) {
254                         fprintf(stderr, _("Couldn't allocate path variable "
255                                           "in chattr_dir_proc"));
256                         exit(1);
257                 }
258                 sprintf (path, "%s/%s", dir_name, de->d_name);
259                 change_attributes (path);
260                 free(path);
261         }
262         return 0;
263 }
264
265 int main (int argc, char ** argv)
266 {
267         int i, j;
268         int end_arg = 0;
269
270 #ifdef ENABLE_NLS
271         setlocale(LC_MESSAGES, "");
272         setlocale(LC_CTYPE, "");
273         bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
274         textdomain(NLS_CAT_NAME);
275 #endif
276         if (argc && *argv)
277                 program_name = *argv;
278         i = 1;
279         while (i < argc && !end_arg) {
280                 /* '--' arg should end option processing */
281                 if (strcmp(argv[i], "--") == 0) {
282                         i++;
283                         end_arg = 1;
284                 } else if (decode_arg (&i, argc, argv) == EOF)
285                         end_arg = 1;
286                 else
287                         i++;
288         }
289         if (i >= argc)
290                 usage ();
291         if (set && (add || rem)) {
292                 fputs(_("= is incompatible with - and +\n"), stderr);
293                 exit (1);
294         }
295         if ((rf & af) != 0) {
296                 fputs("Can't both set and unset same flag.\n", stderr);
297                 exit (1);
298         }
299         if (!(add || rem || set || set_version)) {
300                 fputs(_("Must use '-v', =, - or +\n"), stderr);
301                 exit (1);
302         }
303         if (verbose)
304                 fprintf (stderr, "chattr %s (%s)\n",
305                          E2FSPROGS_VERSION, E2FSPROGS_DATE);
306         for (j = i; j < argc; j++)
307                 change_attributes (argv[j]);
308         exit(0);
309 }