1/* vi: set sw=4 ts=4: */ 2/* 3 * feature.c --- convert between features and strings 4 * 5 * Copyright (C) 1999 Theodore Ts'o <tytso@mit.edu> 6 * 7 * This file can be redistributed under the terms of the GNU Library General 8 * Public License 9 * 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 20struct feature { 21 int compat; 22 unsigned int mask; 23 const char *string; 24}; 25 26static const struct feature feature_list[] = { 27 { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_PREALLOC, 28 "dir_prealloc" }, 29 { E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL, 30 "has_journal" }, 31 { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_IMAGIC_INODES, 32 "imagic_inodes" }, 33 { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_EXT_ATTR, 34 "ext_attr" }, 35 { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_INDEX, 36 "dir_index" }, 37 { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_RESIZE_INODE, 38 "resize_inode" }, 39 { E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER, 40 "sparse_super" }, 41 { E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_LARGE_FILE, 42 "large_file" }, 43 { E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_COMPRESSION, 44 "compression" }, 45 { E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_FILETYPE, 46 "filetype" }, 47 { E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_RECOVER, 48 "needs_recovery" }, 49 { E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_JOURNAL_DEV, 50 "journal_dev" }, 51 { E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_EXTENTS, 52 "extents" }, 53 { E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_META_BG, 54 "meta_bg" }, 55 { 0, 0, 0 }, 56}; 57 58const char *e2p_feature2string(int compat, unsigned int mask) 59{ 60 const struct feature *f; 61 static char buf[20]; 62 char fchar; 63 int fnum; 64 65 for (f = feature_list; f->string; f++) { 66 if ((compat == f->compat) && 67 (mask == f->mask)) 68 return f->string; 69 } 70 switch (compat) { 71 case E2P_FEATURE_COMPAT: 72 fchar = 'C'; 73 break; 74 case E2P_FEATURE_INCOMPAT: 75 fchar = 'I'; 76 break; 77 case E2P_FEATURE_RO_INCOMPAT: 78 fchar = 'R'; 79 break; 80 default: 81 fchar = '?'; 82 break; 83 } 84 for (fnum = 0; mask >>= 1; fnum++); 85 sprintf(buf, "FEATURE_%c%d", fchar, fnum); 86 return buf; 87} 88 89int e2p_string2feature(char *string, int *compat_type, unsigned int *mask) 90{ 91 const struct feature *f; 92 char *eptr; 93 int num; 94 95 for (f = feature_list; f->string; f++) { 96 if (!strcasecmp(string, f->string)) { 97 *compat_type = f->compat; 98 *mask = f->mask; 99 return 0; 100 } 101 } 102 if (strncasecmp(string, "FEATURE_", 8)) 103 return 1; 104 105 switch (string[8]) { 106 case 'c': 107 case 'C': 108 *compat_type = E2P_FEATURE_COMPAT; 109 break; 110 case 'i': 111 case 'I': 112 *compat_type = E2P_FEATURE_INCOMPAT; 113 break; 114 case 'r': 115 case 'R': 116 *compat_type = E2P_FEATURE_RO_INCOMPAT; 117 break; 118 default: 119 return 1; 120 } 121 if (string[9] == 0) 122 return 1; 123 num = strtol(string+9, &eptr, 10); 124 if (num > 32 || num < 0) 125 return 1; 126 if (*eptr) 127 return 1; 128 *mask = 1 << num; 129 return 0; 130} 131 132static inline char *skip_over_blanks(char *cp) 133{ 134 while (*cp && isspace(*cp)) 135 cp++; 136 return cp; 137} 138 139static inline char *skip_over_word(char *cp) 140{ 141 while (*cp && !isspace(*cp) && *cp != ',') 142 cp++; 143 return cp; 144} 145 146/* 147 * Edit a feature set array as requested by the user. The ok_array, 148 * if set, allows the application to limit what features the user is 149 * allowed to set or clear using this function. 150 */ 151int e2p_edit_feature(const char *str, __u32 *compat_array, __u32 *ok_array) 152{ 153 char *cp, *buf, *next; 154 int neg; 155 unsigned int mask; 156 int compat_type; 157 158 buf = xstrdup(str); 159 cp = buf; 160 while (cp && *cp) { 161 neg = 0; 162 cp = skip_over_blanks(cp); 163 next = skip_over_word(cp); 164 if (*next == 0) 165 next = 0; 166 else 167 *next = 0; 168 switch (*cp) { 169 case '-': 170 case '^': 171 neg++; 172 case '+': 173 cp++; 174 break; 175 } 176 if (e2p_string2feature(cp, &compat_type, &mask)) 177 return 1; 178 if (ok_array && !(ok_array[compat_type] & mask)) 179 return 1; 180 if (neg) 181 compat_array[compat_type] &= ~mask; 182 else 183 compat_array[compat_type] |= mask; 184 cp = next ? next+1 : 0; 185 } 186 return 0; 187} 188