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