chattr.c revision 3839e65723771b85975f4263102dd3ceec4523c0
1/* 2 * chattr.c - Change file attributes on an ext2 file system 3 * 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) 7 * 8 * This file can be redistributed under the terms of the GNU General 9 * Public License 10 */ 11 12/* 13 * History: 14 * 93/10/30 - Creation 15 * 93/11/13 - Replace stat() calls by lstat() to avoid loops 16 * 94/02/27 - Integrated in Ted's distribution 17 */ 18 19#include <dirent.h> 20#include <fcntl.h> 21#include <getopt.h> 22#include <stdio.h> 23#include <stdlib.h> 24#include <unistd.h> 25#include <sys/param.h> 26#include <sys/stat.h> 27#include <linux/ext2_fs.h> 28 29#include "et/com_err.h" 30#include "e2p/e2p.h" 31 32#include "../version.h" 33 34const char * program_name = "chattr"; 35 36int add = 0; 37int rem = 0; 38int set = 0; 39int set_version = 0; 40 41unsigned long version; 42 43int recursive = 0; 44int verbose = 0; 45 46unsigned long af; 47unsigned long rf; 48unsigned long sf; 49 50static void volatile fatal_error (const char * fmt_string, int errcode) 51{ 52 fprintf (stderr, fmt_string, program_name); 53 exit (errcode); 54} 55 56#define usage() fatal_error ("usage: %s [-RV] [-+=csu] [-v version] files...\n", \ 57 1) 58 59static int decode_arg (int * i, int argc, char ** argv) 60{ 61 char * p; 62 char * tmp; 63 64 switch (argv[*i][0]) 65 { 66 case '-': 67 for (p = &argv[*i][1]; *p; p++) 68 switch (*p) 69 { 70 case 'R': 71 recursive = 1; 72 break; 73 case 'S': 74 rf |= EXT2_SYNC_FL; 75 rem = 1; 76 break; 77 case 'V': 78 verbose = 1; 79 break; 80 case 'c': 81 rf |= EXT2_COMPR_FL; 82 rem = 1; 83 break; 84 case 's': 85 rf |= EXT2_SECRM_FL; 86 rem = 1; 87 break; 88 case 'u': 89 rf |= EXT2_UNRM_FL; 90 rem = 1; 91 break; 92 case 'v': 93 if (*i >= argc) 94 usage (); 95 (*i)++; 96 version = strtol (argv[*i], &tmp, 0); 97 if (*tmp) 98 { 99 com_err (program_name, 0, 100 "bad version - %s\n", argv[*i]); 101 usage (); 102 } 103 set_version = 1; 104 break; 105 default: 106 fprintf (stderr, "%s: Unrecognized argument: %c\n", 107 program_name, *p); 108 usage (); 109 } 110 break; 111 case '+': 112 add = 1; 113 for (p = &argv[*i][1]; *p; p++) 114 switch (*p) 115 { 116 case 'S': 117 af |= EXT2_SYNC_FL; 118 break; 119 case 'c': 120 af |= EXT2_COMPR_FL; 121 break; 122 case 's': 123 af |= EXT2_SECRM_FL; 124 break; 125 case 'u': 126 af |= EXT2_UNRM_FL; 127 break; 128 default: 129 usage (); 130 } 131 break; 132 case '=': 133 set = 1; 134 for (p = &argv[*i][1]; *p; p++) 135 switch (*p) 136 { 137 case 'S': 138 sf |= EXT2_SYNC_FL; 139 break; 140 case 'c': 141 sf |= EXT2_COMPR_FL; 142 break; 143 case 's': 144 sf |= EXT2_SECRM_FL; 145 break; 146 case 'u': 147 sf |= EXT2_UNRM_FL; 148 break; 149 default: 150 usage (); 151 } 152 break; 153 default: 154 return EOF; 155 break; 156 } 157 return 1; 158} 159 160static int chattr_dir_proc (const char *, struct dirent *, void *); 161 162static void change_attributes (const char * name) 163{ 164 unsigned long flags; 165 struct stat st; 166 167 if (lstat (name, &st) == -1) 168 { 169 com_err (program_name, errno, "while stating %s", name); 170 return; 171 } 172 if (set) 173 { 174 if (verbose) 175 { 176 printf ("Flags of %s set as ", name); 177 print_flags (stdout, sf); 178 printf ("\n"); 179 } 180 if (fsetflags (name, sf) == -1) 181 perror (name); 182 } 183 else 184 { 185 if (fgetflags (name, &flags) == -1) 186 com_err (program_name, errno, 187 "while reading flags on %s", name); 188 else 189 { 190 if (rem) 191 flags &= ~rf; 192 if (add) 193 flags |= af; 194 if (verbose) 195 { 196 printf ("Flags of %s set as ", name); 197 print_flags (stdout, flags); 198 printf ("\n"); 199 } 200 if (fsetflags (name, flags) == -1) 201 com_err (program_name, errno, 202 "while setting flags on %s", name); 203 } 204 } 205 if (set_version) 206 { 207 if (verbose) 208 printf ("Version of %s set as %lu\n", name, version); 209 if (fsetversion (name, version) == -1) 210 com_err (program_name, errno, 211 "while setting version on %s", name); 212 } 213 if (S_ISDIR(st.st_mode) && recursive) 214 iterate_on_dir (name, chattr_dir_proc, (void *) NULL); 215} 216 217static int chattr_dir_proc (const char * dir_name, struct dirent * de, void * private) 218{ 219 char path[MAXPATHLEN]; 220 221 if (strcmp (de->d_name, ".") && strcmp (de->d_name, "..")) 222 { 223 sprintf (path, "%s/%s", dir_name, de->d_name); 224 change_attributes (path); 225 } 226 return 0; 227} 228 229void main (int argc, char ** argv) 230{ 231 int i, j; 232 int end_arg = 0; 233 234 fprintf (stderr, "chattr %s, %s for EXT2 FS %s, %s\n", 235 E2FSPROGS_VERSION, E2FSPROGS_DATE, 236 EXT2FS_VERSION, EXT2FS_DATE); 237 if (argc && *argv) 238 program_name = *argv; 239 i = 1; 240 while (i < argc && !end_arg) 241 { 242 if (decode_arg (&i, argc, argv) == EOF) 243 end_arg = 1; 244 else 245 i++; 246 } 247 if (i >= argc) 248 usage (); 249 if (set && (add || rem)) 250 { 251 fprintf (stderr, "= is incompatible with - and +\n"); 252 exit (1); 253 } 254 if (!(add || rem || set)) 255 { 256 fprintf (stderr, "Must use =, - or +\n"); 257 exit (1); 258 } 259 for (j = i; j < argc; j++) 260 change_attributes (argv[j]); 261} 262