• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * feature.c --- convert between features and strings
3  *
4  * Copyright (C) 1999  Theodore Ts'o <tytso@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 
e2p_feature2string(int compat,unsigned int mask)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 
e2p_string2feature(char * string,int * compat_type,unsigned int * mask)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 
e2p_jrnl_feature2string(int compat,unsigned int mask)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 
e2p_jrnl_string2feature(char * string,int * compat_type,unsigned int * mask)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 }
skip_over_blanks(char * cp)238 static char *skip_over_blanks(char *cp)
239 {
240 	while (*cp && isspace(*cp))
241 		cp++;
242 	return cp;
243 }
244 
skip_over_word(char * cp)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  */
e2p_edit_feature2(const char * str,__u32 * compat_array,__u32 * ok_array,__u32 * clear_ok_array,int * type_err,unsigned int * mask_err)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 
e2p_edit_feature(const char * str,__u32 * compat_array,__u32 * ok_array)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
main(int argc,char ** argv)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