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