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