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