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