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