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