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"
37 #ifndef S_ISLNK /* So we can compile even with gcc-warn */
39 # define S_ISLNK(mode) __S_ISTYPE((mode), __S_IFLNK)
41 # define S_ISLNK(mode) 0
45 #include "et/com_err.h"
48 #include "../version.h"
49 #include "nls-enable.h"
51 static const char * program_name = "chattr";
56 static int set_version;
58 static unsigned long version;
63 static unsigned long af;
64 static unsigned long rf;
65 static unsigned long sf;
67 #ifdef _LFS64_LARGEFILE
69 #define STRUCT_STAT struct stat64
72 #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] [-+=AacdijsSu] [-v version] files...\n"), \
89 static const struct flags_char flags_array[] = {
90 { EXT2_NOATIME_FL, 'A' },
91 { EXT2_SYNC_FL, 'S' },
92 { EXT2_APPEND_FL, 'a' },
93 { EXT2_COMPR_FL, 'c' },
94 { EXT2_NODUMP_FL, 'd' },
95 { EXT2_IMMUTABLE_FL, 'i' },
96 { EXT3_JOURNAL_DATA_FL, 'j' },
97 { EXT2_SECRM_FL, 's' },
98 { EXT2_UNRM_FL, 'u' },
102 static unsigned long get_flag(char c)
104 const struct flags_char *fp;
106 for (fp = flags_array; fp->flag != 0; fp++) {
107 if (fp->optchar == c)
114 static int decode_arg (int * i, int argc, char ** argv)
123 for (p = &argv[*i][1]; *p; p++) {
136 version = strtol (argv[*i], &tmp, 0);
138 com_err (program_name, 0,
139 _("bad version - %s\n"),
146 if ((fl = get_flag(*p)) == 0)
154 for (p = &argv[*i][1]; *p; p++) {
155 if ((fl = get_flag(*p)) == 0)
162 for (p = &argv[*i][1]; *p; p++) {
163 if ((fl = get_flag(*p)) == 0)
175 static int chattr_dir_proc (const char *, struct dirent *, void *);
177 static void change_attributes (const char * name)
182 if (LSTAT (name, &st) == -1) {
183 com_err (program_name, errno, _("while trying to stat %s"),
187 if (S_ISLNK(st.st_mode) && recursive)
190 /* Don't try to open device files, fifos etc. We probably
191 ought to display an error if the file was explicitly given
192 on the command line (whether or not recursive was
194 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) &&
195 !S_ISDIR(st.st_mode))
200 printf (_("Flags of %s set as "), name);
201 print_flags (stdout, sf, 0);
204 if (fsetflags (name, sf) == -1)
207 if (fgetflags (name, &flags) == -1)
208 com_err (program_name, errno,
209 _("while reading flags on %s"), name);
216 printf (_("Flags of %s set as "), name);
217 print_flags (stdout, flags, 0);
220 if (fsetflags (name, flags) == -1)
221 com_err (program_name, errno,
222 _("while setting flags on %s"), name);
227 printf (_("Version of %s set as %lu\n"), name, version);
228 if (fsetversion (name, version) == -1)
229 com_err (program_name, errno,
230 _("while setting version on %s"), name);
232 if (S_ISDIR(st.st_mode) && recursive)
233 iterate_on_dir (name, chattr_dir_proc, NULL);
236 static int chattr_dir_proc (const char * dir_name, struct dirent * de,
237 void * unused_private)
239 if (strcmp (de->d_name, ".") && strcmp (de->d_name, "..")) {
242 path = malloc(strlen (dir_name) + 1 + strlen (de->d_name) + 1);
244 fatal_error(_("Couldn't allocate path variable "
245 "in chattr_dir_proc"), 1);
246 sprintf (path, "%s/%s", dir_name, de->d_name);
247 change_attributes (path);
253 int main (int argc, char ** argv)
259 setlocale(LC_MESSAGES, "");
260 bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
261 textdomain(NLS_CAT_NAME);
264 program_name = *argv;
266 while (i < argc && !end_arg) {
267 if (decode_arg (&i, argc, argv) == EOF)
274 if (set && (add || rem)) {
275 fprintf (stderr, _("= is incompatible with - and +\n"));
278 if ((rf & af) != 0) {
279 fprintf (stderr, "Can't both set and unset same flag.\n");
282 if (!(add || rem || set || set_version)) {
283 fprintf (stderr, _("Must use '-v', =, - or +\n"));
287 fprintf (stderr, "chattr %s (%s)\n",
288 E2FSPROGS_VERSION, E2FSPROGS_DATE);
289 for (j = i; j < argc; j++)
290 change_attributes (argv[j]);