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
22 #define _FILE_OFFSET_BITS 64
24 #include <sys/types.h>
34 #include <sys/param.h>
36 #include <linux/ext2_fs.h>
38 #ifndef S_ISLNK /* So we can compile even with gcc-warn */
40 # define S_ISLNK(mode) __S_ISTYPE((mode), __S_IFLNK)
42 # define S_ISLNK(mode) 0
46 #include "et/com_err.h"
49 #include "../version.h"
50 #include "nls-enable.h"
52 static const char * program_name = "chattr";
57 static int set_version;
59 static unsigned long version;
64 static unsigned long af;
65 static unsigned long rf;
66 static unsigned long sf;
68 static void fatal_error(const char * fmt_string, int errcode)
70 fprintf (stderr, fmt_string, program_name);
74 #define usage() fatal_error(_("usage: %s [-RV] [-+=AacdijsSu] [-v version] files...\n"), \
82 static const struct flags_char flags_array[] = {
83 { EXT2_NOATIME_FL, 'A' },
84 { EXT2_SYNC_FL, 'S' },
85 { EXT2_APPEND_FL, 'a' },
86 { EXT2_COMPR_FL, 'c' },
87 { EXT2_NODUMP_FL, 'd' },
88 { EXT2_IMMUTABLE_FL, 'i' },
89 { EXT3_JOURNAL_DATA_FL, 'j' },
90 { EXT2_SECRM_FL, 's' },
91 { EXT2_UNRM_FL, 'u' },
95 static unsigned long get_flag(char c)
97 const struct flags_char *fp;
99 for (fp = flags_array; fp->flag != 0; fp++) {
100 if (fp->optchar == c)
107 static int decode_arg (int * i, int argc, char ** argv)
116 for (p = &argv[*i][1]; *p; p++) {
129 version = strtol (argv[*i], &tmp, 0);
131 com_err (program_name, 0,
132 _("bad version - %s\n"),
139 if ((fl = get_flag(*p)) == 0)
147 for (p = &argv[*i][1]; *p; p++) {
148 if ((fl = get_flag(*p)) == 0)
155 for (p = &argv[*i][1]; *p; p++) {
156 if ((fl = get_flag(*p)) == 0)
168 static int chattr_dir_proc (const char *, struct dirent *, void *);
170 static void change_attributes (const char * name)
175 if (lstat (name, &st) == -1) {
176 com_err (program_name, errno, _("while trying to stat %s"),
180 if (S_ISLNK(st.st_mode) && recursive)
183 /* Don't try to open device files, fifos etc. We probably
184 ought to display an error if the file was explicitly given
185 on the command line (whether or not recursive was
187 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) &&
188 !S_ISDIR(st.st_mode))
193 printf (_("Flags of %s set as "), name);
194 print_flags (stdout, sf, 0);
197 if (fsetflags (name, sf) == -1)
200 if (fgetflags (name, &flags) == -1)
201 com_err (program_name, errno,
202 _("while reading flags on %s"), name);
209 printf (_("Flags of %s set as "), name);
210 print_flags (stdout, flags, 0);
213 if (fsetflags (name, flags) == -1)
214 com_err (program_name, errno,
215 _("while setting flags on %s"), name);
220 printf (_("Version of %s set as %lu\n"), name, version);
221 if (fsetversion (name, version) == -1)
222 com_err (program_name, errno,
223 _("while setting version on %s"), name);
225 if (S_ISDIR(st.st_mode) && recursive)
226 iterate_on_dir (name, chattr_dir_proc, NULL);
229 static int chattr_dir_proc (const char * dir_name, struct dirent * de,
230 void * unused_private)
232 if (strcmp (de->d_name, ".") && strcmp (de->d_name, "..")) {
235 path = malloc(strlen (dir_name) + 1 + strlen (de->d_name) + 1);
237 fatal_error(_("Couldn't allocate path variable "
238 "in chattr_dir_proc"), 1);
239 sprintf (path, "%s/%s", dir_name, de->d_name);
240 change_attributes (path);
246 int main (int argc, char ** argv)
252 setlocale(LC_MESSAGES, "");
253 bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
254 textdomain(NLS_CAT_NAME);
257 program_name = *argv;
259 while (i < argc && !end_arg) {
260 if (decode_arg (&i, argc, argv) == EOF)
267 if (set && (add || rem)) {
268 fprintf (stderr, _("= is incompatible with - and +\n"));
271 if ((rf & af) != 0) {
272 fprintf (stderr, "Can't both set and unset same flag.\n");
275 if (!(add || rem || set || set_version)) {
276 fprintf (stderr, _("Must use '-v', =, - or +\n"));
280 fprintf (stderr, _("chattr %s, %s for EXT2 FS %s, %s\n"),
281 E2FSPROGS_VERSION, E2FSPROGS_DATE,
282 EXT2FS_VERSION, EXT2FS_DATE);
283 for (j = i; j < argc; j++)
284 change_attributes (argv[j]);