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