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