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