18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2013 HUAWEI 48c2ecf20Sopenharmony_ci * Author: Cai Zhiyong <caizhiyong@huawei.com> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Read block device partition table from the command line. 78c2ecf20Sopenharmony_ci * Typically used for fixed block (eMMC) embedded devices. 88c2ecf20Sopenharmony_ci * It has no MBR, so saves storage space. Bootloader can be easily accessed 98c2ecf20Sopenharmony_ci * by absolute address of data on the block device. 108c2ecf20Sopenharmony_ci * Users can easily change the partition. 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * The format for the command line is just like mtdparts. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * For further information, see "Documentation/block/cmdline-partition.rst" 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/cmdline-parser.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "check.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic char *cmdline; 238c2ecf20Sopenharmony_cistatic struct cmdline_parts *bdev_parts; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic int add_part(int slot, struct cmdline_subpart *subpart, void *param) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci int label_min; 288c2ecf20Sopenharmony_ci struct partition_meta_info *info; 298c2ecf20Sopenharmony_ci char tmp[sizeof(info->volname) + 4]; 308c2ecf20Sopenharmony_ci struct parsed_partitions *state = (struct parsed_partitions *)param; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci if (slot >= state->limit) 338c2ecf20Sopenharmony_ci return 1; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci put_partition(state, slot, subpart->from >> 9, 368c2ecf20Sopenharmony_ci subpart->size >> 9); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci info = &state->parts[slot].info; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci label_min = min_t(int, sizeof(info->volname) - 1, 418c2ecf20Sopenharmony_ci sizeof(subpart->name)); 428c2ecf20Sopenharmony_ci strncpy(info->volname, subpart->name, label_min); 438c2ecf20Sopenharmony_ci info->volname[label_min] = '\0'; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci snprintf(tmp, sizeof(tmp), "(%s)", info->volname); 468c2ecf20Sopenharmony_ci strlcat(state->pp_buf, tmp, PAGE_SIZE); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci state->parts[slot].has_info = true; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci return 0; 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic int __init cmdline_parts_setup(char *s) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci cmdline = s; 568c2ecf20Sopenharmony_ci return 1; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci__setup("blkdevparts=", cmdline_parts_setup); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic bool has_overlaps(sector_t from, sector_t size, 618c2ecf20Sopenharmony_ci sector_t from2, sector_t size2) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci sector_t end = from + size; 648c2ecf20Sopenharmony_ci sector_t end2 = from2 + size2; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci if (from >= from2 && from < end2) 678c2ecf20Sopenharmony_ci return true; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (end > from2 && end <= end2) 708c2ecf20Sopenharmony_ci return true; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (from2 >= from && from2 < end) 738c2ecf20Sopenharmony_ci return true; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci if (end2 > from && end2 <= end) 768c2ecf20Sopenharmony_ci return true; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci return false; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic inline void overlaps_warns_header(void) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci pr_warn("Overlapping partitions are used in command line partitions."); 848c2ecf20Sopenharmony_ci pr_warn("Don't use filesystems on overlapping partitions:"); 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic void cmdline_parts_verifier(int slot, struct parsed_partitions *state) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci int i; 908c2ecf20Sopenharmony_ci bool header = true; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci for (; slot < state->limit && state->parts[slot].has_info; slot++) { 938c2ecf20Sopenharmony_ci for (i = slot+1; i < state->limit && state->parts[i].has_info; 948c2ecf20Sopenharmony_ci i++) { 958c2ecf20Sopenharmony_ci if (has_overlaps(state->parts[slot].from, 968c2ecf20Sopenharmony_ci state->parts[slot].size, 978c2ecf20Sopenharmony_ci state->parts[i].from, 988c2ecf20Sopenharmony_ci state->parts[i].size)) { 998c2ecf20Sopenharmony_ci if (header) { 1008c2ecf20Sopenharmony_ci header = false; 1018c2ecf20Sopenharmony_ci overlaps_warns_header(); 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci pr_warn("%s[%llu,%llu] overlaps with " 1048c2ecf20Sopenharmony_ci "%s[%llu,%llu].", 1058c2ecf20Sopenharmony_ci state->parts[slot].info.volname, 1068c2ecf20Sopenharmony_ci (u64)state->parts[slot].from << 9, 1078c2ecf20Sopenharmony_ci (u64)state->parts[slot].size << 9, 1088c2ecf20Sopenharmony_ci state->parts[i].info.volname, 1098c2ecf20Sopenharmony_ci (u64)state->parts[i].from << 9, 1108c2ecf20Sopenharmony_ci (u64)state->parts[i].size << 9); 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci/* 1178c2ecf20Sopenharmony_ci * Purpose: allocate cmdline partitions. 1188c2ecf20Sopenharmony_ci * Returns: 1198c2ecf20Sopenharmony_ci * -1 if unable to read the partition table 1208c2ecf20Sopenharmony_ci * 0 if this isn't our partition table 1218c2ecf20Sopenharmony_ci * 1 if successful 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_ciint cmdline_partition(struct parsed_partitions *state) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci sector_t disk_size; 1268c2ecf20Sopenharmony_ci char bdev[BDEVNAME_SIZE]; 1278c2ecf20Sopenharmony_ci struct cmdline_parts *parts; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci if (cmdline) { 1308c2ecf20Sopenharmony_ci if (bdev_parts) 1318c2ecf20Sopenharmony_ci cmdline_parts_free(&bdev_parts); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (cmdline_parts_parse(&bdev_parts, cmdline)) { 1348c2ecf20Sopenharmony_ci cmdline = NULL; 1358c2ecf20Sopenharmony_ci return -1; 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci cmdline = NULL; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci if (!bdev_parts) 1418c2ecf20Sopenharmony_ci return 0; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci bdevname(state->bdev, bdev); 1448c2ecf20Sopenharmony_ci parts = cmdline_parts_find(bdev_parts, bdev); 1458c2ecf20Sopenharmony_ci if (!parts) 1468c2ecf20Sopenharmony_ci return 0; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci disk_size = get_capacity(state->bdev->bd_disk) << 9; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci cmdline_parts_set(parts, disk_size, 1, add_part, (void *)state); 1518c2ecf20Sopenharmony_ci cmdline_parts_verifier(1, state); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci strlcat(state->pp_buf, "\n", PAGE_SIZE); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci return 1; 1568c2ecf20Sopenharmony_ci} 157