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