0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #include <linux/blkdev.h>
0018 #include <linux/fs.h>
0019 #include <linux/slab.h>
0020 #include "check.h"
0021
0022
0023
0024 #define PF_RDONLY 0x01
0025 #define PF_POWERUP_LOCK 0x02
0026
0027 struct cmdline_subpart {
0028 char name[BDEVNAME_SIZE];
0029 sector_t from;
0030 sector_t size;
0031 int flags;
0032 struct cmdline_subpart *next_subpart;
0033 };
0034
0035 struct cmdline_parts {
0036 char name[BDEVNAME_SIZE];
0037 unsigned int nr_subparts;
0038 struct cmdline_subpart *subpart;
0039 struct cmdline_parts *next_parts;
0040 };
0041
0042 static int parse_subpart(struct cmdline_subpart **subpart, char *partdef)
0043 {
0044 int ret = 0;
0045 struct cmdline_subpart *new_subpart;
0046
0047 *subpart = NULL;
0048
0049 new_subpart = kzalloc(sizeof(struct cmdline_subpart), GFP_KERNEL);
0050 if (!new_subpart)
0051 return -ENOMEM;
0052
0053 if (*partdef == '-') {
0054 new_subpart->size = (sector_t)(~0ULL);
0055 partdef++;
0056 } else {
0057 new_subpart->size = (sector_t)memparse(partdef, &partdef);
0058 if (new_subpart->size < (sector_t)PAGE_SIZE) {
0059 pr_warn("cmdline partition size is invalid.");
0060 ret = -EINVAL;
0061 goto fail;
0062 }
0063 }
0064
0065 if (*partdef == '@') {
0066 partdef++;
0067 new_subpart->from = (sector_t)memparse(partdef, &partdef);
0068 } else {
0069 new_subpart->from = (sector_t)(~0ULL);
0070 }
0071
0072 if (*partdef == '(') {
0073 int length;
0074 char *next = strchr(++partdef, ')');
0075
0076 if (!next) {
0077 pr_warn("cmdline partition format is invalid.");
0078 ret = -EINVAL;
0079 goto fail;
0080 }
0081
0082 length = min_t(int, next - partdef,
0083 sizeof(new_subpart->name) - 1);
0084 strncpy(new_subpart->name, partdef, length);
0085 new_subpart->name[length] = '\0';
0086
0087 partdef = ++next;
0088 } else
0089 new_subpart->name[0] = '\0';
0090
0091 new_subpart->flags = 0;
0092
0093 if (!strncmp(partdef, "ro", 2)) {
0094 new_subpart->flags |= PF_RDONLY;
0095 partdef += 2;
0096 }
0097
0098 if (!strncmp(partdef, "lk", 2)) {
0099 new_subpart->flags |= PF_POWERUP_LOCK;
0100 partdef += 2;
0101 }
0102
0103 *subpart = new_subpart;
0104 return 0;
0105 fail:
0106 kfree(new_subpart);
0107 return ret;
0108 }
0109
0110 static void free_subpart(struct cmdline_parts *parts)
0111 {
0112 struct cmdline_subpart *subpart;
0113
0114 while (parts->subpart) {
0115 subpart = parts->subpart;
0116 parts->subpart = subpart->next_subpart;
0117 kfree(subpart);
0118 }
0119 }
0120
0121 static int parse_parts(struct cmdline_parts **parts, const char *bdevdef)
0122 {
0123 int ret = -EINVAL;
0124 char *next;
0125 int length;
0126 struct cmdline_subpart **next_subpart;
0127 struct cmdline_parts *newparts;
0128 char buf[BDEVNAME_SIZE + 32 + 4];
0129
0130 *parts = NULL;
0131
0132 newparts = kzalloc(sizeof(struct cmdline_parts), GFP_KERNEL);
0133 if (!newparts)
0134 return -ENOMEM;
0135
0136 next = strchr(bdevdef, ':');
0137 if (!next) {
0138 pr_warn("cmdline partition has no block device.");
0139 goto fail;
0140 }
0141
0142 length = min_t(int, next - bdevdef, sizeof(newparts->name) - 1);
0143 strncpy(newparts->name, bdevdef, length);
0144 newparts->name[length] = '\0';
0145 newparts->nr_subparts = 0;
0146
0147 next_subpart = &newparts->subpart;
0148
0149 while (next && *(++next)) {
0150 bdevdef = next;
0151 next = strchr(bdevdef, ',');
0152
0153 length = (!next) ? (sizeof(buf) - 1) :
0154 min_t(int, next - bdevdef, sizeof(buf) - 1);
0155
0156 strncpy(buf, bdevdef, length);
0157 buf[length] = '\0';
0158
0159 ret = parse_subpart(next_subpart, buf);
0160 if (ret)
0161 goto fail;
0162
0163 newparts->nr_subparts++;
0164 next_subpart = &(*next_subpart)->next_subpart;
0165 }
0166
0167 if (!newparts->subpart) {
0168 pr_warn("cmdline partition has no valid partition.");
0169 ret = -EINVAL;
0170 goto fail;
0171 }
0172
0173 *parts = newparts;
0174
0175 return 0;
0176 fail:
0177 free_subpart(newparts);
0178 kfree(newparts);
0179 return ret;
0180 }
0181
0182 static void cmdline_parts_free(struct cmdline_parts **parts)
0183 {
0184 struct cmdline_parts *next_parts;
0185
0186 while (*parts) {
0187 next_parts = (*parts)->next_parts;
0188 free_subpart(*parts);
0189 kfree(*parts);
0190 *parts = next_parts;
0191 }
0192 }
0193
0194 static int cmdline_parts_parse(struct cmdline_parts **parts,
0195 const char *cmdline)
0196 {
0197 int ret;
0198 char *buf;
0199 char *pbuf;
0200 char *next;
0201 struct cmdline_parts **next_parts;
0202
0203 *parts = NULL;
0204
0205 next = pbuf = buf = kstrdup(cmdline, GFP_KERNEL);
0206 if (!buf)
0207 return -ENOMEM;
0208
0209 next_parts = parts;
0210
0211 while (next && *pbuf) {
0212 next = strchr(pbuf, ';');
0213 if (next)
0214 *next = '\0';
0215
0216 ret = parse_parts(next_parts, pbuf);
0217 if (ret)
0218 goto fail;
0219
0220 if (next)
0221 pbuf = ++next;
0222
0223 next_parts = &(*next_parts)->next_parts;
0224 }
0225
0226 if (!*parts) {
0227 pr_warn("cmdline partition has no valid partition.");
0228 ret = -EINVAL;
0229 goto fail;
0230 }
0231
0232 ret = 0;
0233 done:
0234 kfree(buf);
0235 return ret;
0236
0237 fail:
0238 cmdline_parts_free(parts);
0239 goto done;
0240 }
0241
0242 static struct cmdline_parts *cmdline_parts_find(struct cmdline_parts *parts,
0243 const char *bdev)
0244 {
0245 while (parts && strncmp(bdev, parts->name, sizeof(parts->name)))
0246 parts = parts->next_parts;
0247 return parts;
0248 }
0249
0250 static char *cmdline;
0251 static struct cmdline_parts *bdev_parts;
0252
0253 static int add_part(int slot, struct cmdline_subpart *subpart,
0254 struct parsed_partitions *state)
0255 {
0256 int label_min;
0257 struct partition_meta_info *info;
0258 char tmp[sizeof(info->volname) + 4];
0259
0260 if (slot >= state->limit)
0261 return 1;
0262
0263 put_partition(state, slot, subpart->from >> 9,
0264 subpart->size >> 9);
0265
0266 info = &state->parts[slot].info;
0267
0268 label_min = min_t(int, sizeof(info->volname) - 1,
0269 sizeof(subpart->name));
0270 strncpy(info->volname, subpart->name, label_min);
0271 info->volname[label_min] = '\0';
0272
0273 snprintf(tmp, sizeof(tmp), "(%s)", info->volname);
0274 strlcat(state->pp_buf, tmp, PAGE_SIZE);
0275
0276 state->parts[slot].has_info = true;
0277
0278 return 0;
0279 }
0280
0281 static int cmdline_parts_set(struct cmdline_parts *parts, sector_t disk_size,
0282 struct parsed_partitions *state)
0283 {
0284 sector_t from = 0;
0285 struct cmdline_subpart *subpart;
0286 int slot = 1;
0287
0288 for (subpart = parts->subpart; subpart;
0289 subpart = subpart->next_subpart, slot++) {
0290 if (subpart->from == (sector_t)(~0ULL))
0291 subpart->from = from;
0292 else
0293 from = subpart->from;
0294
0295 if (from >= disk_size)
0296 break;
0297
0298 if (subpart->size > (disk_size - from))
0299 subpart->size = disk_size - from;
0300
0301 from += subpart->size;
0302
0303 if (add_part(slot, subpart, state))
0304 break;
0305 }
0306
0307 return slot;
0308 }
0309
0310 static int __init cmdline_parts_setup(char *s)
0311 {
0312 cmdline = s;
0313 return 1;
0314 }
0315 __setup("blkdevparts=", cmdline_parts_setup);
0316
0317 static bool has_overlaps(sector_t from, sector_t size,
0318 sector_t from2, sector_t size2)
0319 {
0320 sector_t end = from + size;
0321 sector_t end2 = from2 + size2;
0322
0323 if (from >= from2 && from < end2)
0324 return true;
0325
0326 if (end > from2 && end <= end2)
0327 return true;
0328
0329 if (from2 >= from && from2 < end)
0330 return true;
0331
0332 if (end2 > from && end2 <= end)
0333 return true;
0334
0335 return false;
0336 }
0337
0338 static inline void overlaps_warns_header(void)
0339 {
0340 pr_warn("Overlapping partitions are used in command line partitions.");
0341 pr_warn("Don't use filesystems on overlapping partitions:");
0342 }
0343
0344 static void cmdline_parts_verifier(int slot, struct parsed_partitions *state)
0345 {
0346 int i;
0347 bool header = true;
0348
0349 for (; slot < state->limit && state->parts[slot].has_info; slot++) {
0350 for (i = slot+1; i < state->limit && state->parts[i].has_info;
0351 i++) {
0352 if (has_overlaps(state->parts[slot].from,
0353 state->parts[slot].size,
0354 state->parts[i].from,
0355 state->parts[i].size)) {
0356 if (header) {
0357 header = false;
0358 overlaps_warns_header();
0359 }
0360 pr_warn("%s[%llu,%llu] overlaps with "
0361 "%s[%llu,%llu].",
0362 state->parts[slot].info.volname,
0363 (u64)state->parts[slot].from << 9,
0364 (u64)state->parts[slot].size << 9,
0365 state->parts[i].info.volname,
0366 (u64)state->parts[i].from << 9,
0367 (u64)state->parts[i].size << 9);
0368 }
0369 }
0370 }
0371 }
0372
0373
0374
0375
0376
0377
0378
0379
0380 int cmdline_partition(struct parsed_partitions *state)
0381 {
0382 sector_t disk_size;
0383 struct cmdline_parts *parts;
0384
0385 if (cmdline) {
0386 if (bdev_parts)
0387 cmdline_parts_free(&bdev_parts);
0388
0389 if (cmdline_parts_parse(&bdev_parts, cmdline)) {
0390 cmdline = NULL;
0391 return -1;
0392 }
0393 cmdline = NULL;
0394 }
0395
0396 if (!bdev_parts)
0397 return 0;
0398
0399 parts = cmdline_parts_find(bdev_parts, state->disk->disk_name);
0400 if (!parts)
0401 return 0;
0402
0403 disk_size = get_capacity(state->disk) << 9;
0404
0405 cmdline_parts_set(parts, disk_size, state);
0406 cmdline_parts_verifier(1, state);
0407
0408 strlcat(state->pp_buf, "\n", PAGE_SIZE);
0409
0410 return 1;
0411 }