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] [-+=AacDdijsSu] [-v version] files...\n"), \
89 static const struct flags_char flags_array[] = {
90 { EXT2_NOATIME_FL, 'A' },
91 { EXT2_SYNC_FL, 'S' },
92 { EXT2_DIRSYNC_FL, 'D' },
93 { EXT2_APPEND_FL, 'a' },
94 { EXT2_COMPR_FL, 'c' },
95 { EXT2_NODUMP_FL, 'd' },
96 { EXT2_IMMUTABLE_FL, 'i' },
97 { EXT3_JOURNAL_DATA_FL, 'j' },
98 { EXT2_SECRM_FL, 's' },
99 { EXT2_UNRM_FL, 'u' },
100 { EXT2_NOTAIL_FL, 't' },
101 { EXT2_TOPDIR_FL, 'T' },
105 static unsigned long get_flag(char c)
107 const struct flags_char *fp;
109 for (fp = flags_array; fp->flag != 0; fp++) {
110 if (fp->optchar == c)
117 static int decode_arg (int * i, int argc, char ** argv)
126 for (p = &argv[*i][1]; *p; p++) {
139 version = strtol (argv[*i], &tmp, 0);
141 com_err (program_name, 0,
142 _("bad version - %s\n"),
149 if ((fl = get_flag(*p)) == 0)
157 for (p = &argv[*i][1]; *p; p++) {
158 if ((fl = get_flag(*p)) == 0)
165 for (p = &argv[*i][1]; *p; p++) {
166 if ((fl = get_flag(*p)) == 0)
178 static int chattr_dir_proc (const char *, struct dirent *, void *);
180 static void change_attributes (const char * name)
185 if (LSTAT (name, &st) == -1) {
186 com_err (program_name, errno, _("while trying to stat %s"),
190 if (S_ISLNK(st.st_mode) && recursive)
193 /* Don't try to open device files, fifos etc. We probably
194 ought to display an error if the file was explicitly given
195 on the command line (whether or not recursive was
197 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) &&
198 !S_ISDIR(st.st_mode))
203 printf (_("Flags of %s set as "), name);
204 print_flags (stdout, sf, 0);
207 if (fsetflags (name, sf) == -1)
210 if (fgetflags (name, &flags) == -1)
211 com_err (program_name, errno,
212 _("while reading flags on %s"), name);
219 printf (_("Flags of %s set as "), name);
220 print_flags (stdout, flags, 0);
223 if (!S_ISDIR(st.st_mode))
224 flags &= ~EXT2_DIRSYNC_FL;
225 if (fsetflags (name, flags) == -1)
226 com_err (program_name, errno,
227 _("while setting flags on %s"), name);
232 printf (_("Version of %s set as %lu\n"), name, version);
233 if (fsetversion (name, version) == -1)
234 com_err (program_name, errno,
235 _("while setting version on %s"), name);
237 if (S_ISDIR(st.st_mode) && recursive)
238 iterate_on_dir (name, chattr_dir_proc, NULL);
241 static int chattr_dir_proc (const char * dir_name, struct dirent * de,
242 void * unused_private)
244 if (strcmp (de->d_name, ".") && strcmp (de->d_name, "..")) {
247 path = malloc(strlen (dir_name) + 1 + strlen (de->d_name) + 1);
249 fatal_error(_("Couldn't allocate path variable "
250 "in chattr_dir_proc"), 1);
251 sprintf (path, "%s/%s", dir_name, de->d_name);
252 change_attributes (path);
258 int main (int argc, char ** argv)
264 setlocale(LC_MESSAGES, "");
265 setlocale(LC_CTYPE, "");
266 bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
267 textdomain(NLS_CAT_NAME);
270 program_name = *argv;
272 while (i < argc && !end_arg) {
273 if (decode_arg (&i, argc, argv) == EOF)
280 if (set && (add || rem)) {
281 fprintf (stderr, _("= is incompatible with - and +\n"));
284 if ((rf & af) != 0) {
285 fprintf (stderr, "Can't both set and unset same flag.\n");
288 if (!(add || rem || set || set_version)) {
289 fprintf (stderr, _("Must use '-v', =, - or +\n"));
293 fprintf (stderr, "chattr %s (%s)\n",
294 E2FSPROGS_VERSION, E2FSPROGS_DATE);
295 for (j = i; j < argc; j++)
296 change_attributes (argv[j]);