1 1.13 andvar /* $NetBSD: partitions.c,v 1.13 2021/09/11 20:28:06 andvar Exp $ */ 2 1.1 martin 3 1.1 martin /* 4 1.12 martin * Copyright (c) 2020 The NetBSD Foundation, Inc. 5 1.1 martin * All rights reserved. 6 1.1 martin * 7 1.1 martin * Redistribution and use in source and binary forms, with or without 8 1.1 martin * modification, are permitted provided that the following conditions 9 1.1 martin * are met: 10 1.1 martin * 1. Redistributions of source code must retain the above copyright 11 1.1 martin * notice, this list of conditions and the following disclaimer. 12 1.1 martin * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 martin * notice, this list of conditions and the following disclaimer in the 14 1.1 martin * documentation and/or other materials provided with the distribution. 15 1.1 martin * 16 1.12 martin * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 1.12 martin * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 1.12 martin * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 1.12 martin * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 1.12 martin * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 1.1 martin * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 1.1 martin * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 1.1 martin * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 1.1 martin * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 1.12 martin * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 1.12 martin * POSSIBILITY OF SUCH DAMAGE. 27 1.1 martin */ 28 1.1 martin 29 1.1 martin #include "defs.h" 30 1.1 martin #include "mbr.h" 31 1.1 martin #include <assert.h> 32 1.1 martin 33 1.1 martin /* 34 1.1 martin * A list of partitioning schemes, so we can iterate over everything 35 1.1 martin * supported (e.g. when partitioning a new disk). NULL terminated. 36 1.1 martin */ 37 1.1 martin const struct disk_partitioning_scheme **available_part_schemes; 38 1.1 martin /* 39 1.1 martin * The number of valid entries on above list 40 1.1 martin */ 41 1.1 martin size_t num_available_part_schemes; 42 1.1 martin 43 1.10 martin extern const struct disk_partitioning_scheme disklabel_parts; 44 1.10 martin 45 1.1 martin /* 46 1.9 martin * Generic reader - query a disk device and read all partitions from it. 47 1.9 martin * disk_size is in units of physical sector size, which is passe as 48 1.9 martin * bytes_per_sec. 49 1.1 martin */ 50 1.1 martin struct disk_partitions * 51 1.9 martin partitions_read_disk(const char *dev, daddr_t disk_size, size_t bytes_per_sec, 52 1.9 martin bool no_mbr) 53 1.1 martin { 54 1.1 martin const struct disk_partitioning_scheme **ps; 55 1.10 martin #ifdef HAVE_MBR 56 1.10 martin bool mbr_done = false, disklabel_done = false; 57 1.10 martin #endif 58 1.1 martin 59 1.1 martin if (!available_part_schemes) 60 1.1 martin return NULL; 61 1.1 martin 62 1.1 martin for (ps = available_part_schemes; *ps; ps++) { 63 1.4 martin #ifdef HAVE_MBR 64 1.10 martin if (!no_mbr && (*ps) == &disklabel_parts && !mbr_done) 65 1.10 martin continue; 66 1.3 martin if (no_mbr && (*ps)->name == MSG_parttype_mbr) 67 1.3 martin continue; 68 1.10 martin if ((*ps)->name == MSG_parttype_mbr) 69 1.10 martin mbr_done = true; 70 1.10 martin if ((*ps)->read_from_disk == disklabel_parts.read_from_disk) 71 1.10 martin disklabel_done = true; 72 1.4 martin #endif 73 1.1 martin struct disk_partitions *parts = 74 1.9 martin (*ps)->read_from_disk(dev, 0, disk_size, bytes_per_sec, 75 1.9 martin *ps); 76 1.1 martin if (parts) 77 1.1 martin return parts; 78 1.1 martin } 79 1.10 martin #ifdef HAVE_MBR 80 1.10 martin if (!disklabel_done) 81 1.10 martin return disklabel_parts.read_from_disk(dev, 0, disk_size, 82 1.10 martin bytes_per_sec, &disklabel_parts); 83 1.10 martin #endif 84 1.1 martin return NULL; 85 1.1 martin } 86 1.1 martin 87 1.5 martin bool 88 1.5 martin generic_adapt_foreign_part_info(const struct disk_partitions *myself, 89 1.5 martin struct disk_part_info *dest, 90 1.5 martin const struct disk_partitioning_scheme *src_scheme, 91 1.5 martin const struct disk_part_info *src) 92 1.5 martin { 93 1.5 martin *dest = *src; 94 1.5 martin if (myself->pscheme == src_scheme) 95 1.5 martin return true; /* no conversion needed */ 96 1.5 martin 97 1.5 martin if (src->nat_type == NULL) 98 1.5 martin return false; 99 1.5 martin 100 1.5 martin /* slightly simplistic, enhance when needed */ 101 1.7 martin dest->nat_type = myself->pscheme->get_fs_part_type( 102 1.7 martin dest->nat_type ? dest->nat_type->generic_ptype : PT_root, 103 1.7 martin dest->fs_type, 104 1.5 martin dest->fs_sub_type); 105 1.5 martin if (dest->nat_type == NULL) 106 1.5 martin dest->nat_type = myself->pscheme->get_generic_part_type( 107 1.5 martin src->nat_type->generic_ptype); 108 1.5 martin if (dest->nat_type == NULL) 109 1.5 martin dest->nat_type = myself->pscheme->create_unknown_part_type(); 110 1.5 martin if (dest->nat_type == NULL) 111 1.5 martin dest->nat_type = myself->pscheme->get_generic_part_type( 112 1.5 martin PT_unknown); 113 1.5 martin 114 1.5 martin return true; 115 1.5 martin } 116 1.5 martin 117 1.1 martin /*************** global init ****************************************/ 118 1.1 martin /* 119 1.1 martin * Helper structure to fill our global list of available partitioning 120 1.1 martin * schemes. 121 1.1 martin */ 122 1.1 martin struct part_scheme_desc { 123 1.1 martin bool (*is_available)(void); 124 1.1 martin const struct disk_partitioning_scheme *ps; 125 1.1 martin }; 126 1.1 martin 127 1.1 martin #ifdef HAVE_GPT 128 1.1 martin bool gpt_parts_check(void); 129 1.1 martin extern const struct disk_partitioning_scheme gpt_parts; 130 1.1 martin #endif 131 1.1 martin #ifdef HAVE_MBR 132 1.1 martin extern const struct disk_partitioning_scheme mbr_parts; 133 1.1 martin #endif 134 1.2 martin 135 1.11 martin #if RAW_PART == 3 136 1.2 martin static struct disk_partitioning_scheme only_disklabel_parts; 137 1.2 martin 138 1.2 martin /* 139 1.13 andvar * If not overridden by MD code, we can not boot from plain 140 1.2 martin * disklabel disks (w/o MBR). 141 1.2 martin */ 142 1.2 martin static bool have_only_disklabel_boot_support(const char *disk) 143 1.2 martin { 144 1.2 martin #ifdef HAVE_PLAIN_DISKLABEL_BOOT 145 1.2 martin return HAVE_PLAIN_DISKLABEL_BOOT(disk); 146 1.2 martin #else 147 1.2 martin return false; 148 1.2 martin #endif 149 1.2 martin } 150 1.1 martin #endif 151 1.1 martin 152 1.1 martin /* 153 1.1 martin * One time initialization 154 1.1 martin */ 155 1.1 martin void 156 1.1 martin partitions_init(void) 157 1.1 martin { 158 1.1 martin /* 159 1.1 martin * List of partitioning schemes. 160 1.1 martin * Order is important, the selection menu is created from start 161 1.1 martin * to end. Keep good defaults early. Most architectures will 162 1.1 martin * only offer very few entries. 163 1.1 martin */ 164 1.1 martin static const struct part_scheme_desc all_descs[] = { 165 1.11 martin #if RAW_PART != 3 /* only available as primary on some architectures */ 166 1.1 martin { NULL, &disklabel_parts }, 167 1.1 martin #endif 168 1.1 martin #ifdef HAVE_GPT 169 1.1 martin { gpt_parts_check, &gpt_parts }, 170 1.1 martin #endif 171 1.1 martin #ifdef HAVE_MBR 172 1.1 martin { NULL, &mbr_parts }, 173 1.1 martin #endif 174 1.11 martin #if RAW_PART == 3 /* "whole disk NetBSD" disklabel variant */ 175 1.2 martin { NULL, &only_disklabel_parts }, 176 1.2 martin #endif 177 1.1 martin }; 178 1.1 martin 179 1.1 martin size_t i, avail; 180 1.1 martin const struct disk_partitioning_scheme **out; 181 1.1 martin bool *is_available; 182 1.1 martin static const size_t all_cnt = __arraycount(all_descs); 183 1.1 martin 184 1.1 martin check_available_binaries(); 185 1.1 martin 186 1.11 martin #if RAW_PART == 3 187 1.2 martin /* generate a variant of disklabel w/o parent scheme */ 188 1.2 martin only_disklabel_parts = disklabel_parts; 189 1.2 martin only_disklabel_parts.name = MSG_parttype_only_disklabel; 190 1.2 martin only_disklabel_parts.have_boot_support = 191 1.2 martin have_only_disklabel_boot_support; 192 1.2 martin #endif 193 1.2 martin 194 1.2 martin 195 1.1 martin is_available = malloc(all_cnt); 196 1.1 martin 197 1.1 martin for (avail = i = 0; i < all_cnt; i++) { 198 1.1 martin is_available[i] = all_descs[i].is_available == NULL 199 1.1 martin || all_descs[i].is_available(); 200 1.1 martin if (is_available[i]) 201 1.1 martin avail++; 202 1.1 martin } 203 1.1 martin 204 1.1 martin if (avail == 0) 205 1.1 martin return; 206 1.1 martin 207 1.1 martin num_available_part_schemes = avail; 208 1.1 martin available_part_schemes = malloc(sizeof(*available_part_schemes) 209 1.1 martin * (avail+1)); 210 1.1 martin if (available_part_schemes == NULL) 211 1.1 martin return; 212 1.1 martin 213 1.1 martin for (out = available_part_schemes, i = 0; i < all_cnt; i++) { 214 1.1 martin if (!is_available[i]) 215 1.1 martin continue; 216 1.1 martin *out++ = all_descs[i].ps; 217 1.1 martin } 218 1.1 martin *out = NULL; 219 1.1 martin 220 1.1 martin free(is_available); 221 1.1 martin } 222 1.5 martin 223 1.5 martin /* 224 1.5 martin * Final cleanup 225 1.5 martin */ 226 1.5 martin void 227 1.5 martin partitions_cleanup(void) 228 1.5 martin { 229 1.5 martin for (size_t i = 0; i < num_available_part_schemes; i++) 230 1.5 martin if (available_part_schemes[i]->cleanup != NULL) 231 1.5 martin available_part_schemes[i]->cleanup(); 232 1.5 martin free(available_part_schemes); 233 1.5 martin } 234