feature.c revision 8c778b3acd885c79d76d94b4ba0b7fad7b031607
1/* 2 * feature.c --- convert between features and strings 3 * 4 * Copyright (C) 1999 Theodore Ts'o <tytso@mit.edu> 5 * 6 * %Begin-Header% 7 * This file may be redistributed under the terms of the GNU Library 8 * General Public License, version 2. 9 * %End-Header% 10 */ 11 12#include "config.h" 13#include <stdio.h> 14#include <stdlib.h> 15#include <string.h> 16#include <ctype.h> 17#include <errno.h> 18 19#include "e2p.h" 20#include <ext2fs/ext2fs.h> 21#include <ext2fs/jfs_user.h> 22 23struct feature { 24 int compat; 25 unsigned int mask; 26 const char *string; 27}; 28 29static struct feature feature_list[] = { 30 { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_PREALLOC, 31 "dir_prealloc" }, 32 { E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL, 33 "has_journal" }, 34 { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_IMAGIC_INODES, 35 "imagic_inodes" }, 36 { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_EXT_ATTR, 37 "ext_attr" }, 38 { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_INDEX, 39 "dir_index" }, 40 { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_RESIZE_INODE, 41 "resize_inode" }, 42 { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_LAZY_BG, 43 "lazy_bg" }, 44 { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_EXCLUDE_BITMAP, 45 "snapshot_bitmap" }, 46 47 { E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER, 48 "sparse_super" }, 49 { E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_LARGE_FILE, 50 "large_file" }, 51 { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_HUGE_FILE, 52 "huge_file" }, 53 { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_GDT_CSUM, 54 "uninit_bg" }, 55 { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_GDT_CSUM, 56 "uninit_groups" }, 57 { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_DIR_NLINK, 58 "dir_nlink" }, 59 { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE, 60 "extra_isize" }, 61 { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_QUOTA, 62 "quota" }, 63 { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_BIGALLOC, 64 "bigalloc"}, 65 { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_METADATA_CSUM, 66 "metadata_csum"}, 67 { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_REPLICA, 68 "replica" }, 69 70 { E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_COMPRESSION, 71 "compression" }, 72 { E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_FILETYPE, 73 "filetype" }, 74 { E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_RECOVER, 75 "needs_recovery" }, 76 { E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_JOURNAL_DEV, 77 "journal_dev" }, 78 { E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_EXTENTS, 79 "extent" }, 80 { E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_EXTENTS, 81 "extents" }, 82 { E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_META_BG, 83 "meta_bg" }, 84 { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_64BIT, 85 "64bit" }, 86 { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_MMP, 87 "mmp" }, 88 { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_FLEX_BG, 89 "flex_bg"}, 90 { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_EA_INODE, 91 "ea_inode"}, 92 { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_DIRDATA, 93 "dirdata"}, 94 { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_LARGEDIR, 95 "large_dir"}, 96 { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_INLINEDATA, 97 "inline_data"}, 98 { 0, 0, 0 }, 99}; 100 101static struct feature jrnl_feature_list[] = { 102 { E2P_FEATURE_COMPAT, JFS_FEATURE_COMPAT_CHECKSUM, 103 "journal_checksum" }, 104 105 { E2P_FEATURE_INCOMPAT, JFS_FEATURE_INCOMPAT_REVOKE, 106 "journal_incompat_revoke" }, 107 { E2P_FEATURE_INCOMPAT, JFS_FEATURE_INCOMPAT_64BIT, 108 "journal_64bit" }, 109 { E2P_FEATURE_INCOMPAT, JFS_FEATURE_INCOMPAT_ASYNC_COMMIT, 110 "journal_async_commit" }, 111 { 0, 0, 0 }, 112}; 113 114const char *e2p_feature2string(int compat, unsigned int mask) 115{ 116 struct feature *f; 117 static char buf[20]; 118 char fchar; 119 int fnum; 120 121 for (f = feature_list; f->string; f++) { 122 if ((compat == f->compat) && 123 (mask == f->mask)) 124 return f->string; 125 } 126 switch (compat) { 127 case E2P_FEATURE_COMPAT: 128 fchar = 'C'; 129 break; 130 case E2P_FEATURE_INCOMPAT: 131 fchar = 'I'; 132 break; 133 case E2P_FEATURE_RO_INCOMPAT: 134 fchar = 'R'; 135 break; 136 default: 137 fchar = '?'; 138 break; 139 } 140 for (fnum = 0; mask >>= 1; fnum++); 141 sprintf(buf, "FEATURE_%c%d", fchar, fnum); 142 return buf; 143} 144 145int e2p_string2feature(char *string, int *compat_type, unsigned int *mask) 146{ 147 struct feature *f; 148 char *eptr; 149 int num; 150 151 for (f = feature_list; f->string; f++) { 152 if (!strcasecmp(string, f->string)) { 153 *compat_type = f->compat; 154 *mask = f->mask; 155 return 0; 156 } 157 } 158 if (strncasecmp(string, "FEATURE_", 8)) 159 return 1; 160 161 switch (string[8]) { 162 case 'c': 163 case 'C': 164 *compat_type = E2P_FEATURE_COMPAT; 165 break; 166 case 'i': 167 case 'I': 168 *compat_type = E2P_FEATURE_INCOMPAT; 169 break; 170 case 'r': 171 case 'R': 172 *compat_type = E2P_FEATURE_RO_INCOMPAT; 173 break; 174 default: 175 return 1; 176 } 177 if (string[9] == 0) 178 return 1; 179 num = strtol(string+9, &eptr, 10); 180 if (num > 32 || num < 0) 181 return 1; 182 if (*eptr) 183 return 1; 184 *mask = 1 << num; 185 return 0; 186} 187 188const char *e2p_jrnl_feature2string(int compat, unsigned int mask) 189{ 190 struct feature *f; 191 static char buf[20]; 192 char fchar; 193 int fnum; 194 195 for (f = jrnl_feature_list; f->string; f++) { 196 if ((compat == f->compat) && 197 (mask == f->mask)) 198 return f->string; 199 } 200 switch (compat) { 201 case E2P_FEATURE_COMPAT: 202 fchar = 'C'; 203 break; 204 case E2P_FEATURE_INCOMPAT: 205 fchar = 'I'; 206 break; 207 case E2P_FEATURE_RO_INCOMPAT: 208 fchar = 'R'; 209 break; 210 default: 211 fchar = '?'; 212 break; 213 } 214 for (fnum = 0; mask >>= 1; fnum++); 215 sprintf(buf, "FEATURE_%c%d", fchar, fnum); 216 return buf; 217} 218 219int e2p_jrnl_string2feature(char *string, int *compat_type, unsigned int *mask) 220{ 221 struct feature *f; 222 char *eptr; 223 int num; 224 225 for (f = jrnl_feature_list; f->string; f++) { 226 if (!strcasecmp(string, f->string)) { 227 *compat_type = f->compat; 228 *mask = f->mask; 229 return 0; 230 } 231 } 232 if (strncasecmp(string, "FEATURE_", 8)) 233 return 1; 234 235 switch (string[8]) { 236 case 'c': 237 case 'C': 238 *compat_type = E2P_FEATURE_COMPAT; 239 break; 240 case 'i': 241 case 'I': 242 *compat_type = E2P_FEATURE_INCOMPAT; 243 break; 244 case 'r': 245 case 'R': 246 *compat_type = E2P_FEATURE_RO_INCOMPAT; 247 break; 248 default: 249 return 1; 250 } 251 if (string[9] == 0) 252 return 1; 253 num = strtol(string+9, &eptr, 10); 254 if (num > 32 || num < 0) 255 return 1; 256 if (*eptr) 257 return 1; 258 *mask = 1 << num; 259 return 0; 260} 261static char *skip_over_blanks(char *cp) 262{ 263 while (*cp && isspace(*cp)) 264 cp++; 265 return cp; 266} 267 268static char *skip_over_word(char *cp) 269{ 270 while (*cp && !isspace(*cp) && *cp != ',') 271 cp++; 272 return cp; 273} 274 275/* 276 * Edit a feature set array as requested by the user. The ok_array, 277 * if set, allows the application to limit what features the user is 278 * allowed to set or clear using this function. If clear_ok_array is set, 279 * then use it tell whether or not it is OK to clear a filesystem feature. 280 */ 281int e2p_edit_feature2(const char *str, __u32 *compat_array, __u32 *ok_array, 282 __u32 *clear_ok_array, int *type_err, 283 unsigned int *mask_err) 284{ 285 char *cp, *buf, *next; 286 int neg; 287 unsigned int mask; 288 int compat_type; 289 int rc = 0; 290 291 if (!clear_ok_array) 292 clear_ok_array = ok_array; 293 294 if (type_err) 295 *type_err = 0; 296 if (mask_err) 297 *mask_err = 0; 298 299 buf = malloc(strlen(str)+1); 300 if (!buf) 301 return 1; 302 strcpy(buf, str); 303 for (cp = buf; cp && *cp; cp = next ? next+1 : 0) { 304 neg = 0; 305 cp = skip_over_blanks(cp); 306 next = skip_over_word(cp); 307 308 if (*next == 0) 309 next = 0; 310 else 311 *next = 0; 312 313 if ((strcasecmp(cp, "none") == 0) || 314 (strcasecmp(cp, "clear") == 0)) { 315 compat_array[0] = 0; 316 compat_array[1] = 0; 317 compat_array[2] = 0; 318 continue; 319 } 320 321 switch (*cp) { 322 case '-': 323 case '^': 324 neg++; 325 /* fallthrough */ 326 case '+': 327 cp++; 328 break; 329 } 330 if (e2p_string2feature(cp, &compat_type, &mask)) { 331 rc = 1; 332 break; 333 } 334 if (neg) { 335 if (clear_ok_array && 336 !(clear_ok_array[compat_type] & mask)) { 337 rc = 1; 338 if (type_err) 339 *type_err = (compat_type | 340 E2P_FEATURE_NEGATE_FLAG); 341 if (mask_err) 342 *mask_err = mask; 343 break; 344 } 345 compat_array[compat_type] &= ~mask; 346 } else { 347 if (ok_array && !(ok_array[compat_type] & mask)) { 348 rc = 1; 349 if (type_err) 350 *type_err = compat_type; 351 if (mask_err) 352 *mask_err = mask; 353 break; 354 } 355 compat_array[compat_type] |= mask; 356 } 357 } 358 free(buf); 359 return rc; 360} 361 362int e2p_edit_feature(const char *str, __u32 *compat_array, __u32 *ok_array) 363{ 364 return e2p_edit_feature2(str, compat_array, ok_array, 0, 0, 0); 365} 366 367#ifdef TEST_PROGRAM 368int main(int argc, char **argv) 369{ 370 int compat, compat2, i; 371 unsigned int mask, mask2; 372 const char *str; 373 struct feature *f; 374 375 for (i = 0; i < 2; i++) { 376 if (i == 0) { 377 f = feature_list; 378 printf("Feature list:\n"); 379 } else { 380 printf("\nJournal feature list:\n"); 381 f = jrnl_feature_list; 382 } 383 for (; f->string; f++) { 384 if (i == 0) { 385 e2p_string2feature((char *)f->string, &compat, 386 &mask); 387 str = e2p_feature2string(compat, mask); 388 } else { 389 e2p_jrnl_string2feature((char *)f->string, 390 &compat, &mask); 391 str = e2p_jrnl_feature2string(compat, mask); 392 } 393 394 printf("\tCompat = %d, Mask = %u, %s\n", 395 compat, mask, f->string); 396 if (strcmp(f->string, str)) { 397 if (e2p_string2feature((char *) str, &compat2, 398 &mask2) || 399 (compat2 != compat) || 400 (mask2 != mask)) { 401 fprintf(stderr, "Failure!\n"); 402 exit(1); 403 } 404 } 405 } 406 } 407 exit(0); 408} 409#endif 410