Root/block/cmdline-parser.c

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

Archive Download this file



interactive