1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2013 HUAWEI 4 * Author: Cai Zhiyong <caizhiyong@huawei.com> 5 * 6 * Read block device partition table from the command line. 7 * Typically used for fixed block (eMMC) embedded devices. 8 * It has no MBR, so saves storage space. Bootloader can be easily accessed 9 * by absolute address of data on the block device. 10 * Users can easily change the partition. 11 * 12 * The format for the command line is just like mtdparts. 13 * 14 * For further information, see "Documentation/block/cmdline-partition.rst" 15 * 16 */ 17 #include <linux/blkdev.h> 18 #include <linux/fs.h> 19 #include <linux/slab.h> 20 #include "check.h" 21 22 23 /* partition flags */ 24 #define PF_RDONLY 0x01 /* Device is read only */ 25 #define PF_POWERUP_LOCK 0x02 /* Always locked after reset */ 26 27 struct cmdline_subpart { 28 char name[BDEVNAME_SIZE]; /* partition name, such as 'rootfs' */ 29 sector_t from; 30 sector_t size; 31 int flags; 32 struct cmdline_subpart *next_subpart; 33 }; 34 35 struct cmdline_parts { 36 char name[BDEVNAME_SIZE]; /* block device, such as 'mmcblk0' */ 37 unsigned int nr_subparts; 38 struct cmdline_subpart *subpart; 39 struct cmdline_parts *next_parts; 40 }; 41 42 static int parse_subpart(struct cmdline_subpart **subpart, char *partdef) 43 { 44 int ret = 0; 45 struct cmdline_subpart *new_subpart; 46 47 *subpart = NULL; 48 49 new_subpart = kzalloc_obj(struct cmdline_subpart); 50 if (!new_subpart) 51 return -ENOMEM; 52 53 if (*partdef == '-') { 54 new_subpart->size = (sector_t)(~0ULL); 55 partdef++; 56 } else { 57 new_subpart->size = (sector_t)memparse(partdef, &partdef); 58 if (new_subpart->size < (sector_t)PAGE_SIZE) { 59 pr_warn("cmdline partition size is invalid."); 60 ret = -EINVAL; 61 goto fail; 62 } 63 } 64 65 if (*partdef == '@') { 66 partdef++; 67 new_subpart->from = (sector_t)memparse(partdef, &partdef); 68 } else { 69 new_subpart->from = (sector_t)(~0ULL); 70 } 71 72 if (*partdef == '(') { 73 partdef++; 74 char *next = strsep(&partdef, ")"); 75 76 if (!next) { 77 pr_warn("cmdline partition format is invalid."); 78 ret = -EINVAL; 79 goto fail; 80 } 81 82 strscpy(new_subpart->name, next, sizeof(new_subpart->name)); 83 } else 84 new_subpart->name[0] = '\0'; 85 86 new_subpart->flags = 0; 87 88 if (!strncmp(partdef, "ro", 2)) { 89 new_subpart->flags |= PF_RDONLY; 90 partdef += 2; 91 } 92 93 if (!strncmp(partdef, "lk", 2)) { 94 new_subpart->flags |= PF_POWERUP_LOCK; 95 partdef += 2; 96 } 97 98 *subpart = new_subpart; 99 return 0; 100 fail: 101 kfree(new_subpart); 102 return ret; 103 } 104 105 static void free_subpart(struct cmdline_parts *parts) 106 { 107 struct cmdline_subpart *subpart; 108 109 while (parts->subpart) { 110 subpart = parts->subpart; 111 parts->subpart = subpart->next_subpart; 112 kfree(subpart); 113 } 114 } 115 116 static int parse_parts(struct cmdline_parts **parts, char *bdevdef) 117 { 118 int ret = -EINVAL; 119 char *next; 120 struct cmdline_subpart **next_subpart; 121 struct cmdline_parts *newparts; 122 123 *parts = NULL; 124 125 newparts = kzalloc_obj(struct cmdline_parts); 126 if (!newparts) 127 return -ENOMEM; 128 129 next = strsep(&bdevdef, ":"); 130 if (!next) { 131 pr_warn("cmdline partition has no block device."); 132 goto fail; 133 } 134 135 strscpy(newparts->name, next, sizeof(newparts->name)); 136 newparts->nr_subparts = 0; 137 138 next_subpart = &newparts->subpart; 139 140 while ((next = strsep(&bdevdef, ","))) { 141 ret = parse_subpart(next_subpart, next); 142 if (ret) 143 goto fail; 144 145 newparts->nr_subparts++; 146 next_subpart = &(*next_subpart)->next_subpart; 147 } 148 149 if (!newparts->subpart) { 150 pr_warn("cmdline partition has no valid partition."); 151 ret = -EINVAL; 152 goto fail; 153 } 154 155 *parts = newparts; 156 157 return 0; 158 fail: 159 free_subpart(newparts); 160 kfree(newparts); 161 return ret; 162 } 163 164 static void cmdline_parts_free(struct cmdline_parts **parts) 165 { 166 struct cmdline_parts *next_parts; 167 168 while (*parts) { 169 next_parts = (*parts)->next_parts; 170 free_subpart(*parts); 171 kfree(*parts); 172 *parts = next_parts; 173 } 174 } 175 176 static int cmdline_parts_parse(struct cmdline_parts **parts, 177 const char *cmdline) 178 { 179 int ret; 180 char *buf; 181 char *pbuf; 182 char *next; 183 struct cmdline_parts **next_parts; 184 185 *parts = NULL; 186 187 pbuf = buf = kstrdup(cmdline, GFP_KERNEL); 188 if (!buf) 189 return -ENOMEM; 190 191 next_parts = parts; 192 193 while ((next = strsep(&pbuf, ";"))) { 194 ret = parse_parts(next_parts, next); 195 if (ret) 196 goto fail; 197 198 next_parts = &(*next_parts)->next_parts; 199 } 200 201 if (!*parts) { 202 pr_warn("cmdline partition has no valid partition."); 203 ret = -EINVAL; 204 goto fail; 205 } 206 207 ret = 0; 208 done: 209 kfree(buf); 210 return ret; 211 212 fail: 213 cmdline_parts_free(parts); 214 goto done; 215 } 216 217 static struct cmdline_parts *cmdline_parts_find(struct cmdline_parts *parts, 218 const char *bdev) 219 { 220 while (parts && strncmp(bdev, parts->name, sizeof(parts->name))) 221 parts = parts->next_parts; 222 return parts; 223 } 224 225 static char *cmdline; 226 static struct cmdline_parts *bdev_parts; 227 228 static int add_part(int slot, struct cmdline_subpart *subpart, 229 struct parsed_partitions *state) 230 { 231 struct partition_meta_info *info; 232 233 if (slot >= state->limit) 234 return 1; 235 236 put_partition(state, slot, subpart->from >> 9, 237 subpart->size >> 9); 238 239 if (subpart->flags & PF_RDONLY) 240 state->parts[slot].flags |= ADDPART_FLAG_READONLY; 241 242 info = &state->parts[slot].info; 243 244 strscpy(info->volname, subpart->name, sizeof(info->volname)); 245 246 seq_buf_printf(&state->pp_buf, "(%s)", info->volname); 247 248 state->parts[slot].has_info = true; 249 250 return 0; 251 } 252 253 static int cmdline_parts_set(struct cmdline_parts *parts, sector_t disk_size, 254 struct parsed_partitions *state) 255 { 256 sector_t from = 0; 257 struct cmdline_subpart *subpart; 258 int slot = 1; 259 260 for (subpart = parts->subpart; subpart; 261 subpart = subpart->next_subpart, slot++) { 262 if (subpart->from == (sector_t)(~0ULL)) 263 subpart->from = from; 264 else 265 from = subpart->from; 266 267 if (from >= disk_size) 268 break; 269 270 if (subpart->size > (disk_size - from)) 271 subpart->size = disk_size - from; 272 273 from += subpart->size; 274 275 if (add_part(slot, subpart, state)) 276 break; 277 } 278 279 return slot; 280 } 281 282 static int __init cmdline_parts_setup(char *s) 283 { 284 cmdline = s; 285 return 1; 286 } 287 __setup("blkdevparts=", cmdline_parts_setup); 288 289 static bool has_overlaps(sector_t from, sector_t size, 290 sector_t from2, sector_t size2) 291 { 292 sector_t end = from + size; 293 sector_t end2 = from2 + size2; 294 295 if (from >= from2 && from < end2) 296 return true; 297 298 if (end > from2 && end <= end2) 299 return true; 300 301 if (from2 >= from && from2 < end) 302 return true; 303 304 if (end2 > from && end2 <= end) 305 return true; 306 307 return false; 308 } 309 310 static inline void overlaps_warns_header(void) 311 { 312 pr_warn("Overlapping partitions are used in command line partitions."); 313 pr_warn("Don't use filesystems on overlapping partitions:"); 314 } 315 316 static void cmdline_parts_verifier(int slot, struct parsed_partitions *state) 317 { 318 int i; 319 bool header = true; 320 321 for (; slot < state->limit && state->parts[slot].has_info; slot++) { 322 for (i = slot+1; i < state->limit && state->parts[i].has_info; 323 i++) { 324 if (has_overlaps(state->parts[slot].from, 325 state->parts[slot].size, 326 state->parts[i].from, 327 state->parts[i].size)) { 328 if (header) { 329 header = false; 330 overlaps_warns_header(); 331 } 332 pr_warn("%s[%llu,%llu] overlaps with " 333 "%s[%llu,%llu].", 334 state->parts[slot].info.volname, 335 (u64)state->parts[slot].from << 9, 336 (u64)state->parts[slot].size << 9, 337 state->parts[i].info.volname, 338 (u64)state->parts[i].from << 9, 339 (u64)state->parts[i].size << 9); 340 } 341 } 342 } 343 } 344 345 /* 346 * Purpose: allocate cmdline partitions. 347 * Returns: 348 * -1 if unable to read the partition table 349 * 0 if this isn't our partition table 350 * 1 if successful 351 */ 352 int cmdline_partition(struct parsed_partitions *state) 353 { 354 sector_t disk_size; 355 struct cmdline_parts *parts; 356 357 if (cmdline) { 358 if (bdev_parts) 359 cmdline_parts_free(&bdev_parts); 360 361 if (cmdline_parts_parse(&bdev_parts, cmdline)) { 362 cmdline = NULL; 363 return -1; 364 } 365 cmdline = NULL; 366 } 367 368 if (!bdev_parts) 369 return 0; 370 371 parts = cmdline_parts_find(bdev_parts, state->disk->disk_name); 372 if (!parts) 373 return 0; 374 375 disk_size = get_capacity(state->disk) << 9; 376 377 cmdline_parts_set(parts, disk_size, state); 378 cmdline_parts_verifier(1, state); 379 380 seq_buf_puts(&state->pp_buf, "\n"); 381 382 return 1; 383 } 384