/* * chattr.c - Change file attributes on an ext2 file system * * Copyright (C) 1993, 1994 Remy Card * Laboratoire MASI, Institut Blaise Pascal * Universite Pierre et Marie Curie (Paris VI) * * This file can be redistributed under the terms of the GNU General * Public License */ /* * History: * 93/10/30 - Creation * 93/11/13 - Replace stat() calls by lstat() to avoid loops * 94/02/27 - Integrated in Ted's distribution */ #include #include #include #include #include #include #include #ifdef HAVE_ERRNO_H #include #endif #include #include #include #include "et/com_err.h" #include "e2p/e2p.h" #include "../version.h" const char * program_name = "chattr"; int add = 0; int rem = 0; int set = 0; int set_version = 0; unsigned long version; int recursive = 0; int verbose = 0; unsigned long af; unsigned long rf; unsigned long sf; static void volatile fatal_error (const char * fmt_string, int errcode) { fprintf (stderr, fmt_string, program_name); exit (errcode); } #define usage() fatal_error ("usage: %s [-RV] [-+=AacdisSu] [-v version] files...\n", \ 1) static int decode_arg (int * i, int argc, char ** argv) { char * p; char * tmp; switch (argv[*i][0]) { case '-': for (p = &argv[*i][1]; *p; p++) switch (*p) { case 'R': recursive = 1; break; case 'S': rf |= EXT2_SYNC_FL; rem = 1; break; case 'V': verbose = 1; break; #ifdef EXT2_APPEND_FL case 'a': rf |= EXT2_APPEND_FL; rem = 1; break; #endif #ifdef EXT2_NOATIME_FL case 'A': rf |= EXT2_NOATIME_FL; rem = 1; break; #endif case 'c': rf |= EXT2_COMPR_FL; rem = 1; break; #ifdef EXT2_NODUMP_FL case 'd': rf |= EXT2_NODUMP_FL; rem = 1; break; #endif #ifdef EXT2_IMMUTABLE_FL case 'i': rf |= EXT2_IMMUTABLE_FL; rem = 1; break; #endif case 's': rf |= EXT2_SECRM_FL; rem = 1; break; case 'u': rf |= EXT2_UNRM_FL; rem = 1; break; case 'v': (*i)++; if (*i >= argc) usage (); version = strtol (argv[*i], &tmp, 0); if (*tmp) { com_err (program_name, 0, "bad version - %s\n", argv[*i]); usage (); } set_version = 1; break; default: fprintf (stderr, "%s: Unrecognized argument: %c\n", program_name, *p); usage (); } break; case '+': add = 1; for (p = &argv[*i][1]; *p; p++) switch (*p) { case 'S': af |= EXT2_SYNC_FL; break; #ifdef EXT2_APPEND_FL case 'a': af |= EXT2_APPEND_FL; break; #endif #ifdef EXT2_NOATIME_FL case 'A': af |= EXT2_NOATIME_FL; break; #endif case 'c': af |= EXT2_COMPR_FL; break; #ifdef EXT2_NODUMP_FL case 'd': af |= EXT2_NODUMP_FL; break; #endif #ifdef EXT2_IMMUTABLE_FL case 'i': af |= EXT2_IMMUTABLE_FL; break; #endif case 's': af |= EXT2_SECRM_FL; break; case 'u': af |= EXT2_UNRM_FL; break; default: usage (); } break; case '=': set = 1; for (p = &argv[*i][1]; *p; p++) switch (*p) { case 'S': sf |= EXT2_SYNC_FL; break; #ifdef EXT2_APPEND_FL case 'a': sf |= EXT2_APPEND_FL; break; #endif #ifdef EXT2_NOATIME_FL case 'A': sf |= EXT2_NOATIME_FL; break; #endif case 'c': sf |= EXT2_COMPR_FL; break; #ifdef EXT2_NODUMP_FL case 'd': sf |= EXT2_NODUMP_FL; break; #endif #ifdef EXT2_IMMUTABLE_FL case 'i': sf |= EXT2_IMMUTABLE_FL; break; #endif case 's': sf |= EXT2_SECRM_FL; break; case 'u': sf |= EXT2_UNRM_FL; break; default: usage (); } break; default: return EOF; break; } return 1; } static int chattr_dir_proc (const char *, struct dirent *, void *); static void change_attributes (const char * name) { unsigned long flags; struct stat st; if (lstat (name, &st) == -1) { com_err (program_name, errno, "while stating %s", name); return; } if (set) { if (verbose) { printf ("Flags of %s set as ", name); print_flags (stdout, sf, 0); printf ("\n"); } if (fsetflags (name, sf) == -1) perror (name); } else { if (fgetflags (name, &flags) == -1) com_err (program_name, errno, "while reading flags on %s", name); else { if (rem) flags &= ~rf; if (add) flags |= af; if (verbose) { printf ("Flags of %s set as ", name); print_flags (stdout, flags, 0); printf ("\n"); } if (fsetflags (name, flags) == -1) com_err (program_name, errno, "while setting flags on %s", name); } } if (set_version) { if (verbose) printf ("Version of %s set as %lu\n", name, version); if (fsetversion (name, version) == -1) com_err (program_name, errno, "while setting version on %s", name); } if (S_ISDIR(st.st_mode) && recursive) iterate_on_dir (name, chattr_dir_proc, (void *) NULL); } static int chattr_dir_proc (const char * dir_name, struct dirent * de, void * private) { if (strcmp (de->d_name, ".") && strcmp (de->d_name, "..")) { char *path; path = malloc(strlen (dir_name) + 1 + strlen (de->d_name) + 1); if (!path) fatal_error("Couldn't allocate path variable " "in chattr_dir_proc", 1); sprintf (path, "%s/%s", dir_name, de->d_name); change_attributes (path); free(path); } return 0; } int main (int argc, char ** argv) { int i, j; int end_arg = 0; fprintf (stderr, "chattr %s, %s for EXT2 FS %s, %s\n", E2FSPROGS_VERSION, E2FSPROGS_DATE, EXT2FS_VERSION, EXT2FS_DATE); if (argc && *argv) program_name = *argv; i = 1; while (i < argc && !end_arg) { if (decode_arg (&i, argc, argv) == EOF) end_arg = 1; else i++; } if (i >= argc) usage (); if (set && (add || rem)) { fprintf (stderr, "= is incompatible with - and +\n"); exit (1); } if (!(add || rem || set || set_version)) { fprintf (stderr, "Must use '-v', =, - or +\n"); exit (1); } for (j = i; j < argc; j++) change_attributes (argv[j]); exit(0); }