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(sizeof(struct cmdline_subpart), GFP_KERNEL); 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(sizeof(struct cmdline_parts), GFP_KERNEL); 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 char tmp[sizeof(info->volname) + 4]; 233 234 if (slot >= state->limit) 235 return 1; 236 237 put_partition(state, slot, subpart->from >> 9, 238 subpart->size >> 9); 239 240 if (subpart->flags & PF_RDONLY) 241 state->parts[slot].flags |= ADDPART_FLAG_READONLY; 242 243 info = &state->parts[slot].info; 244 245 strscpy(info->volname, subpart->name, sizeof(info->volname)); 246 247 snprintf(tmp, sizeof(tmp), "(%s)", info->volname); 248 strlcat(state->pp_buf, tmp, PAGE_SIZE); 249 250 state->parts[slot].has_info = true; 251 252 return 0; 253 } 254 255 static int cmdline_parts_set(struct cmdline_parts *parts, sector_t disk_size, 256 struct parsed_partitions *state) 257 { 258 sector_t from = 0; 259 struct cmdline_subpart *subpart; 260 int slot = 1; 261 262 for (subpart = parts->subpart; subpart; 263 subpart = subpart->next_subpart, slot++) { 264 if (subpart->from == (sector_t)(~0ULL)) 265 subpart->from = from; 266 else 267 from = subpart->from; 268 269 if (from >= disk_size) 270 break; 271 272 if (subpart->size > (disk_size - from)) 273 subpart->size = disk_size - from; 274 275 from += subpart->size; 276 277 if (add_part(slot, subpart, state)) 278 break; 279 } 280 281 return slot; 282 } 283 284 static int __init cmdline_parts_setup(char *s) 285 { 286 cmdline = s; 287 return 1; 288 } 289 __setup("blkdevparts=", cmdline_parts_setup); 290 291 static bool has_overlaps(sector_t from, sector_t size, 292 sector_t from2, sector_t size2) 293 { 294 sector_t end = from + size; 295 sector_t end2 = from2 + size2; 296 297 if (from >= from2 && from < end2) 298 return true; 299 300 if (end > from2 && end <= end2) 301 return true; 302 303 if (from2 >= from && from2 < end) 304 return true; 305 306 if (end2 > from && end2 <= end) 307 return true; 308 309 return false; 310 } 311 312 static inline void overlaps_warns_header(void) 313 { 314 pr_warn("Overlapping partitions are used in command line partitions."); 315 pr_warn("Don't use filesystems on overlapping partitions:"); 316 } 317 318 static void cmdline_parts_verifier(int slot, struct parsed_partitions *state) 319 { 320 int i; 321 bool header = true; 322 323 for (; slot < state->limit && state->parts[slot].has_info; slot++) { 324 for (i = slot+1; i < state->limit && state->parts[i].has_info; 325 i++) { 326 if (has_overlaps(state->parts[slot].from, 327 state->parts[slot].size, 328 state->parts[i].from, 329 state->parts[i].size)) { 330 if (header) { 331 header = false; 332 overlaps_warns_header(); 333 } 334 pr_warn("%s[%llu,%llu] overlaps with " 335 "%s[%llu,%llu].", 336 state->parts[slot].info.volname, 337 (u64)state->parts[slot].from << 9, 338 (u64)state->parts[slot].size << 9, 339 state->parts[i].info.volname, 340 (u64)state->parts[i].from << 9, 341 (u64)state->parts[i].size << 9); 342 } 343 } 344 } 345 } 346 347 /* 348 * Purpose: allocate cmdline partitions. 349 * Returns: 350 * -1 if unable to read the partition table 351 * 0 if this isn't our partition table 352 * 1 if successful 353 */ 354 int cmdline_partition(struct parsed_partitions *state) 355 { 356 sector_t disk_size; 357 struct cmdline_parts *parts; 358 359 if (cmdline) { 360 if (bdev_parts) 361 cmdline_parts_free(&bdev_parts); 362 363 if (cmdline_parts_parse(&bdev_parts, cmdline)) { 364 cmdline = NULL; 365 return -1; 366 } 367 cmdline = NULL; 368 } 369 370 if (!bdev_parts) 371 return 0; 372 373 parts = cmdline_parts_find(bdev_parts, state->disk->disk_name); 374 if (!parts) 375 return 0; 376 377 disk_size = get_capacity(state->disk) << 9; 378 379 cmdline_parts_set(parts, disk_size, state); 380 cmdline_parts_verifier(1, state); 381 382 strlcat(state->pp_buf, "\n", PAGE_SIZE); 383 384 return 1; 385 } 386