blob: 9dbc67e42a993193fb56d169cab00ecf4b825ef0
1 | /* |
2 | * Parse command line, get partition information |
3 | * |
4 | * Written by Cai Zhiyong <caizhiyong@huawei.com> |
5 | * |
6 | */ |
7 | #include <linux/export.h> |
8 | #include <linux/cmdline-parser.h> |
9 | |
10 | static int parse_subpart(struct cmdline_subpart **subpart, char *partdef) |
11 | { |
12 | int ret = 0; |
13 | struct cmdline_subpart *new_subpart; |
14 | |
15 | *subpart = NULL; |
16 | |
17 | new_subpart = kzalloc(sizeof(struct cmdline_subpart), GFP_KERNEL); |
18 | if (!new_subpart) |
19 | return -ENOMEM; |
20 | |
21 | if (*partdef == '-') { |
22 | new_subpart->size = (sector_t)(~0ULL); |
23 | partdef++; |
24 | } else { |
25 | new_subpart->size = (sector_t)memparse(partdef, &partdef); |
26 | if (new_subpart->size < (sector_t)PAGE_SIZE) { |
27 | pr_warn("cmdline partition size is invalid."); |
28 | ret = -EINVAL; |
29 | goto fail; |
30 | } |
31 | } |
32 | |
33 | if (*partdef == '@') { |
34 | partdef++; |
35 | new_subpart->from = (sector_t)memparse(partdef, &partdef); |
36 | } else { |
37 | new_subpart->from = (sector_t)(~0ULL); |
38 | } |
39 | |
40 | if (*partdef == '(') { |
41 | int length; |
42 | char *next = strchr(++partdef, ')'); |
43 | |
44 | if (!next) { |
45 | pr_warn("cmdline partition format is invalid."); |
46 | ret = -EINVAL; |
47 | goto fail; |
48 | } |
49 | |
50 | length = min_t(int, next - partdef, |
51 | sizeof(new_subpart->name) - 1); |
52 | strncpy(new_subpart->name, partdef, length); |
53 | new_subpart->name[length] = '\0'; |
54 | |
55 | partdef = ++next; |
56 | } else |
57 | new_subpart->name[0] = '\0'; |
58 | |
59 | new_subpart->flags = 0; |
60 | |
61 | if (!strncmp(partdef, "ro", 2)) { |
62 | new_subpart->flags |= PF_RDONLY; |
63 | partdef += 2; |
64 | } |
65 | |
66 | if (!strncmp(partdef, "lk", 2)) { |
67 | new_subpart->flags |= PF_POWERUP_LOCK; |
68 | partdef += 2; |
69 | } |
70 | |
71 | *subpart = new_subpart; |
72 | return 0; |
73 | fail: |
74 | kfree(new_subpart); |
75 | return ret; |
76 | } |
77 | |
78 | static void free_subpart(struct cmdline_parts *parts) |
79 | { |
80 | struct cmdline_subpart *subpart; |
81 | |
82 | while (parts->subpart) { |
83 | subpart = parts->subpart; |
84 | parts->subpart = subpart->next_subpart; |
85 | kfree(subpart); |
86 | } |
87 | } |
88 | |
89 | static int parse_parts(struct cmdline_parts **parts, const char *bdevdef) |
90 | { |
91 | int ret = -EINVAL; |
92 | char *next; |
93 | int length; |
94 | struct cmdline_subpart **next_subpart; |
95 | struct cmdline_parts *newparts; |
96 | char buf[BDEVNAME_SIZE + 32 + 4]; |
97 | |
98 | *parts = NULL; |
99 | |
100 | newparts = kzalloc(sizeof(struct cmdline_parts), GFP_KERNEL); |
101 | if (!newparts) |
102 | return -ENOMEM; |
103 | |
104 | next = strchr(bdevdef, ':'); |
105 | if (!next) { |
106 | pr_warn("cmdline partition has no block device."); |
107 | goto fail; |
108 | } |
109 | |
110 | length = min_t(int, next - bdevdef, sizeof(newparts->name) - 1); |
111 | strncpy(newparts->name, bdevdef, length); |
112 | newparts->name[length] = '\0'; |
113 | newparts->nr_subparts = 0; |
114 | |
115 | next_subpart = &newparts->subpart; |
116 | |
117 | while (next && *(++next)) { |
118 | bdevdef = next; |
119 | next = strchr(bdevdef, ','); |
120 | |
121 | length = (!next) ? (sizeof(buf) - 1) : |
122 | min_t(int, next - bdevdef, sizeof(buf) - 1); |
123 | |
124 | strncpy(buf, bdevdef, length); |
125 | buf[length] = '\0'; |
126 | |
127 | ret = parse_subpart(next_subpart, buf); |
128 | if (ret) |
129 | goto fail; |
130 | |
131 | newparts->nr_subparts++; |
132 | next_subpart = &(*next_subpart)->next_subpart; |
133 | } |
134 | |
135 | if (!newparts->subpart) { |
136 | pr_warn("cmdline partition has no valid partition."); |
137 | ret = -EINVAL; |
138 | goto fail; |
139 | } |
140 | |
141 | *parts = newparts; |
142 | |
143 | return 0; |
144 | fail: |
145 | free_subpart(newparts); |
146 | kfree(newparts); |
147 | return ret; |
148 | } |
149 | |
150 | void cmdline_parts_free(struct cmdline_parts **parts) |
151 | { |
152 | struct cmdline_parts *next_parts; |
153 | |
154 | while (*parts) { |
155 | next_parts = (*parts)->next_parts; |
156 | free_subpart(*parts); |
157 | kfree(*parts); |
158 | *parts = next_parts; |
159 | } |
160 | } |
161 | EXPORT_SYMBOL(cmdline_parts_free); |
162 | |
163 | int cmdline_parts_parse(struct cmdline_parts **parts, const char *cmdline) |
164 | { |
165 | int ret; |
166 | char *buf; |
167 | char *pbuf; |
168 | char *next; |
169 | struct cmdline_parts **next_parts; |
170 | |
171 | *parts = NULL; |
172 | |
173 | next = pbuf = buf = kstrdup(cmdline, GFP_KERNEL); |
174 | if (!buf) |
175 | return -ENOMEM; |
176 | |
177 | next_parts = parts; |
178 | |
179 | while (next && *pbuf) { |
180 | next = strchr(pbuf, ';'); |
181 | if (next) |
182 | *next = '\0'; |
183 | |
184 | ret = parse_parts(next_parts, pbuf); |
185 | if (ret) |
186 | goto fail; |
187 | |
188 | if (next) |
189 | pbuf = ++next; |
190 | |
191 | next_parts = &(*next_parts)->next_parts; |
192 | } |
193 | |
194 | if (!*parts) { |
195 | pr_warn("cmdline partition has no valid partition."); |
196 | ret = -EINVAL; |
197 | goto fail; |
198 | } |
199 | |
200 | ret = 0; |
201 | done: |
202 | kfree(buf); |
203 | return ret; |
204 | |
205 | fail: |
206 | cmdline_parts_free(parts); |
207 | goto done; |
208 | } |
209 | EXPORT_SYMBOL(cmdline_parts_parse); |
210 | |
211 | struct cmdline_parts *cmdline_parts_find(struct cmdline_parts *parts, |
212 | const char *bdev) |
213 | { |
214 | while (parts && strncmp(bdev, parts->name, sizeof(parts->name))) |
215 | parts = parts->next_parts; |
216 | return parts; |
217 | } |
218 | EXPORT_SYMBOL(cmdline_parts_find); |
219 | |
220 | /* |
221 | * add_part() |
222 | * 0 success. |
223 | * 1 can not add so many partitions. |
224 | */ |
225 | int cmdline_parts_set(struct cmdline_parts *parts, sector_t disk_size, |
226 | int slot, |
227 | int (*add_part)(int, struct cmdline_subpart *, void *), |
228 | void *param) |
229 | { |
230 | sector_t from = 0; |
231 | struct cmdline_subpart *subpart; |
232 | |
233 | for (subpart = parts->subpart; subpart; |
234 | subpart = subpart->next_subpart, slot++) { |
235 | if (subpart->from == (sector_t)(~0ULL)) |
236 | subpart->from = from; |
237 | else |
238 | from = subpart->from; |
239 | |
240 | if (from >= disk_size) |
241 | break; |
242 | |
243 | if (subpart->size > (disk_size - from)) |
244 | subpart->size = disk_size - from; |
245 | |
246 | from += subpart->size; |
247 | |
248 | if (add_part(slot, subpart, param)) |
249 | break; |
250 | } |
251 | |
252 | return slot; |
253 | } |
254 | EXPORT_SYMBOL(cmdline_parts_set); |
255 |