2 * chattr.c - Change file attributes on an ext2 file system
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)
8 * This file can be redistributed under the terms of the GNU General
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)
21 #define _LARGEFILE64_SOURCE
23 #include <sys/types.h>
33 #include <sys/param.h>
35 #include "ext2fs/ext2_fs.h"
38 #define EXT2FS_ATTR(x) __attribute__(x)
40 #define EXT2FS_ATTR(x)
43 #ifndef S_ISLNK /* So we can compile even with gcc-warn */
45 # define S_ISLNK(mode) __S_ISTYPE((mode), __S_IFLNK)
47 # define S_ISLNK(mode) 0
51 #include "et/com_err.h"
54 #include "../version.h"
55 #include "nls-enable.h"
57 static const char * program_name = "chattr";
62 static int set_version;
64 static unsigned long version;
69 static unsigned long af;
70 static unsigned long rf;
71 static unsigned long sf;
73 #ifdef _LFS64_LARGEFILE
75 #define STRUCT_STAT struct stat64
78 #define STRUCT_STAT struct stat
81 static void usage(void)
84 _("Usage: %s [-RV] [-+=AacDdijsSu] [-v version] files...\n"),
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' },
110 static unsigned long get_flag(char c)
112 const struct flags_char *fp;
114 for (fp = flags_array; fp->flag != 0; fp++) {
115 if (fp->optchar == c)
122 static int decode_arg (int * i, int argc, char ** argv)
131 for (p = &argv[*i][1]; *p; p++) {
144 version = strtol (argv[*i], &tmp, 0);
146 com_err (program_name, 0,
147 _("bad version - %s\n"),
154 if ((fl = get_flag(*p)) == 0)
162 for (p = &argv[*i][1]; *p; p++) {
163 if ((fl = get_flag(*p)) == 0)
170 for (p = &argv[*i][1]; *p; p++) {
171 if ((fl = get_flag(*p)) == 0)
183 static int chattr_dir_proc (const char *, struct dirent *, void *);
185 static void change_attributes (const char * name)
190 if (LSTAT (name, &st) == -1) {
191 com_err (program_name, errno, _("while trying to stat %s"),
195 if (S_ISLNK(st.st_mode) && recursive)
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
202 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) &&
203 !S_ISDIR(st.st_mode))
208 printf (_("Flags of %s set as "), name);
209 print_flags (stdout, sf, 0);
212 if (fsetflags (name, sf) == -1)
215 if (fgetflags (name, &flags) == -1)
216 com_err (program_name, errno,
217 _("while reading flags on %s"), name);
224 printf (_("Flags of %s set as "), name);
225 print_flags (stdout, flags, 0);
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);
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);
242 if (S_ISDIR(st.st_mode) && recursive)
243 iterate_on_dir (name, chattr_dir_proc, NULL);
246 static int chattr_dir_proc (const char * dir_name, struct dirent * de,
247 void * private EXT2FS_ATTR((unused)))
249 if (strcmp (de->d_name, ".") && strcmp (de->d_name, "..")) {
252 path = malloc(strlen (dir_name) + 1 + strlen (de->d_name) + 1);
254 fprintf(stderr, _("Couldn't allocate path variable "
255 "in chattr_dir_proc"));
258 sprintf (path, "%s/%s", dir_name, de->d_name);
259 change_attributes (path);
265 int main (int argc, char ** argv)
271 setlocale(LC_MESSAGES, "");
272 setlocale(LC_CTYPE, "");
273 bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
274 textdomain(NLS_CAT_NAME);
277 program_name = *argv;
279 while (i < argc && !end_arg) {
280 /* '--' arg should end option processing */
281 if (strcmp(argv[i], "--") == 0) {
284 } else if (decode_arg (&i, argc, argv) == EOF)
291 if (set && (add || rem)) {
292 fputs(_("= is incompatible with - and +\n"), stderr);
295 if ((rf & af) != 0) {
296 fputs("Can't both set and unset same flag.\n", stderr);
299 if (!(add || rem || set || set_version)) {
300 fputs(_("Must use '-v', =, - or +\n"), stderr);
304 fprintf (stderr, "chattr %s (%s)\n",
305 E2FSPROGS_VERSION, E2FSPROGS_DATE);
306 for (j = i; j < argc; j++)
307 change_attributes (argv[j]);