feature.c revision d1154eb460efe588eaed3d439c1caaca149fa362
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 68 { E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_COMPRESSION, 69 "compression" }, 70 { E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_FILETYPE, 71 "filetype" }, 72 { E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_RECOVER, 73 "needs_recovery" }, 74 { E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_JOURNAL_DEV, 75 "journal_dev" }, 76 { E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_EXTENTS, 77 "extent" }, 78 { E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_EXTENTS, 79 "extents" }, 80 { E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_META_BG, 81 "meta_bg" }, 82 { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_64BIT, 83 "64bit" }, 84 { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_FLEX_BG, 85 "flex_bg"}, 86 { 0, 0, 0 }, 87}; 88 89static struct feature jrnl_feature_list[] = { 90 { E2P_FEATURE_COMPAT, JFS_FEATURE_COMPAT_CHECKSUM, 91 "journal_checksum" }, 92 93 { E2P_FEATURE_INCOMPAT, JFS_FEATURE_INCOMPAT_REVOKE, 94 "journal_incompat_revoke" }, 95 { E2P_FEATURE_INCOMPAT, JFS_FEATURE_INCOMPAT_ASYNC_COMMIT, 96 "journal_async_commit" }, 97 { 0, 0, 0 }, 98}; 99 100const char *e2p_feature2string(int compat, unsigned int mask) 101{ 102 struct feature *f; 103 static char buf[20]; 104 char fchar; 105 int fnum; 106 107 for (f = feature_list; f->string; f++) { 108 if ((compat == f->compat) && 109 (mask == f->mask)) 110 return f->string; 111 } 112 switch (compat) { 113 case E2P_FEATURE_COMPAT: 114 fchar = 'C'; 115 break; 116 case E2P_FEATURE_INCOMPAT: 117 fchar = 'I'; 118 break; 119 case E2P_FEATURE_RO_INCOMPAT: 120 fchar = 'R'; 121 break; 122 default: 123 fchar = '?'; 124 break; 125 } 126 for (fnum = 0; mask >>= 1; fnum++); 127 sprintf(buf, "FEATURE_%c%d", fchar, fnum); 128 return buf; 129} 130 131int e2p_string2feature(char *string, int *compat_type, unsigned int *mask) 132{ 133 struct feature *f; 134 char *eptr; 135 int num; 136 137 for (f = feature_list; f->string; f++) { 138 if (!strcasecmp(string, f->string)) { 139 *compat_type = f->compat; 140 *mask = f->mask; 141 return 0; 142 } 143 } 144 if (strncasecmp(string, "FEATURE_", 8)) 145 return 1; 146 147 switch (string[8]) { 148 case 'c': 149 case 'C': 150 *compat_type = E2P_FEATURE_COMPAT; 151 break; 152 case 'i': 153 case 'I': 154 *compat_type = E2P_FEATURE_INCOMPAT; 155 break; 156 case 'r': 157 case 'R': 158 *compat_type = E2P_FEATURE_RO_INCOMPAT; 159 break; 160 default: 161 return 1; 162 } 163 if (string[9] == 0) 164 return 1; 165 num = strtol(string+9, &eptr, 10); 166 if (num > 32 || num < 0) 167 return 1; 168 if (*eptr) 169 return 1; 170 *mask = 1 << num; 171 return 0; 172} 173 174const char *e2p_jrnl_feature2string(int compat, unsigned int mask) 175{ 176 struct feature *f; 177 static char buf[20]; 178 char fchar; 179 int fnum; 180 181 for (f = jrnl_feature_list; f->string; f++) { 182 if ((compat == f->compat) && 183 (mask == f->mask)) 184 return f->string; 185 } 186 switch (compat) { 187 case E2P_FEATURE_COMPAT: 188 fchar = 'C'; 189 break; 190 case E2P_FEATURE_INCOMPAT: 191 fchar = 'I'; 192 break; 193 case E2P_FEATURE_RO_INCOMPAT: 194 fchar = 'R'; 195 break; 196 default: 197 fchar = '?'; 198 break; 199 } 200 for (fnum = 0; mask >>= 1; fnum++); 201 sprintf(buf, "FEATURE_%c%d", fchar, fnum); 202 return buf; 203} 204 205int e2p_jrnl_string2feature(char *string, int *compat_type, unsigned int *mask) 206{ 207 struct feature *f; 208 char *eptr; 209 int num; 210 211 for (f = jrnl_feature_list; f->string; f++) { 212 if (!strcasecmp(string, f->string)) { 213 *compat_type = f->compat; 214 *mask = f->mask; 215 return 0; 216 } 217 } 218 if (strncasecmp(string, "FEATURE_", 8)) 219 return 1; 220 221 switch (string[8]) { 222 case 'c': 223 case 'C': 224 *compat_type = E2P_FEATURE_COMPAT; 225 break; 226 case 'i': 227 case 'I': 228 *compat_type = E2P_FEATURE_INCOMPAT; 229 break; 230 case 'r': 231 case 'R': 232 *compat_type = E2P_FEATURE_RO_INCOMPAT; 233 break; 234 default: 235 return 1; 236 } 237 if (string[9] == 0) 238 return 1; 239 num = strtol(string+9, &eptr, 10); 240 if (num > 32 || num < 0) 241 return 1; 242 if (*eptr) 243 return 1; 244 *mask = 1 << num; 245 return 0; 246} 247static char *skip_over_blanks(char *cp) 248{ 249 while (*cp && isspace(*cp)) 250 cp++; 251 return cp; 252} 253 254static char *skip_over_word(char *cp) 255{ 256 while (*cp && !isspace(*cp) && *cp != ',') 257 cp++; 258 return cp; 259} 260 261/* 262 * Edit a feature set array as requested by the user. The ok_array, 263 * if set, allows the application to limit what features the user is 264 * allowed to set or clear using this function. If clear_ok_array is set, 265 * then use it tell whether or not it is OK to clear a filesystem feature. 266 */ 267int e2p_edit_feature2(const char *str, __u32 *compat_array, __u32 *ok_array, 268 __u32 *clear_ok_array, int *type_err, 269 unsigned int *mask_err) 270{ 271 char *cp, *buf, *next; 272 int neg; 273 unsigned int mask; 274 int compat_type; 275 int rc = 0; 276 277 if (!clear_ok_array) 278 clear_ok_array = ok_array; 279 280 if (type_err) 281 *type_err = 0; 282 if (mask_err) 283 *mask_err = 0; 284 285 buf = malloc(strlen(str)+1); 286 if (!buf) 287 return 1; 288 strcpy(buf, str); 289 for (cp = buf; cp && *cp; cp = next ? next+1 : 0) { 290 neg = 0; 291 cp = skip_over_blanks(cp); 292 next = skip_over_word(cp); 293 294 if (*next == 0) 295 next = 0; 296 else 297 *next = 0; 298 299 if ((strcasecmp(cp, "none") == 0) || 300 (strcasecmp(cp, "clear") == 0)) { 301 compat_array[0] = 0; 302 compat_array[1] = 0; 303 compat_array[2] = 0; 304 continue; 305 } 306 307 switch (*cp) { 308 case '-': 309 case '^': 310 neg++; 311 /* fallthrough */ 312 case '+': 313 cp++; 314 break; 315 } 316 if (e2p_string2feature(cp, &compat_type, &mask)) { 317 rc = 1; 318 break; 319 } 320 if (neg) { 321 if (clear_ok_array && 322 !(clear_ok_array[compat_type] & mask)) { 323 rc = 1; 324 if (type_err) 325 *type_err = (compat_type | 326 E2P_FEATURE_NEGATE_FLAG); 327 if (mask_err) 328 *mask_err = mask; 329 break; 330 } 331 compat_array[compat_type] &= ~mask; 332 } else { 333 if (ok_array && !(ok_array[compat_type] & mask)) { 334 rc = 1; 335 if (type_err) 336 *type_err = compat_type; 337 if (mask_err) 338 *mask_err = mask; 339 break; 340 } 341 compat_array[compat_type] |= mask; 342 } 343 } 344 free(buf); 345 return rc; 346} 347 348int e2p_edit_feature(const char *str, __u32 *compat_array, __u32 *ok_array) 349{ 350 return e2p_edit_feature2(str, compat_array, ok_array, 0, 0, 0); 351} 352 353#ifdef TEST_PROGRAM 354int main(int argc, char **argv) 355{ 356 int compat, compat2, i; 357 unsigned int mask, mask2; 358 const char *str; 359 struct feature *f; 360 361 for (i = 0; i < 2; i++) { 362 if (i == 0) { 363 f = feature_list; 364 printf("Feature list:\n"); 365 } else { 366 printf("\nJournal feature list:\n"); 367 f = jrnl_feature_list; 368 } 369 for (; f->string; f++) { 370 if (i == 0) { 371 e2p_string2feature((char *)f->string, &compat, 372 &mask); 373 str = e2p_feature2string(compat, mask); 374 } else { 375 e2p_jrnl_string2feature((char *)f->string, 376 &compat, &mask); 377 str = e2p_jrnl_feature2string(compat, mask); 378 } 379 380 printf("\tCompat = %d, Mask = %u, %s\n", 381 compat, mask, f->string); 382 if (strcmp(f->string, str)) { 383 if (e2p_string2feature((char *) str, &compat2, 384 &mask2) || 385 (compat2 != compat) || 386 (mask2 != mask)) { 387 fprintf(stderr, "Failure!\n"); 388 exit(1); 389 } 390 } 391 } 392 } 393 exit(0); 394} 395#endif 396