blob: b45754f971b1a68b2486a1cd391f6a5ed2293471 [file] [log] [blame]
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001/* vi: set sw=4 ts=4: */
2/*
3 * feature.c --- convert between features and strings
4 *
5 * Copyright (C) 1999 Theodore Ts'o <tytso@mit.edu>
6 *
7 * This file can be redistributed under the terms of the GNU Library General
8 * Public License
9 *
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
20struct feature {
21 int compat;
22 unsigned int mask;
23 const char *string;
24};
25
26static const struct feature feature_list[] = {
27 { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_PREALLOC,
28 "dir_prealloc" },
29 { E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL,
30 "has_journal" },
31 { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_IMAGIC_INODES,
32 "imagic_inodes" },
33 { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_EXT_ATTR,
34 "ext_attr" },
35 { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_INDEX,
36 "dir_index" },
37 { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_RESIZE_INODE,
38 "resize_inode" },
39 { E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER,
40 "sparse_super" },
41 { E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_LARGE_FILE,
42 "large_file" },
43 { E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_COMPRESSION,
44 "compression" },
45 { E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_FILETYPE,
46 "filetype" },
47 { E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_RECOVER,
48 "needs_recovery" },
49 { E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_JOURNAL_DEV,
50 "journal_dev" },
51 { E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_EXTENTS,
52 "extents" },
53 { E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_META_BG,
54 "meta_bg" },
55 { 0, 0, 0 },
56};
57
58const char *e2p_feature2string(int compat, unsigned int mask)
59{
60 const struct feature *f;
61 static char buf[20];
62 char fchar;
63 int fnum;
64
65 for (f = feature_list; f->string; f++) {
66 if ((compat == f->compat) &&
67 (mask == f->mask))
68 return f->string;
69 }
70 switch (compat) {
71 case E2P_FEATURE_COMPAT:
72 fchar = 'C';
73 break;
74 case E2P_FEATURE_INCOMPAT:
75 fchar = 'I';
76 break;
77 case E2P_FEATURE_RO_INCOMPAT:
78 fchar = 'R';
79 break;
80 default:
81 fchar = '?';
82 break;
83 }
84 for (fnum = 0; mask >>= 1; fnum++);
85 sprintf(buf, "FEATURE_%c%d", fchar, fnum);
86 return buf;
87}
88
89int e2p_string2feature(char *string, int *compat_type, unsigned int *mask)
90{
91 const struct feature *f;
92 char *eptr;
93 int num;
94
95 for (f = feature_list; f->string; f++) {
96 if (!strcasecmp(string, f->string)) {
97 *compat_type = f->compat;
98 *mask = f->mask;
99 return 0;
100 }
101 }
102 if (strncasecmp(string, "FEATURE_", 8))
103 return 1;
104
105 switch (string[8]) {
106 case 'c':
107 case 'C':
108 *compat_type = E2P_FEATURE_COMPAT;
109 break;
110 case 'i':
111 case 'I':
112 *compat_type = E2P_FEATURE_INCOMPAT;
113 break;
114 case 'r':
115 case 'R':
116 *compat_type = E2P_FEATURE_RO_INCOMPAT;
117 break;
118 default:
119 return 1;
120 }
121 if (string[9] == 0)
122 return 1;
123 num = strtol(string+9, &eptr, 10);
124 if (num > 32 || num < 0)
125 return 1;
126 if (*eptr)
127 return 1;
128 *mask = 1 << num;
129 return 0;
130}
131
132static inline char *skip_over_blanks(char *cp)
133{
134 while (*cp && isspace(*cp))
135 cp++;
136 return cp;
137}
138
139static inline char *skip_over_word(char *cp)
140{
141 while (*cp && !isspace(*cp) && *cp != ',')
142 cp++;
143 return cp;
144}
145
146/*
147 * Edit a feature set array as requested by the user. The ok_array,
148 * if set, allows the application to limit what features the user is
149 * allowed to set or clear using this function.
150 */
151int e2p_edit_feature(const char *str, __u32 *compat_array, __u32 *ok_array)
152{
153 char *cp, *buf, *next;
154 int neg;
155 unsigned int mask;
156 int compat_type;
157
158 buf = xstrdup(str);
159 cp = buf;
160 while (cp && *cp) {
161 neg = 0;
162 cp = skip_over_blanks(cp);
163 next = skip_over_word(cp);
164 if (*next == 0)
165 next = 0;
166 else
167 *next = 0;
168 switch (*cp) {
169 case '-':
170 case '^':
171 neg++;
172 case '+':
173 cp++;
174 break;
175 }
176 if (e2p_string2feature(cp, &compat_type, &mask))
177 return 1;
178 if (ok_array && !(ok_array[compat_type] & mask))
179 return 1;
180 if (neg)
181 compat_array[compat_type] &= ~mask;
182 else
183 compat_array[compat_type] |= mask;
184 cp = next ? next+1 : 0;
185 }
186 return 0;
187}