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 18 #include <linux/cmdline-parser.h> 19 20 #include "check.h" 21 #include "cmdline.h" 22 23 static char *cmdline; 24 static struct cmdline_parts *bdev_parts; 25 26 static int add_part(int slot, struct cmdline_subpart *subpart, void *param) 27 { 28 int label_min; 29 struct partition_meta_info *info; 30 char tmp[sizeof(info->volname) + 4]; 31 struct parsed_partitions *state = (struct parsed_partitions *)param; 32 33 if (slot >= state->limit) 34 return 1; 35 36 put_partition(state, slot, subpart->from >> 9, 37 subpart->size >> 9); 38 39 info = &state->parts[slot].info; 40 41 label_min = min_t(int, sizeof(info->volname) - 1, 42 sizeof(subpart->name)); 43 strncpy(info->volname, subpart->name, label_min); 44 info->volname[label_min] = '\0'; 45 46 snprintf(tmp, sizeof(tmp), "(%s)", info->volname); 47 strlcat(state->pp_buf, tmp, PAGE_SIZE); 48 49 state->parts[slot].has_info = true; 50 51 return 0; 52 } 53 54 static int __init cmdline_parts_setup(char *s) 55 { 56 cmdline = s; 57 return 1; 58 } 59 __setup("blkdevparts=", cmdline_parts_setup); 60 61 static bool has_overlaps(sector_t from, sector_t size, 62 sector_t from2, sector_t size2) 63 { 64 sector_t end = from + size; 65 sector_t end2 = from2 + size2; 66 67 if (from >= from2 && from < end2) 68 return true; 69 70 if (end > from2 && end <= end2) 71 return true; 72 73 if (from2 >= from && from2 < end) 74 return true; 75 76 if (end2 > from && end2 <= end) 77 return true; 78 79 return false; 80 } 81 82 static inline void overlaps_warns_header(void) 83 { 84 pr_warn("Overlapping partitions are used in command line partitions."); 85 pr_warn("Don't use filesystems on overlapping partitions:"); 86 } 87 88 static void cmdline_parts_verifier(int slot, struct parsed_partitions *state) 89 { 90 int i; 91 bool header = true; 92 93 for (; slot < state->limit && state->parts[slot].has_info; slot++) { 94 for (i = slot+1; i < state->limit && state->parts[i].has_info; 95 i++) { 96 if (has_overlaps(state->parts[slot].from, 97 state->parts[slot].size, 98 state->parts[i].from, 99 state->parts[i].size)) { 100 if (header) { 101 header = false; 102 overlaps_warns_header(); 103 } 104 pr_warn("%s[%llu,%llu] overlaps with " 105 "%s[%llu,%llu].", 106 state->parts[slot].info.volname, 107 (u64)state->parts[slot].from << 9, 108 (u64)state->parts[slot].size << 9, 109 state->parts[i].info.volname, 110 (u64)state->parts[i].from << 9, 111 (u64)state->parts[i].size << 9); 112 } 113 } 114 } 115 } 116 117 /* 118 * Purpose: allocate cmdline partitions. 119 * Returns: 120 * -1 if unable to read the partition table 121 * 0 if this isn't our partition table 122 * 1 if successful 123 */ 124 int cmdline_partition(struct parsed_partitions *state) 125 { 126 sector_t disk_size; 127 char bdev[BDEVNAME_SIZE]; 128 struct cmdline_parts *parts; 129 130 if (cmdline) { 131 if (bdev_parts) 132 cmdline_parts_free(&bdev_parts); 133 134 if (cmdline_parts_parse(&bdev_parts, cmdline)) { 135 cmdline = NULL; 136 return -1; 137 } 138 cmdline = NULL; 139 } 140 141 if (!bdev_parts) 142 return 0; 143 144 bdevname(state->bdev, bdev); 145 parts = cmdline_parts_find(bdev_parts, bdev); 146 if (!parts) 147 return 0; 148 149 disk_size = get_capacity(state->bdev->bd_disk) << 9; 150 151 cmdline_parts_set(parts, disk_size, 1, add_part, (void *)state); 152 cmdline_parts_verifier(1, state); 153 154 strlcat(state->pp_buf, "\n", PAGE_SIZE); 155 156 return 1; 157 } 158