]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blob - lib/e2p/feature.c
Merge branch 'maint' into next
[thirdparty/e2fsprogs.git] / lib / e2p / feature.c
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 { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_FNAME_ENCODING,
113 "fname_encoding"},
114 { 0, 0, 0 },
115 };
116
117 static struct feature jrnl_feature_list[] = {
118 { E2P_FEATURE_COMPAT, JFS_FEATURE_COMPAT_CHECKSUM,
119 "journal_checksum" },
120
121 { E2P_FEATURE_INCOMPAT, JFS_FEATURE_INCOMPAT_REVOKE,
122 "journal_incompat_revoke" },
123 { E2P_FEATURE_INCOMPAT, JFS_FEATURE_INCOMPAT_64BIT,
124 "journal_64bit" },
125 { E2P_FEATURE_INCOMPAT, JFS_FEATURE_INCOMPAT_ASYNC_COMMIT,
126 "journal_async_commit" },
127 { E2P_FEATURE_INCOMPAT, JFS_FEATURE_INCOMPAT_CSUM_V2,
128 "journal_checksum_v2" },
129 { E2P_FEATURE_INCOMPAT, JFS_FEATURE_INCOMPAT_CSUM_V3,
130 "journal_checksum_v3" },
131 { 0, 0, 0 },
132 };
133
134 const char *e2p_feature2string(int compat, unsigned int mask)
135 {
136 struct feature *f;
137 static char buf[20];
138 char fchar;
139 int fnum;
140
141 for (f = feature_list; f->string; f++) {
142 if ((compat == f->compat) &&
143 (mask == f->mask))
144 return f->string;
145 }
146 switch (compat) {
147 case E2P_FEATURE_COMPAT:
148 fchar = 'C';
149 break;
150 case E2P_FEATURE_INCOMPAT:
151 fchar = 'I';
152 break;
153 case E2P_FEATURE_RO_INCOMPAT:
154 fchar = 'R';
155 break;
156 default:
157 fchar = '?';
158 break;
159 }
160 for (fnum = 0; mask >>= 1; fnum++);
161 sprintf(buf, "FEATURE_%c%d", fchar, fnum);
162 return buf;
163 }
164
165 int e2p_string2feature(char *string, int *compat_type, unsigned int *mask)
166 {
167 struct feature *f;
168 char *eptr;
169 int num;
170
171 for (f = feature_list; f->string; f++) {
172 if (!strcasecmp(string, f->string)) {
173 *compat_type = f->compat;
174 *mask = f->mask;
175 return 0;
176 }
177 }
178 if (strncasecmp(string, "FEATURE_", 8))
179 return 1;
180
181 switch (string[8]) {
182 case 'c':
183 case 'C':
184 *compat_type = E2P_FEATURE_COMPAT;
185 break;
186 case 'i':
187 case 'I':
188 *compat_type = E2P_FEATURE_INCOMPAT;
189 break;
190 case 'r':
191 case 'R':
192 *compat_type = E2P_FEATURE_RO_INCOMPAT;
193 break;
194 default:
195 return 1;
196 }
197 if (string[9] == 0)
198 return 1;
199 num = strtol(string+9, &eptr, 10);
200 if (num > 31 || num < 0)
201 return 1;
202 if (*eptr)
203 return 1;
204 *mask = 1 << num;
205 return 0;
206 }
207
208 const char *e2p_jrnl_feature2string(int compat, unsigned int mask)
209 {
210 struct feature *f;
211 static char buf[20];
212 char fchar;
213 int fnum;
214
215 for (f = jrnl_feature_list; f->string; f++) {
216 if ((compat == f->compat) &&
217 (mask == f->mask))
218 return f->string;
219 }
220 switch (compat) {
221 case E2P_FEATURE_COMPAT:
222 fchar = 'C';
223 break;
224 case E2P_FEATURE_INCOMPAT:
225 fchar = 'I';
226 break;
227 case E2P_FEATURE_RO_INCOMPAT:
228 fchar = 'R';
229 break;
230 default:
231 fchar = '?';
232 break;
233 }
234 for (fnum = 0; mask >>= 1; fnum++);
235 sprintf(buf, "FEATURE_%c%d", fchar, fnum);
236 return buf;
237 }
238
239 int e2p_jrnl_string2feature(char *string, int *compat_type, unsigned int *mask)
240 {
241 struct feature *f;
242 char *eptr;
243 int num;
244
245 for (f = jrnl_feature_list; f->string; f++) {
246 if (!strcasecmp(string, f->string)) {
247 *compat_type = f->compat;
248 *mask = f->mask;
249 return 0;
250 }
251 }
252 if (strncasecmp(string, "FEATURE_", 8))
253 return 1;
254
255 switch (string[8]) {
256 case 'c':
257 case 'C':
258 *compat_type = E2P_FEATURE_COMPAT;
259 break;
260 case 'i':
261 case 'I':
262 *compat_type = E2P_FEATURE_INCOMPAT;
263 break;
264 case 'r':
265 case 'R':
266 *compat_type = E2P_FEATURE_RO_INCOMPAT;
267 break;
268 default:
269 return 1;
270 }
271 if (string[9] == 0)
272 return 1;
273 num = strtol(string+9, &eptr, 10);
274 if (num > 31 || num < 0)
275 return 1;
276 if (*eptr)
277 return 1;
278 *mask = 1 << num;
279 return 0;
280 }
281 static char *skip_over_blanks(char *cp)
282 {
283 while (*cp && isspace(*cp))
284 cp++;
285 return cp;
286 }
287
288 static char *skip_over_word(char *cp)
289 {
290 while (*cp && !isspace(*cp) && *cp != ',')
291 cp++;
292 return cp;
293 }
294
295 /*
296 * Edit a feature set array as requested by the user. The ok_array,
297 * if set, allows the application to limit what features the user is
298 * allowed to set or clear using this function. If clear_ok_array is set,
299 * then use it tell whether or not it is OK to clear a filesystem feature.
300 */
301 int e2p_edit_feature2(const char *str, __u32 *compat_array, __u32 *ok_array,
302 __u32 *clear_ok_array, int *type_err,
303 unsigned int *mask_err)
304 {
305 char *cp, *buf, *next;
306 int neg;
307 unsigned int mask;
308 int compat_type;
309 int rc = 0;
310
311 if (!clear_ok_array)
312 clear_ok_array = ok_array;
313
314 if (type_err)
315 *type_err = 0;
316 if (mask_err)
317 *mask_err = 0;
318
319 buf = malloc(strlen(str)+1);
320 if (!buf)
321 return 1;
322 strcpy(buf, str);
323 for (cp = buf; cp && *cp; cp = next ? next+1 : 0) {
324 neg = 0;
325 cp = skip_over_blanks(cp);
326 next = skip_over_word(cp);
327
328 if (*next == 0)
329 next = 0;
330 else
331 *next = 0;
332
333 if ((strcasecmp(cp, "none") == 0) ||
334 (strcasecmp(cp, "clear") == 0)) {
335 compat_array[0] = 0;
336 compat_array[1] = 0;
337 compat_array[2] = 0;
338 continue;
339 }
340
341 switch (*cp) {
342 case '-':
343 case '^':
344 neg++;
345 /* fallthrough */
346 case '+':
347 cp++;
348 break;
349 }
350 if (e2p_string2feature(cp, &compat_type, &mask)) {
351 rc = 1;
352 break;
353 }
354 if (neg) {
355 if (clear_ok_array &&
356 !(clear_ok_array[compat_type] & mask)) {
357 rc = 1;
358 if (type_err)
359 *type_err = (compat_type |
360 E2P_FEATURE_NEGATE_FLAG);
361 if (mask_err)
362 *mask_err = mask;
363 break;
364 }
365 compat_array[compat_type] &= ~mask;
366 } else {
367 if (ok_array && !(ok_array[compat_type] & mask)) {
368 rc = 1;
369 if (type_err)
370 *type_err = compat_type;
371 if (mask_err)
372 *mask_err = mask;
373 break;
374 }
375 compat_array[compat_type] |= mask;
376 }
377 }
378 free(buf);
379 return rc;
380 }
381
382 int e2p_edit_feature(const char *str, __u32 *compat_array, __u32 *ok_array)
383 {
384 return e2p_edit_feature2(str, compat_array, ok_array, 0, 0, 0);
385 }
386
387 #ifdef TEST_PROGRAM
388 int main(int argc, char **argv)
389 {
390 int compat, compat2, i;
391 unsigned int mask, mask2;
392 const char *str;
393 struct feature *f;
394
395 for (i = 0; i < 2; i++) {
396 if (i == 0) {
397 f = feature_list;
398 printf("Feature list:\n");
399 } else {
400 printf("\nJournal feature list:\n");
401 f = jrnl_feature_list;
402 }
403 for (; f->string; f++) {
404 if (i == 0) {
405 e2p_string2feature((char *)f->string, &compat,
406 &mask);
407 str = e2p_feature2string(compat, mask);
408 } else {
409 e2p_jrnl_string2feature((char *)f->string,
410 &compat, &mask);
411 str = e2p_jrnl_feature2string(compat, mask);
412 }
413
414 printf("\tCompat = %d, Mask = %u, %s\n",
415 compat, mask, f->string);
416 if (strcmp(f->string, str)) {
417 if (e2p_string2feature((char *) str, &compat2,
418 &mask2) ||
419 (compat2 != compat) ||
420 (mask2 != mask)) {
421 fprintf(stderr, "Failure!\n");
422 exit(1);
423 }
424 }
425 }
426 }
427 exit(0);
428 }
429 #endif