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 fatal_error(const char * fmt_string, int errcode)
83 fprintf (stderr, fmt_string, program_name);
87 #define usage() fatal_error(_("Usage: %s [-RV] [-+=AacDdijsSu] [-v version] files...\n"), \
95 static const struct flags_char flags_array[] = {
96 { EXT2_NOATIME_FL, 'A' },
97 { EXT2_SYNC_FL, 'S' },
98 { EXT2_DIRSYNC_FL, 'D' },
99 { EXT2_APPEND_FL, 'a' },
100 { EXT2_COMPR_FL, 'c' },
101 { EXT2_NODUMP_FL, 'd' },
102 { EXT2_IMMUTABLE_FL, 'i' },
103 { EXT3_JOURNAL_DATA_FL, 'j' },
104 { EXT2_SECRM_FL, 's' },
105 { EXT2_UNRM_FL, 'u' },
106 { EXT2_NOTAIL_FL, 't' },
107 { EXT2_TOPDIR_FL, 'T' },
111 static unsigned long get_flag(char c)
113 const struct flags_char *fp;
115 for (fp = flags_array; fp->flag != 0; fp++) {
116 if (fp->optchar == c)
123 static int decode_arg (int * i, int argc, char ** argv)
132 for (p = &argv[*i][1]; *p; p++) {
145 version = strtol (argv[*i], &tmp, 0);
147 com_err (program_name, 0,
148 _("bad version - %s\n"),
155 if ((fl = get_flag(*p)) == 0)
163 for (p = &argv[*i][1]; *p; p++) {
164 if ((fl = get_flag(*p)) == 0)
171 for (p = &argv[*i][1]; *p; p++) {
172 if ((fl = get_flag(*p)) == 0)
184 static int chattr_dir_proc (const char *, struct dirent *, void *);
186 static void change_attributes (const char * name)
191 if (LSTAT (name, &st) == -1) {
192 com_err (program_name, errno, _("while trying to stat %s"),
196 if (S_ISLNK(st.st_mode) && recursive)
199 /* Don't try to open device files, fifos etc. We probably
200 ought to display an error if the file was explicitly given
201 on the command line (whether or not recursive was
203 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) &&
204 !S_ISDIR(st.st_mode))
209 printf (_("Flags of %s set as "), name);
210 print_flags (stdout, sf, 0);
213 if (fsetflags (name, sf) == -1)
216 if (fgetflags (name, &flags) == -1)
217 com_err (program_name, errno,
218 _("while reading flags on %s"), name);
225 printf (_("Flags of %s set as "), name);
226 print_flags (stdout, flags, 0);
229 if (!S_ISDIR(st.st_mode))
230 flags &= ~EXT2_DIRSYNC_FL;
231 if (fsetflags (name, flags) == -1)
232 com_err (program_name, errno,
233 _("while setting flags on %s"), name);
238 printf (_("Version of %s set as %lu\n"), name, version);
239 if (fsetversion (name, version) == -1)
240 com_err (program_name, errno,
241 _("while setting version on %s"), name);
243 if (S_ISDIR(st.st_mode) && recursive)
244 iterate_on_dir (name, chattr_dir_proc, NULL);
247 static int chattr_dir_proc (const char * dir_name, struct dirent * de,
248 void * private EXT2FS_ATTR((unused)))
250 if (strcmp (de->d_name, ".") && strcmp (de->d_name, "..")) {
253 path = malloc(strlen (dir_name) + 1 + strlen (de->d_name) + 1);
255 fatal_error(_("Couldn't allocate path variable "
256 "in chattr_dir_proc"), 1);
257 sprintf (path, "%s/%s", dir_name, de->d_name);
258 change_attributes (path);
264 int main (int argc, char ** argv)
270 setlocale(LC_MESSAGES, "");
271 setlocale(LC_CTYPE, "");
272 bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
273 textdomain(NLS_CAT_NAME);
276 program_name = *argv;
278 while (i < argc && !end_arg) {
279 /* '--' arg should end option processing */
280 if (strcmp(argv[i], "--") == 0) {
283 } else if (decode_arg (&i, argc, argv) == EOF)
290 if (set && (add || rem)) {
291 fputs(_("= is incompatible with - and +\n"), stderr);
294 if ((rf & af) != 0) {
295 fputs("Can't both set and unset same flag.\n", stderr);
298 if (!(add || rem || set || set_version)) {
299 fputs(_("Must use '-v', =, - or +\n"), stderr);
303 fprintf (stderr, "chattr %s (%s)\n",
304 E2FSPROGS_VERSION, E2FSPROGS_DATE);
305 for (j = i; j < argc; j++)
306 change_attributes (argv[j]);