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