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