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 
     19 struct feature {
     20 	int		compat;
     21 	unsigned int	mask;
     22 	const char	*string;
     23 };
     24 
     25 static struct feature feature_list[] = {
     26 	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_PREALLOC,
     27 			"dir_prealloc" },
     28 	{	E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL,
     29 			"has_journal" },
     30 	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_IMAGIC_INODES,
     31 			"imagic_inodes" },
     32 	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_EXT_ATTR,
     33 			"ext_attr" },
     34 	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_INDEX,
     35 			"dir_index" },
     36 	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_RESIZE_INODE,
     37 			"resize_inode" },
     38 	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_LAZY_BG,
     39 			"lazy_bg" },
     40 
     41 	{	E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER,
     42 			"sparse_super" },
     43 	{	E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_LARGE_FILE,
     44 			"large_file" },
     45 	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_HUGE_FILE,
     46 			"huge_file" },
     47 	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_GDT_CSUM,
     48 			"gdt_checksum" },
     49 	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_DIR_NLINK,
     50 			"dir_nlink" },
     51 	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE,
     52 			"extra_isize" },
     53 
     54 	{	E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_COMPRESSION,
     55 			"compression" },
     56 	{	E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_FILETYPE,
     57 			"filetype" },
     58 	{	E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_RECOVER,
     59 			"needs_recovery" },
     60 	{	E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_JOURNAL_DEV,
     61 			"journal_dev" },
     62 	{	E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_EXTENTS,
     63 			"extents" },
     64 	{	E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_META_BG,
     65 			"meta_bg" },
     66 	{	E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_EXTENTS,
     67 			"extent" },
     68 	{	E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_64BIT,
     69 			"64bit" },
     70 	{	0, 0, 0 },
     71 };
     72 
     73 const char *e2p_feature2string(int compat, unsigned int mask)
     74 {
     75 	struct feature  *f;
     76 	static char buf[20];
     77 	char	fchar;
     78 	int	fnum;
     79 
     80 	for (f = feature_list; f->string; f++) {
     81 		if ((compat == f->compat) &&
     82 		    (mask == f->mask))
     83 			return f->string;
     84 	}
     85 	switch (compat) {
     86 	case  E2P_FEATURE_COMPAT:
     87 		fchar = 'C';
     88 		break;
     89 	case E2P_FEATURE_INCOMPAT:
     90 		fchar = 'I';
     91 		break;
     92 	case E2P_FEATURE_RO_INCOMPAT:
     93 		fchar = 'R';
     94 		break;
     95 	default:
     96 		fchar = '?';
     97 		break;
     98 	}
     99 	for (fnum = 0; mask >>= 1; fnum++);
    100 	sprintf(buf, "FEATURE_%c%d", fchar, fnum);
    101 	return buf;
    102 }
    103 
    104 int e2p_string2feature(char *string, int *compat_type, unsigned int *mask)
    105 {
    106 	struct feature  *f;
    107 	char		*eptr;
    108 	int		num;
    109 
    110 	for (f = feature_list; f->string; f++) {
    111 		if (!strcasecmp(string, f->string)) {
    112 			*compat_type = f->compat;
    113 			*mask = f->mask;
    114 			return 0;
    115 		}
    116 	}
    117 	if (strncasecmp(string, "FEATURE_", 8))
    118 		return 1;
    119 
    120 	switch (string[8]) {
    121 	case 'c':
    122 	case 'C':
    123 		*compat_type = E2P_FEATURE_COMPAT;
    124 		break;
    125 	case 'i':
    126 	case 'I':
    127 		*compat_type = E2P_FEATURE_INCOMPAT;
    128 		break;
    129 	case 'r':
    130 	case 'R':
    131 		*compat_type = E2P_FEATURE_RO_INCOMPAT;
    132 		break;
    133 	default:
    134 		return 1;
    135 	}
    136 	if (string[9] == 0)
    137 		return 1;
    138 	num = strtol(string+9, &eptr, 10);
    139 	if (num > 32 || num < 0)
    140 		return 1;
    141 	if (*eptr)
    142 		return 1;
    143 	*mask = 1 << num;
    144 	return 0;
    145 }
    146 
    147 static char *skip_over_blanks(char *cp)
    148 {
    149 	while (*cp && isspace(*cp))
    150 		cp++;
    151 	return cp;
    152 }
    153 
    154 static char *skip_over_word(char *cp)
    155 {
    156 	while (*cp && !isspace(*cp) && *cp != ',')
    157 		cp++;
    158 	return cp;
    159 }
    160 
    161 /*
    162  * Edit a feature set array as requested by the user.  The ok_array,
    163  * if set, allows the application to limit what features the user is
    164  * allowed to set or clear using this function.  If clear_ok_array is set,
    165  * then use it tell whether or not it is OK to clear a filesystem feature.
    166  */
    167 int e2p_edit_feature2(const char *str, __u32 *compat_array, __u32 *ok_array,
    168 		      __u32 *clear_ok_array, int *type_err,
    169 		      unsigned int *mask_err)
    170 {
    171 	char		*cp, *buf, *next;
    172 	int		neg;
    173 	unsigned int	mask;
    174 	int		compat_type;
    175 	int		rc = 0;
    176 
    177 	if (!clear_ok_array)
    178 		clear_ok_array = ok_array;
    179 
    180 	if (type_err)
    181 		*type_err = 0;
    182 	if (mask_err)
    183 		*mask_err = 0;
    184 
    185 	buf = malloc(strlen(str)+1);
    186 	if (!buf)
    187 		return 1;
    188 	strcpy(buf, str);
    189 	for (cp = buf; cp && *cp; cp = next ? next+1 : 0) {
    190 		neg = 0;
    191 		cp = skip_over_blanks(cp);
    192 		next = skip_over_word(cp);
    193 
    194 		if (*next == 0)
    195 			next = 0;
    196 		else
    197 			*next = 0;
    198 
    199 		if ((strcasecmp(cp, "none") == 0) ||
    200 		    (strcasecmp(cp, "clear") == 0)) {
    201 			compat_array[0] = 0;
    202 			compat_array[1] = 0;
    203 			compat_array[2] = 0;
    204 			continue;
    205 		}
    206 
    207 		switch (*cp) {
    208 		case '-':
    209 		case '^':
    210 			neg++;
    211 		case '+':
    212 			cp++;
    213 			break;
    214 		}
    215 		if (e2p_string2feature(cp, &compat_type, &mask)) {
    216 			rc = 1;
    217 			break;
    218 		}
    219 		if (neg) {
    220 			if (clear_ok_array &&
    221 			    !(clear_ok_array[compat_type] & mask)) {
    222 				rc = 1;
    223 				if (type_err)
    224 					*type_err = (compat_type |
    225 						     E2P_FEATURE_NEGATE_FLAG);
    226 				if (mask_err)
    227 					*mask_err = mask;
    228 				break;
    229 			}
    230 			compat_array[compat_type] &= ~mask;
    231 		} else {
    232 			if (ok_array && !(ok_array[compat_type] & mask)) {
    233 				rc = 1;
    234 				if (type_err)
    235 					*type_err = compat_type;
    236 				if (mask_err)
    237 					*mask_err = mask;
    238 				break;
    239 			}
    240 			compat_array[compat_type] |= mask;
    241 		}
    242 	}
    243 	free(buf);
    244 	return rc;
    245 }
    246 
    247 int e2p_edit_feature(const char *str, __u32 *compat_array, __u32 *ok_array)
    248 {
    249 	return e2p_edit_feature2(str, compat_array, ok_array, 0, 0, 0);
    250 }
    251