chattr.c revision 36caf25f8d61eb8ffddc9895463bce5807e96808
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 * 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) 19 */ 20 21#include <sys/types.h> 22#include <dirent.h> 23#include <fcntl.h> 24#include <stdio.h> 25#include <stdlib.h> 26#include <unistd.h> 27#include <string.h> 28#ifdef HAVE_ERRNO_H 29#include <errno.h> 30#endif 31#include <sys/param.h> 32#include <sys/stat.h> 33#include <linux/ext2_fs.h> 34 35#ifndef S_ISLNK /* So we can compile even with gcc-warn */ 36# ifdef __S_IFLNK 37# define S_ISLNK(mode) __S_ISTYPE((mode), __S_IFLNK) 38# else 39# define S_ISLNK(mode) 0 40# endif 41#endif 42 43#include "et/com_err.h" 44#include "e2p/e2p.h" 45 46#include "../version.h" 47 48const char * program_name = "chattr"; 49 50int add = 0; 51int rem = 0; 52int set = 0; 53int set_version = 0; 54 55unsigned long version; 56 57int recursive = 0; 58int verbose = 0; 59 60unsigned long af; 61unsigned long rf; 62unsigned long sf; 63 64static void fatal_error(const char * fmt_string, int errcode) 65{ 66 fprintf (stderr, fmt_string, program_name); 67 exit (errcode); 68} 69 70#define usage() fatal_error("usage: %s [-RV] [-+=AacdisSu] [-v version] files...\n", \ 71 1) 72 73static int decode_arg (int * i, int argc, char ** argv) 74{ 75 char * p; 76 char * tmp; 77 78 switch (argv[*i][0]) 79 { 80 case '-': 81 for (p = &argv[*i][1]; *p; p++) 82 switch (*p) 83 { 84 case 'R': 85 recursive = 1; 86 break; 87 case 'S': 88 rf |= EXT2_SYNC_FL; 89 rem = 1; 90 break; 91 case 'V': 92 verbose = 1; 93 break; 94#ifdef EXT2_APPEND_FL 95 case 'a': 96 rf |= EXT2_APPEND_FL; 97 rem = 1; 98 break; 99#endif 100#ifdef EXT2_NOATIME_FL 101 case 'A': 102 rf |= EXT2_NOATIME_FL; 103 rem = 1; 104 break; 105#endif 106 case 'c': 107 rf |= EXT2_COMPR_FL; 108 rem = 1; 109 break; 110#ifdef EXT2_NODUMP_FL 111 case 'd': 112 rf |= EXT2_NODUMP_FL; 113 rem = 1; 114 break; 115#endif 116#ifdef EXT2_IMMUTABLE_FL 117 case 'i': 118 rf |= EXT2_IMMUTABLE_FL; 119 rem = 1; 120 break; 121#endif 122 case 's': 123 rf |= EXT2_SECRM_FL; 124 rem = 1; 125 break; 126 case 'u': 127 rf |= EXT2_UNRM_FL; 128 rem = 1; 129 break; 130 case 'v': 131 (*i)++; 132 if (*i >= argc) 133 usage (); 134 version = strtol (argv[*i], &tmp, 0); 135 if (*tmp) 136 { 137 com_err (program_name, 0, 138 "bad version - %s\n", argv[*i]); 139 usage (); 140 } 141 set_version = 1; 142 break; 143 default: 144 fprintf (stderr, "%s: Unrecognized argument: %c\n", 145 program_name, *p); 146 usage (); 147 } 148 break; 149 case '+': 150 add = 1; 151 for (p = &argv[*i][1]; *p; p++) 152 switch (*p) 153 { 154 case 'S': 155 af |= EXT2_SYNC_FL; 156 break; 157#ifdef EXT2_APPEND_FL 158 case 'a': 159 af |= EXT2_APPEND_FL; 160 break; 161#endif 162#ifdef EXT2_NOATIME_FL 163 case 'A': 164 af |= EXT2_NOATIME_FL; 165 break; 166#endif 167 case 'c': 168 af |= EXT2_COMPR_FL; 169 break; 170#ifdef EXT2_NODUMP_FL 171 case 'd': 172 af |= EXT2_NODUMP_FL; 173 break; 174#endif 175#ifdef EXT2_IMMUTABLE_FL 176 case 'i': 177 af |= EXT2_IMMUTABLE_FL; 178 break; 179#endif 180 case 's': 181 af |= EXT2_SECRM_FL; 182 break; 183 case 'u': 184 af |= EXT2_UNRM_FL; 185 break; 186 default: 187 usage (); 188 } 189 break; 190 case '=': 191 set = 1; 192 for (p = &argv[*i][1]; *p; p++) 193 switch (*p) 194 { 195 case 'S': 196 sf |= EXT2_SYNC_FL; 197 break; 198#ifdef EXT2_APPEND_FL 199 case 'a': 200 sf |= EXT2_APPEND_FL; 201 break; 202#endif 203#ifdef EXT2_NOATIME_FL 204 case 'A': 205 sf |= EXT2_NOATIME_FL; 206 break; 207#endif 208 case 'c': 209 sf |= EXT2_COMPR_FL; 210 break; 211#ifdef EXT2_NODUMP_FL 212 case 'd': 213 sf |= EXT2_NODUMP_FL; 214 break; 215#endif 216#ifdef EXT2_IMMUTABLE_FL 217 case 'i': 218 sf |= EXT2_IMMUTABLE_FL; 219 break; 220#endif 221 case 's': 222 sf |= EXT2_SECRM_FL; 223 break; 224 case 'u': 225 sf |= EXT2_UNRM_FL; 226 break; 227 default: 228 usage (); 229 } 230 break; 231 default: 232 return EOF; 233 break; 234 } 235 return 1; 236} 237 238static int chattr_dir_proc (const char *, struct dirent *, void *); 239 240static void change_attributes (const char * name) 241{ 242 unsigned long flags; 243 struct stat st; 244 245 if (lstat (name, &st) == -1) 246 { 247 com_err (program_name, errno, "while stating %s", name); 248 return; 249 } 250 if (S_ISLNK(st.st_mode) && recursive) 251 return; 252 if (set) 253 { 254 if (verbose) 255 { 256 printf ("Flags of %s set as ", name); 257 print_flags (stdout, sf, 0); 258 printf ("\n"); 259 } 260 if (fsetflags (name, sf) == -1) 261 perror (name); 262 } 263 else 264 { 265 if (fgetflags (name, &flags) == -1) 266 com_err (program_name, errno, 267 "while reading flags on %s", name); 268 else 269 { 270 if (rem) 271 flags &= ~rf; 272 if (add) 273 flags |= af; 274 if (verbose) 275 { 276 printf ("Flags of %s set as ", name); 277 print_flags (stdout, flags, 0); 278 printf ("\n"); 279 } 280 if (fsetflags (name, flags) == -1) 281 com_err (program_name, errno, 282 "while setting flags on %s", name); 283 } 284 } 285 if (set_version) 286 { 287 if (verbose) 288 printf ("Version of %s set as %lu\n", name, version); 289 if (fsetversion (name, version) == -1) 290 com_err (program_name, errno, 291 "while setting version on %s", name); 292 } 293 if (S_ISDIR(st.st_mode) && recursive) 294 iterate_on_dir (name, chattr_dir_proc, (void *) NULL); 295} 296 297static int chattr_dir_proc (const char * dir_name, struct dirent * de, void * private) 298{ 299 if (strcmp (de->d_name, ".") && strcmp (de->d_name, "..")) 300 { 301 char *path; 302 303 path = malloc(strlen (dir_name) + 1 + strlen (de->d_name) + 1); 304 if (!path) 305 fatal_error("Couldn't allocate path variable " 306 "in chattr_dir_proc", 1); 307 sprintf (path, "%s/%s", dir_name, de->d_name); 308 change_attributes (path); 309 free(path); 310 } 311 return 0; 312} 313 314int main (int argc, char ** argv) 315{ 316 int i, j; 317 int end_arg = 0; 318 319 if (argc && *argv) 320 program_name = *argv; 321 i = 1; 322 while (i < argc && !end_arg) 323 { 324 if (decode_arg (&i, argc, argv) == EOF) 325 end_arg = 1; 326 else 327 i++; 328 } 329 if (i >= argc) 330 usage (); 331 if (set && (add || rem)) 332 { 333 fprintf (stderr, "= is incompatible with - and +\n"); 334 exit (1); 335 } 336 if (!(add || rem || set || set_version)) 337 { 338 fprintf (stderr, "Must use '-v', =, - or +\n"); 339 exit (1); 340 } 341 if (verbose) 342 fprintf (stderr, "chattr %s, %s for EXT2 FS %s, %s\n", 343 E2FSPROGS_VERSION, E2FSPROGS_DATE, 344 EXT2FS_VERSION, EXT2FS_DATE); 345 for (j = i; j < argc; j++) 346 change_attributes (argv[j]); 347 exit(0); 348} 349