upload tizen1.0 source
[external/busybox.git] / util-linux / e2fsprogs / old_e2fsprogs / chattr.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * chattr.c             - Change file attributes on an ext2 file system
4  *
5  * Copyright (C) 1993, 1994  Remy Card <card@masi.ibp.fr>
6  *                           Laboratoire MASI, Institut Blaise Pascal
7  *                           Universite Pierre et Marie Curie (Paris VI)
8  *
9  * This file can be redistributed under the terms of the GNU General
10  * Public License
11  */
12
13 /*
14  * History:
15  * 93/10/30     - Creation
16  * 93/11/13     - Replace stat() calls by lstat() to avoid loops
17  * 94/02/27     - Integrated in Ted's distribution
18  * 98/12/29     - Ignore symlinks when working recursively (G M Sipe)
19  * 98/12/29     - Display version info only when -V specified (G M Sipe)
20  */
21
22 #include <sys/types.h>
23 #include <dirent.h>
24 #include <fcntl.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <sys/param.h>
31 #include <sys/stat.h>
32 #include "ext2fs/ext2_fs.h"
33
34 #ifdef __GNUC__
35 # define EXT2FS_ATTR(x) __attribute__(x)
36 #else
37 # define EXT2FS_ATTR(x)
38 #endif
39
40 #include "e2fsbb.h"
41 #include "e2p/e2p.h"
42
43 #define OPT_ADD 1
44 #define OPT_REM 2
45 #define OPT_SET 4
46 #define OPT_SET_VER 8
47 static int flags;
48 static int recursive;
49
50 static unsigned long version;
51
52 static unsigned long af;
53 static unsigned long rf;
54 static unsigned long sf;
55
56 struct flags_char {
57         unsigned long flag;
58         char optchar;
59 };
60
61 static const struct flags_char flags_array[] = {
62         { EXT2_NOATIME_FL,      'A' },
63         { EXT2_SYNC_FL,         'S' },
64         { EXT2_DIRSYNC_FL,      'D' },
65         { EXT2_APPEND_FL,       'a' },
66         { EXT2_COMPR_FL,        'c' },
67         { EXT2_NODUMP_FL,       'd' },
68         { EXT2_IMMUTABLE_FL,    'i' },
69         { EXT3_JOURNAL_DATA_FL, 'j' },
70         { EXT2_SECRM_FL,        's' },
71         { EXT2_UNRM_FL,         'u' },
72         { EXT2_NOTAIL_FL,       't' },
73         { EXT2_TOPDIR_FL,       'T' },
74         { 0, 0 }
75 };
76
77 static unsigned long get_flag(char c)
78 {
79         const struct flags_char *fp;
80         for (fp = flags_array; fp->flag; fp++)
81                 if (fp->optchar == c)
82                         return fp->flag;
83         bb_show_usage();
84         return 0;
85 }
86
87 static int decode_arg(char *arg)
88 {
89         unsigned long *fl;
90         char opt = *arg++;
91
92         if (opt == '-') {
93                 flags |= OPT_REM;
94                 fl = &rf;
95         } else if (opt == '+') {
96                 flags |= OPT_ADD;
97                 fl = &af;
98         } else if (opt == '=') {
99                 flags |= OPT_SET;
100                 fl = &sf;
101         } else
102                 return EOF;
103
104         for (; *arg; ++arg)
105                 (*fl) |= get_flag(*arg);
106
107         return 1;
108 }
109
110 static int chattr_dir_proc(const char *, struct dirent *, void *);
111
112 static void change_attributes(const char * name)
113 {
114         unsigned long fsflags;
115         struct stat st;
116
117         if (lstat(name, &st) == -1) {
118                 bb_error_msg("stat %s failed", name);
119                 return;
120         }
121         if (S_ISLNK(st.st_mode) && recursive)
122                 return;
123
124         /* Don't try to open device files, fifos etc.  We probably
125          * ought to display an error if the file was explicitly given
126          * on the command line (whether or not recursive was
127          * requested).  */
128         if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) && !S_ISDIR(st.st_mode))
129                 return;
130
131         if (flags & OPT_SET_VER)
132                 if (fsetversion(name, version) == -1)
133                         bb_error_msg("setting version on %s", name);
134
135         if (flags & OPT_SET) {
136                 fsflags = sf;
137         } else {
138                 if (fgetflags(name, &fsflags) == -1) {
139                         bb_error_msg("reading flags on %s", name);
140                         goto skip_setflags;
141                 }
142                 if (flags & OPT_REM)
143                         fsflags &= ~rf;
144                 if (flags & OPT_ADD)
145                         fsflags |= af;
146                 if (!S_ISDIR(st.st_mode))
147                         fsflags &= ~EXT2_DIRSYNC_FL;
148         }
149         if (fsetflags(name, fsflags) == -1)
150                 bb_error_msg("setting flags on %s", name);
151
152 skip_setflags:
153         if (S_ISDIR(st.st_mode) && recursive)
154                 iterate_on_dir(name, chattr_dir_proc, NULL);
155 }
156
157 static int chattr_dir_proc(const char *dir_name, struct dirent *de,
158                            void *private EXT2FS_ATTR((unused)))
159 {
160         /*if (strcmp(de->d_name, ".") || strcmp(de->d_name, "..")) {*/
161         if (de->d_name[0] == '.'
162          && (!de->d_name[1] || (de->d_name[1] == '.' && !de->d_name[2]))
163         ) {
164                 char *path = concat_subpath_file(dir_name, de->d_name);
165                 if (path) {
166                         change_attributes(path);
167                         free(path);
168                 }
169         }
170         return 0;
171 }
172
173 int chattr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
174 int chattr_main(int argc, char **argv)
175 {
176         int i;
177         char *arg;
178
179         /* parse the args */
180         for (i = 1; i < argc; ++i) {
181                 arg = argv[i];
182
183                 /* take care of -R and -v <version> */
184                 if (arg[0] == '-') {
185                         if (arg[1] == 'R' && arg[2] == '\0') {
186                                 recursive = 1;
187                                 continue;
188                         } else if (arg[1] == 'v' && arg[2] == '\0') {
189                                 char *tmp;
190                                 ++i;
191                                 if (i >= argc)
192                                         bb_show_usage();
193                                 version = strtol(argv[i], &tmp, 0);
194                                 if (*tmp)
195                                         bb_error_msg_and_die("bad version '%s'", arg);
196                                 flags |= OPT_SET_VER;
197                                 continue;
198                         }
199                 }
200
201                 if (decode_arg(arg) == EOF)
202                         break;
203         }
204
205         /* run sanity checks on all the arguments given us */
206         if (i >= argc)
207                 bb_show_usage();
208         if ((flags & OPT_SET) && ((flags & OPT_ADD) || (flags & OPT_REM)))
209                 bb_error_msg_and_die("= is incompatible with - and +");
210         if ((rf & af) != 0)
211                 bb_error_msg_and_die("Can't set and unset a flag");
212         if (!flags)
213                 bb_error_msg_and_die("Must use '-v', =, - or +");
214
215         /* now run chattr on all the files passed to us */
216         while (i < argc)
217                 change_attributes(argv[i++]);
218
219         return EXIT_SUCCESS;
220 }