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 #include <sys/types.h>
29 #include <sys/param.h>
34 #define EXT2FS_ATTR(x) __attribute__(x)
36 #define EXT2FS_ATTR(x)
39 #ifndef S_ISLNK /* So we can compile even with gcc-warn */
41 # define S_ISLNK(mode) __S_ISTYPE((mode), __S_IFLNK)
43 # define S_ISLNK(mode) 0
50 #define main chattr_main
55 static int set_version;
57 static unsigned long version;
62 static unsigned long af;
63 static unsigned long rf;
64 static unsigned long sf;
66 #ifdef _LFS64_LARGEFILE
68 #define STRUCT_STAT struct stat64
71 #define STRUCT_STAT struct stat
75 static void fatal_error(const char * fmt_string, int errcode)
77 fprintf (stderr, fmt_string, program_name);
81 #define usage() fatal_error(_("usage: %s [-RV] [-+=AacDdijsSu] [-v version] files...\n"), \
90 static 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' },
106 static unsigned long get_flag(char c)
108 const struct flags_char *fp;
110 for (fp = flags_array; fp->flag != 0; fp++) {
111 if (fp->optchar == c)
118 static int decode_arg (int * i, int argc, char ** argv)
127 for (p = &argv[*i][1]; *p; p++) {
140 version = strtol (argv[*i], &tmp, 0);
142 com_err (program_name, 0,
143 _("bad version - %s\n"),
150 if ((fl = get_flag(*p)) == 0)
158 for (p = &argv[*i][1]; *p; p++) {
159 if ((fl = get_flag(*p)) == 0)
166 for (p = &argv[*i][1]; *p; p++) {
167 if ((fl = get_flag(*p)) == 0)
179 static int chattr_dir_proc (const char *, struct dirent *, void *);
181 static void change_attributes (const char * name)
186 if (LSTAT (name, &st) == -1) {
187 com_err (program_name, errno, _("while trying to stat %s"),
191 if (S_ISLNK(st.st_mode) && recursive)
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
198 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) &&
199 !S_ISDIR(st.st_mode))
204 printf (_("Flags of %s set as "), name);
205 print_flags (stdout, sf, 0);
208 if (fsetflags (name, sf) == -1)
211 if (fgetflags (name, &flags) == -1)
212 com_err (program_name, errno,
213 _("while reading flags on %s"), name);
220 printf (_("Flags of %s set as "), name);
221 print_flags (stdout, flags, 0);
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);
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);
238 if (S_ISDIR(st.st_mode) && recursive)
239 iterate_on_dir (name, chattr_dir_proc, NULL);
242 static int chattr_dir_proc (const char * dir_name, struct dirent * de,
243 void * private EXT2FS_ATTR((unused)))
245 if (strcmp (de->d_name, ".") && strcmp (de->d_name, "..")) {
248 path = malloc(strlen (dir_name) + 1 + strlen (de->d_name) + 1);
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);
259 int main (int argc, char ** argv)
265 setlocale(LC_MESSAGES, "");
266 setlocale(LC_CTYPE, "");
267 bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
268 textdomain(NLS_CAT_NAME);
272 program_name = *argv;
275 while (i < argc && !end_arg) {
276 /* '--' arg should end option processing */
277 if (strcmp(argv[i], "--") == 0) {
280 } else if (decode_arg (&i, argc, argv) == EOF)
287 if (set && (add || rem)) {
288 fputs(_("= is incompatible with - and +\n"), stderr);
291 if ((rf & af) != 0) {
292 fputs("Can't both set and unset same flag.\n", stderr);
295 if (!(add || rem || set || set_version)) {
296 fputs(_("Must use '-v', =, - or +\n"), stderr);
301 fprintf (stderr, "chattr %s (%s)\n",
302 E2FSPROGS_VERSION, E2FSPROGS_DATE);
304 for (j = i; j < argc; j++)
305 change_attributes (argv[j]);