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