feature.c revision 3542ba0d37fe58eba91b1b42f20de0fdbfb2ac43
1/*
2 * feature.c --- convert between features and strings
3 *
4 * Copyright (C) 1999  Theodore Ts'o <tytso@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
19struct feature {
20	int		compat;
21	unsigned int	mask;
22	const char	*string;
23};
24
25static 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			"uninit_groups" },
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	{       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_FLEX_BG,
71                        "flex_bg"},
72	{	0, 0, 0 },
73};
74
75const char *e2p_feature2string(int compat, unsigned int mask)
76{
77	struct feature  *f;
78	static char buf[20];
79	char	fchar;
80	int	fnum;
81
82	for (f = feature_list; f->string; f++) {
83		if ((compat == f->compat) &&
84		    (mask == f->mask))
85			return f->string;
86	}
87	switch (compat) {
88	case  E2P_FEATURE_COMPAT:
89		fchar = 'C';
90		break;
91	case E2P_FEATURE_INCOMPAT:
92		fchar = 'I';
93		break;
94	case E2P_FEATURE_RO_INCOMPAT:
95		fchar = 'R';
96		break;
97	default:
98		fchar = '?';
99		break;
100	}
101	for (fnum = 0; mask >>= 1; fnum++);
102	sprintf(buf, "FEATURE_%c%d", fchar, fnum);
103	return buf;
104}
105
106int e2p_string2feature(char *string, int *compat_type, unsigned int *mask)
107{
108	struct feature  *f;
109	char		*eptr;
110	int		num;
111
112	for (f = feature_list; f->string; f++) {
113		if (!strcasecmp(string, f->string)) {
114			*compat_type = f->compat;
115			*mask = f->mask;
116			return 0;
117		}
118	}
119	if (strncasecmp(string, "FEATURE_", 8))
120		return 1;
121
122	switch (string[8]) {
123	case 'c':
124	case 'C':
125		*compat_type = E2P_FEATURE_COMPAT;
126		break;
127	case 'i':
128	case 'I':
129		*compat_type = E2P_FEATURE_INCOMPAT;
130		break;
131	case 'r':
132	case 'R':
133		*compat_type = E2P_FEATURE_RO_INCOMPAT;
134		break;
135	default:
136		return 1;
137	}
138	if (string[9] == 0)
139		return 1;
140	num = strtol(string+9, &eptr, 10);
141	if (num > 32 || num < 0)
142		return 1;
143	if (*eptr)
144		return 1;
145	*mask = 1 << num;
146	return 0;
147}
148
149static char *skip_over_blanks(char *cp)
150{
151	while (*cp && isspace(*cp))
152		cp++;
153	return cp;
154}
155
156static char *skip_over_word(char *cp)
157{
158	while (*cp && !isspace(*cp) && *cp != ',')
159		cp++;
160	return cp;
161}
162
163/*
164 * Edit a feature set array as requested by the user.  The ok_array,
165 * if set, allows the application to limit what features the user is
166 * allowed to set or clear using this function.  If clear_ok_array is set,
167 * then use it tell whether or not it is OK to clear a filesystem feature.
168 */
169int e2p_edit_feature2(const char *str, __u32 *compat_array, __u32 *ok_array,
170		      __u32 *clear_ok_array, int *type_err,
171		      unsigned int *mask_err)
172{
173	char		*cp, *buf, *next;
174	int		neg;
175	unsigned int	mask;
176	int		compat_type;
177	int		rc = 0;
178
179	if (!clear_ok_array)
180		clear_ok_array = ok_array;
181
182	if (type_err)
183		*type_err = 0;
184	if (mask_err)
185		*mask_err = 0;
186
187	buf = malloc(strlen(str)+1);
188	if (!buf)
189		return 1;
190	strcpy(buf, str);
191	for (cp = buf; cp && *cp; cp = next ? next+1 : 0) {
192		neg = 0;
193		cp = skip_over_blanks(cp);
194		next = skip_over_word(cp);
195
196		if (*next == 0)
197			next = 0;
198		else
199			*next = 0;
200
201		if ((strcasecmp(cp, "none") == 0) ||
202		    (strcasecmp(cp, "clear") == 0)) {
203			compat_array[0] = 0;
204			compat_array[1] = 0;
205			compat_array[2] = 0;
206			continue;
207		}
208
209		switch (*cp) {
210		case '-':
211		case '^':
212			neg++;
213		case '+':
214			cp++;
215			break;
216		}
217		if (e2p_string2feature(cp, &compat_type, &mask)) {
218			rc = 1;
219			break;
220		}
221		if (neg) {
222			if (clear_ok_array &&
223			    !(clear_ok_array[compat_type] & mask)) {
224				rc = 1;
225				if (type_err)
226					*type_err = (compat_type |
227						     E2P_FEATURE_NEGATE_FLAG);
228				if (mask_err)
229					*mask_err = mask;
230				break;
231			}
232			compat_array[compat_type] &= ~mask;
233		} else {
234			if (ok_array && !(ok_array[compat_type] & mask)) {
235				rc = 1;
236				if (type_err)
237					*type_err = compat_type;
238				if (mask_err)
239					*mask_err = mask;
240				break;
241			}
242			compat_array[compat_type] |= mask;
243		}
244	}
245	free(buf);
246	return rc;
247}
248
249int e2p_edit_feature(const char *str, __u32 *compat_array, __u32 *ok_array)
250{
251	return e2p_edit_feature2(str, compat_array, ok_array, 0, 0, 0);
252}
253