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