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