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