Sat Jun 15 07:57:39 2019 UTC ()
After deleting all partitions, reset alignment to the values we would
have used on an empty disk.


(martin)
diff -r1.11 -r1.12 src/usr.sbin/sysinst/mbr.c

cvs diff -r1.11 -r1.12 src/usr.sbin/sysinst/mbr.c (switch to unified diff)

--- src/usr.sbin/sysinst/mbr.c 2019/06/12 06:20:17 1.11
+++ src/usr.sbin/sysinst/mbr.c 2019/06/15 07:57:38 1.12
@@ -1,2685 +1,2694 @@ @@ -1,2685 +1,2694 @@
1/* $NetBSD: mbr.c,v 1.11 2019/06/12 06:20:17 martin Exp $ */ 1/* $NetBSD: mbr.c,v 1.12 2019/06/15 07:57:38 martin Exp $ */
2 2
3/* 3/*
4 * Copyright 1997 Piermont Information Systems Inc. 4 * Copyright 1997 Piermont Information Systems Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Written by Philip A. Nelson for Piermont Information Systems Inc. 7 * Written by Philip A. Nelson for Piermont Information Systems Inc.
8 * 8 *
9 * Redistribution and use in source and binary forms, with or without 9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions 10 * modification, are permitted provided that the following conditions
11 * are met: 11 * are met:
12 * 1. Redistributions of source code must retain the above copyright 12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer. 13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright 14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the 15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution. 16 * documentation and/or other materials provided with the distribution.
17 * 3. The name of Piermont Information Systems Inc. may not be used to endorse 17 * 3. The name of Piermont Information Systems Inc. may not be used to endorse
18 * or promote products derived from this software without specific prior 18 * or promote products derived from this software without specific prior
19 * written permission. 19 * written permission.
20 * 20 *
21 * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS'' 21 * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS''
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE 24 * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31 * THE POSSIBILITY OF SUCH DAMAGE. 31 * THE POSSIBILITY OF SUCH DAMAGE.
32 * 32 *
33 */ 33 */
34 34
35/* 35/*
36 * Following applies to the geometry guessing code 36 * Following applies to the geometry guessing code
37 */ 37 */
38 38
39/* 39/*
40 * Mach Operating System 40 * Mach Operating System
41 * Copyright (c) 1992 Carnegie Mellon University 41 * Copyright (c) 1992 Carnegie Mellon University
42 * All Rights Reserved. 42 * All Rights Reserved.
43 * 43 *
44 * Permission to use, copy, modify and distribute this software and its 44 * Permission to use, copy, modify and distribute this software and its
45 * documentation is hereby granted, provided that both the copyright 45 * documentation is hereby granted, provided that both the copyright
46 * notice and this permission notice appear in all copies of the 46 * notice and this permission notice appear in all copies of the
47 * software, derivative works or modified versions, and any portions 47 * software, derivative works or modified versions, and any portions
48 * thereof, and that both notices appear in supporting documentation. 48 * thereof, and that both notices appear in supporting documentation.
49 * 49 *
50 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 50 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
51 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 51 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
52 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 52 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
53 * 53 *
54 * Carnegie Mellon requests users of this software to return to 54 * Carnegie Mellon requests users of this software to return to
55 * 55 *
56 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 56 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
57 * School of Computer Science 57 * School of Computer Science
58 * Carnegie Mellon University 58 * Carnegie Mellon University
59 * Pittsburgh PA 15213-3890 59 * Pittsburgh PA 15213-3890
60 * 60 *
61 * any improvements or extensions that they make and grant Carnegie Mellon 61 * any improvements or extensions that they make and grant Carnegie Mellon
62 * the rights to redistribute these changes. 62 * the rights to redistribute these changes.
63 */ 63 */
64 64
65/* mbr.c -- DOS Master Boot Record editing code */ 65/* mbr.c -- DOS Master Boot Record editing code */
66 66
67#ifdef HAVE_MBR 67#ifdef HAVE_MBR
68 68
69#include <sys/param.h> 69#include <sys/param.h>
70#include <sys/types.h> 70#include <sys/types.h>
71#include <assert.h> 71#include <assert.h>
72#include <stdio.h> 72#include <stdio.h>
73#include <stdlib.h> 73#include <stdlib.h>
74#include <unistd.h> 74#include <unistd.h>
75#include <fcntl.h> 75#include <fcntl.h>
76#include <util.h> 76#include <util.h>
77#include "defs.h" 77#include "defs.h"
78#include "mbr.h" 78#include "mbr.h"
79#include "md.h" 79#include "md.h"
80#include "msg_defs.h" 80#include "msg_defs.h"
81#include "menu_defs.h" 81#include "menu_defs.h"
82#include "defsizes.h" 82#include "defsizes.h"
83#include "endian.h" 83#include "endian.h"
84 84
85#define NO_BOOTMENU (-0x100) 85#define NO_BOOTMENU (-0x100)
86 86
87#define MAXCYL 1023 /* Possibly 1024 */ 87#define MAXCYL 1023 /* Possibly 1024 */
88#define MAXHEAD 255 /* Possibly 256 */ 88#define MAXHEAD 255 /* Possibly 256 */
89#define MAXSECTOR 63 89#define MAXSECTOR 63
90 90
91 91
92/* A list of predefined partition types */ 92/* A list of predefined partition types */
93const struct { 93const struct {
94 unsigned int ptype; 94 unsigned int ptype;
95 char short_desc[12]; 95 char short_desc[12];
96 const char *desc; 96 const char *desc;
97} mbr_part_types_src[] = { 97} mbr_part_types_src[] = {
98 { .ptype=MBR_PTYPE_NETBSD, .desc="NetBSD" }, 98 { .ptype=MBR_PTYPE_NETBSD, .desc="NetBSD" },
99 { .ptype=MBR_PTYPE_FAT32L, .desc="Windows FAT32, LBA" }, 99 { .ptype=MBR_PTYPE_FAT32L, .desc="Windows FAT32, LBA" },
100 { .ptype=MBR_PTYPE_EXT_LBA, .desc="Extended partition, LBA" }, 100 { .ptype=MBR_PTYPE_EXT_LBA, .desc="Extended partition, LBA" },
101 { .ptype=MBR_PTYPE_386BSD, .desc="FreeBSD/386BSD" }, 101 { .ptype=MBR_PTYPE_386BSD, .desc="FreeBSD/386BSD" },
102 { .ptype=MBR_PTYPE_OPENBSD, .desc="OpenBSD" }, 102 { .ptype=MBR_PTYPE_OPENBSD, .desc="OpenBSD" },
103 { .ptype=MBR_PTYPE_LNXEXT2, .desc="Linux native" }, 103 { .ptype=MBR_PTYPE_LNXEXT2, .desc="Linux native" },
104 { .ptype=MBR_PTYPE_LNXSWAP, .desc="Linux swap" }, 104 { .ptype=MBR_PTYPE_LNXSWAP, .desc="Linux swap" },
105 { .ptype=MBR_PTYPE_NTFSVOL, .desc="NTFS volume set" }, 105 { .ptype=MBR_PTYPE_NTFSVOL, .desc="NTFS volume set" },
106 { .ptype=MBR_PTYPE_NTFS, .desc="NTFS" }, 106 { .ptype=MBR_PTYPE_NTFS, .desc="NTFS" },
107 { .ptype=MBR_PTYPE_PREP, .desc="PReP Boot" }, 107 { .ptype=MBR_PTYPE_PREP, .desc="PReP Boot" },
108#ifdef MBR_PTYPE_SOLARIS 108#ifdef MBR_PTYPE_SOLARIS
109 { .ptype=MBR_PTYPE_SOLARIS, .desc="Solaris" }, 109 { .ptype=MBR_PTYPE_SOLARIS, .desc="Solaris" },
110#endif 110#endif
111 { .ptype=MBR_PTYPE_FAT12, .desc="DOS FAT12" }, 111 { .ptype=MBR_PTYPE_FAT12, .desc="DOS FAT12" },
112 { .ptype=MBR_PTYPE_FAT16S, .desc="DOS FAT16, <32M" }, 112 { .ptype=MBR_PTYPE_FAT16S, .desc="DOS FAT16, <32M" },
113 { .ptype=MBR_PTYPE_FAT16B, .desc="DOS FAT16, >32M" }, 113 { .ptype=MBR_PTYPE_FAT16B, .desc="DOS FAT16, >32M" },
114 { .ptype=MBR_PTYPE_FAT16L, .desc="Windows FAT16, LBA" }, 114 { .ptype=MBR_PTYPE_FAT16L, .desc="Windows FAT16, LBA" },
115 { .ptype=MBR_PTYPE_FAT32, .desc="Windows FAT32" }, 115 { .ptype=MBR_PTYPE_FAT32, .desc="Windows FAT32" },
116}; 116};
117 117
118/* bookeeping of available partition types (including custom ones) */ 118/* bookeeping of available partition types (including custom ones) */
119struct mbr_part_type_info { 119struct mbr_part_type_info {
120 struct part_type_desc gen; /* generic description */ 120 struct part_type_desc gen; /* generic description */
121 char desc_buf[40], short_buf[10]; 121 char desc_buf[40], short_buf[10];
122 size_t next_ptype; /* user interface order */ 122 size_t next_ptype; /* user interface order */
123}; 123};
124 124
125const struct disk_partitioning_scheme mbr_parts; 125const struct disk_partitioning_scheme mbr_parts;
126struct mbr_disk_partitions { 126struct mbr_disk_partitions {
127 struct disk_partitions dp, *dlabel; 127 struct disk_partitions dp, *dlabel;
128 mbr_info_t mbr; 128 mbr_info_t mbr;
129 uint ptn_alignment, ptn_0_offset, ext_ptn_alignment, 129 uint ptn_alignment, ptn_0_offset, ext_ptn_alignment,
130 geo_sec, geo_head, geo_cyl; 130 geo_sec, geo_head, geo_cyl;
131}; 131};
132 132
133const struct disk_partitioning_scheme mbr_parts; 133const struct disk_partitioning_scheme mbr_parts;
134 134
135static size_t known_part_types = 0, last_added_part_type = 0; 135static size_t known_part_types = 0, last_added_part_type = 0;
136static const size_t first_part_type = MBR_PTYPE_NETBSD; 136static const size_t first_part_type = MBR_PTYPE_NETBSD;
137 137
138/* all partition types (we are lucky, only a fixed number is possible) */ 138/* all partition types (we are lucky, only a fixed number is possible) */
139struct mbr_part_type_info mbr_gen_type_desc[256]; 139struct mbr_part_type_info mbr_gen_type_desc[256];
140 140
141const struct disk_partitioning_scheme disklabel_parts; 141const struct disk_partitioning_scheme disklabel_parts;
142 142
143static void convert_mbr_chs(int, int, int, uint8_t *, uint8_t *, 143static void convert_mbr_chs(int, int, int, uint8_t *, uint8_t *,
144 uint8_t *, uint32_t); 144 uint8_t *, uint32_t);
145 145
146/* 146/*
147 * Notes on the extended partition editor. 147 * Notes on the extended partition editor.
148 * 148 *
149 * The extended partition structure is actually a singly linked list. 149 * The extended partition structure is actually a singly linked list.
150 * Each of the 'mbr' sectors can only contain 2 items, the first describes 150 * Each of the 'mbr' sectors can only contain 2 items, the first describes
151 * a user partition (relative to that mbr sector), the second describes 151 * a user partition (relative to that mbr sector), the second describes
152 * the following partition (relative to the start of the extended partition). 152 * the following partition (relative to the start of the extended partition).
153 * 153 *
154 * The 'start' sector for the user partition is always the size of one 154 * The 'start' sector for the user partition is always the size of one
155 * track - very often 63. The extended partitions themselves should 155 * track - very often 63. The extended partitions themselves should
156 * always start on a cylinder boundary using the BIOS geometry - often 156 * always start on a cylinder boundary using the BIOS geometry - often
157 * 16065 sectors per cylinder. 157 * 16065 sectors per cylinder.
158 * 158 *
159 * The disk is also always described in increasing sector order. 159 * The disk is also always described in increasing sector order.
160 * 160 *
161 * During editing we keep the mbr sectors accurate (it might have been 161 * During editing we keep the mbr sectors accurate (it might have been
162 * easier to use absolute sector numbers though), and keep a copy of the 162 * easier to use absolute sector numbers though), and keep a copy of the
163 * entire sector - to preserve any information any other OS has tried 163 * entire sector - to preserve any information any other OS has tried
164 * to squirrel away in the (apparently) unused space. 164 * to squirrel away in the (apparently) unused space.
165 * 165 *
166 * Typical disk (with some small numbers): 166 * Typical disk (with some small numbers):
167 * 167 *
168 * 0 -> a 63 37 dos 168 * 0 -> a 63 37 dos
169 * b 100 1000 extended LBA (type 15) 169 * b 100 1000 extended LBA (type 15)
170 * 170 *
171 * 100 -> a 63 37 user 171 * 100 -> a 63 37 user
172 * b 100 200 extended partiton (type 5) 172 * b 100 200 extended partiton (type 5)
173 * 173 *
174 * 200 -> a 63 37 user 174 * 200 -> a 63 37 user
175 * b 200 300 extended partiton (type 5) 175 * b 200 300 extended partiton (type 5)
176 * 176 *
177 * 300 -> a 63 37 user 177 * 300 -> a 63 37 user
178 * b 0 0 0 (end of chain) 178 * b 0 0 0 (end of chain)
179 * 179 *
180 */ 180 */
181 181
182#ifndef debug_extended 182#ifndef debug_extended
183#define dump_mbr(mbr, msg) 183#define dump_mbr(mbr, msg)
184#else 184#else
185static void 185static void
186dump_mbr(mbr_info_t *m, const char *label) 186dump_mbr(mbr_info_t *m, const char *label)
187{ 187{
188 int i; 188 int i;
189 uint ext_base = 0; 189 uint ext_base = 0;
190 190
191 fprintf(stderr, "\n%s: bsec %d\n", label, bsec); 191 fprintf(stderr, "\n%s: bsec %d\n", label, bsec);
192 do { 192 do {
193 fprintf(stderr, "%p: %12u %p\n", 193 fprintf(stderr, "%p: %12u %p\n",
194 m, m->sector, m->extended); 194 m, m->sector, m->extended);
195 for (i = 0; i < MBR_PART_COUNT; i++) { 195 for (i = 0; i < MBR_PART_COUNT; i++) {
196 fprintf(stderr, " %*d %12u %12u %12" PRIu64, 196 fprintf(stderr, " %*d %12u %12u %12" PRIu64,
197 10, 197 10,
198 m->mbr.mbr_parts[i].mbrp_type, 198 m->mbr.mbr_parts[i].mbrp_type,
199 m->mbr.mbr_parts[i].mbrp_start, 199 m->mbr.mbr_parts[i].mbrp_start,
200 m->mbr.mbr_parts[i].mbrp_size, 200 m->mbr.mbr_parts[i].mbrp_size,
201 (uint64_t)m->mbr.mbr_parts[i].mbrp_start + 201 (uint64_t)m->mbr.mbr_parts[i].mbrp_start +
202 (uint64_t)m->mbr.mbr_parts[i].mbrp_size); 202 (uint64_t)m->mbr.mbr_parts[i].mbrp_size);
203 if (m->sector == 0 && 203 if (m->sector == 0 &&
204 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 204 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type))
205 ext_base = m->mbr.mbr_parts[i].mbrp_start; 205 ext_base = m->mbr.mbr_parts[i].mbrp_start;
206 if (m->sector > 0 && 206 if (m->sector > 0 &&
207 m->mbr.mbr_parts[i].mbrp_size > 0) { 207 m->mbr.mbr_parts[i].mbrp_size > 0) {
208 uint off = MBR_IS_EXTENDED( 208 uint off = MBR_IS_EXTENDED(
209 m->mbr.mbr_parts[i].mbrp_type) 209 m->mbr.mbr_parts[i].mbrp_type)
210 ? ext_base : m->sector; 210 ? ext_base : m->sector;
211 fprintf(stderr, " -> [%u .. %u]", 211 fprintf(stderr, " -> [%u .. %u]",
212 m->mbr.mbr_parts[i].mbrp_start + off, 212 m->mbr.mbr_parts[i].mbrp_start + off,
213 m->mbr.mbr_parts[i].mbrp_size + 213 m->mbr.mbr_parts[i].mbrp_size +
214 m->mbr.mbr_parts[i].mbrp_start + off); 214 m->mbr.mbr_parts[i].mbrp_start + off);
215 } 215 }
216 fprintf(stderr, ",\n"); 216 fprintf(stderr, ",\n");
217 if (m->sector > 0 && i >= 1) 217 if (m->sector > 0 && i >= 1)
218 break; 218 break;
219 } 219 }
220 } while ((m = m->extended)); 220 } while ((m = m->extended));
221} 221}
222#endif 222#endif
223 223
224static void 224static void
225free_mbr_info(mbr_info_t *m) 225free_mbr_info(mbr_info_t *m)
226{ 226{
227 if (m == NULL) 227 if (m == NULL)
228 return; 228 return;
229 229
230 for (int i = 0; i < MBR_PART_COUNT; i++) 230 for (int i = 0; i < MBR_PART_COUNT; i++)
231 free(__UNCONST(m->last_mounted[i])); 231 free(__UNCONST(m->last_mounted[i]));
232 free(m); 232 free(m);
233} 233}
234 234
235/* 235/*
236 * To be used only on ports which cannot provide any bios geometry 236 * To be used only on ports which cannot provide any bios geometry
237 */ 237 */
238bool 238bool
239set_bios_geom_with_mbr_guess(struct disk_partitions *parts) 239set_bios_geom_with_mbr_guess(struct disk_partitions *parts)
240{ 240{
241 int cyl, head, sec; 241 int cyl, head, sec;
242 242
243 msg_display(MSG_nobiosgeom, pm->dlcyl, pm->dlhead, pm->dlsec); 243 msg_display(MSG_nobiosgeom, pm->dlcyl, pm->dlhead, pm->dlsec);
244 if (guess_biosgeom_from_parts(parts, &cyl, &head, &sec) >= 0) 244 if (guess_biosgeom_from_parts(parts, &cyl, &head, &sec) >= 0)
245 msg_display_add(MSG_biosguess, cyl, head, sec); 245 msg_display_add(MSG_biosguess, cyl, head, sec);
246 set_bios_geom(parts, cyl, head, sec); 246 set_bios_geom(parts, cyl, head, sec);
247 if (parts->pscheme->change_disk_geom) 247 if (parts->pscheme->change_disk_geom)
248 parts->pscheme->change_disk_geom(parts, cyl, head, sec); 248 parts->pscheme->change_disk_geom(parts, cyl, head, sec);
249 249
250 return edit_outer_parts(parts); 250 return edit_outer_parts(parts);
251} 251}
252 252
253static void 253static void
254mbr_init_chs(struct mbr_disk_partitions *parts, int ncyl, int nhead, int nsec) 254mbr_init_chs(struct mbr_disk_partitions *parts, int ncyl, int nhead, int nsec)
255{ 255{
256 if (ncyl > MAXCYL) 256 if (ncyl > MAXCYL)
257 ncyl = MAXCYL; 257 ncyl = MAXCYL;
258 pm->current_cylsize = nhead*nsec; 258 pm->current_cylsize = nhead*nsec;
259 pm->max_chs = (unsigned long)ncyl*nhead*nsec; 259 pm->max_chs = (unsigned long)ncyl*nhead*nsec;
260 parts->geo_sec = nsec; 260 parts->geo_sec = nsec;
261 parts->geo_head = nhead; 261 parts->geo_head = nhead;
262 parts->geo_cyl = ncyl; 262 parts->geo_cyl = ncyl;
263} 263}
264 264
265/* 265/*
266 * get C/H/S geometry from user via menu interface and 266 * get C/H/S geometry from user via menu interface and
267 * store in globals. 267 * store in globals.
268 */ 268 */
269void 269void
270set_bios_geom(struct disk_partitions *parts, int cyl, int head, int sec) 270set_bios_geom(struct disk_partitions *parts, int cyl, int head, int sec)
271{ 271{
272 char res[80]; 272 char res[80];
273 int bsec, bhead, bcyl; 273 int bsec, bhead, bcyl;
274 daddr_t s; 274 daddr_t s;
275 275
276 if (parts->pscheme->change_disk_geom == NULL) 276 if (parts->pscheme->change_disk_geom == NULL)
277 return; 277 return;
278 278
279 msg_display_add(MSG_setbiosgeom); 279 msg_display_add(MSG_setbiosgeom);
280 280
281 do { 281 do {
282 snprintf(res, 80, "%d", sec); 282 snprintf(res, 80, "%d", sec);
283 msg_prompt_add(MSG_sectors, res, res, 80); 283 msg_prompt_add(MSG_sectors, res, res, 80);
284 bsec = atoi(res); 284 bsec = atoi(res);
285 } while (bsec <= 0 || bsec > MAXSECTOR); 285 } while (bsec <= 0 || bsec > MAXSECTOR);
286 286
287 do { 287 do {
288 snprintf(res, 80, "%d", head); 288 snprintf(res, 80, "%d", head);
289 msg_prompt_add(MSG_heads, res, res, 80); 289 msg_prompt_add(MSG_heads, res, res, 80);
290 bhead = atoi(res); 290 bhead = atoi(res);
291 } while (bhead <= 0 || bhead > MAXHEAD); 291 } while (bhead <= 0 || bhead > MAXHEAD);
292 s = min(pm->dlsize, mbr_parts.size_limit); 292 s = min(pm->dlsize, mbr_parts.size_limit);
293 bcyl = s / bsec / bhead; 293 bcyl = s / bsec / bhead;
294 if (s != bcyl * bsec * bhead) 294 if (s != bcyl * bsec * bhead)
295 bcyl++; 295 bcyl++;
296 if (bcyl > MAXCYL) 296 if (bcyl > MAXCYL)
297 bcyl = MAXCYL; 297 bcyl = MAXCYL;
298 pm->max_chs = (unsigned long)bcyl * bhead * bsec; 298 pm->max_chs = (unsigned long)bcyl * bhead * bsec;
299 pm->current_cylsize = bhead * bsec; 299 pm->current_cylsize = bhead * bsec;
300 parts->pscheme->change_disk_geom(parts, cyl, head, sec); 300 parts->pscheme->change_disk_geom(parts, cyl, head, sec);
301} 301}
302 302
303static int 303static int
304find_mbr_space(const struct mbr_info_t *mbrs, uint *start, uint *size, 304find_mbr_space(const struct mbr_info_t *mbrs, uint *start, uint *size,
305 uint from, uint end_of_disk, uint ignore_at, bool primary_only) 305 uint from, uint end_of_disk, uint ignore_at, bool primary_only)
306{ 306{
307 uint sz; 307 uint sz;
308 int i, j; 308 int i, j;
309 uint s, e; 309 uint s, e;
310 const mbr_info_t *m, *me; 310 const mbr_info_t *m, *me;
311 bool is_extended; 311 bool is_extended;
312 312
313 check_again: 313 check_again:
314 m = mbrs; 314 m = mbrs;
315 sz = end_of_disk-from; 315 sz = end_of_disk-from;
316 if (from >= end_of_disk) 316 if (from >= end_of_disk)
317 return -1; 317 return -1;
318 318
319 for (i = 0; i < MBR_PART_COUNT; i++) { 319 for (i = 0; i < MBR_PART_COUNT; i++) {
320 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 320 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED)
321 continue; 321 continue;
322 322
323 is_extended = MBR_IS_EXTENDED( 323 is_extended = MBR_IS_EXTENDED(
324 m->mbr.mbr_parts[i].mbrp_type); 324 m->mbr.mbr_parts[i].mbrp_type);
325 325
326 s = m->mbr.mbr_parts[i].mbrp_start + m->sector; 326 s = m->mbr.mbr_parts[i].mbrp_start + m->sector;
327 if (s == ignore_at) 327 if (s == ignore_at)
328 continue; 328 continue;
329 e = s + m->mbr.mbr_parts[i].mbrp_size; 329 e = s + m->mbr.mbr_parts[i].mbrp_size;
330 if (s <= from && e > from 330 if (s <= from && e > from
331 && (!is_extended || primary_only)) { 331 && (!is_extended || primary_only)) {
332 if (e - 1 >= end_of_disk) 332 if (e - 1 >= end_of_disk)
333 break; 333 break;
334 if (e >= UINT_MAX) { 334 if (e >= UINT_MAX) {
335 sz = 0; 335 sz = 0;
336 break; 336 break;
337 } 337 }
338 from = e + 1; 338 from = e + 1;
339 goto check_again; 339 goto check_again;
340 } 340 }
341 if (s <= from && e > from && is_extended) { 341 if (s <= from && e > from && is_extended) {
342 /* 342 /*
343 * if we start in the extended partiton, 343 * if we start in the extended partiton,
344 * we must end before its end 344 * we must end before its end
345 */ 345 */
346 sz = e - from; 346 sz = e - from;
347 } 347 }
348 if (s > from && s - from < sz) 348 if (s > from && s - from < sz)
349 sz = s - from; 349 sz = s - from;
350 350
351 if (is_extended) { 351 if (is_extended) {
352 for (me = m->extended; me != NULL; me = me->extended) { 352 for (me = m->extended; me != NULL; me = me->extended) {
353 for (j = 0; j < MBR_PART_COUNT; j++) { 353 for (j = 0; j < MBR_PART_COUNT; j++) {
354 if (me->mbr.mbr_parts[j].mbrp_type == 354 if (me->mbr.mbr_parts[j].mbrp_type ==
355 MBR_PTYPE_UNUSED) 355 MBR_PTYPE_UNUSED)
356 continue; 356 continue;
357 357
358 is_extended = MBR_IS_EXTENDED( 358 is_extended = MBR_IS_EXTENDED(
359 me->mbr.mbr_parts[j].mbrp_type); 359 me->mbr.mbr_parts[j].mbrp_type);
360 360
361 if (is_extended && i > 0) 361 if (is_extended && i > 0)
362 break; 362 break;
363 363
364 s = me->mbr.mbr_parts[j].mbrp_start + 364 s = me->mbr.mbr_parts[j].mbrp_start +
365 me->sector; 365 me->sector;
366 if (s == ignore_at) 366 if (s == ignore_at)
367 continue; 367 continue;
368 e = s + me->mbr.mbr_parts[j].mbrp_size; 368 e = s + me->mbr.mbr_parts[j].mbrp_size;
369 if (me->sector != 0 && me->sector< s) 369 if (me->sector != 0 && me->sector< s)
370 /* 370 /*
371 * can not allow to overwrite 371 * can not allow to overwrite
372 * the ext mbr 372 * the ext mbr
373 */ 373 */
374 s = me->sector; 374 s = me->sector;
375 if (s <= from && e > from) { 375 if (s <= from && e > from) {
376 if (e - 1 >= end_of_disk) 376 if (e - 1 >= end_of_disk)
377 break; 377 break;
378 from = e + 1; 378 from = e + 1;
379 goto check_again; 379 goto check_again;
380 } 380 }
381 if (s > from && s - from < sz) 381 if (s > from && s - from < sz)
382 sz = s - from; 382 sz = s - from;
383 383
384 } 384 }
385 } 385 }
386 } 386 }
387 } 387 }
388 388
389 if (sz == 0) 389 if (sz == 0)
390 return -1; 390 return -1;
391 if (start != NULL) 391 if (start != NULL)
392 *start = from; 392 *start = from;
393 if (size != NULL) 393 if (size != NULL)
394 *size = sz; 394 *size = sz;
395 return 0; 395 return 0;
396} 396}
397 397
398#ifdef BOOTSEL 398#ifdef BOOTSEL
399static int 399static int
400validate_and_set_names(mbr_info_t *mbri, const struct mbr_bootsel *src, 400validate_and_set_names(mbr_info_t *mbri, const struct mbr_bootsel *src,
401 uint32_t ext_base) 401 uint32_t ext_base)
402{ 402{
403 size_t i, l; 403 size_t i, l;
404 const unsigned char *p; 404 const unsigned char *p;
405 405
406 /* 406 /*
407 * The 16 bit magic used to detect whether mbr_bootsel is valid 407 * The 16 bit magic used to detect whether mbr_bootsel is valid
408 * or not is pretty week - collisions have been seen in the wild; 408 * or not is pretty week - collisions have been seen in the wild;
409 * but maybe it is just foreign tools corruption reminiscents 409 * but maybe it is just foreign tools corruption reminiscents
410 * of NetBSD MBRs. Anyway, before accepting a boot menu definition, 410 * of NetBSD MBRs. Anyway, before accepting a boot menu definition,
411 * make sure it is kinda "sane". 411 * make sure it is kinda "sane".
412 */ 412 */
413 413
414 for (i = 0; i < MBR_PART_COUNT; i++) { 414 for (i = 0; i < MBR_PART_COUNT; i++) {
415 /* 415 /*
416 * Make sure the name does not contain controll chars 416 * Make sure the name does not contain controll chars
417 * (not using iscntrl due to minimalistic locale support 417 * (not using iscntrl due to minimalistic locale support
418 * in miniroot environments) and is properly 0-terminated. 418 * in miniroot environments) and is properly 0-terminated.
419 */ 419 */
420 for (l = 0, p = (const unsigned char *)&src->mbrbs_nametab[i]; 420 for (l = 0, p = (const unsigned char *)&src->mbrbs_nametab[i];
421 *p != 0; l++, p++) { 421 *p != 0; l++, p++) {
422 if (l > MBR_BS_PARTNAMESIZE) 422 if (l > MBR_BS_PARTNAMESIZE)
423 return 0; 423 return 0;
424 if (*p < ' ') /* hacky 'iscntrl' */ 424 if (*p < ' ') /* hacky 'iscntrl' */
425 return 0; 425 return 0;
426 } 426 }
427 } 427 }
428 428
429 memcpy(&mbri->mbrb, src, sizeof(*src)); 429 memcpy(&mbri->mbrb, src, sizeof(*src));
430 430
431 if (ext_base == 0) 431 if (ext_base == 0)
432 return mbri->mbrb.mbrbs_defkey - SCAN_1; 432 return mbri->mbrb.mbrbs_defkey - SCAN_1;
433 return 0; 433 return 0;
434} 434}
435#endif 435#endif
436 436
437static void 437static void
438free_mbr(mbr_info_t *mbri) 438free_mbr(mbr_info_t *mbri)
439{ 439{
440 mbr_info_t *m = mbri->extended, *next; 440 mbr_info_t *m = mbri->extended, *next;
441 441
442 while (m != NULL) { 442 while (m != NULL) {
443 next = m->extended; 443 next = m->extended;
444 free_mbr_info(m); 444 free_mbr_info(m);
445 m = next; 445 m = next;
446 } 446 }
447 free_mbr_info(mbri); 447 free_mbr_info(mbri);
448} 448}
449 449
450static int 450static int
451valid_mbr(struct mbr_sector *mbrs) 451valid_mbr(struct mbr_sector *mbrs)
452{ 452{
453 453
454 return (le16toh(mbrs->mbr_magic) == MBR_MAGIC); 454 return (le16toh(mbrs->mbr_magic) == MBR_MAGIC);
455} 455}
456 456
457static int 457static int
458read_mbr(const char *disk, mbr_info_t *mbri) 458read_mbr(const char *disk, mbr_info_t *mbri)
459{ 459{
460 struct mbr_partition *mbrp; 460 struct mbr_partition *mbrp;
461 struct mbr_sector *mbrs = &mbri->mbr; 461 struct mbr_sector *mbrs = &mbri->mbr;
462 mbr_info_t *ext = NULL; 462 mbr_info_t *ext = NULL;
463 char diskpath[MAXPATHLEN]; 463 char diskpath[MAXPATHLEN];
464 int fd, i; 464 int fd, i;
465 uint32_t ext_base = 0, next_ext = 0; 465 uint32_t ext_base = 0, next_ext = 0;
466 int rval = -1; 466 int rval = -1;
467#ifdef BOOTSEL 467#ifdef BOOTSEL
468 mbr_info_t *ombri = mbri; 468 mbr_info_t *ombri = mbri;
469 int bootkey = 0; 469 int bootkey = 0;
470#endif 470#endif
471 471
472 memset(mbri, 0, sizeof *mbri); 472 memset(mbri, 0, sizeof *mbri);
473 473
474 /* Open the disk. */ 474 /* Open the disk. */
475 fd = opendisk(disk, O_RDONLY, diskpath, sizeof(diskpath), 0); 475 fd = opendisk(disk, O_RDONLY, diskpath, sizeof(diskpath), 0);
476 if (fd < 0) 476 if (fd < 0)
477 goto bad_mbr; 477 goto bad_mbr;
478 478
479 for (;;) { 479 for (;;) {
480 if (pread(fd, mbrs, sizeof *mbrs, 480 if (pread(fd, mbrs, sizeof *mbrs,
481 (ext_base + next_ext) * (off_t)MBR_SECSIZE) - sizeof *mbrs != 0) 481 (ext_base + next_ext) * (off_t)MBR_SECSIZE) - sizeof *mbrs != 0)
482 break; 482 break;
483 483
484 if (!valid_mbr(mbrs)) 484 if (!valid_mbr(mbrs))
485 break; 485 break;
486 486
487 mbrp = &mbrs->mbr_parts[0]; 487 mbrp = &mbrs->mbr_parts[0];
488 if (ext_base != 0) { 488 if (ext_base != 0) {
489 /* sanity check extended chain */ 489 /* sanity check extended chain */
490 if (MBR_IS_EXTENDED(mbrp[0].mbrp_type)) 490 if (MBR_IS_EXTENDED(mbrp[0].mbrp_type))
491 break; 491 break;
492 if (mbrp[1].mbrp_type != MBR_PTYPE_UNUSED && 492 if (mbrp[1].mbrp_type != MBR_PTYPE_UNUSED &&
493 !MBR_IS_EXTENDED(mbrp[1].mbrp_type)) 493 !MBR_IS_EXTENDED(mbrp[1].mbrp_type))
494 break; 494 break;
495 if (mbrp[2].mbrp_type != MBR_PTYPE_UNUSED 495 if (mbrp[2].mbrp_type != MBR_PTYPE_UNUSED
496 || mbrp[3].mbrp_type != MBR_PTYPE_UNUSED) 496 || mbrp[3].mbrp_type != MBR_PTYPE_UNUSED)
497 break; 497 break;
498 /* Looks ok, link into extended chain */ 498 /* Looks ok, link into extended chain */
499 mbri->extended = ext; 499 mbri->extended = ext;
500 ext->extended = NULL; 500 ext->extended = NULL;
501 mbri = ext; 501 mbri = ext;
502 ext = NULL; 502 ext = NULL;
503 } 503 }
504#if BOOTSEL 504#if BOOTSEL
505 if (mbrs->mbr_bootsel_magic == htole16(MBR_MAGIC)) { 505 if (mbrs->mbr_bootsel_magic == htole16(MBR_MAGIC)) {
506 /* old bootsel, grab bootsel info */ 506 /* old bootsel, grab bootsel info */
507 bootkey = validate_and_set_names(mbri, 507 bootkey = validate_and_set_names(mbri,
508 (struct mbr_bootsel *) 508 (struct mbr_bootsel *)
509 ((uint8_t *)mbrs + MBR_BS_OLD_OFFSET), 509 ((uint8_t *)mbrs + MBR_BS_OLD_OFFSET),
510 ext_base); 510 ext_base);
511 } else if (mbrs->mbr_bootsel_magic == htole16(MBR_BS_MAGIC)) { 511 } else if (mbrs->mbr_bootsel_magic == htole16(MBR_BS_MAGIC)) {
512 /* new location */ 512 /* new location */
513 bootkey = validate_and_set_names(mbri, 513 bootkey = validate_and_set_names(mbri,
514 &mbrs->mbr_bootsel, ext_base); 514 &mbrs->mbr_bootsel, ext_base);
515 } 515 }
516 /* Save original flags for mbr code update tests */ 516 /* Save original flags for mbr code update tests */
517 mbri->oflags = mbri->mbrb.mbrbs_flags; 517 mbri->oflags = mbri->mbrb.mbrbs_flags;
518#endif 518#endif
519 mbri->sector = next_ext + ext_base; 519 mbri->sector = next_ext + ext_base;
520 next_ext = 0; 520 next_ext = 0;
521 rval = 0; 521 rval = 0;
522 for (i = 0; i < MBR_PART_COUNT; mbrp++, i++) { 522 for (i = 0; i < MBR_PART_COUNT; mbrp++, i++) {
523 if (mbrp->mbrp_type == MBR_PTYPE_UNUSED) { 523 if (mbrp->mbrp_type == MBR_PTYPE_UNUSED) {
524 /* type is unused, discard scum */ 524 /* type is unused, discard scum */
525 memset(mbrp, 0, sizeof *mbrp); 525 memset(mbrp, 0, sizeof *mbrp);
526 continue; 526 continue;
527 } 527 }
528 mbrp->mbrp_start = le32toh(mbrp->mbrp_start); 528 mbrp->mbrp_start = le32toh(mbrp->mbrp_start);
529 mbrp->mbrp_size = le32toh(mbrp->mbrp_size); 529 mbrp->mbrp_size = le32toh(mbrp->mbrp_size);
530 if (MBR_IS_EXTENDED(mbrp->mbrp_type)) { 530 if (MBR_IS_EXTENDED(mbrp->mbrp_type)) {
531 next_ext = mbrp->mbrp_start; 531 next_ext = mbrp->mbrp_start;
532 } else { 532 } else {
533 uint flags = 0; 533 uint flags = 0;
534 if (mbrp->mbrp_type == MBR_PTYPE_NETBSD) 534 if (mbrp->mbrp_type == MBR_PTYPE_NETBSD)
535 flags |= GLM_LIKELY_FFS; 535 flags |= GLM_LIKELY_FFS;
536 else if (mbrp->mbrp_type == MBR_PTYPE_FAT12 || 536 else if (mbrp->mbrp_type == MBR_PTYPE_FAT12 ||
537 mbrp->mbrp_type == MBR_PTYPE_FAT16S || 537 mbrp->mbrp_type == MBR_PTYPE_FAT16S ||
538 mbrp->mbrp_type == MBR_PTYPE_FAT16B || 538 mbrp->mbrp_type == MBR_PTYPE_FAT16B ||
539 mbrp->mbrp_type == MBR_PTYPE_FAT32 || 539 mbrp->mbrp_type == MBR_PTYPE_FAT32 ||
540 mbrp->mbrp_type == MBR_PTYPE_FAT32L || 540 mbrp->mbrp_type == MBR_PTYPE_FAT32L ||
541 mbrp->mbrp_type == MBR_PTYPE_FAT16L) 541 mbrp->mbrp_type == MBR_PTYPE_FAT16L)
542 flags |= GLM_MAYBE_FAT32; 542 flags |= GLM_MAYBE_FAT32;
543 else if (mbrp->mbrp_type == MBR_PTYPE_NTFS) 543 else if (mbrp->mbrp_type == MBR_PTYPE_NTFS)
544 flags |= GLM_MAYBE_NTFS; 544 flags |= GLM_MAYBE_NTFS;
545 if (flags != 0) { 545 if (flags != 0) {
546 const char *mount = get_last_mounted( 546 const char *mount = get_last_mounted(
547 fd, mbri->sector + mbrp->mbrp_start, 547 fd, mbri->sector + mbrp->mbrp_start,
548 &mbri->fs_type[i], 548 &mbri->fs_type[i],
549 &mbri->fs_sub_type[i], 549 &mbri->fs_sub_type[i],
550 flags); 550 flags);
551 mbri->last_mounted[i] = strdup(mount); 551 mbri->last_mounted[i] = strdup(mount);
552 } 552 }
553 } 553 }
554#if BOOTSEL 554#if BOOTSEL
555 if (mbri->mbrb.mbrbs_nametab[i][0] != 0 555 if (mbri->mbrb.mbrbs_nametab[i][0] != 0
556 && bootkey-- == 0) 556 && bootkey-- == 0)
557 ombri->bootsec = mbri->sector + 557 ombri->bootsec = mbri->sector +
558 mbrp->mbrp_start; 558 mbrp->mbrp_start;
559#endif 559#endif
560 } 560 }
561 561
562 if (next_ext == 0 || ext_base + next_ext <= mbri->sector) 562 if (next_ext == 0 || ext_base + next_ext <= mbri->sector)
563 break; 563 break;
564 if (ext_base == 0) { 564 if (ext_base == 0) {
565 ext_base = next_ext; 565 ext_base = next_ext;
566 next_ext = 0; 566 next_ext = 0;
567 } 567 }
568 ext = calloc(sizeof *ext, 1); 568 ext = calloc(sizeof *ext, 1);
569 if (!ext) 569 if (!ext)
570 break; 570 break;
571 mbrs = &ext->mbr; 571 mbrs = &ext->mbr;
572 } 572 }
573 573
574 bad_mbr: 574 bad_mbr:
575 free_mbr_info(ext); 575 free_mbr_info(ext);
576 if (fd >= 0) 576 if (fd >= 0)
577 close(fd); 577 close(fd);
578 if (rval == -1) { 578 if (rval == -1) {
579 memset(&mbrs->mbr_parts, 0, sizeof mbrs->mbr_parts); 579 memset(&mbrs->mbr_parts, 0, sizeof mbrs->mbr_parts);
580 mbrs->mbr_magic = htole16(MBR_MAGIC); 580 mbrs->mbr_magic = htole16(MBR_MAGIC);
581 } 581 }
582 dump_mbr(ombri, "read"); 582 dump_mbr(ombri, "read");
583 return rval; 583 return rval;
584} 584}
585 585
586static int 586static int
587write_mbr(const char *disk, mbr_info_t *mbri, int bsec, int bhead, int bcyl) 587write_mbr(const char *disk, mbr_info_t *mbri, int bsec, int bhead, int bcyl)
588{ 588{
589 char diskpath[MAXPATHLEN]; 589 char diskpath[MAXPATHLEN];
590 int fd, i, ret = 0; 590 int fd, i, ret = 0;
591 struct mbr_partition *mbrp; 591 struct mbr_partition *mbrp;
592 u_int32_t pstart, psize; 592 u_int32_t pstart, psize;
593#ifdef BOOTSEL 593#ifdef BOOTSEL
594 struct mbr_sector *mbrs; 594 struct mbr_sector *mbrs;
595#endif 595#endif
596 struct mbr_sector mbrsec; 596 struct mbr_sector mbrsec;
597 mbr_info_t *ext; 597 mbr_info_t *ext;
598 uint sector; 598 uint sector;
599 599
600 dump_mbr(mbri, "write"); 600 dump_mbr(mbri, "write");
601 601
602 /* Open the disk. */ 602 /* Open the disk. */
603 fd = opendisk(disk, O_WRONLY, diskpath, sizeof(diskpath), 0); 603 fd = opendisk(disk, O_WRONLY, diskpath, sizeof(diskpath), 0);
604 if (fd < 0) 604 if (fd < 0)
605 return -1; 605 return -1;
606 606
607#ifdef BOOTSEL 607#ifdef BOOTSEL
608 /* 608 /*
609 * If the main boot code (appears to) contain the netbsd bootcode, 609 * If the main boot code (appears to) contain the netbsd bootcode,
610 * copy in all the menu strings and set the default keycode 610 * copy in all the menu strings and set the default keycode
611 * to be that for the default partition. 611 * to be that for the default partition.
612 * Unfortunately we can't rely on the user having actually updated 612 * Unfortunately we can't rely on the user having actually updated
613 * to the new mbr code :-( 613 * to the new mbr code :-(
614 */ 614 */
615 if (mbri->mbr.mbr_bootsel_magic == htole16(MBR_BS_MAGIC) 615 if (mbri->mbr.mbr_bootsel_magic == htole16(MBR_BS_MAGIC)
616 || mbri->mbr.mbr_bootsel_magic == htole16(MBR_MAGIC)) { 616 || mbri->mbr.mbr_bootsel_magic == htole16(MBR_MAGIC)) {
617 int8_t key = SCAN_1; 617 int8_t key = SCAN_1;
618 uint offset = MBR_BS_OFFSET; 618 uint offset = MBR_BS_OFFSET;
619 if (mbri->mbr.mbr_bootsel_magic == htole16(MBR_MAGIC)) 619 if (mbri->mbr.mbr_bootsel_magic == htole16(MBR_MAGIC))
620 offset = MBR_BS_OLD_OFFSET; 620 offset = MBR_BS_OLD_OFFSET;
621 mbri->mbrb.mbrbs_defkey = SCAN_ENTER; 621 mbri->mbrb.mbrbs_defkey = SCAN_ENTER;
622 if (mbri->mbrb.mbrbs_timeo == 0) 622 if (mbri->mbrb.mbrbs_timeo == 0)
623 mbri->mbrb.mbrbs_timeo = 182; /* 10 seconds */ 623 mbri->mbrb.mbrbs_timeo = 182; /* 10 seconds */
624 for (ext = mbri; ext != NULL; ext = ext->extended) { 624 for (ext = mbri; ext != NULL; ext = ext->extended) {
625 mbrs = &ext->mbr; 625 mbrs = &ext->mbr;
626 mbrp = &mbrs->mbr_parts[0]; 626 mbrp = &mbrs->mbr_parts[0];
627 /* Ensure marker is set in each sector */ 627 /* Ensure marker is set in each sector */
628 mbrs->mbr_bootsel_magic = mbri->mbr.mbr_bootsel_magic; 628 mbrs->mbr_bootsel_magic = mbri->mbr.mbr_bootsel_magic;
629 /* and copy in bootsel parameters */ 629 /* and copy in bootsel parameters */
630 *(struct mbr_bootsel *)((uint8_t *)mbrs + offset) = 630 *(struct mbr_bootsel *)((uint8_t *)mbrs + offset) =
631 ext->mbrb; 631 ext->mbrb;
632 for (i = 0; i < MBR_PART_COUNT; i++) { 632 for (i = 0; i < MBR_PART_COUNT; i++) {
633 if (ext->mbrb.mbrbs_nametab[i][0] == 0) 633 if (ext->mbrb.mbrbs_nametab[i][0] == 0)
634 continue; 634 continue;
635 if (ext->sector + mbrp->mbrp_start == 635 if (ext->sector + mbrp->mbrp_start ==
636 mbri->bootsec) 636 mbri->bootsec)
637 mbri->mbrb.mbrbs_defkey = key; 637 mbri->mbrb.mbrbs_defkey = key;
638 key++; 638 key++;
639 } 639 }
640 } 640 }
641 /* copy main data (again) since we've put the 'key' in */ 641 /* copy main data (again) since we've put the 'key' in */
642 *(struct mbr_bootsel *)((uint8_t *)&mbri->mbr + offset) = 642 *(struct mbr_bootsel *)((uint8_t *)&mbri->mbr + offset) =
643 mbri->mbrb; 643 mbri->mbrb;
644 } 644 }
645#endif 645#endif
646 646
647 for (ext = mbri; ext != NULL; ext = ext->extended) { 647 for (ext = mbri; ext != NULL; ext = ext->extended) {
648 sector = ext->sector; 648 sector = ext->sector;
649 mbrsec = ext->mbr; /* copy sector */ 649 mbrsec = ext->mbr; /* copy sector */
650 mbrp = &mbrsec.mbr_parts[0]; 650 mbrp = &mbrsec.mbr_parts[0];
651 651
652 if (sector != 0 && ext->extended != NULL 652 if (sector != 0 && ext->extended != NULL
653 && ext->extended->mbr.mbr_parts[0].mbrp_type 653 && ext->extended->mbr.mbr_parts[0].mbrp_type
654 == MBR_PTYPE_UNUSED) { 654 == MBR_PTYPE_UNUSED) {
655 655
656 /* 656 /*
657 * This should never happen nowadays, old code 657 * This should never happen nowadays, old code
658 * inserted empty ext sectors in the chain to 658 * inserted empty ext sectors in the chain to
659 * help the gui out - we do not do that anymore. 659 * help the gui out - we do not do that anymore.
660 */ 660 */
661 assert(false); 661 assert(false);
662 662
663 /* We are followed by an empty slot, collapse out */ 663 /* We are followed by an empty slot, collapse out */
664 ext = ext->extended; 664 ext = ext->extended;
665 /* Make us describe the next non-empty partition */ 665 /* Make us describe the next non-empty partition */
666 mbrp[1] = ext->mbr.mbr_parts[1]; 666 mbrp[1] = ext->mbr.mbr_parts[1];
667 } 667 }
668 668
669 for (i = 0; i < MBR_PART_COUNT; i++) { 669 for (i = 0; i < MBR_PART_COUNT; i++) {
670 if (mbrp[i].mbrp_start == 0 && mbrp[i].mbrp_size == 0) { 670 if (mbrp[i].mbrp_start == 0 && mbrp[i].mbrp_size == 0) {
671 mbrp[i].mbrp_scyl = 0; 671 mbrp[i].mbrp_scyl = 0;
672 mbrp[i].mbrp_shd = 0; 672 mbrp[i].mbrp_shd = 0;
673 mbrp[i].mbrp_ssect = 0; 673 mbrp[i].mbrp_ssect = 0;
674 mbrp[i].mbrp_ecyl = 0; 674 mbrp[i].mbrp_ecyl = 0;
675 mbrp[i].mbrp_ehd = 0; 675 mbrp[i].mbrp_ehd = 0;
676 mbrp[i].mbrp_esect = 0; 676 mbrp[i].mbrp_esect = 0;
677 continue; 677 continue;
678 } 678 }
679 pstart = mbrp[i].mbrp_start; 679 pstart = mbrp[i].mbrp_start;
680 psize = mbrp[i].mbrp_size; 680 psize = mbrp[i].mbrp_size;
681 mbrp[i].mbrp_start = htole32(pstart); 681 mbrp[i].mbrp_start = htole32(pstart);
682 mbrp[i].mbrp_size = htole32(psize); 682 mbrp[i].mbrp_size = htole32(psize);
683 if (bsec && bcyl && bhead) { 683 if (bsec && bcyl && bhead) {
684 convert_mbr_chs(bcyl, bhead, bsec, 684 convert_mbr_chs(bcyl, bhead, bsec,
685 &mbrp[i].mbrp_scyl, &mbrp[i].mbrp_shd, 685 &mbrp[i].mbrp_scyl, &mbrp[i].mbrp_shd,
686 &mbrp[i].mbrp_ssect, pstart); 686 &mbrp[i].mbrp_ssect, pstart);
687 convert_mbr_chs(bcyl, bhead, bsec, 687 convert_mbr_chs(bcyl, bhead, bsec,
688 &mbrp[i].mbrp_ecyl, &mbrp[i].mbrp_ehd, 688 &mbrp[i].mbrp_ecyl, &mbrp[i].mbrp_ehd,
689 &mbrp[i].mbrp_esect, pstart + psize - 1); 689 &mbrp[i].mbrp_esect, pstart + psize - 1);
690 } 690 }
691 } 691 }
692 692
693 mbrsec.mbr_magic = htole16(MBR_MAGIC); 693 mbrsec.mbr_magic = htole16(MBR_MAGIC);
694 if (pwrite(fd, &mbrsec, sizeof mbrsec, 694 if (pwrite(fd, &mbrsec, sizeof mbrsec,
695 sector * (off_t)MBR_SECSIZE) < 0) { 695 sector * (off_t)MBR_SECSIZE) < 0) {
696 ret = -1; 696 ret = -1;
697 break; 697 break;
698 } 698 }
699 } 699 }
700 700
701 (void)close(fd); 701 (void)close(fd);
702 return ret; 702 return ret;
703} 703}
704 704
705static void 705static void
706convert_mbr_chs(int cyl, int head, int sec, 706convert_mbr_chs(int cyl, int head, int sec,
707 uint8_t *cylp, uint8_t *headp, uint8_t *secp, 707 uint8_t *cylp, uint8_t *headp, uint8_t *secp,
708 uint32_t relsecs) 708 uint32_t relsecs)
709{ 709{
710 unsigned int tcyl, temp, thead, tsec; 710 unsigned int tcyl, temp, thead, tsec;
711 711
712 temp = head * sec; 712 temp = head * sec;
713 tcyl = relsecs / temp; 713 tcyl = relsecs / temp;
714 relsecs -= tcyl * temp; 714 relsecs -= tcyl * temp;
715 715
716 thead = relsecs / sec; 716 thead = relsecs / sec;
717 tsec = relsecs - thead * sec + 1; 717 tsec = relsecs - thead * sec + 1;
718 718
719 if (tcyl > MAXCYL) 719 if (tcyl > MAXCYL)
720 tcyl = MAXCYL; 720 tcyl = MAXCYL;
721 721
722 *cylp = MBR_PUT_LSCYL(tcyl); 722 *cylp = MBR_PUT_LSCYL(tcyl);
723 *headp = thead; 723 *headp = thead;
724 *secp = MBR_PUT_MSCYLANDSEC(tcyl, tsec); 724 *secp = MBR_PUT_MSCYLANDSEC(tcyl, tsec);
725} 725}
726 726
727/* 727/*
728 * This function is ONLY to be used as a last resort to provide a 728 * This function is ONLY to be used as a last resort to provide a
729 * hint for the user. Ports should provide a more reliable way 729 * hint for the user. Ports should provide a more reliable way
730 * of getting the BIOS geometry. The i386 code, for example, 730 * of getting the BIOS geometry. The i386 code, for example,
731 * uses the BIOS geometry as passed on from the bootblocks, 731 * uses the BIOS geometry as passed on from the bootblocks,
732 * and only uses this as a hint to the user when that information 732 * and only uses this as a hint to the user when that information
733 * is not present, or a match could not be made with a NetBSD 733 * is not present, or a match could not be made with a NetBSD
734 * device. 734 * device.
735 */ 735 */
736int 736int
737guess_biosgeom_from_parts(struct disk_partitions *parts, 737guess_biosgeom_from_parts(struct disk_partitions *parts,
738 int *cyl, int *head, int *sec) 738 int *cyl, int *head, int *sec)
739{ 739{
740 740
741 /* 741 /*
742 * The physical parameters may be invalid as bios geometry. 742 * The physical parameters may be invalid as bios geometry.
743 * If we cannot determine the actual bios geometry, we are 743 * If we cannot determine the actual bios geometry, we are
744 * better off picking a likely 'faked' geometry than leaving 744 * better off picking a likely 'faked' geometry than leaving
745 * the invalid physical one. 745 * the invalid physical one.
746 */ 746 */
747 747
748 int xcylinders = pm->dlcyl; 748 int xcylinders = pm->dlcyl;
749 int xheads = pm->dlhead; 749 int xheads = pm->dlhead;
750 daddr_t xsectors = pm->dlsec; 750 daddr_t xsectors = pm->dlsec;
751 daddr_t xsize = min(pm->dlsize, mbr_parts.size_limit); 751 daddr_t xsize = min(pm->dlsize, mbr_parts.size_limit);
752 if (xcylinders > MAXCYL || xheads > MAXHEAD || xsectors > MAXSECTOR) { 752 if (xcylinders > MAXCYL || xheads > MAXHEAD || xsectors > MAXSECTOR) {
753 xsectors = MAXSECTOR; 753 xsectors = MAXSECTOR;
754 xheads = MAXHEAD; 754 xheads = MAXHEAD;
755 xcylinders = xsize / (MAXSECTOR * MAXHEAD); 755 xcylinders = xsize / (MAXSECTOR * MAXHEAD);
756 if (xcylinders > MAXCYL) 756 if (xcylinders > MAXCYL)
757 xcylinders = MAXCYL; 757 xcylinders = MAXCYL;
758 } 758 }
759 *cyl = xcylinders; 759 *cyl = xcylinders;
760 *head = xheads; 760 *head = xheads;
761 *sec = xsectors; 761 *sec = xsectors;
762 762
763 if (parts->pscheme->guess_disk_geom == NULL) 763 if (parts->pscheme->guess_disk_geom == NULL)
764 return -1; 764 return -1;
765 765
766 return parts->pscheme->guess_disk_geom(parts, cyl, head, sec); 766 return parts->pscheme->guess_disk_geom(parts, cyl, head, sec);
767} 767}
768 768
769static int 769static int
770mbr_comp_part_entry(const void *a, const void *b) 770mbr_comp_part_entry(const void *a, const void *b)
771{ 771{
772 const struct mbr_partition *part_a = a, 772 const struct mbr_partition *part_a = a,
773 *part_b = b; 773 *part_b = b;
774 774
775 if (part_a->mbrp_type == MBR_PTYPE_UNUSED 775 if (part_a->mbrp_type == MBR_PTYPE_UNUSED
776 && part_b->mbrp_type != MBR_PTYPE_UNUSED) 776 && part_b->mbrp_type != MBR_PTYPE_UNUSED)
777 return 1; 777 return 1;
778 778
779 if (part_b->mbrp_type == MBR_PTYPE_UNUSED 779 if (part_b->mbrp_type == MBR_PTYPE_UNUSED
780 && part_a->mbrp_type != MBR_PTYPE_UNUSED) 780 && part_a->mbrp_type != MBR_PTYPE_UNUSED)
781 return -1; 781 return -1;
782 782
783 return part_a->mbrp_start < part_b->mbrp_start ? -1 : 1; 783 return part_a->mbrp_start < part_b->mbrp_start ? -1 : 1;
784} 784}
785 785
786static void 786static void
787mbr_sort_main_mbr(struct mbr_sector *m) 787mbr_sort_main_mbr(struct mbr_sector *m)
788{ 788{
789 qsort(&m->mbr_parts[0], MBR_PART_COUNT, 789 qsort(&m->mbr_parts[0], MBR_PART_COUNT,
790 sizeof(m->mbr_parts[0]), mbr_comp_part_entry); 790 sizeof(m->mbr_parts[0]), mbr_comp_part_entry);
791} 791}
792 792
793static void 793static void
794mbr_init_default_alignments(struct mbr_disk_partitions *parts, uint track) 794mbr_init_default_alignments(struct mbr_disk_partitions *parts, uint track)
795{ 795{
796 if (track == 0) 796 if (track == 0)
797 track = 16065; 797 track = 16065;
798 798
799 assert(parts->dp.disk_size > 0); 799 assert(parts->dp.disk_size > 0);
800 if (parts->dp.disk_size < 0) 800 if (parts->dp.disk_size < 0)
801 return; 801 return;
802 802
803 /* Use 1MB offset/alignemnt for large (>128GB) disks */ 803 /* Use 1MB offset/alignemnt for large (>128GB) disks */
804 if (parts->dp.disk_size > HUGE_DISK_SIZE) { 804 if (parts->dp.disk_size > HUGE_DISK_SIZE) {
805 parts->ptn_alignment = 2048; 805 parts->ptn_alignment = 2048;
806 parts->ptn_0_offset = 2048; 806 parts->ptn_0_offset = 2048;
807 } else if (parts->dp.disk_size > TINY_DISK_SIZE) { 807 } else if (parts->dp.disk_size > TINY_DISK_SIZE) {
808 parts->ptn_alignment = 64; 808 parts->ptn_alignment = 64;
809 parts->ptn_0_offset = parts->geo_sec; 809 parts->ptn_0_offset = parts->geo_sec;
810 } else { 810 } else {
811 parts->ptn_alignment = 1; 811 parts->ptn_alignment = 1;
812 parts->ptn_0_offset = parts->geo_sec; 812 parts->ptn_0_offset = parts->geo_sec;
813 } 813 }
814 parts->ext_ptn_alignment = track; 814 parts->ext_ptn_alignment = track;
815} 815}
816 816
817static struct disk_partitions * 817static struct disk_partitions *
818mbr_create_new(const char *disk, daddr_t start, daddr_t len, daddr_t total, 818mbr_create_new(const char *disk, daddr_t start, daddr_t len, daddr_t total,
819 bool is_boot_drive) 819 bool is_boot_drive)
820{ 820{
821 struct mbr_disk_partitions *parts; 821 struct mbr_disk_partitions *parts;
822 822
823 assert(start == 0); 823 assert(start == 0);
824 if (start != 0) 824 if (start != 0)
825 return NULL; 825 return NULL;
826 826
827 parts = calloc(sizeof(*parts), 1); 827 parts = calloc(sizeof(*parts), 1);
828 if (!parts) 828 if (!parts)
829 return NULL; 829 return NULL;
830 830
831 parts->dp.pscheme = &mbr_parts; 831 parts->dp.pscheme = &mbr_parts;
832 parts->dp.disk = disk; 832 parts->dp.disk = disk;
833 if (len > mbr_parts.size_limit) 833 if (len > mbr_parts.size_limit)
834 len = mbr_parts.size_limit; 834 len = mbr_parts.size_limit;
835 parts->dp.disk_start = start; 835 parts->dp.disk_start = start;
836 parts->dp.disk_size = len; 836 parts->dp.disk_size = len;
837 parts->dp.free_space = len-1; 837 parts->dp.free_space = len-1;
838 parts->geo_sec = MAXSECTOR; 838 parts->geo_sec = MAXSECTOR;
839 parts->geo_head = MAXHEAD; 839 parts->geo_head = MAXHEAD;
840 parts->geo_cyl = len/MAXHEAD/MAXSECTOR+1; 840 parts->geo_cyl = len/MAXHEAD/MAXSECTOR+1;
841 mbr_init_default_alignments(parts, 0); 841 mbr_init_default_alignments(parts, 0);
842 842
843 return &parts->dp; 843 return &parts->dp;
844} 844}
845 845
846static void 846static void
847mbr_calc_free_space(struct mbr_disk_partitions *parts) 847mbr_calc_free_space(struct mbr_disk_partitions *parts)
848{ 848{
849 size_t i; 849 size_t i;
850 mbr_info_t *m; 850 mbr_info_t *m;
851 851
852 parts->dp.free_space = parts->dp.disk_size - 1; 852 parts->dp.free_space = parts->dp.disk_size - 1;
853 parts->dp.num_part = 0; 853 parts->dp.num_part = 0;
854 m = &parts->mbr; 854 m = &parts->mbr;
855 do { 855 do {
856 for (i = 0; i < MBR_PART_COUNT; i++) { 856 for (i = 0; i < MBR_PART_COUNT; i++) {
857 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 857 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED)
858 continue; 858 continue;
859 859
860 if (m != &parts->mbr && i > 0 && 860 if (m != &parts->mbr && i > 0 &&
861 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 861 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type))
862 break; 862 break;
863 863
864 parts->dp.num_part++; 864 parts->dp.num_part++;
865 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 865 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type))
866 continue; 866 continue;
867 867
868 daddr_t psize = m->mbr.mbr_parts[i].mbrp_size; 868 daddr_t psize = m->mbr.mbr_parts[i].mbrp_size;
869 if (m != &parts->mbr) 869 if (m != &parts->mbr)
870 psize += m->mbr.mbr_parts[i].mbrp_start; 870 psize += m->mbr.mbr_parts[i].mbrp_start;
871 871
872 if (psize > parts->dp.free_space) 872 if (psize > parts->dp.free_space)
873 parts->dp.free_space = 0; 873 parts->dp.free_space = 0;
874 else 874 else
875 parts->dp.free_space -= psize; 875 parts->dp.free_space -= psize;
876  876
877 } 877 }
878 } while ((m = m->extended)); 878 } while ((m = m->extended));
879} 879}
880 880
881static struct disk_partitions * 881static struct disk_partitions *
882mbr_read_from_disk(const char *disk, daddr_t start, daddr_t len) 882mbr_read_from_disk(const char *disk, daddr_t start, daddr_t len)
883{ 883{
884 struct mbr_disk_partitions *parts; 884 struct mbr_disk_partitions *parts;
885 885
886 assert(start == 0); 886 assert(start == 0);
887 if (start != 0) 887 if (start != 0)
888 return NULL; 888 return NULL;
889 889
890 parts = calloc(sizeof(*parts), 1); 890 parts = calloc(sizeof(*parts), 1);
891 if (!parts) 891 if (!parts)
892 return NULL; 892 return NULL;
893 893
894 parts->dp.pscheme = &mbr_parts; 894 parts->dp.pscheme = &mbr_parts;
895 parts->dp.disk = disk; 895 parts->dp.disk = disk;
896 if (len >= mbr_parts.size_limit) 896 if (len >= mbr_parts.size_limit)
897 len = mbr_parts.size_limit; 897 len = mbr_parts.size_limit;
898 parts->dp.disk_start = start; 898 parts->dp.disk_start = start;
899 parts->dp.disk_size = len; 899 parts->dp.disk_size = len;
900 parts->geo_sec = MAXSECTOR; 900 parts->geo_sec = MAXSECTOR;
901 parts->geo_head = MAXHEAD; 901 parts->geo_head = MAXHEAD;
902 parts->geo_cyl = len/MAXHEAD/MAXSECTOR+1; 902 parts->geo_cyl = len/MAXHEAD/MAXSECTOR+1;
903 mbr_init_default_alignments(parts, 0); 903 mbr_init_default_alignments(parts, 0);
904 if (read_mbr(disk, &parts->mbr) == -1) { 904 if (read_mbr(disk, &parts->mbr) == -1) {
905 free(parts); 905 free(parts);
906 return NULL; 906 return NULL;
907 } 907 }
908 mbr_calc_free_space(parts); 908 mbr_calc_free_space(parts);
909 909
910 return &parts->dp; 910 return &parts->dp;
911} 911}
912 912
913static bool 913static bool
914mbr_write_to_disk(struct disk_partitions *new_state) 914mbr_write_to_disk(struct disk_partitions *new_state)
915{ 915{
916 struct mbr_disk_partitions *parts = 916 struct mbr_disk_partitions *parts =
917 (struct mbr_disk_partitions *)new_state; 917 (struct mbr_disk_partitions *)new_state;
918 unsigned long bsec = parts->geo_sec, 918 unsigned long bsec = parts->geo_sec,
919 bhead = parts->ext_ptn_alignment / bsec, 919 bhead = parts->ext_ptn_alignment / bsec,
920 bcyl; 920 bcyl;
921 daddr_t t; 921 daddr_t t;
922 922
923 t = bsec * bhead; 923 t = bsec * bhead;
924 if ((daddr_t)(1UL<<10) * t <= parts->dp.disk_size) 924 if ((daddr_t)(1UL<<10) * t <= parts->dp.disk_size)
925 bcyl = (1UL<<10) - 1; 925 bcyl = (1UL<<10) - 1;
926 else 926 else
927 bcyl = (unsigned long)(parts->dp.disk_size / t); 927 bcyl = (unsigned long)(parts->dp.disk_size / t);
928 928
929 return write_mbr(parts->dp.disk, &parts->mbr, 929 return write_mbr(parts->dp.disk, &parts->mbr,
930 bsec, bhead, bcyl) == 0; 930 bsec, bhead, bcyl) == 0;
931} 931}
932 932
933static bool 933static bool
934mbr_change_disk_geom(struct disk_partitions *arg, int ncyl, int nhead, 934mbr_change_disk_geom(struct disk_partitions *arg, int ncyl, int nhead,
935 int nsec) 935 int nsec)
936{ 936{
937 struct mbr_disk_partitions *parts = (struct mbr_disk_partitions *)arg; 937 struct mbr_disk_partitions *parts = (struct mbr_disk_partitions *)arg;
938 daddr_t ptn_0_base, ptn_0_limit; 938 daddr_t ptn_0_base, ptn_0_limit;
939 struct disk_part_info info; 939 struct disk_part_info info;
940 940
941 /* Default to using 'traditional' cylinder alignment */ 941 /* Default to using 'traditional' cylinder alignment */
942 mbr_init_chs(parts, ncyl, nhead, nsec); 942 mbr_init_chs(parts, ncyl, nhead, nsec);
943 mbr_init_default_alignments(parts, nhead * nsec); 943 mbr_init_default_alignments(parts, nhead * nsec);
944 944
945 if (parts->dp.disk_size <= TINY_DISK_SIZE) { 945 if (parts->dp.disk_size <= TINY_DISK_SIZE) {
946 set_default_sizemult(1); 946 set_default_sizemult(1);
947 return true; 947 return true;
948 } 948 }
949 949
950 if (parts->dp.num_part > 0 && 950 if (parts->dp.num_part > 0 &&
951 parts->dp.pscheme->get_part_info(arg, 0, &info)) { 951 parts->dp.pscheme->get_part_info(arg, 0, &info)) {
952 952
953 /* Try to copy offset of first partition */ 953 /* Try to copy offset of first partition */
954 ptn_0_base = info.start; 954 ptn_0_base = info.start;
955 ptn_0_limit = info.start + info.size; 955 ptn_0_limit = info.start + info.size;
956 if (!(ptn_0_limit & 2047)) { 956 if (!(ptn_0_limit & 2047)) {
957 /* Partition ends on a 1MB boundary, align to 1MB */ 957 /* Partition ends on a 1MB boundary, align to 1MB */
958 parts->ptn_alignment = 2048; 958 parts->ptn_alignment = 2048;
959 if (ptn_0_base <= 2048 959 if (ptn_0_base <= 2048
960 && !(ptn_0_base & (ptn_0_base - 1))) { 960 && !(ptn_0_base & (ptn_0_base - 1))) {
961 /* ptn_base is a power of 2, use it */ 961 /* ptn_base is a power of 2, use it */
962 parts->ptn_0_offset = ptn_0_base; 962 parts->ptn_0_offset = ptn_0_base;
963 } 963 }
964 } 964 }
965 } 965 }
966 set_default_sizemult(MEG/512); 966 set_default_sizemult(MEG/512);
967 return true; 967 return true;
968} 968}
969 969
970static size_t 970static size_t
971mbr_type_from_gen_desc(const struct part_type_desc *desc) 971mbr_type_from_gen_desc(const struct part_type_desc *desc)
972{ 972{
973 for (size_t i = 0; i < __arraycount(mbr_gen_type_desc); i++) 973 for (size_t i = 0; i < __arraycount(mbr_gen_type_desc); i++)
974 if (&mbr_gen_type_desc[i].gen == desc) 974 if (&mbr_gen_type_desc[i].gen == desc)
975 return i; 975 return i;
976 976
977 return SIZE_T_MAX; 977 return SIZE_T_MAX;
978} 978}
979 979
980static enum part_type 980static enum part_type
981mbr_map_part_type(unsigned int t) 981mbr_map_part_type(unsigned int t)
982{ 982{
983 /* Map some special MBR partition types */ 983 /* Map some special MBR partition types */
984 switch (t) { 984 switch (t) {
985 case MBR_PTYPE_FAT32: 985 case MBR_PTYPE_FAT32:
986 case MBR_PTYPE_FAT32L: 986 case MBR_PTYPE_FAT32L:
987 case MBR_PTYPE_FT_FAT32: 987 case MBR_PTYPE_FT_FAT32:
988 case MBR_PTYPE_FT_FAT32_EXT: 988 case MBR_PTYPE_FT_FAT32_EXT:
989 return PT_FAT; 989 return PT_FAT;
990 case MBR_PTYPE_EFI: 990 case MBR_PTYPE_EFI:
991 return PT_EFI_SYSTEM; 991 return PT_EFI_SYSTEM;
992 case MBR_PTYPE_NETBSD: 992 case MBR_PTYPE_NETBSD:
993 return PT_root; 993 return PT_root;
994 } 994 }
995 995
996 return PT_unknown; 996 return PT_unknown;
997} 997}
998 998
999static void 999static void
1000map_mbr_part_types(void) 1000map_mbr_part_types(void)
1001{ 1001{
1002 1002
1003 for (size_t i = 0; i < __arraycount(mbr_part_types_src); i++) { 1003 for (size_t i = 0; i < __arraycount(mbr_part_types_src); i++) {
1004 unsigned int v = mbr_part_types_src[i].ptype; 1004 unsigned int v = mbr_part_types_src[i].ptype;
1005 1005
1006 snprintf(mbr_gen_type_desc[v].short_buf, 1006 snprintf(mbr_gen_type_desc[v].short_buf,
1007 sizeof(mbr_gen_type_desc[v].short_buf), "%u", v); 1007 sizeof(mbr_gen_type_desc[v].short_buf), "%u", v);
1008 mbr_gen_type_desc[v].gen.short_desc = 1008 mbr_gen_type_desc[v].gen.short_desc =
1009 mbr_gen_type_desc[v].short_buf; 1009 mbr_gen_type_desc[v].short_buf;
1010 mbr_gen_type_desc[v].gen.description = 1010 mbr_gen_type_desc[v].gen.description =
1011 mbr_part_types_src[i].desc; 1011 mbr_part_types_src[i].desc;
1012 mbr_gen_type_desc[v].gen.generic_ptype = mbr_map_part_type(v); 1012 mbr_gen_type_desc[v].gen.generic_ptype = mbr_map_part_type(v);
1013 mbr_gen_type_desc[v].next_ptype = ~0U; 1013 mbr_gen_type_desc[v].next_ptype = ~0U;
1014 mbr_gen_type_desc[last_added_part_type].next_ptype = v; 1014 mbr_gen_type_desc[last_added_part_type].next_ptype = v;
1015 known_part_types++; 1015 known_part_types++;
1016 last_added_part_type = v; 1016 last_added_part_type = v;
1017 } 1017 }
1018} 1018}
1019 1019
1020static size_t 1020static size_t
1021mbr_get_part_type_count(void) 1021mbr_get_part_type_count(void)
1022{ 1022{
1023 if (known_part_types == 0) 1023 if (known_part_types == 0)
1024 map_mbr_part_types(); 1024 map_mbr_part_types();
1025 1025
1026 return known_part_types; 1026 return known_part_types;
1027} 1027}
1028 1028
1029static const struct part_type_desc * 1029static const struct part_type_desc *
1030mbr_get_fs_part_type(unsigned fs_type, unsigned sub_type) 1030mbr_get_fs_part_type(unsigned fs_type, unsigned sub_type)
1031{ 1031{
1032 if (known_part_types == 0) 1032 if (known_part_types == 0)
1033 map_mbr_part_types(); 1033 map_mbr_part_types();
1034 1034
1035 switch (fs_type) { 1035 switch (fs_type) {
1036 case FS_BSDFFS: 1036 case FS_BSDFFS:
1037 return &mbr_gen_type_desc[MBR_PTYPE_NETBSD].gen; 1037 return &mbr_gen_type_desc[MBR_PTYPE_NETBSD].gen;
1038 case FS_EX2FS: 1038 case FS_EX2FS:
1039 return &mbr_gen_type_desc[MBR_PTYPE_LNXEXT2].gen; 1039 return &mbr_gen_type_desc[MBR_PTYPE_LNXEXT2].gen;
1040 case FS_MSDOS: 1040 case FS_MSDOS:
1041 switch (sub_type) { 1041 switch (sub_type) {
1042 case MBR_PTYPE_FAT12: 1042 case MBR_PTYPE_FAT12:
1043 case MBR_PTYPE_FAT16S: 1043 case MBR_PTYPE_FAT16S:
1044 case MBR_PTYPE_FAT16B: 1044 case MBR_PTYPE_FAT16B:
1045 case MBR_PTYPE_FAT32: 1045 case MBR_PTYPE_FAT32:
1046 case MBR_PTYPE_FAT32L: 1046 case MBR_PTYPE_FAT32L:
1047 case MBR_PTYPE_FAT16L: 1047 case MBR_PTYPE_FAT16L:
1048 return &mbr_gen_type_desc[sub_type].gen; 1048 return &mbr_gen_type_desc[sub_type].gen;
1049 } 1049 }
1050 break; 1050 break;
1051 } 1051 }
1052 1052
1053 return NULL; 1053 return NULL;
1054} 1054}
1055 1055
1056static const struct part_type_desc * 1056static const struct part_type_desc *
1057mbr_get_part_type(size_t index) 1057mbr_get_part_type(size_t index)
1058{ 1058{
1059 size_t i, no; 1059 size_t i, no;
1060 1060
1061 if (known_part_types == 0) 1061 if (known_part_types == 0)
1062 map_mbr_part_types(); 1062 map_mbr_part_types();
1063 1063
1064 if (index >= known_part_types) 1064 if (index >= known_part_types)
1065 return NULL; 1065 return NULL;
1066 1066
1067 for (i = first_part_type, no = 0; i < __arraycount(mbr_gen_type_desc) 1067 for (i = first_part_type, no = 0; i < __arraycount(mbr_gen_type_desc)
1068 && no != index; no++) 1068 && no != index; no++)
1069 i = mbr_gen_type_desc[i].next_ptype; 1069 i = mbr_gen_type_desc[i].next_ptype;
1070 1070
1071 if (i >= __arraycount(mbr_gen_type_desc)) 1071 if (i >= __arraycount(mbr_gen_type_desc))
1072 return NULL; 1072 return NULL;
1073 return &mbr_gen_type_desc[i].gen; 1073 return &mbr_gen_type_desc[i].gen;
1074} 1074}
1075 1075
1076static const struct part_type_desc * 1076static const struct part_type_desc *
1077mbr_new_custom_part_type(unsigned int v) 1077mbr_new_custom_part_type(unsigned int v)
1078{ 1078{
1079 snprintf(mbr_gen_type_desc[v].short_buf, 1079 snprintf(mbr_gen_type_desc[v].short_buf,
1080 sizeof(mbr_gen_type_desc[v].short_buf), "%u", v); 1080 sizeof(mbr_gen_type_desc[v].short_buf), "%u", v);
1081 snprintf(mbr_gen_type_desc[v].desc_buf, 1081 snprintf(mbr_gen_type_desc[v].desc_buf,
1082 sizeof(mbr_gen_type_desc[v].desc_buf), "%s (%u)", 1082 sizeof(mbr_gen_type_desc[v].desc_buf), "%s (%u)",
1083 msg_string(MSG_custom_type), v); 1083 msg_string(MSG_custom_type), v);
1084 mbr_gen_type_desc[v].gen.short_desc = mbr_gen_type_desc[v].short_buf; 1084 mbr_gen_type_desc[v].gen.short_desc = mbr_gen_type_desc[v].short_buf;
1085 mbr_gen_type_desc[v].gen.description = mbr_gen_type_desc[v].desc_buf; 1085 mbr_gen_type_desc[v].gen.description = mbr_gen_type_desc[v].desc_buf;
1086 mbr_gen_type_desc[v].gen.generic_ptype = mbr_map_part_type(v); 1086 mbr_gen_type_desc[v].gen.generic_ptype = mbr_map_part_type(v);
1087 mbr_gen_type_desc[v].next_ptype = ~0U; 1087 mbr_gen_type_desc[v].next_ptype = ~0U;
1088 mbr_gen_type_desc[last_added_part_type].next_ptype = v; 1088 mbr_gen_type_desc[last_added_part_type].next_ptype = v;
1089 known_part_types++; 1089 known_part_types++;
1090 last_added_part_type = v; 1090 last_added_part_type = v;
1091 1091
1092 return &mbr_gen_type_desc[v].gen; 1092 return &mbr_gen_type_desc[v].gen;
1093} 1093}
1094 1094
1095static const struct part_type_desc * 1095static const struct part_type_desc *
1096mbr_custom_part_type(const char *custom, const char **err_msg) 1096mbr_custom_part_type(const char *custom, const char **err_msg)
1097{ 1097{
1098 unsigned long v; 1098 unsigned long v;
1099 char *endp; 1099 char *endp;
1100 1100
1101 if (known_part_types == 0) 1101 if (known_part_types == 0)
1102 map_mbr_part_types(); 1102 map_mbr_part_types();
1103 1103
1104 v = strtoul(custom, &endp, 10); 1104 v = strtoul(custom, &endp, 10);
1105 if (v > 255 || (v == 0 && *endp != 0)) { 1105 if (v > 255 || (v == 0 && *endp != 0)) {
1106 if (err_msg != NULL) 1106 if (err_msg != NULL)
1107 *err_msg = msg_string(MSG_mbr_type_invalid); 1107 *err_msg = msg_string(MSG_mbr_type_invalid);
1108 return NULL; 1108 return NULL;
1109 } 1109 }
1110 1110
1111 if (mbr_gen_type_desc[v].gen.short_desc != NULL) 1111 if (mbr_gen_type_desc[v].gen.short_desc != NULL)
1112 return &mbr_gen_type_desc[v].gen; 1112 return &mbr_gen_type_desc[v].gen;
1113 1113
1114 return mbr_new_custom_part_type(v); 1114 return mbr_new_custom_part_type(v);
1115} 1115}
1116 1116
1117static const struct part_type_desc * 1117static const struct part_type_desc *
1118mbr_get_gen_type_desc(unsigned int pt) 1118mbr_get_gen_type_desc(unsigned int pt)
1119{ 1119{
1120 1120
1121 if (known_part_types == 0) 1121 if (known_part_types == 0)
1122 map_mbr_part_types(); 1122 map_mbr_part_types();
1123 1123
1124 if (pt >= __arraycount(mbr_gen_type_desc)) 1124 if (pt >= __arraycount(mbr_gen_type_desc))
1125 return NULL; 1125 return NULL;
1126 1126
1127 if (mbr_gen_type_desc[pt].gen.short_desc != NULL) 1127 if (mbr_gen_type_desc[pt].gen.short_desc != NULL)
1128 return &mbr_gen_type_desc[pt].gen; 1128 return &mbr_gen_type_desc[pt].gen;
1129 1129
1130 return mbr_new_custom_part_type(pt); 1130 return mbr_new_custom_part_type(pt);
1131} 1131}
1132 1132
1133static const struct part_type_desc * 1133static const struct part_type_desc *
1134mbr_get_generic_part_type(enum part_type pt) 1134mbr_get_generic_part_type(enum part_type pt)
1135{ 1135{
1136 switch (pt) { 1136 switch (pt) {
1137 case PT_root: 1137 case PT_root:
1138 return mbr_get_gen_type_desc(MBR_PTYPE_NETBSD); 1138 return mbr_get_gen_type_desc(MBR_PTYPE_NETBSD);
1139 case PT_FAT: 1139 case PT_FAT:
1140 return mbr_get_gen_type_desc(MBR_PTYPE_FAT32L); 1140 return mbr_get_gen_type_desc(MBR_PTYPE_FAT32L);
1141 case PT_EFI_SYSTEM: 1141 case PT_EFI_SYSTEM:
1142 return mbr_get_gen_type_desc(MBR_PTYPE_EFI); 1142 return mbr_get_gen_type_desc(MBR_PTYPE_EFI);
1143 default: 1143 default:
1144 break; 1144 break;
1145 } 1145 }
1146 assert(false); 1146 assert(false);
1147 return NULL; 1147 return NULL;
1148} 1148}
1149 1149
1150static void 1150static void
1151mbr_partition_to_info(const struct mbr_partition *mp, daddr_t start_off, 1151mbr_partition_to_info(const struct mbr_partition *mp, daddr_t start_off,
1152 struct disk_part_info *info) 1152 struct disk_part_info *info)
1153{ 1153{
1154 memset(info, 0, sizeof(*info)); 1154 memset(info, 0, sizeof(*info));
1155 info->start = mp->mbrp_start + start_off; 1155 info->start = mp->mbrp_start + start_off;
1156 info->size = mp->mbrp_size; 1156 info->size = mp->mbrp_size;
1157 info->nat_type = mbr_get_gen_type_desc(mp->mbrp_type); 1157 info->nat_type = mbr_get_gen_type_desc(mp->mbrp_type);
1158 if (mp->mbrp_type == MBR_PTYPE_NETBSD) { 1158 if (mp->mbrp_type == MBR_PTYPE_NETBSD) {
1159 info->flags |= PTI_SEC_CONTAINER; 1159 info->flags |= PTI_SEC_CONTAINER;
1160 } else if (MBR_IS_EXTENDED(mp->mbrp_type)) 1160 } else if (MBR_IS_EXTENDED(mp->mbrp_type))
1161 info->flags |= PTI_PSCHEME_INTERNAL; 1161 info->flags |= PTI_PSCHEME_INTERNAL;
1162} 1162}
1163 1163
1164static bool 1164static bool
1165mbr_part_apply(const struct disk_partitions *arg, part_id id, 1165mbr_part_apply(const struct disk_partitions *arg, part_id id,
1166 bool (*func)(const struct disk_partitions *arg, part_id id, 1166 bool (*func)(const struct disk_partitions *arg, part_id id,
1167 const mbr_info_t *mb, int i, bool primary, 1167 const mbr_info_t *mb, int i, bool primary,
1168 const struct mbr_partition *mp, void *), 1168 const struct mbr_partition *mp, void *),
1169 void *cookie) 1169 void *cookie)
1170{ 1170{
1171 const struct mbr_disk_partitions *parts = 1171 const struct mbr_disk_partitions *parts =
1172 (const struct mbr_disk_partitions*)arg; 1172 (const struct mbr_disk_partitions*)arg;
1173 part_id i, j, no; 1173 part_id i, j, no;
1174 const mbr_info_t *m = &parts->mbr, *me; 1174 const mbr_info_t *m = &parts->mbr, *me;
1175 1175
1176 no = 0; 1176 no = 0;
1177 for (i = 0; i < MBR_PART_COUNT; i++) { 1177 for (i = 0; i < MBR_PART_COUNT; i++) {
1178 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 1178 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED)
1179 continue; 1179 continue;
1180 1180
1181 if (no == id) { 1181 if (no == id) {
1182 return func(arg, id, m, i, true, 1182 return func(arg, id, m, i, true,
1183 &m->mbr.mbr_parts[i], cookie); 1183 &m->mbr.mbr_parts[i], cookie);
1184 } 1184 }
1185 no++; 1185 no++;
1186 1186
1187 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) { 1187 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) {
1188 for (me = m->extended; me != NULL; me = me->extended) { 1188 for (me = m->extended; me != NULL; me = me->extended) {
1189 for (j = 0; j < MBR_PART_COUNT; j++) { 1189 for (j = 0; j < MBR_PART_COUNT; j++) {
1190 if (me->mbr.mbr_parts[j].mbrp_type == 1190 if (me->mbr.mbr_parts[j].mbrp_type ==
1191 MBR_PTYPE_UNUSED) 1191 MBR_PTYPE_UNUSED)
1192 continue; 1192 continue;
1193 if (j > 0 && MBR_IS_EXTENDED( 1193 if (j > 0 && MBR_IS_EXTENDED(
1194 me->mbr.mbr_parts[j].mbrp_type)) 1194 me->mbr.mbr_parts[j].mbrp_type))
1195 break; 1195 break;
1196 if (no == id) { 1196 if (no == id) {
1197 return func(arg, id, me, j, 1197 return func(arg, id, me, j,
1198 false, 1198 false,
1199 &me->mbr.mbr_parts[j], 1199 &me->mbr.mbr_parts[j],
1200 cookie); 1200 cookie);
1201 } 1201 }
1202 no++; 1202 no++;
1203 } 1203 }
1204 } 1204 }
1205 } 1205 }
1206 } 1206 }
1207 1207
1208 1208
1209 return false; 1209 return false;
1210} 1210}
1211 1211
1212static bool 1212static bool
1213mbr_do_get_part_info(const struct disk_partitions *arg, part_id id, 1213mbr_do_get_part_info(const struct disk_partitions *arg, part_id id,
1214 const mbr_info_t *mb, int i, bool primary, 1214 const mbr_info_t *mb, int i, bool primary,
1215 const struct mbr_partition *mp, void *cookie) 1215 const struct mbr_partition *mp, void *cookie)
1216{ 1216{
1217 struct disk_part_info *info = cookie; 1217 struct disk_part_info *info = cookie;
1218 1218
1219 mbr_partition_to_info(mp, mb->sector, info); 1219 mbr_partition_to_info(mp, mb->sector, info);
1220 if (mb->last_mounted[i] != NULL && mb->last_mounted[i][0] != 0) 1220 if (mb->last_mounted[i] != NULL && mb->last_mounted[i][0] != 0)
1221 info->last_mounted = mb->last_mounted[i]; 1221 info->last_mounted = mb->last_mounted[i];
1222 info->fs_type = mb->fs_type[i]; 1222 info->fs_type = mb->fs_type[i];
1223 info->fs_sub_type = mb->fs_sub_type[i]; 1223 info->fs_sub_type = mb->fs_sub_type[i];
1224 return true; 1224 return true;
1225} 1225}
1226 1226
1227static bool 1227static bool
1228mbr_get_part_info(const struct disk_partitions *arg, part_id id, 1228mbr_get_part_info(const struct disk_partitions *arg, part_id id,
1229 struct disk_part_info *info) 1229 struct disk_part_info *info)
1230{ 1230{
1231 return mbr_part_apply(arg, id, mbr_do_get_part_info, info); 1231 return mbr_part_apply(arg, id, mbr_do_get_part_info, info);
1232} 1232}
1233 1233
1234static bool 1234static bool
1235type_can_change(const struct disk_partitions *arg, part_id id, 1235type_can_change(const struct disk_partitions *arg, part_id id,
1236 const mbr_info_t *mb, int i, bool primary, 1236 const mbr_info_t *mb, int i, bool primary,
1237 const struct mbr_partition *mp, void *cookie) 1237 const struct mbr_partition *mp, void *cookie)
1238{ 1238{
1239 /* 1239 /*
1240 * The extended partition can only change type or be 1240 * The extended partition can only change type or be
1241 * deleted if it is empty 1241 * deleted if it is empty
1242 */ 1242 */
1243 if (!MBR_IS_EXTENDED(mp->mbrp_type)) 1243 if (!MBR_IS_EXTENDED(mp->mbrp_type))
1244 return true; 1244 return true;
1245 return primary && mb->extended == NULL; 1245 return primary && mb->extended == NULL;
1246} 1246}
1247 1247
1248static bool 1248static bool
1249mbr_part_type_can_change(const struct disk_partitions *arg, part_id id) 1249mbr_part_type_can_change(const struct disk_partitions *arg, part_id id)
1250{ 1250{
1251 return mbr_part_apply(arg, id, type_can_change, NULL); 1251 return mbr_part_apply(arg, id, type_can_change, NULL);
1252} 1252}
1253 1253
1254struct part_get_str_data { 1254struct part_get_str_data {
1255 char *str; 1255 char *str;
1256 size_t avail_space; 1256 size_t avail_space;
1257 size_t col; 1257 size_t col;
1258}; 1258};
1259 1259
1260 1260
1261static bool 1261static bool
1262mbr_get_part_table_str(const struct disk_partitions *arg, part_id id, 1262mbr_get_part_table_str(const struct disk_partitions *arg, part_id id,
1263 const mbr_info_t *mb, int i, bool primary, 1263 const mbr_info_t *mb, int i, bool primary,
1264 const struct mbr_partition *mp, void *cookie) 1264 const struct mbr_partition *mp, void *cookie)
1265{ 1265{
1266 struct part_get_str_data *data = cookie; 1266 struct part_get_str_data *data = cookie;
1267 char *str = data->str; 1267 char *str = data->str;
1268 const struct part_type_desc *ptype; 1268 const struct part_type_desc *ptype;
1269 1269
1270 switch (data->col) { 1270 switch (data->col) {
1271 case 0: 1271 case 0:
1272 ptype = mbr_get_gen_type_desc(mp->mbrp_type); 1272 ptype = mbr_get_gen_type_desc(mp->mbrp_type);
1273 if (ptype != NULL) 1273 if (ptype != NULL)
1274 strncpy(str, ptype->description, data->avail_space); 1274 strncpy(str, ptype->description, data->avail_space);
1275 else 1275 else
1276 snprintf(str, data->avail_space, "%u", mp->mbrp_type); 1276 snprintf(str, data->avail_space, "%u", mp->mbrp_type);
1277 str[data->avail_space-1] = 0; 1277 str[data->avail_space-1] = 0;
1278 break; 1278 break;
1279 case 1: 1279 case 1:
1280 if (mb->last_mounted[i]) 1280 if (mb->last_mounted[i])
1281 strlcpy(str, mb->last_mounted[i], data->avail_space); 1281 strlcpy(str, mb->last_mounted[i], data->avail_space);
1282 else 1282 else
1283 *str = 0; 1283 *str = 0;
1284 break; 1284 break;
1285#ifdef BOOTSEL 1285#ifdef BOOTSEL
1286 case 2: 1286 case 2:
1287 if (mb->mbrb.mbrbs_nametab[i][0] != 0) 1287 if (mb->mbrb.mbrbs_nametab[i][0] != 0)
1288 strlcpy(str, mb->mbrb.mbrbs_nametab[i], 1288 strlcpy(str, mb->mbrb.mbrbs_nametab[i],
1289 data->avail_space); 1289 data->avail_space);
1290 else 1290 else
1291 *str = 0; 1291 *str = 0;
1292 break; 1292 break;
1293#endif 1293#endif
1294 } 1294 }
1295 1295
1296 return true; 1296 return true;
1297} 1297}
1298 1298
1299static bool 1299static bool
1300mbr_table_str(const struct disk_partitions *arg, part_id id, size_t col, 1300mbr_table_str(const struct disk_partitions *arg, part_id id, size_t col,
1301 char *str, size_t avail_space) 1301 char *str, size_t avail_space)
1302{ 1302{
1303 struct part_get_str_data data; 1303 struct part_get_str_data data;
1304 1304
1305 data.str = str; 1305 data.str = str;
1306 data.avail_space = avail_space; 1306 data.avail_space = avail_space;
1307 data.col = col; 1307 data.col = col;
1308 return mbr_part_apply(arg, id, mbr_get_part_table_str, &data); 1308 return mbr_part_apply(arg, id, mbr_get_part_table_str, &data);
1309} 1309}
1310 1310
1311static bool 1311static bool
1312mbr_get_part_attr_str(const struct disk_partitions *arg, part_id id, 1312mbr_get_part_attr_str(const struct disk_partitions *arg, part_id id,
1313 const mbr_info_t *mb, int i, bool primary, 1313 const mbr_info_t *mb, int i, bool primary,
1314 const struct mbr_partition *mp, void *cookie) 1314 const struct mbr_partition *mp, void *cookie)
1315{ 1315{
1316#ifdef BOOTSEL 1316#ifdef BOOTSEL
1317 const struct mbr_disk_partitions *parts = 1317 const struct mbr_disk_partitions *parts =
1318 (const struct mbr_disk_partitions*)arg; 1318 (const struct mbr_disk_partitions*)arg;
1319#endif 1319#endif
1320 struct part_get_str_data *data = cookie; 1320 struct part_get_str_data *data = cookie;
1321 static const char *flags = NULL; 1321 static const char *flags = NULL;
1322 char *str = data->str; 1322 char *str = data->str;
1323 1323
1324 if (flags == NULL) 1324 if (flags == NULL)
1325 flags = msg_string(MSG_mbr_flags); 1325 flags = msg_string(MSG_mbr_flags);
1326 1326
1327 if (mp->mbrp_flag & MBR_PFLAG_ACTIVE) 1327 if (mp->mbrp_flag & MBR_PFLAG_ACTIVE)
1328 *str++ = flags[0]; 1328 *str++ = flags[0];
1329#ifdef BOOTSEL 1329#ifdef BOOTSEL
1330 if (parts->mbr.bootsec == mb->sector+mp->mbrp_start) 1330 if (parts->mbr.bootsec == mb->sector+mp->mbrp_start)
1331 *str++ = flags[1]; 1331 *str++ = flags[1];
1332#endif 1332#endif
1333 *str = 0; 1333 *str = 0;
1334 return true; 1334 return true;
1335} 1335}
1336 1336
1337static bool 1337static bool
1338mbr_part_attr_str(const struct disk_partitions *arg, part_id id, 1338mbr_part_attr_str(const struct disk_partitions *arg, part_id id,
1339 char *str, size_t avail_space) 1339 char *str, size_t avail_space)
1340{ 1340{
1341 struct part_get_str_data data; 1341 struct part_get_str_data data;
1342 1342
1343 if (avail_space < 3) 1343 if (avail_space < 3)
1344 return false; 1344 return false;
1345 1345
1346 data.str = str; 1346 data.str = str;
1347 data.avail_space = avail_space; 1347 data.avail_space = avail_space;
1348 return mbr_part_apply(arg, id, mbr_get_part_attr_str, &data); 1348 return mbr_part_apply(arg, id, mbr_get_part_attr_str, &data);
1349} 1349}
1350 1350
1351static bool 1351static bool
1352mbr_info_to_partitition(const struct disk_part_info *info, 1352mbr_info_to_partitition(const struct disk_part_info *info,
1353 struct mbr_partition *mp, uint sector, const char **err_msg) 1353 struct mbr_partition *mp, uint sector, const char **err_msg)
1354{ 1354{
1355 size_t pt = mbr_type_from_gen_desc(info->nat_type); 1355 size_t pt = mbr_type_from_gen_desc(info->nat_type);
1356 if (info->start + info->size > UINT_MAX 1356 if (info->start + info->size > UINT_MAX
1357 || pt > __arraycount(mbr_gen_type_desc)) { 1357 || pt > __arraycount(mbr_gen_type_desc)) {
1358 if (err_msg) 1358 if (err_msg)
1359 *err_msg = err_outofmem; 1359 *err_msg = err_outofmem;
1360 return false; 1360 return false;
1361 } 1361 }
1362 mp->mbrp_start = info->start - sector; 1362 mp->mbrp_start = info->start - sector;
1363 mp->mbrp_size = info->size; 1363 mp->mbrp_size = info->size;
1364 mp->mbrp_type = pt; 1364 mp->mbrp_type = pt;
1365 1365
1366 return true; 1366 return true;
1367} 1367}
1368 1368
1369static bool 1369static bool
1370inside_ext_part(mbr_info_t *m, daddr_t start) 1370inside_ext_part(mbr_info_t *m, daddr_t start)
1371{ 1371{
1372 size_t i; 1372 size_t i;
1373 struct mbr_partition *mp = NULL; 1373 struct mbr_partition *mp = NULL;
1374 1374
1375 for (i = 0; i < MBR_PART_COUNT; i++) { 1375 for (i = 0; i < MBR_PART_COUNT; i++) {
1376 if (!MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 1376 if (!MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type))
1377 continue; 1377 continue;
1378 mp = &m->mbr.mbr_parts[i]; 1378 mp = &m->mbr.mbr_parts[i];
1379 break; 1379 break;
1380 } 1380 }
1381 1381
1382 if (mp == NULL) { 1382 if (mp == NULL) {
1383 assert(false); 1383 assert(false);
1384 return false; 1384 return false;
1385 } 1385 }
1386 1386
1387 if (mp->mbrp_start > start) 1387 if (mp->mbrp_start > start)
1388 return false; 1388 return false;
1389 1389
1390 return true; 1390 return true;
1391} 1391}
1392 1392
1393static void 1393static void
1394adjust_ext_part(mbr_info_t *m, daddr_t start, daddr_t size) 1394adjust_ext_part(mbr_info_t *m, daddr_t start, daddr_t size)
1395{ 1395{
1396 size_t i; 1396 size_t i;
1397 struct mbr_partition *mp = NULL; 1397 struct mbr_partition *mp = NULL;
1398 1398
1399 for (i = 0; i < MBR_PART_COUNT; i++) { 1399 for (i = 0; i < MBR_PART_COUNT; i++) {
1400 if (!MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 1400 if (!MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type))
1401 continue; 1401 continue;
1402 mp = &m->mbr.mbr_parts[i]; 1402 mp = &m->mbr.mbr_parts[i];
1403 break; 1403 break;
1404 } 1404 }
1405 1405
1406 if (mp == NULL) { 1406 if (mp == NULL) {
1407 assert(false); 1407 assert(false);
1408 return; 1408 return;
1409 } 1409 }
1410 1410
1411 if (mp->mbrp_start + mp->mbrp_size >= start + size) 1411 if (mp->mbrp_start + mp->mbrp_size >= start + size)
1412 return; 1412 return;
1413 1413
1414 daddr_t new_end = start + size; 1414 daddr_t new_end = start + size;
1415 mp->mbrp_size = new_end - mp->mbrp_start; 1415 mp->mbrp_size = new_end - mp->mbrp_start;
1416} 1416}
1417 1417
1418static bool 1418static bool
1419ext_part_good(mbr_info_t *m, daddr_t ext_start, daddr_t ext_size) 1419ext_part_good(mbr_info_t *m, daddr_t ext_start, daddr_t ext_size)
1420{ 1420{
1421 for (m = m->extended; m != NULL; m = m->extended) { 1421 for (m = m->extended; m != NULL; m = m->extended) {
1422 for (size_t i = 0; i < MBR_PART_COUNT; i++) { 1422 for (size_t i = 0; i < MBR_PART_COUNT; i++) {
1423 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 1423 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED)
1424 continue; 1424 continue;
1425 1425
1426 if (i > 0 && 1426 if (i > 0 &&
1427 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 1427 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type))
1428 break; 1428 break;
1429 1429
1430 daddr_t pstart = m->mbr.mbr_parts[i].mbrp_start + 1430 daddr_t pstart = m->mbr.mbr_parts[i].mbrp_start +
1431 m->sector; 1431 m->sector;
1432 daddr_t pend = pstart + m->mbr.mbr_parts[i].mbrp_size; 1432 daddr_t pend = pstart + m->mbr.mbr_parts[i].mbrp_size;
1433 1433
1434 if (pstart < ext_start || pend > ext_start+ext_size) 1434 if (pstart < ext_start || pend > ext_start+ext_size)
1435 return false; 1435 return false;
1436 } 1436 }
1437 } 1437 }
1438 1438
1439 return true; 1439 return true;
1440} 1440}
1441 1441
1442static bool 1442static bool
1443mbr_set_part_info(struct disk_partitions *arg, part_id id, 1443mbr_set_part_info(struct disk_partitions *arg, part_id id,
1444 const struct disk_part_info *info, const char **err_msg) 1444 const struct disk_part_info *info, const char **err_msg)
1445{ 1445{
1446 struct mbr_disk_partitions *parts = 1446 struct mbr_disk_partitions *parts =
1447 (struct mbr_disk_partitions*)arg; 1447 (struct mbr_disk_partitions*)arg;
1448 struct disk_part_info data = *info; 1448 struct disk_part_info data = *info;
1449 part_id i, j, no, ext_ndx, t; 1449 part_id i, j, no, ext_ndx, t;
1450 mbr_info_t *m = &parts->mbr, *me; 1450 mbr_info_t *m = &parts->mbr, *me;
1451 uint pt = mbr_type_from_gen_desc(info->nat_type); 1451 uint pt = mbr_type_from_gen_desc(info->nat_type);
1452 1452
1453 if (MBR_IS_EXTENDED(pt)) { 1453 if (MBR_IS_EXTENDED(pt)) {
1454 /* check for duplicate ext part */ 1454 /* check for duplicate ext part */
1455 no = 0; 1455 no = 0;
1456 t = ext_ndx = MBR_PART_COUNT; 1456 t = ext_ndx = MBR_PART_COUNT;
1457 for (i = 0; i < MBR_PART_COUNT; i++) { 1457 for (i = 0; i < MBR_PART_COUNT; i++) {
1458 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 1458 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED)
1459 continue; 1459 continue;
1460 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 1460 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type))
1461 ext_ndx = i; 1461 ext_ndx = i;
1462 if (no == id) 1462 if (no == id)
1463 t = i; 1463 t = i;
1464 no++; 1464 no++;
1465 } 1465 }
1466 if (ext_ndx < MBR_PART_COUNT && t != ext_ndx) { 1466 if (ext_ndx < MBR_PART_COUNT && t != ext_ndx) {
1467 if (err_msg) 1467 if (err_msg)
1468 *err_msg = 1468 *err_msg =
1469 msg_string(MSG_Only_one_extended_ptn); 1469 msg_string(MSG_Only_one_extended_ptn);
1470 return false; 1470 return false;
1471 } 1471 }
1472 /* this partition becomes an extended one, apply alignment */ 1472 /* this partition becomes an extended one, apply alignment */
1473 data.start = max(roundup(data.start, parts->ext_ptn_alignment), 1473 data.start = max(roundup(data.start, parts->ext_ptn_alignment),
1474 parts->ext_ptn_alignment); 1474 parts->ext_ptn_alignment);
1475 } 1475 }
1476 1476
1477 no = 0; 1477 no = 0;
1478 for (i = 0; i < MBR_PART_COUNT; i++) { 1478 for (i = 0; i < MBR_PART_COUNT; i++) {
1479 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 1479 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED)
1480 continue; 1480 continue;
1481 1481
1482 if (no == id) 1482 if (no == id)
1483 goto found; 1483 goto found;
1484 no++; 1484 no++;
1485 1485
1486 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) { 1486 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) {
1487 for (me = m->extended; me != NULL; me = me->extended) { 1487 for (me = m->extended; me != NULL; me = me->extended) {
1488 for (j = 0; j < MBR_PART_COUNT; j++) { 1488 for (j = 0; j < MBR_PART_COUNT; j++) {
1489 if (me->mbr.mbr_parts[j].mbrp_type == 1489 if (me->mbr.mbr_parts[j].mbrp_type ==
1490 MBR_PTYPE_UNUSED) 1490 MBR_PTYPE_UNUSED)
1491 continue; 1491 continue;
1492 if (j > 0 && MBR_IS_EXTENDED( 1492 if (j > 0 && MBR_IS_EXTENDED(
1493 me->mbr.mbr_parts[j].mbrp_type)) 1493 me->mbr.mbr_parts[j].mbrp_type))
1494 break; 1494 break;
1495 if (no == id) { 1495 if (no == id) {
1496 i = j; 1496 i = j;
1497 m = me; 1497 m = me;
1498 goto found; 1498 goto found;
1499 } 1499 }
1500 no++; 1500 no++;
1501 } 1501 }
1502 } 1502 }
1503 } 1503 }
1504 } 1504 }
1505 1505
1506 if (err_msg) 1506 if (err_msg)
1507 *err_msg = INTERNAL_ERROR; 1507 *err_msg = INTERNAL_ERROR;
1508 return false; 1508 return false;
1509 1509
1510found: 1510found:
1511 /* 1511 /*
1512 * We assume that m is the mbr we want to update and 1512 * We assume that m is the mbr we want to update and
1513 * i is the local partition index into it. 1513 * i is the local partition index into it.
1514 */ 1514 */
1515 if (m == &parts->mbr) { 1515 if (m == &parts->mbr) {
1516 if (MBR_IS_EXTENDED( 1516 if (MBR_IS_EXTENDED(
1517 m->mbr.mbr_parts[i].mbrp_type) && 1517 m->mbr.mbr_parts[i].mbrp_type) &&
1518 !ext_part_good(&parts->mbr, data.start, data.size)) { 1518 !ext_part_good(&parts->mbr, data.start, data.size)) {
1519 if (err_msg) 1519 if (err_msg)
1520 *err_msg = 1520 *err_msg =
1521 MSG_mbr_ext_nofit; 1521 MSG_mbr_ext_nofit;
1522 return false; 1522 return false;
1523 } 1523 }
1524 } else if (!inside_ext_part(&parts->mbr, data.start)) { 1524 } else if (!inside_ext_part(&parts->mbr, data.start)) {
1525 if (err_msg) 1525 if (err_msg)
1526 *err_msg = msg_string(MSG_mbr_inside_ext); 1526 *err_msg = msg_string(MSG_mbr_inside_ext);
1527 return false; 1527 return false;
1528 } 1528 }
1529 uint start = data.start, size = data.size; 1529 uint start = data.start, size = data.size;
1530 uint oldstart = m->mbr.mbr_parts[i].mbrp_start + m->sector; 1530 uint oldstart = m->mbr.mbr_parts[i].mbrp_start + m->sector;
1531 if (parts->ptn_0_offset > 0 && 1531 if (parts->ptn_0_offset > 0 &&
1532 start < parts->ptn_0_offset) 1532 start < parts->ptn_0_offset)
1533 start = parts->ptn_0_offset; 1533 start = parts->ptn_0_offset;
1534 if (find_mbr_space(m, &start, &size, start, parts->dp.disk_size, 1534 if (find_mbr_space(m, &start, &size, start, parts->dp.disk_size,
1535 oldstart, false) < 0) { 1535 oldstart, false) < 0) {
1536 if (err_msg != NULL) 1536 if (err_msg != NULL)
1537 *err_msg = INTERNAL_ERROR; 1537 *err_msg = INTERNAL_ERROR;
1538 return false; 1538 return false;
1539 } 1539 }
1540 data.start = start; 1540 data.start = start;
1541 if (size < data.size) 1541 if (size < data.size)
1542 data.size = size; 1542 data.size = size;
1543 uint old_start = m->mbr.mbr_parts[i].mbrp_start; 1543 uint old_start = m->mbr.mbr_parts[i].mbrp_start;
1544 if (!mbr_info_to_partitition(&data, 1544 if (!mbr_info_to_partitition(&data,
1545 &m->mbr.mbr_parts[i], m->sector, err_msg)) 1545 &m->mbr.mbr_parts[i], m->sector, err_msg))
1546 return false; 1546 return false;
1547 if (data.last_mounted && m->last_mounted[i] && 1547 if (data.last_mounted && m->last_mounted[i] &&
1548 data.last_mounted != m->last_mounted[i]) { 1548 data.last_mounted != m->last_mounted[i]) {
1549 free(__UNCONST(m->last_mounted[i])); 1549 free(__UNCONST(m->last_mounted[i]));
1550 m->last_mounted[i] = strdup(data.last_mounted); 1550 m->last_mounted[i] = strdup(data.last_mounted);
1551 } 1551 }
1552 if (data.fs_type != 0) 1552 if (data.fs_type != 0)
1553 m->fs_type[i] = data.fs_type; 1553 m->fs_type[i] = data.fs_type;
1554 if (data.fs_sub_type != 0) 1554 if (data.fs_sub_type != 0)
1555 m->fs_sub_type[i] = data.fs_sub_type; 1555 m->fs_sub_type[i] = data.fs_sub_type;
1556 1556
1557 if (m == &parts->mbr) { 1557 if (m == &parts->mbr) {
1558 if (m->mbr.mbr_parts[i].mbrp_start != 1558 if (m->mbr.mbr_parts[i].mbrp_start !=
1559 old_start) 1559 old_start)
1560 mbr_sort_main_mbr(&m->mbr); 1560 mbr_sort_main_mbr(&m->mbr);
1561 } else { 1561 } else {
1562 adjust_ext_part(&parts->mbr, 1562 adjust_ext_part(&parts->mbr,
1563 data.start, data.size); 1563 data.start, data.size);
1564 } 1564 }
1565 mbr_calc_free_space(parts); 1565 mbr_calc_free_space(parts);
1566 return true; 1566 return true;
1567} 1567}
1568 1568
1569static bool 1569static bool
1570mbr_find_netbsd(const struct mbr_info_t *m, uint start, 1570mbr_find_netbsd(const struct mbr_info_t *m, uint start,
1571 struct disk_part_info *info) 1571 struct disk_part_info *info)
1572{ 1572{
1573 size_t i; 1573 size_t i;
1574 bool prim = true; 1574 bool prim = true;
1575 1575
1576 do { 1576 do {
1577 for (i = 0; i < MBR_PART_COUNT; i++) { 1577 for (i = 0; i < MBR_PART_COUNT; i++) {
1578 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 1578 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED)
1579 continue; 1579 continue;
1580 1580
1581 if (!prim && i > 0 && 1581 if (!prim && i > 0 &&
1582 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 1582 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type))
1583 break; 1583 break;
1584 1584
1585 const struct mbr_partition *mp = &m->mbr.mbr_parts[i]; 1585 const struct mbr_partition *mp = &m->mbr.mbr_parts[i];
1586 if (mp->mbrp_type != MBR_PTYPE_NETBSD) 1586 if (mp->mbrp_type != MBR_PTYPE_NETBSD)
1587 continue; 1587 continue;
1588 1588
1589 mbr_partition_to_info(mp, m->sector, info); 1589 mbr_partition_to_info(mp, m->sector, info);
1590 if (m->last_mounted[i] && *m->last_mounted[i] != 0) 1590 if (m->last_mounted[i] && *m->last_mounted[i] != 0)
1591 info->last_mounted = 1591 info->last_mounted =
1592 m->last_mounted[i]; 1592 m->last_mounted[i];
1593 info->fs_type = m->fs_type[i]; 1593 info->fs_type = m->fs_type[i];
1594 info->fs_sub_type = m->fs_sub_type[i]; 1594 info->fs_sub_type = m->fs_sub_type[i];
1595 if (start > 0 && start != info->start) 1595 if (start > 0 && start != info->start)
1596 continue; 1596 continue;
1597 return true; 1597 return true;
1598 } 1598 }
1599 prim = false; 1599 prim = false;
1600 } while ((m = m->extended)); 1600 } while ((m = m->extended));
1601 1601
1602 return false; 1602 return false;
1603} 1603}
1604 1604
1605static struct disk_partitions * 1605static struct disk_partitions *
1606mbr_read_disklabel(struct disk_partitions *arg, daddr_t start) 1606mbr_read_disklabel(struct disk_partitions *arg, daddr_t start)
1607{ 1607{
1608 struct mbr_disk_partitions *myparts = 1608 struct mbr_disk_partitions *myparts =
1609 (struct mbr_disk_partitions*)arg; 1609 (struct mbr_disk_partitions*)arg;
1610 struct disk_part_info part; 1610 struct disk_part_info part;
1611 1611
1612 if (myparts->dlabel == NULL) { 1612 if (myparts->dlabel == NULL) {
1613 /* 1613 /*
1614 * Find the NetBSD MBR partition 1614 * Find the NetBSD MBR partition
1615 */ 1615 */
1616 if (!mbr_find_netbsd(&myparts->mbr, start, &part)) 1616 if (!mbr_find_netbsd(&myparts->mbr, start, &part))
1617 return NULL; 1617 return NULL;
1618 1618
1619 myparts->dlabel = disklabel_parts.read_from_disk( 1619 myparts->dlabel = disklabel_parts.read_from_disk(
1620 myparts->dp.disk, part.start, part.size); 1620 myparts->dp.disk, part.start, part.size);
1621 1621
1622 if (myparts->dlabel == NULL && part.size > 0) { 1622 if (myparts->dlabel == NULL && part.size > 0) {
1623 /* we just created the outer partitions? */ 1623 /* we just created the outer partitions? */
1624 myparts->dlabel =  1624 myparts->dlabel =
1625 disklabel_parts.create_new_for_disk( 1625 disklabel_parts.create_new_for_disk(
1626 myparts->dp.disk, part.start, part.size, 1626 myparts->dp.disk, part.start, part.size,
1627 myparts->dp.disk_size, false); 1627 myparts->dp.disk_size, false);
1628 } 1628 }
1629 1629
1630 if (myparts->dlabel != NULL) { 1630 if (myparts->dlabel != NULL) {
1631 myparts->dlabel->parent = arg; 1631 myparts->dlabel->parent = arg;
1632 myparts->dlabel->pscheme->change_disk_geom( 1632 myparts->dlabel->pscheme->change_disk_geom(
1633 myparts->dlabel, myparts->geo_cyl, 1633 myparts->dlabel, myparts->geo_cyl,
1634 myparts->geo_head, myparts->geo_sec); 1634 myparts->geo_head, myparts->geo_sec);
1635 } 1635 }
1636 } 1636 }
1637 return myparts->dlabel; 1637 return myparts->dlabel;
1638} 1638}
1639 1639
1640static int 1640static int
1641get_mapping(struct mbr_partition *parts, int i, 1641get_mapping(struct mbr_partition *parts, int i,
1642 int *cylinder, int *head, int *sector, daddr_t *absolute) 1642 int *cylinder, int *head, int *sector, daddr_t *absolute)
1643{ 1643{
1644 struct mbr_partition *apart = &parts[i / 2]; 1644 struct mbr_partition *apart = &parts[i / 2];
1645 1645
1646 if (apart->mbrp_type == MBR_PTYPE_UNUSED) 1646 if (apart->mbrp_type == MBR_PTYPE_UNUSED)
1647 return -1; 1647 return -1;
1648 if (i % 2 == 0) { 1648 if (i % 2 == 0) {
1649 *cylinder = MBR_PCYL(apart->mbrp_scyl, apart->mbrp_ssect); 1649 *cylinder = MBR_PCYL(apart->mbrp_scyl, apart->mbrp_ssect);
1650 *head = apart->mbrp_shd; 1650 *head = apart->mbrp_shd;
1651 *sector = MBR_PSECT(apart->mbrp_ssect) - 1; 1651 *sector = MBR_PSECT(apart->mbrp_ssect) - 1;
1652 *absolute = le32toh(apart->mbrp_start); 1652 *absolute = le32toh(apart->mbrp_start);
1653 } else { 1653 } else {
1654 *cylinder = MBR_PCYL(apart->mbrp_ecyl, apart->mbrp_esect); 1654 *cylinder = MBR_PCYL(apart->mbrp_ecyl, apart->mbrp_esect);
1655 *head = apart->mbrp_ehd; 1655 *head = apart->mbrp_ehd;
1656 *sector = MBR_PSECT(apart->mbrp_esect) - 1; 1656 *sector = MBR_PSECT(apart->mbrp_esect) - 1;
1657 *absolute = le32toh(apart->mbrp_start) 1657 *absolute = le32toh(apart->mbrp_start)
1658 + le32toh(apart->mbrp_size) - 1; 1658 + le32toh(apart->mbrp_size) - 1;
1659 } 1659 }
1660 /* Sanity check the data against max values */ 1660 /* Sanity check the data against max values */
1661 if ((((*cylinder * MAXHEAD) + *head) * (uint32_t)MAXSECTOR + *sector) < *absolute) 1661 if ((((*cylinder * MAXHEAD) + *head) * (uint32_t)MAXSECTOR + *sector) < *absolute)
1662 /* cannot be a CHS mapping */ 1662 /* cannot be a CHS mapping */
1663 return -1; 1663 return -1;
1664 1664
1665 return 0; 1665 return 0;
1666} 1666}
1667 1667
1668static bool 1668static bool
1669mbr_delete_all(struct disk_partitions *arg) 1669mbr_delete_all(struct disk_partitions *arg)
1670{ 1670{
1671 struct mbr_disk_partitions *myparts = (struct mbr_disk_partitions*)arg; 1671 struct mbr_disk_partitions *myparts = (struct mbr_disk_partitions*)arg;
1672 struct mbr_sector *mbrs = &myparts->mbr.mbr; 1672 struct mbr_sector *mbrs = &myparts->mbr.mbr;
1673 struct mbr_info_t *mbri = &myparts->mbr; 1673 struct mbr_info_t *mbri = &myparts->mbr;
1674 mbr_info_t *ext; 1674 mbr_info_t *ext;
1675 struct mbr_partition *part; 1675 struct mbr_partition *part;
1676 1676
1677 part = &mbrs->mbr_parts[0]; 1677 part = &mbrs->mbr_parts[0];
1678 /* Set the partition information for full disk usage. */ 1678 /* Set the partition information for full disk usage. */
1679 while ((ext = mbri->extended)) { 1679 while ((ext = mbri->extended)) {
1680 mbri->extended = ext->extended; 1680 mbri->extended = ext->extended;
1681 free_mbr_info(ext); 1681 free_mbr_info(ext);
1682 } 1682 }
1683 memset(part, 0, MBR_PART_COUNT * sizeof *part); 1683 memset(part, 0, MBR_PART_COUNT * sizeof *part);
1684#ifdef BOOTSEL 1684#ifdef BOOTSEL
1685 memset(&mbri->mbrb, 0, sizeof mbri->mbrb); 1685 memset(&mbri->mbrb, 0, sizeof mbri->mbrb);
1686#endif 1686#endif
 1687
 1688 /*
 1689 * We may have changed alignment settings due to partitions
 1690 * ending on an MB boundary - undo that, now that the partitions
 1691 * are gone.
 1692 */
 1693 mbr_change_disk_geom(arg, myparts->geo_cyl, myparts->geo_head,
 1694 myparts->geo_sec);
 1695
1687 return true; 1696 return true;
1688} 1697}
1689 1698
1690/* 1699/*
1691 * helper function to fix up mbrp_start and mbrp_size for the 1700 * helper function to fix up mbrp_start and mbrp_size for the
1692 * extended MBRs "partition b" entries after addition/deletion 1701 * extended MBRs "partition b" entries after addition/deletion
1693 * of some partition. 1702 * of some partition.
1694 */ 1703 */
1695static void 1704static void
1696mbr_fixup_ext_chain(mbr_info_t *primary, uint ext_start, uint ext_end) 1705mbr_fixup_ext_chain(mbr_info_t *primary, uint ext_start, uint ext_end)
1697{ 1706{
1698 for (mbr_info_t *m = primary->extended; m != NULL; m = m->extended) { 1707 for (mbr_info_t *m = primary->extended; m != NULL; m = m->extended) {
1699 if (m->extended == NULL) { 1708 if (m->extended == NULL) {
1700 m->mbr.mbr_parts[1].mbrp_type = MBR_PTYPE_UNUSED; 1709 m->mbr.mbr_parts[1].mbrp_type = MBR_PTYPE_UNUSED;
1701 m->mbr.mbr_parts[1].mbrp_start = 0; 1710 m->mbr.mbr_parts[1].mbrp_start = 0;
1702 m->mbr.mbr_parts[1].mbrp_size = 0; 1711 m->mbr.mbr_parts[1].mbrp_size = 0;
1703 } else { 1712 } else {
1704 uint n_end, n_start = m->extended->sector; 1713 uint n_end, n_start = m->extended->sector;
1705 if (m->extended->extended) 1714 if (m->extended->extended)
1706 n_end = m->extended->extended->sector; 1715 n_end = m->extended->extended->sector;
1707 else 1716 else
1708 n_end = ext_end; 1717 n_end = ext_end;
1709 m->mbr.mbr_parts[1].mbrp_type = MBR_PTYPE_EXT; 1718 m->mbr.mbr_parts[1].mbrp_type = MBR_PTYPE_EXT;
1710 m->mbr.mbr_parts[1].mbrp_start = n_start - ext_start; 1719 m->mbr.mbr_parts[1].mbrp_start = n_start - ext_start;
1711 m->mbr.mbr_parts[1].mbrp_size = n_end - n_start; 1720 m->mbr.mbr_parts[1].mbrp_size = n_end - n_start;
1712 } 1721 }
1713 } 1722 }
1714} 1723}
1715 1724
1716struct delete_part_args { 1725struct delete_part_args {
1717 struct mbr_disk_partitions *parts; 1726 struct mbr_disk_partitions *parts;
1718 daddr_t start, size; 1727 daddr_t start, size;
1719 const char **err_msg; 1728 const char **err_msg;
1720}; 1729};
1721 1730
1722static bool 1731static bool
1723mbr_do_delete_part(const struct disk_partitions *arg, part_id id, 1732mbr_do_delete_part(const struct disk_partitions *arg, part_id id,
1724 const mbr_info_t *mb, int i, bool primary, 1733 const mbr_info_t *mb, int i, bool primary,
1725 const struct mbr_partition *mp, void *cookie) 1734 const struct mbr_partition *mp, void *cookie)
1726{ 1735{
1727 struct delete_part_args *marg = cookie; 1736 struct delete_part_args *marg = cookie;
1728 bool is_ext_part = MBR_IS_EXTENDED(mp->mbrp_type); 1737 bool is_ext_part = MBR_IS_EXTENDED(mp->mbrp_type);
1729 1738
1730 /* can not delete non-empty extended partitions */ 1739 /* can not delete non-empty extended partitions */
1731 if (MBR_IS_EXTENDED(mp->mbrp_type) 1740 if (MBR_IS_EXTENDED(mp->mbrp_type)
1732 && marg->parts->mbr.extended != NULL) { 1741 && marg->parts->mbr.extended != NULL) {
1733 if (marg->err_msg) 1742 if (marg->err_msg)
1734 *marg->err_msg = msg_string(MSG_mbr_ext_not_empty); 1743 *marg->err_msg = msg_string(MSG_mbr_ext_not_empty);
1735 return false; 1744 return false;
1736 } 1745 }
1737 1746
1738 /* return position/size to caller */ 1747 /* return position/size to caller */
1739 marg->start = mb->sector + mp->mbrp_start; 1748 marg->start = mb->sector + mp->mbrp_start;
1740 marg->size = mp->mbrp_size; 1749 marg->size = mp->mbrp_size;
1741 1750
1742 if (primary) { 1751 if (primary) {
1743 /* if deleting the primary extended partition, just kill it */ 1752 /* if deleting the primary extended partition, just kill it */
1744 struct mbr_partition *md = &marg->parts->mbr.mbr.mbr_parts[i]; 1753 struct mbr_partition *md = &marg->parts->mbr.mbr.mbr_parts[i];
1745 md->mbrp_size = 0; 1754 md->mbrp_size = 0;
1746 md->mbrp_start = 0; 1755 md->mbrp_start = 0;
1747 md->mbrp_type = MBR_PTYPE_UNUSED; 1756 md->mbrp_type = MBR_PTYPE_UNUSED;
1748 if (marg->parts->mbr.last_mounted[i]) { 1757 if (marg->parts->mbr.last_mounted[i]) {
1749 free(__UNCONST(marg->parts->mbr.last_mounted[i])); 1758 free(__UNCONST(marg->parts->mbr.last_mounted[i]));
1750 marg->parts->mbr.last_mounted[i] = NULL; 1759 marg->parts->mbr.last_mounted[i] = NULL;
1751 } 1760 }
1752 if (is_ext_part) { 1761 if (is_ext_part) {
1753 for (mbr_info_t *m = marg->parts->mbr.extended; 1762 for (mbr_info_t *m = marg->parts->mbr.extended;
1754 m != NULL; ) { 1763 m != NULL; ) {
1755 mbr_info_t *n = m->extended; 1764 mbr_info_t *n = m->extended;
1756 free_mbr_info(m); 1765 free_mbr_info(m);
1757 m = n; 1766 m = n;
1758 } 1767 }
1759 marg->parts->mbr.extended = NULL; 1768 marg->parts->mbr.extended = NULL;
1760 } 1769 }
1761 } else { 1770 } else {
1762 /* find the size of the primary extended partition */ 1771 /* find the size of the primary extended partition */
1763 uint ext_start = 0, ext_size = 0; 1772 uint ext_start = 0, ext_size = 0;
1764 for (i = 0; i < MBR_PART_COUNT; i++) { 1773 for (i = 0; i < MBR_PART_COUNT; i++) {
1765 if (!MBR_IS_EXTENDED(marg->parts->mbr.mbr.mbr_parts[i] 1774 if (!MBR_IS_EXTENDED(marg->parts->mbr.mbr.mbr_parts[i]
1766 .mbrp_type)) 1775 .mbrp_type))
1767 continue; 1776 continue;
1768 ext_start = marg->parts->mbr.mbr.mbr_parts[i] 1777 ext_start = marg->parts->mbr.mbr.mbr_parts[i]
1769 .mbrp_start; 1778 .mbrp_start;
1770 ext_size = marg->parts->mbr.mbr.mbr_parts[i] 1779 ext_size = marg->parts->mbr.mbr.mbr_parts[i]
1771 .mbrp_size; 1780 .mbrp_size;
1772 break; 1781 break;
1773 } 1782 }
1774 1783
1775 /* 1784 /*
1776 * If we are in an extended partition chain, unlink this MBR, 1785 * If we are in an extended partition chain, unlink this MBR,
1777 * unless it is the very first one at the start of the extended 1786 * unless it is the very first one at the start of the extended
1778 * partition (we would have no previos ext mbr to fix up 1787 * partition (we would have no previos ext mbr to fix up
1779 * the chain in that case) 1788 * the chain in that case)
1780 */ 1789 */
1781 if (marg->parts->mbr.extended == mb) { 1790 if (marg->parts->mbr.extended == mb) {
1782 struct mbr_partition *part = 1791 struct mbr_partition *part =
1783 &marg->parts->mbr.extended->mbr.mbr_parts[0]; 1792 &marg->parts->mbr.extended->mbr.mbr_parts[0];
1784 part->mbrp_type = MBR_PTYPE_UNUSED; 1793 part->mbrp_type = MBR_PTYPE_UNUSED;
1785 part->mbrp_start = 0; 1794 part->mbrp_start = 0;
1786 part->mbrp_size = 0; 1795 part->mbrp_size = 0;
1787 } else { 1796 } else {
1788 mbr_info_t *p, *last; 1797 mbr_info_t *p, *last;
1789 for (last = NULL, p = &marg->parts->mbr; p != NULL; 1798 for (last = NULL, p = &marg->parts->mbr; p != NULL;
1790 last = p, p = p->extended) 1799 last = p, p = p->extended)
1791 if (p == mb) 1800 if (p == mb)
1792 break; 1801 break;
1793 if (last == NULL) { 1802 if (last == NULL) {
1794 if (marg->err_msg != NULL) 1803 if (marg->err_msg != NULL)
1795 *marg->err_msg= INTERNAL_ERROR; 1804 *marg->err_msg= INTERNAL_ERROR;
1796 return false; 1805 return false;
1797 } 1806 }
1798 last->extended = p->extended; 1807 last->extended = p->extended;
1799 free_mbr_info(p); 1808 free_mbr_info(p);
1800 if (last == &marg->parts->mbr && last->extended && 1809 if (last == &marg->parts->mbr && last->extended &&
1801 last->extended->extended == NULL && 1810 last->extended->extended == NULL &&
1802 last->extended->mbr.mbr_parts[0].mbrp_type == 1811 last->extended->mbr.mbr_parts[0].mbrp_type ==
1803 MBR_PTYPE_UNUSED) { 1812 MBR_PTYPE_UNUSED) {
1804 /* 1813 /*
1805 * we deleted the last extended sector, 1814 * we deleted the last extended sector,
1806 * remove the whole chain 1815 * remove the whole chain
1807 */ 1816 */
1808 free_mbr_info(last->extended); 1817 free_mbr_info(last->extended);
1809 last->extended = NULL; 1818 last->extended = NULL;
1810 } 1819 }
1811 } 1820 }
1812 mbr_fixup_ext_chain(&marg->parts->mbr, ext_start, 1821 mbr_fixup_ext_chain(&marg->parts->mbr, ext_start,
1813 ext_start+ext_size); 1822 ext_start+ext_size);
1814 } 1823 }
1815 mbr_calc_free_space(marg->parts); 1824 mbr_calc_free_space(marg->parts);
1816 return true; 1825 return true;
1817} 1826}
1818 1827
1819static bool 1828static bool
1820mbr_delete_part(struct disk_partitions *arg, part_id pno, const char **err_msg) 1829mbr_delete_part(struct disk_partitions *arg, part_id pno, const char **err_msg)
1821{ 1830{
1822 struct mbr_disk_partitions *parts = 1831 struct mbr_disk_partitions *parts =
1823 (struct mbr_disk_partitions*)arg; 1832 (struct mbr_disk_partitions*)arg;
1824 struct delete_part_args data = { .parts = parts, .err_msg = err_msg }; 1833 struct delete_part_args data = { .parts = parts, .err_msg = err_msg };
1825 1834
1826 if (!mbr_part_apply(arg, pno, mbr_do_delete_part, &data)) { 1835 if (!mbr_part_apply(arg, pno, mbr_do_delete_part, &data)) {
1827 if (err_msg) 1836 if (err_msg)
1828 *err_msg = INTERNAL_ERROR; 1837 *err_msg = INTERNAL_ERROR;
1829 return false; 1838 return false;
1830 } 1839 }
1831 1840
1832 if (parts->dlabel) { 1841 if (parts->dlabel) {
1833 /* 1842 /*
1834 * If we change the mbr partitioning, the we must 1843 * If we change the mbr partitioning, the we must
1835 * remove any references in the netbsd disklabel 1844 * remove any references in the netbsd disklabel
1836 * to the part we changed. 1845 * to the part we changed.
1837 */ 1846 */
1838 parts->dlabel->pscheme->delete_partitions_in_range( 1847 parts->dlabel->pscheme->delete_partitions_in_range(
1839 parts->dlabel, data.start, data.size); 1848 parts->dlabel, data.start, data.size);
1840 } 1849 }
1841 1850
1842 if (err_msg) 1851 if (err_msg)
1843 *err_msg = NULL; 1852 *err_msg = NULL;
1844 1853
1845 dump_mbr(&parts->mbr, "after delete"); 1854 dump_mbr(&parts->mbr, "after delete");
1846 return true; 1855 return true;
1847} 1856}
1848 1857
1849static struct mbr_partition * 1858static struct mbr_partition *
1850mbr_ptr_from_start(mbr_info_t *m, daddr_t start) 1859mbr_ptr_from_start(mbr_info_t *m, daddr_t start)
1851{ 1860{
1852 bool primary = true; 1861 bool primary = true;
1853 1862
1854 do { 1863 do {
1855 for (uint i = 0; i < MBR_PART_COUNT; i++) { 1864 for (uint i = 0; i < MBR_PART_COUNT; i++) {
1856 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 1865 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED)
1857 continue; 1866 continue;
1858 if (!primary && 1867 if (!primary &&
1859 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 1868 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type))
1860 break; 1869 break;
1861 1870
1862 daddr_t pstart = m->sector + 1871 daddr_t pstart = m->sector +
1863 m->mbr.mbr_parts[i].mbrp_start; 1872 m->mbr.mbr_parts[i].mbrp_start;
1864 if (pstart == start) 1873 if (pstart == start)
1865 return &m->mbr.mbr_parts[i]; 1874 return &m->mbr.mbr_parts[i];
1866 1875
1867 } 1876 }
1868 primary = false; 1877 primary = false;
1869 } while ((m = m->extended)); 1878 } while ((m = m->extended));
1870 1879
1871 return NULL; 1880 return NULL;
1872} 1881}
1873 1882
1874static uint8_t 1883static uint8_t
1875mbr_type_from_start(const mbr_info_t *m, daddr_t start) 1884mbr_type_from_start(const mbr_info_t *m, daddr_t start)
1876{ 1885{
1877 bool primary = true; 1886 bool primary = true;
1878 1887
1879 do { 1888 do {
1880 for (uint i = 0; i < MBR_PART_COUNT; i++) { 1889 for (uint i = 0; i < MBR_PART_COUNT; i++) {
1881 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 1890 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED)
1882 continue; 1891 continue;
1883 if (!primary && 1892 if (!primary &&
1884 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 1893 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type))
1885 break; 1894 break;
1886 1895
1887 daddr_t pstart = m->sector + 1896 daddr_t pstart = m->sector +
1888 m->mbr.mbr_parts[i].mbrp_start; 1897 m->mbr.mbr_parts[i].mbrp_start;
1889 if (pstart == start) 1898 if (pstart == start)
1890 return m->mbr.mbr_parts[i].mbrp_type; 1899 return m->mbr.mbr_parts[i].mbrp_type;
1891 1900
1892 } 1901 }
1893 primary = false; 1902 primary = false;
1894 } while ((m = m->extended)); 1903 } while ((m = m->extended));
1895 1904
1896 return MBR_PTYPE_UNUSED; 1905 return MBR_PTYPE_UNUSED;
1897} 1906}
1898 1907
1899static part_id 1908static part_id
1900mbr_add_part(struct disk_partitions *arg, 1909mbr_add_part(struct disk_partitions *arg,
1901 const struct disk_part_info *info, const char **errmsg) 1910 const struct disk_part_info *info, const char **errmsg)
1902{ 1911{
1903 struct mbr_disk_partitions *parts = 1912 struct mbr_disk_partitions *parts =
1904 (struct mbr_disk_partitions*)arg; 1913 (struct mbr_disk_partitions*)arg;
1905 part_id i, j, no, free_primary = UINT_MAX; 1914 part_id i, j, no, free_primary = UINT_MAX;
1906 mbr_info_t *m = &parts->mbr, *me, *last, *t; 1915 mbr_info_t *m = &parts->mbr, *me, *last, *t;
1907 daddr_t ext_start = 0, ext_size = 0; 1916 daddr_t ext_start = 0, ext_size = 0;
1908 uint start, size; 1917 uint start, size;
1909 struct disk_part_info data = *info; 1918 struct disk_part_info data = *info;
1910 struct mbr_partition *newp; 1919 struct mbr_partition *newp;
1911 1920
1912 if (errmsg != NULL) 1921 if (errmsg != NULL)
1913 *errmsg = NULL; 1922 *errmsg = NULL;
1914 1923
1915 assert(info->nat_type != NULL); 1924 assert(info->nat_type != NULL);
1916 if (info->nat_type == NULL) { 1925 if (info->nat_type == NULL) {
1917 if (errmsg != NULL) 1926 if (errmsg != NULL)
1918 *errmsg = INTERNAL_ERROR; 1927 *errmsg = INTERNAL_ERROR;
1919 return NO_PART; 1928 return NO_PART;
1920 } 1929 }
1921 if (mbr_type_from_gen_desc(info->nat_type) == MBR_PTYPE_UNUSED) { 1930 if (mbr_type_from_gen_desc(info->nat_type) == MBR_PTYPE_UNUSED) {
1922 if (errmsg != NULL) 1931 if (errmsg != NULL)
1923 *errmsg = INTERNAL_ERROR; 1932 *errmsg = INTERNAL_ERROR;
1924 return NO_PART; 1933 return NO_PART;
1925 } 1934 }
1926 1935
1927 /* do we have free primary slots and/or an extended partition? */ 1936 /* do we have free primary slots and/or an extended partition? */
1928 for (i = 0; i < MBR_PART_COUNT; i++) { 1937 for (i = 0; i < MBR_PART_COUNT; i++) {
1929 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED 1938 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED
1930 && free_primary > MBR_PART_COUNT) 1939 && free_primary > MBR_PART_COUNT)
1931 free_primary = i; 1940 free_primary = i;
1932 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) { 1941 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) {
1933 ext_start = m->mbr.mbr_parts[i].mbrp_start+m->sector; 1942 ext_start = m->mbr.mbr_parts[i].mbrp_start+m->sector;
1934 ext_size = m->mbr.mbr_parts[i].mbrp_size; 1943 ext_size = m->mbr.mbr_parts[i].mbrp_size;
1935 continue; 1944 continue;
1936 } 1945 }
1937 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED 1946 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED
1938 && m->mbr.mbr_parts[i].mbrp_size == 0) 1947 && m->mbr.mbr_parts[i].mbrp_size == 0)
1939 continue; 1948 continue;
1940 } 1949 }
1941 if (ext_start > 0 && ext_size > 0 && 1950 if (ext_start > 0 && ext_size > 0 &&
1942 MBR_IS_EXTENDED(mbr_type_from_gen_desc(info->nat_type))) { 1951 MBR_IS_EXTENDED(mbr_type_from_gen_desc(info->nat_type))) {
1943 /* 1952 /*
1944 * Do not allow a second extended partition 1953 * Do not allow a second extended partition
1945 */ 1954 */
1946 if (errmsg) 1955 if (errmsg)
1947 *errmsg = MSG_Only_one_extended_ptn; 1956 *errmsg = MSG_Only_one_extended_ptn;
1948 return NO_PART; 1957 return NO_PART;
1949 } 1958 }
1950 1959
1951 /* should this go into the extended partition? */ 1960 /* should this go into the extended partition? */
1952 if (ext_size > 0 && info->start >= ext_start 1961 if (ext_size > 0 && info->start >= ext_start
1953 && info->start < ext_start + ext_size) { 1962 && info->start < ext_start + ext_size) {
1954 1963
1955 /* must fit into the extended partition */ 1964 /* must fit into the extended partition */
1956 if (info->start + info->size > ext_start + ext_size) { 1965 if (info->start + info->size > ext_start + ext_size) {
1957 if (errmsg != NULL) 1966 if (errmsg != NULL)
1958 *errmsg = MSG_mbr_ext_nofit; 1967 *errmsg = MSG_mbr_ext_nofit;
1959 return NO_PART; 1968 return NO_PART;
1960 } 1969 }
1961 1970
1962 /* walk the chain untill we find a proper insert position */ 1971 /* walk the chain untill we find a proper insert position */
1963 daddr_t e_end, e_start; 1972 daddr_t e_end, e_start;
1964 for (last = m, m = m->extended; m != NULL; 1973 for (last = m, m = m->extended; m != NULL;
1965 last = m, m = m->extended) { 1974 last = m, m = m->extended) {
1966 e_start = m->mbr.mbr_parts[1].mbrp_start 1975 e_start = m->mbr.mbr_parts[1].mbrp_start
1967 + ext_start; 1976 + ext_start;
1968 e_end = e_start + m->mbr.mbr_parts[1].mbrp_size; 1977 e_end = e_start + m->mbr.mbr_parts[1].mbrp_size;
1969 if (data.start <= e_start) 1978 if (data.start <= e_start)
1970 break; 1979 break;
1971 } 1980 }
1972 if (m == NULL) { 1981 if (m == NULL) {
1973 /* add new tail record */ 1982 /* add new tail record */
1974 e_end = ext_start + ext_size; 1983 e_end = ext_start + ext_size;
1975 /* new part needs to fit inside primary extended one */ 1984 /* new part needs to fit inside primary extended one */
1976 if (data.start + data.size > e_end) { 1985 if (data.start + data.size > e_end) {
1977 if (errmsg) 1986 if (errmsg)
1978 *errmsg = MSG_No_free_space; 1987 *errmsg = MSG_No_free_space;
1979 return NO_PART; 1988 return NO_PART;
1980 } 1989 }
1981 } else if (data.start + data.size > e_start) { 1990 } else if (data.start + data.size > e_start) {
1982 /* new part needs to fit before next extended */ 1991 /* new part needs to fit before next extended */
1983 if (errmsg) 1992 if (errmsg)
1984 *errmsg = MSG_No_free_space; 1993 *errmsg = MSG_No_free_space;
1985 return NO_PART; 1994 return NO_PART;
1986 } 1995 }
1987 /* 1996 /*
1988 * now last points to previous mbr (maybe primary), m 1997 * now last points to previous mbr (maybe primary), m
1989 * points to the one that should take the new partition 1998 * points to the one that should take the new partition
1990 * or we have to insert a new mbr between the two, or 1999 * or we have to insert a new mbr between the two, or
1991 * m needs to be split and we go into the one after it. 2000 * m needs to be split and we go into the one after it.
1992 */ 2001 */
1993 if (m && m->mbr.mbr_parts[0].mbrp_type == MBR_PTYPE_UNUSED) { 2002 if (m && m->mbr.mbr_parts[0].mbrp_type == MBR_PTYPE_UNUSED) {
1994 /* empty slot, we can just use it */ 2003 /* empty slot, we can just use it */
1995 newp = &m->mbr.mbr_parts[0]; 2004 newp = &m->mbr.mbr_parts[0];
1996 mbr_info_to_partitition(&data, &m->mbr.mbr_parts[0], 2005 mbr_info_to_partitition(&data, &m->mbr.mbr_parts[0],
1997 m->sector, errmsg); 2006 m->sector, errmsg);
1998 if (data.last_mounted && m->last_mounted[0] && 2007 if (data.last_mounted && m->last_mounted[0] &&
1999 data.last_mounted != m->last_mounted[0]) { 2008 data.last_mounted != m->last_mounted[0]) {
2000 free(__UNCONST(m->last_mounted[0])); 2009 free(__UNCONST(m->last_mounted[0]));
2001 m->last_mounted[0] = strdup(data.last_mounted); 2010 m->last_mounted[0] = strdup(data.last_mounted);
2002 } 2011 }
2003 } else { 2012 } else {
2004 mbr_info_t *new_mbr; 2013 mbr_info_t *new_mbr;
2005 if (m == NULL) 2014 if (m == NULL)
2006 m = last; 2015 m = last;
2007 daddr_t p_start = m->mbr.mbr_parts[0].mbrp_start 2016 daddr_t p_start = m->mbr.mbr_parts[0].mbrp_start
2008 + m->sector; 2017 + m->sector;
2009 daddr_t p_end = p_start 2018 daddr_t p_end = p_start
2010 + m->mbr.mbr_parts[0].mbrp_size; 2019 + m->mbr.mbr_parts[0].mbrp_size;
2011 bool before; 2020 bool before;
2012 if (m == last || data.start > p_end) 2021 if (m == last || data.start > p_end)
2013 before = false; 2022 before = false;
2014 else if (data.start + data.size < p_start) 2023 else if (data.start + data.size < p_start)
2015 before = true; 2024 before = true;
2016 else { 2025 else {
2017 if (errmsg) 2026 if (errmsg)
2018 *errmsg = MSG_No_free_space; 2027 *errmsg = MSG_No_free_space;
2019 return NO_PART; 2028 return NO_PART;
2020 } 2029 }
2021 new_mbr = calloc(1, sizeof *new_mbr); 2030 new_mbr = calloc(1, sizeof *new_mbr);
2022 if (!new_mbr) { 2031 if (!new_mbr) {
2023 if (errmsg) 2032 if (errmsg)
2024 *errmsg = err_outofmem; 2033 *errmsg = err_outofmem;
2025 return NO_PART; 2034 return NO_PART;
2026 } 2035 }
2027 new_mbr->mbr.mbr_magic = htole16(MBR_MAGIC); 2036 new_mbr->mbr.mbr_magic = htole16(MBR_MAGIC);
2028 new_mbr->mbr.mbr_parts[1].mbrp_type = MBR_PTYPE_EXT; 2037 new_mbr->mbr.mbr_parts[1].mbrp_type = MBR_PTYPE_EXT;
2029 if (before) { 2038 if (before) {
2030 /* 2039 /*
2031 * This is a hypthetical case where 2040 * This is a hypthetical case where
2032 * an extended MBR uses an unusual high 2041 * an extended MBR uses an unusual high
2033 * offset (m->sector to parts[0].mbrp_start) 2042 * offset (m->sector to parts[0].mbrp_start)
2034 * and we want to go into that space. 2043 * and we want to go into that space.
2035 * Should not happen in the real world (tm) 2044 * Should not happen in the real world (tm)
2036 * and is untested.... 2045 * and is untested....
2037 */ 2046 */
2038 2047
2039 /* make sure the aligned new mbr fits */ 2048 /* make sure the aligned new mbr fits */
2040 uint mbrsec = rounddown(p_start, 2049 uint mbrsec = rounddown(p_start,
2041 parts->ext_ptn_alignment); 2050 parts->ext_ptn_alignment);
2042 if (mbrsec <= data.start + data.size) 2051 if (mbrsec <= data.start + data.size)
2043 data.size = mbrsec-1-data.start; 2052 data.size = mbrsec-1-data.start;
2044 2053
2045 /* now the new partition data is ready, 2054 /* now the new partition data is ready,
2046 * write out to old position */ 2055 * write out to old position */
2047 new_mbr->sector = m->sector; 2056 new_mbr->sector = m->sector;
2048 newp = &new_mbr->mbr.mbr_parts[0]; 2057 newp = &new_mbr->mbr.mbr_parts[0];
2049 mbr_info_to_partitition(&data, 2058 mbr_info_to_partitition(&data,
2050 &new_mbr->mbr.mbr_parts[0], 2059 &new_mbr->mbr.mbr_parts[0],
2051 new_mbr->sector, errmsg); 2060 new_mbr->sector, errmsg);
2052 if (data.last_mounted && m->last_mounted[0] && 2061 if (data.last_mounted && m->last_mounted[0] &&
2053 data.last_mounted != m->last_mounted[0]) { 2062 data.last_mounted != m->last_mounted[0]) {
2054 free(__UNCONST(m->last_mounted[0])); 2063 free(__UNCONST(m->last_mounted[0]));
2055 m->last_mounted[0] = 2064 m->last_mounted[0] =
2056 strdup(data.last_mounted); 2065 strdup(data.last_mounted);
2057 } 2066 }
2058 new_mbr->extended = m; 2067 new_mbr->extended = m;
2059 } else { 2068 } else {
2060 new_mbr->sector = max(roundup(data.start, 2069 new_mbr->sector = max(roundup(data.start,
2061 parts->ext_ptn_alignment), 2070 parts->ext_ptn_alignment),
2062 parts->ext_ptn_alignment); 2071 parts->ext_ptn_alignment);
2063 uint off = new_mbr->sector - data.start; 2072 uint off = new_mbr->sector - data.start;
2064 data.start += parts->ptn_0_offset+off; 2073 data.start += parts->ptn_0_offset+off;
2065 if (data.start + data.size > e_end) 2074 if (data.start + data.size > e_end)
2066 data.size = e_end - data.start; 2075 data.size = e_end - data.start;
2067 newp = &new_mbr->mbr.mbr_parts[0]; 2076 newp = &new_mbr->mbr.mbr_parts[0];
2068 mbr_info_to_partitition(&data, 2077 mbr_info_to_partitition(&data,
2069 &new_mbr->mbr.mbr_parts[0], 2078 &new_mbr->mbr.mbr_parts[0],
2070 new_mbr->sector, errmsg); 2079 new_mbr->sector, errmsg);
2071 if (data.last_mounted && m->last_mounted[0] && 2080 if (data.last_mounted && m->last_mounted[0] &&
2072 data.last_mounted != m->last_mounted[0]) { 2081 data.last_mounted != m->last_mounted[0]) {
2073 free(__UNCONST(m->last_mounted[0])); 2082 free(__UNCONST(m->last_mounted[0]));
2074 m->last_mounted[0] = 2083 m->last_mounted[0] =
2075 strdup(data.last_mounted); 2084 strdup(data.last_mounted);
2076 } 2085 }
2077 /* 2086 /*
2078 * Special case: if we are creating the 2087 * Special case: if we are creating the
2079 * first extended mbr, but do not start 2088 * first extended mbr, but do not start
2080 * at the beginning of the primary 2089 * at the beginning of the primary
2081 * extended partition, we need to insert 2090 * extended partition, we need to insert
2082 * another extended mbr at the start. 2091 * another extended mbr at the start.
2083 */ 2092 */
2084 if (m == &parts->mbr && m->extended == NULL 2093 if (m == &parts->mbr && m->extended == NULL
2085 && new_mbr->sector > ext_start) { 2094 && new_mbr->sector > ext_start) {
2086 t = calloc(1, sizeof *new_mbr); 2095 t = calloc(1, sizeof *new_mbr);
2087 if (!t) { 2096 if (!t) {
2088 free_mbr_info(new_mbr); 2097 free_mbr_info(new_mbr);
2089 if (errmsg) 2098 if (errmsg)
2090 *errmsg = err_outofmem; 2099 *errmsg = err_outofmem;
2091 return NO_PART; 2100 return NO_PART;
2092 } 2101 }
2093 t->sector = ext_start; 2102 t->sector = ext_start;
2094 t->mbr.mbr_magic = htole16(MBR_MAGIC); 2103 t->mbr.mbr_magic = htole16(MBR_MAGIC);
2095 t->mbr.mbr_parts[1].mbrp_type = 2104 t->mbr.mbr_parts[1].mbrp_type =
2096 MBR_PTYPE_EXT; 2105 MBR_PTYPE_EXT;
2097 m->extended = t; 2106 m->extended = t;
2098 m = t; 2107 m = t;
2099 } 2108 }
2100 new_mbr->extended = m->extended; 2109 new_mbr->extended = m->extended;
2101 m->extended = new_mbr; 2110 m->extended = new_mbr;
2102 } 2111 }
2103 } 2112 }
2104 mbr_fixup_ext_chain(&parts->mbr, ext_start, ext_start+ext_size); 2113 mbr_fixup_ext_chain(&parts->mbr, ext_start, ext_start+ext_size);
2105 dump_mbr(&parts->mbr, "after adding in extended"); 2114 dump_mbr(&parts->mbr, "after adding in extended");
2106 goto find_rval; 2115 goto find_rval;
2107 } 2116 }
2108 2117
2109 /* this one is for the primary boot block */ 2118 /* this one is for the primary boot block */
2110 if (free_primary > MBR_PART_COUNT) { 2119 if (free_primary > MBR_PART_COUNT) {
2111 if (errmsg != NULL) 2120 if (errmsg != NULL)
2112 *errmsg = ext_size > 0 ? 2121 *errmsg = ext_size > 0 ?
2113 MSG_mbr_no_free_primary_have_ext 2122 MSG_mbr_no_free_primary_have_ext
2114 : MSG_mbr_no_free_primary_no_ext; 2123 : MSG_mbr_no_free_primary_no_ext;
2115 return NO_PART; 2124 return NO_PART;
2116 } 2125 }
2117 2126
2118 start = max(info->start, parts->ptn_0_offset); 2127 start = max(info->start, parts->ptn_0_offset);
2119 size = info->size; 2128 size = info->size;
2120 if (find_mbr_space(m, &start, &size, start, parts->dp.disk_size, 2129 if (find_mbr_space(m, &start, &size, start, parts->dp.disk_size,
2121 start, true) < 0 || size < info->size) { 2130 start, true) < 0 || size < info->size) {
2122 if (errmsg != NULL) 2131 if (errmsg != NULL)
2123 *errmsg = MSG_No_free_space; 2132 *errmsg = MSG_No_free_space;
2124 return NO_PART; 2133 return NO_PART;
2125 } 2134 }
2126 data.start = start; 2135 data.start = start;
2127 if (MBR_IS_EXTENDED(mbr_type_from_gen_desc(info->nat_type))) { 2136 if (MBR_IS_EXTENDED(mbr_type_from_gen_desc(info->nat_type))) {
2128 data.start = max(roundup(data.start, parts->ext_ptn_alignment), 2137 data.start = max(roundup(data.start, parts->ext_ptn_alignment),
2129 parts->ext_ptn_alignment); 2138 parts->ext_ptn_alignment);
2130 } 2139 }
2131 if (data.start + data.size > start + size) 2140 if (data.start + data.size > start + size)
2132 data.size = start + size - data.start; 2141 data.size = start + size - data.start;
2133 mbr_info_to_partitition(&data, &m->mbr.mbr_parts[free_primary], 2142 mbr_info_to_partitition(&data, &m->mbr.mbr_parts[free_primary],
2134 m->sector, errmsg); 2143 m->sector, errmsg);
2135 if (data.last_mounted && m->last_mounted[free_primary] && 2144 if (data.last_mounted && m->last_mounted[free_primary] &&
2136 data.last_mounted != m->last_mounted[free_primary]) { 2145 data.last_mounted != m->last_mounted[free_primary]) {
2137 free(__UNCONST(m->last_mounted[free_primary])); 2146 free(__UNCONST(m->last_mounted[free_primary]));
2138 m->last_mounted[free_primary] = strdup(data.last_mounted); 2147 m->last_mounted[free_primary] = strdup(data.last_mounted);
2139 } 2148 }
2140 start = m->mbr.mbr_parts[free_primary].mbrp_start; 2149 start = m->mbr.mbr_parts[free_primary].mbrp_start;
2141 mbr_sort_main_mbr(&m->mbr); 2150 mbr_sort_main_mbr(&m->mbr);
2142 2151
2143 /* find the partition again after sorting */ 2152 /* find the partition again after sorting */
2144 newp = NULL; 2153 newp = NULL;
2145 for (i = 0; i < MBR_PART_COUNT; i++) { 2154 for (i = 0; i < MBR_PART_COUNT; i++) {
2146 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 2155 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED)
2147 continue; 2156 continue;
2148 if (m->mbr.mbr_parts[i].mbrp_start != start) 2157 if (m->mbr.mbr_parts[i].mbrp_start != start)
2149 continue; 2158 continue;
2150 newp = &m->mbr.mbr_parts[i]; 2159 newp = &m->mbr.mbr_parts[i];
2151 break; 2160 break;
2152 } 2161 }
2153 2162
2154 dump_mbr(&parts->mbr, "after adding in primary"); 2163 dump_mbr(&parts->mbr, "after adding in primary");
2155 2164
2156find_rval: 2165find_rval:
2157 mbr_calc_free_space(parts); 2166 mbr_calc_free_space(parts);
2158 if (newp == NULL) 2167 if (newp == NULL)
2159 return 0; 2168 return 0;
2160 2169
2161 /* 2170 /*
2162 * Now newp points to the modified partition entry but we do not know 2171 * Now newp points to the modified partition entry but we do not know
2163 * a good part_id for it. 2172 * a good part_id for it.
2164 * Iterate from start and find it. 2173 * Iterate from start and find it.
2165 */ 2174 */
2166 no = 0; 2175 no = 0;
2167 for (i = 0; i < MBR_PART_COUNT; i++) { 2176 for (i = 0; i < MBR_PART_COUNT; i++) {
2168 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 2177 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED)
2169 continue; 2178 continue;
2170 2179
2171 if (newp == &m->mbr.mbr_parts[i]) 2180 if (newp == &m->mbr.mbr_parts[i])
2172 return no; 2181 return no;
2173 no++; 2182 no++;
2174 2183
2175 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) { 2184 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) {
2176 for (me = m->extended; me != NULL; me = me->extended) { 2185 for (me = m->extended; me != NULL; me = me->extended) {
2177 for (j = 0; j < MBR_PART_COUNT; j++) { 2186 for (j = 0; j < MBR_PART_COUNT; j++) {
2178 if (me->mbr.mbr_parts[j].mbrp_type == 2187 if (me->mbr.mbr_parts[j].mbrp_type ==
2179 MBR_PTYPE_UNUSED) 2188 MBR_PTYPE_UNUSED)
2180 continue; 2189 continue;
2181 if (j > 0 && MBR_IS_EXTENDED( 2190 if (j > 0 && MBR_IS_EXTENDED(
2182 me->mbr.mbr_parts[j].mbrp_type)) 2191 me->mbr.mbr_parts[j].mbrp_type))
2183 break; 2192 break;
2184 if (newp == &me->mbr.mbr_parts[j]) 2193 if (newp == &me->mbr.mbr_parts[j])
2185 return no; 2194 return no;
2186 no++; 2195 no++;
2187 } 2196 }
2188 } 2197 }
2189 } 2198 }
2190 } 2199 }
2191 return 0; 2200 return 0;
2192} 2201}
2193 2202
2194static int 2203static int
2195mbr_guess_geom(struct disk_partitions *arg, int *cyl, int *head, int *sec) 2204mbr_guess_geom(struct disk_partitions *arg, int *cyl, int *head, int *sec)
2196{ 2205{
2197 struct mbr_disk_partitions *myparts = (struct mbr_disk_partitions*)arg; 2206 struct mbr_disk_partitions *myparts = (struct mbr_disk_partitions*)arg;
2198 struct mbr_sector *mbrs = &myparts->mbr.mbr; 2207 struct mbr_sector *mbrs = &myparts->mbr.mbr;
2199 struct mbr_partition *parts = &mbrs->mbr_parts[0]; 2208 struct mbr_partition *parts = &mbrs->mbr_parts[0];
2200 int xcylinders, xheads, i, j; 2209 int xcylinders, xheads, i, j;
2201 daddr_t xsectors, xsize; 2210 daddr_t xsectors, xsize;
2202 int c1, h1, s1, c2, h2, s2; 2211 int c1, h1, s1, c2, h2, s2;
2203 daddr_t a1, a2; 2212 daddr_t a1, a2;
2204 uint64_t num, denom; 2213 uint64_t num, denom;
2205 2214
2206 xheads = -1; 2215 xheads = -1;
2207 2216
2208 /* Try to deduce the number of heads from two different mappings. */ 2217 /* Try to deduce the number of heads from two different mappings. */
2209 for (i = 0; i < MBR_PART_COUNT * 2 - 1; i++) { 2218 for (i = 0; i < MBR_PART_COUNT * 2 - 1; i++) {
2210 if (get_mapping(parts, i, &c1, &h1, &s1, &a1) < 0) 2219 if (get_mapping(parts, i, &c1, &h1, &s1, &a1) < 0)
2211 continue; 2220 continue;
2212 a1 -= s1; 2221 a1 -= s1;
2213 for (j = i + 1; j < MBR_PART_COUNT * 2; j++) { 2222 for (j = i + 1; j < MBR_PART_COUNT * 2; j++) {
2214 if (get_mapping(parts, j, &c2, &h2, &s2, &a2) < 0) 2223 if (get_mapping(parts, j, &c2, &h2, &s2, &a2) < 0)
2215 continue; 2224 continue;
2216 a2 -= s2; 2225 a2 -= s2;
2217 num = (uint64_t)h1 * a2 - (quad_t)h2 * a1; 2226 num = (uint64_t)h1 * a2 - (quad_t)h2 * a1;
2218 denom = (uint64_t)c2 * a1 - (quad_t)c1 * a2; 2227 denom = (uint64_t)c2 * a1 - (quad_t)c1 * a2;
2219 if (num != 0 && denom != 0 && num % denom == 0) { 2228 if (num != 0 && denom != 0 && num % denom == 0) {
2220 xheads = (int)(num / denom); 2229 xheads = (int)(num / denom);
2221 xsectors = a1 / (c1 * xheads + h1); 2230 xsectors = a1 / (c1 * xheads + h1);
2222 break; 2231 break;
2223 } 2232 }
2224 } 2233 }
2225 if (xheads != -1) 2234 if (xheads != -1)
2226 break; 2235 break;
2227 } 2236 }
2228 2237
2229 if (xheads == -1) 2238 if (xheads == -1)
2230 return -1; 2239 return -1;
2231 2240
2232 /* 2241 /*
2233 * Estimate the number of cylinders. 2242 * Estimate the number of cylinders.
2234 * XXX relies on get_disks having been called. 2243 * XXX relies on get_disks having been called.
2235 */ 2244 */
2236 xsize = min(pm->dlsize, mbr_parts.size_limit); 2245 xsize = min(pm->dlsize, mbr_parts.size_limit);
2237 xcylinders = xsize / xheads / xsectors; 2246 xcylinders = xsize / xheads / xsectors;
2238 if (xsize != xcylinders * xheads * xsectors) 2247 if (xsize != xcylinders * xheads * xsectors)
2239 xcylinders++; 2248 xcylinders++;
2240 2249
2241 /* 2250 /*
2242 * Now verify consistency with each of the partition table entries. 2251 * Now verify consistency with each of the partition table entries.
2243 * Be willing to shove cylinders up a little bit to make things work, 2252 * Be willing to shove cylinders up a little bit to make things work,
2244 * but translation mismatches are fatal. 2253 * but translation mismatches are fatal.
2245 */ 2254 */
2246 for (i = 0; i < MBR_PART_COUNT * 2; i++) { 2255 for (i = 0; i < MBR_PART_COUNT * 2; i++) {
2247 if (get_mapping(parts, i, &c1, &h1, &s1, &a1) < 0) 2256 if (get_mapping(parts, i, &c1, &h1, &s1, &a1) < 0)
2248 continue; 2257 continue;
2249 if (c1 >= MAXCYL - 1) 2258 if (c1 >= MAXCYL - 1)
2250 /* Ignore anything that is near the CHS limit */ 2259 /* Ignore anything that is near the CHS limit */
2251 continue; 2260 continue;
2252 if (xsectors * (c1 * xheads + h1) + s1 != a1) 2261 if (xsectors * (c1 * xheads + h1) + s1 != a1)
2253 return -1; 2262 return -1;
2254 } 2263 }
2255 2264
2256 /* 2265 /*
2257 * Everything checks out. Reset the geometry to use for further 2266 * Everything checks out. Reset the geometry to use for further
2258 * calculations. 2267 * calculations.
2259 */ 2268 */
2260 *cyl = MIN(xcylinders, MAXCYL); 2269 *cyl = MIN(xcylinders, MAXCYL);
2261 *head = xheads; 2270 *head = xheads;
2262 *sec = xsectors; 2271 *sec = xsectors;
2263 return 0; 2272 return 0;
2264} 2273}
2265 2274
2266static daddr_t 2275static daddr_t
2267mbr_max_part_size(const struct disk_partitions *arg, daddr_t fp_start) 2276mbr_max_part_size(const struct disk_partitions *arg, daddr_t fp_start)
2268{ 2277{
2269 const struct mbr_disk_partitions *parts = 2278 const struct mbr_disk_partitions *parts =
2270 (const struct mbr_disk_partitions*)arg; 2279 (const struct mbr_disk_partitions*)arg;
2271 uint start = fp_start, size = 0; 2280 uint start = fp_start, size = 0;
2272 uint8_t pt; 2281 uint8_t pt;
2273 2282
2274 start = fp_start; 2283 start = fp_start;
2275 pt = mbr_type_from_start(&parts->mbr, start); 2284 pt = mbr_type_from_start(&parts->mbr, start);
2276 if (find_mbr_space(&parts->mbr, &start, &size, start, 2285 if (find_mbr_space(&parts->mbr, &start, &size, start,
2277 parts->dp.disk_size, start, MBR_IS_EXTENDED(pt)) < 0) 2286 parts->dp.disk_size, start, MBR_IS_EXTENDED(pt)) < 0)
2278 return 0; 2287 return 0;
2279 2288
2280 return size; 2289 return size;
2281} 2290}
2282 2291
2283static size_t 2292static size_t
2284mbr_get_free_spaces(const struct disk_partitions *arg, 2293mbr_get_free_spaces(const struct disk_partitions *arg,
2285 struct disk_part_free_space *result, size_t max_num_result, 2294 struct disk_part_free_space *result, size_t max_num_result,
2286 daddr_t min_size, daddr_t align, daddr_t lower_bound, daddr_t ignore) 2295 daddr_t min_size, daddr_t align, daddr_t lower_bound, daddr_t ignore)
2287{ 2296{
2288 const struct mbr_disk_partitions *parts = 2297 const struct mbr_disk_partitions *parts =
2289 (const struct mbr_disk_partitions*)arg; 2298 (const struct mbr_disk_partitions*)arg;
2290 uint start = 0, size = 0, from, next; 2299 uint start = 0, size = 0, from, next;
2291 size_t spaces = 0; 2300 size_t spaces = 0;
2292 2301
2293 if (min_size < 1) 2302 if (min_size < 1)
2294 min_size = 1; 2303 min_size = 1;
2295 from = parts->ptn_0_offset; 2304 from = parts->ptn_0_offset;
2296 if (lower_bound > from) 2305 if (lower_bound > from)
2297 from = lower_bound; 2306 from = lower_bound;
2298 for ( ; from < parts->dp.disk_size && spaces < max_num_result; ) { 2307 for ( ; from < parts->dp.disk_size && spaces < max_num_result; ) {
2299 if (find_mbr_space(&parts->mbr, &start, &size, from, 2308 if (find_mbr_space(&parts->mbr, &start, &size, from,
2300 parts->dp.disk_size, ignore > 0 ? (uint)ignore : UINT_MAX, 2309 parts->dp.disk_size, ignore > 0 ? (uint)ignore : UINT_MAX,
2301 false) < 0) 2310 false) < 0)
2302 break; 2311 break;
2303 next = start + size + 1; 2312 next = start + size + 1;
2304 if (align > 0) { 2313 if (align > 0) {
2305 uint nv = max(roundup(start, align), align); 2314 uint nv = max(roundup(start, align), align);
2306 uint off = nv - start; 2315 uint off = nv - start;
2307 start = nv; 2316 start = nv;
2308 if (size > off) 2317 if (size > off)
2309 size -= off; 2318 size -= off;
2310 else 2319 else
2311 size = 0; 2320 size = 0;
2312 } 2321 }
2313 if (size > min_size) { 2322 if (size > min_size) {
2314 result[spaces].start = start; 2323 result[spaces].start = start;
2315 result[spaces].size = size; 2324 result[spaces].size = size;
2316 spaces++; 2325 spaces++;
2317 } 2326 }
2318 if ((daddr_t)start + (daddr_t)size + 1 >= mbr_parts.size_limit) 2327 if ((daddr_t)start + (daddr_t)size + 1 >= mbr_parts.size_limit)
2319 break; 2328 break;
2320 from = next; 2329 from = next;
2321 } 2330 }
2322 2331
2323 return spaces; 2332 return spaces;
2324} 2333}
2325 2334
2326static bool 2335static bool
2327mbr_can_add_partition(const struct disk_partitions *arg) 2336mbr_can_add_partition(const struct disk_partitions *arg)
2328{ 2337{
2329 const struct mbr_disk_partitions *myparts = 2338 const struct mbr_disk_partitions *myparts =
2330 (const struct mbr_disk_partitions*)arg; 2339 (const struct mbr_disk_partitions*)arg;
2331 struct disk_part_free_space space; 2340 struct disk_part_free_space space;
2332 bool free_primary, have_extended; 2341 bool free_primary, have_extended;
2333 2342
2334 if (arg->free_space < myparts->ptn_alignment) 2343 if (arg->free_space < myparts->ptn_alignment)
2335 return false; 2344 return false;
2336 2345
2337 if (mbr_get_free_spaces(arg, &space, 1, myparts->ptn_alignment, 2346 if (mbr_get_free_spaces(arg, &space, 1, myparts->ptn_alignment,
2338 myparts->ptn_alignment, 0, -1) < 1) 2347 myparts->ptn_alignment, 0, -1) < 1)
2339 return false; 2348 return false;
2340 2349
2341 for (int i = 0; i < MBR_PART_COUNT; i++) { 2350 for (int i = 0; i < MBR_PART_COUNT; i++) {
2342 uint8_t t = myparts->mbr.mbr.mbr_parts[i].mbrp_type; 2351 uint8_t t = myparts->mbr.mbr.mbr_parts[i].mbrp_type;
2343 2352
2344 if (t == MBR_PTYPE_UNUSED && 2353 if (t == MBR_PTYPE_UNUSED &&
2345 myparts->mbr.mbr.mbr_parts[i].mbrp_size == 0) 2354 myparts->mbr.mbr.mbr_parts[i].mbrp_size == 0)
2346 free_primary = true; 2355 free_primary = true;
2347 2356
2348 if (MBR_IS_EXTENDED(t)) 2357 if (MBR_IS_EXTENDED(t))
2349 have_extended = true; 2358 have_extended = true;
2350 } 2359 }
2351 2360
2352 if (have_extended) 2361 if (have_extended)
2353 return true; 2362 return true;
2354 2363
2355 return free_primary; 2364 return free_primary;
2356} 2365}
2357 2366
2358static void 2367static void
2359mbr_free(struct disk_partitions *arg) 2368mbr_free(struct disk_partitions *arg)
2360{ 2369{
2361 struct mbr_disk_partitions *parts = (struct mbr_disk_partitions*)arg; 2370 struct mbr_disk_partitions *parts = (struct mbr_disk_partitions*)arg;
2362 2371
2363 assert(parts != NULL); 2372 assert(parts != NULL);
2364 2373
2365 if (parts->dlabel) 2374 if (parts->dlabel)
2366 parts->dlabel->pscheme->free(parts->dlabel); 2375 parts->dlabel->pscheme->free(parts->dlabel);
2367 2376
2368 free_mbr(&parts->mbr); 2377 free_mbr(&parts->mbr);
2369 free(parts); 2378 free(parts);
2370} 2379}
2371 2380
2372static bool 2381static bool
2373mbr_verify_for_update(struct disk_partitions *arg) 2382mbr_verify_for_update(struct disk_partitions *arg)
2374{ 2383{
2375 struct mbr_disk_partitions *parts = 2384 struct mbr_disk_partitions *parts =
2376 (struct mbr_disk_partitions*)arg; 2385 (struct mbr_disk_partitions*)arg;
2377 2386
2378 return md_mbr_update_check(arg, &parts->mbr); 2387 return md_mbr_update_check(arg, &parts->mbr);
2379} 2388}
2380 2389
2381static int 2390static int
2382mbr_verify(struct disk_partitions *arg, bool quiet) 2391mbr_verify(struct disk_partitions *arg, bool quiet)
2383{ 2392{
2384 struct mbr_disk_partitions *parts = 2393 struct mbr_disk_partitions *parts =
2385 (struct mbr_disk_partitions*)arg; 2394 (struct mbr_disk_partitions*)arg;
2386 mbr_info_t *m = &parts->mbr; 2395 mbr_info_t *m = &parts->mbr;
2387 int i; 2396 int i;
2388 bool active_found = false; 2397 bool active_found = false;
2389 2398
2390 for (i = 0; i < MBR_PART_COUNT; i++) { 2399 for (i = 0; i < MBR_PART_COUNT; i++) {
2391 if (m->mbr.mbr_parts[i].mbrp_flag & MBR_PFLAG_ACTIVE) { 2400 if (m->mbr.mbr_parts[i].mbrp_flag & MBR_PFLAG_ACTIVE) {
2392 active_found = true; 2401 active_found = true;
2393 break; 2402 break;
2394 } 2403 }
2395 } 2404 }
2396 2405
2397 if (!active_found && pm->ptstart > 0) { 2406 if (!active_found && pm->ptstart > 0) {
2398 struct mbr_partition *mp = mbr_ptr_from_start(m, pm->ptstart); 2407 struct mbr_partition *mp = mbr_ptr_from_start(m, pm->ptstart);
2399 2408
2400 if (mp) { 2409 if (mp) {
2401 if (!quiet) 2410 if (!quiet)
2402 msg_display(MSG_noactivepart); 2411 msg_display(MSG_noactivepart);
2403 if (quiet || ask_yesno(MSG_fixactivepart)) { 2412 if (quiet || ask_yesno(MSG_fixactivepart)) {
2404 mp->mbrp_flag |= MBR_PFLAG_ACTIVE; 2413 mp->mbrp_flag |= MBR_PFLAG_ACTIVE;
2405 active_found = true; 2414 active_found = true;
2406 } 2415 }
2407 } 2416 }
2408 } 2417 }
2409 if (!active_found && !quiet) { 2418 if (!active_found && !quiet) {
2410 msg_display(MSG_noactivepart); 2419 msg_display(MSG_noactivepart);
2411 i = ask_reedit(arg); 2420 i = ask_reedit(arg);
2412 if (i <= 1) 2421 if (i <= 1)
2413 return i; 2422 return i;
2414 } 2423 }
2415 2424
2416 for (i = 0; i < MBR_PART_COUNT; i++) { 2425 for (i = 0; i < MBR_PART_COUNT; i++) {
2417 if (m->mbr.mbr_parts[i].mbrp_type != MBR_PTYPE_NETBSD) 2426 if (m->mbr.mbr_parts[i].mbrp_type != MBR_PTYPE_NETBSD)
2418 continue; 2427 continue;
2419 m->mbr.mbr_parts[i].mbrp_flag |= MBR_PFLAG_ACTIVE; 2428 m->mbr.mbr_parts[i].mbrp_flag |= MBR_PFLAG_ACTIVE;
2420 break; 2429 break;
2421 } 2430 }
2422 2431
2423 return md_check_mbr(arg, &parts->mbr, quiet); 2432 return md_check_mbr(arg, &parts->mbr, quiet);
2424} 2433}
2425 2434
2426static bool 2435static bool
2427mbr_guess_root(const struct disk_partitions *arg, 2436mbr_guess_root(const struct disk_partitions *arg,
2428 daddr_t *start, daddr_t *size) 2437 daddr_t *start, daddr_t *size)
2429{ 2438{
2430 const struct mbr_disk_partitions *parts = 2439 const struct mbr_disk_partitions *parts =
2431 (const struct mbr_disk_partitions*)arg; 2440 (const struct mbr_disk_partitions*)arg;
2432 const mbr_info_t *m = &parts->mbr; 2441 const mbr_info_t *m = &parts->mbr;
2433 size_t i, num_found; 2442 size_t i, num_found;
2434 bool prim = true; 2443 bool prim = true;
2435 daddr_t pstart, psize; 2444 daddr_t pstart, psize;
2436 2445
2437 num_found = 0; 2446 num_found = 0;
2438 do { 2447 do {
2439 for (i = 0; i < MBR_PART_COUNT; i++) { 2448 for (i = 0; i < MBR_PART_COUNT; i++) {
2440 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 2449 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED)
2441 continue; 2450 continue;
2442 2451
2443 if (!prim && i > 0 && 2452 if (!prim && i > 0 &&
2444 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 2453 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type))
2445 break; 2454 break;
2446 2455
2447 const struct mbr_partition *mp = &m->mbr.mbr_parts[i]; 2456 const struct mbr_partition *mp = &m->mbr.mbr_parts[i];
2448 if (mp->mbrp_type != MBR_PTYPE_NETBSD) 2457 if (mp->mbrp_type != MBR_PTYPE_NETBSD)
2449 continue; 2458 continue;
2450 2459
2451 if (num_found == 0) { 2460 if (num_found == 0) {
2452 pstart = m->sector + mp->mbrp_start; 2461 pstart = m->sector + mp->mbrp_start;
2453 psize = mp->mbrp_size; 2462 psize = mp->mbrp_size;
2454 } 2463 }
2455 num_found++; 2464 num_found++;
2456 2465
2457 if (m->last_mounted[i] != NULL && 2466 if (m->last_mounted[i] != NULL &&
2458 strcmp(m->last_mounted[i], "/") == 0) { 2467 strcmp(m->last_mounted[i], "/") == 0) {
2459 *start = pstart; 2468 *start = pstart;
2460 *size = psize; 2469 *size = psize;
2461 return true; 2470 return true;
2462 } 2471 }
2463 } 2472 }
2464 prim = false; 2473 prim = false;
2465 } while ((m = m->extended)); 2474 } while ((m = m->extended));
2466 2475
2467 if (num_found == 1) { 2476 if (num_found == 1) {
2468 *start = pstart; 2477 *start = pstart;
2469 *size = psize; 2478 *size = psize;
2470 return true; 2479 return true;
2471 } 2480 }
2472 2481
2473 return false; 2482 return false;
2474} 2483}
2475 2484
2476struct part_attr_fmt_data { 2485struct part_attr_fmt_data {
2477 char *str; 2486 char *str;
2478 size_t avail_space, attr_no; 2487 size_t avail_space, attr_no;
2479 const struct mbr_disk_partitions *parts; 2488 const struct mbr_disk_partitions *parts;
2480 const struct disk_part_info *info; 2489 const struct disk_part_info *info;
2481}; 2490};
2482 2491
2483struct part_attr_set_data { 2492struct part_attr_set_data {
2484 size_t attr_no; 2493 size_t attr_no;
2485 const struct mbr_disk_partitions *parts; 2494 const struct mbr_disk_partitions *parts;
2486 const char *str; 2495 const char *str;
2487 mbr_info_t *mbr; 2496 mbr_info_t *mbr;
2488}; 2497};
2489 2498
2490static bool 2499static bool
2491part_attr_fornat_str(const struct disk_partitions *arg, part_id id, 2500part_attr_fornat_str(const struct disk_partitions *arg, part_id id,
2492 const mbr_info_t *mb, int i, bool primary, 2501 const mbr_info_t *mb, int i, bool primary,
2493 const struct mbr_partition *mp, void *cookie) 2502 const struct mbr_partition *mp, void *cookie)
2494{ 2503{
2495 const struct mbr_disk_partitions *parts = 2504 const struct mbr_disk_partitions *parts =
2496 (const struct mbr_disk_partitions*)arg; 2505 (const struct mbr_disk_partitions*)arg;
2497 struct part_attr_fmt_data *data = cookie; 2506 struct part_attr_fmt_data *data = cookie;
2498 const char *attrtype = parts->dp.pscheme 2507 const char *attrtype = parts->dp.pscheme
2499 ->custom_attributes[data->attr_no].label; 2508 ->custom_attributes[data->attr_no].label;
2500 2509
2501 if (attrtype == MSG_ptn_active) { 2510 if (attrtype == MSG_ptn_active) {
2502 strlcpy(data->str, 2511 strlcpy(data->str,
2503 msg_string(primary && (mp->mbrp_flag & MBR_PFLAG_ACTIVE) ? 2512 msg_string(primary && (mp->mbrp_flag & MBR_PFLAG_ACTIVE) ?
2504 MSG_Yes : MSG_No), data->avail_space); 2513 MSG_Yes : MSG_No), data->avail_space);
2505 return true; 2514 return true;
2506#if BOOTSEL 2515#if BOOTSEL
2507 } else if (attrtype == MSG_boot_dflt) { 2516 } else if (attrtype == MSG_boot_dflt) {
2508 strlcpy(data->str, 2517 strlcpy(data->str,
2509 msg_string( 2518 msg_string(
2510 (parts->mbr.bootsec == mb->sector+mp->mbrp_start) ? 2519 (parts->mbr.bootsec == mb->sector+mp->mbrp_start) ?
2511 MSG_Yes : MSG_No), data->avail_space); 2520 MSG_Yes : MSG_No), data->avail_space);
2512 return true; 2521 return true;
2513 } else if (attrtype == MSG_bootmenu) { 2522 } else if (attrtype == MSG_bootmenu) {
2514 strlcpy(data->str, mb->mbrb.mbrbs_nametab[i], 2523 strlcpy(data->str, mb->mbrb.mbrbs_nametab[i],
2515 data->avail_space); 2524 data->avail_space);
2516#endif 2525#endif
2517 } 2526 }
2518 2527
2519 return false; 2528 return false;
2520} 2529}
2521 2530
2522static bool 2531static bool
2523part_attr_set_str(const struct disk_partitions *arg, part_id id, 2532part_attr_set_str(const struct disk_partitions *arg, part_id id,
2524 const mbr_info_t *mb, int i, bool primary, 2533 const mbr_info_t *mb, int i, bool primary,
2525 const struct mbr_partition *mp, void *cookie) 2534 const struct mbr_partition *mp, void *cookie)
2526{ 2535{
2527 struct part_attr_set_data *data = cookie; 2536 struct part_attr_set_data *data = cookie;
2528 const char *str = data->str; 2537 const char *str = data->str;
2529#ifdef BOOTSEL 2538#ifdef BOOTSEL
2530 const struct mbr_disk_partitions *parts = 2539 const struct mbr_disk_partitions *parts =
2531 (const struct mbr_disk_partitions*)arg; 2540 (const struct mbr_disk_partitions*)arg;
2532 const char *attrtype = parts->dp.pscheme 2541 const char *attrtype = parts->dp.pscheme
2533 ->custom_attributes[data->attr_no].label; 2542 ->custom_attributes[data->attr_no].label;
2534 mbr_info_t *m; 2543 mbr_info_t *m;
2535#endif 2544#endif
2536 2545
2537 while (*str == ' ') 2546 while (*str == ' ')
2538 str++; 2547 str++;
2539 2548
2540#if BOOTSEL 2549#if BOOTSEL
2541 if (attrtype == MSG_bootmenu) { 2550 if (attrtype == MSG_bootmenu) {
2542 for (m = data->mbr; m != mb; m = m->extended) 2551 for (m = data->mbr; m != mb; m = m->extended)
2543 ; 2552 ;
2544 strncpy(m->mbrb.mbrbs_nametab[i], str, 2553 strncpy(m->mbrb.mbrbs_nametab[i], str,
2545 sizeof(m->mbrb.mbrbs_nametab[i])); 2554 sizeof(m->mbrb.mbrbs_nametab[i]));
2546 } 2555 }
2547#endif 2556#endif
2548 2557
2549 return false; 2558 return false;
2550} 2559}
2551 2560
2552static bool 2561static bool
2553part_attr_toggle(const struct disk_partitions *arg, part_id id, 2562part_attr_toggle(const struct disk_partitions *arg, part_id id,
2554 const mbr_info_t *mb, int i, bool primary, 2563 const mbr_info_t *mb, int i, bool primary,
2555 const struct mbr_partition *mp, void *cookie) 2564 const struct mbr_partition *mp, void *cookie)
2556{ 2565{
2557 const struct mbr_disk_partitions *parts = 2566 const struct mbr_disk_partitions *parts =
2558 (const struct mbr_disk_partitions*)arg; 2567 (const struct mbr_disk_partitions*)arg;
2559 struct part_attr_set_data *data = cookie; 2568 struct part_attr_set_data *data = cookie;
2560 const char *attrtype = parts->dp.pscheme 2569 const char *attrtype = parts->dp.pscheme
2561 ->custom_attributes[data->attr_no].label; 2570 ->custom_attributes[data->attr_no].label;
2562 int j; 2571 int j;
2563 2572
2564 if (attrtype == MSG_ptn_active) { 2573 if (attrtype == MSG_ptn_active) {
2565 if (!primary) 2574 if (!primary)
2566 return false; 2575 return false;
2567 2576
2568 data->mbr->mbr.mbr_parts[i].mbrp_flag ^= MBR_PFLAG_ACTIVE; 2577 data->mbr->mbr.mbr_parts[i].mbrp_flag ^= MBR_PFLAG_ACTIVE;
2569 for (j = 0; j < MBR_PART_COUNT; j++) { 2578 for (j = 0; j < MBR_PART_COUNT; j++) {
2570 if (j == i) 2579 if (j == i)
2571 continue; 2580 continue;
2572 data->mbr->mbr.mbr_parts[j].mbrp_flag 2581 data->mbr->mbr.mbr_parts[j].mbrp_flag
2573 &= ~MBR_PFLAG_ACTIVE; 2582 &= ~MBR_PFLAG_ACTIVE;
2574 } 2583 }
2575 return true; 2584 return true;
2576#ifdef BOOTSEL 2585#ifdef BOOTSEL
2577 } else if (attrtype == MSG_boot_dflt) { 2586 } else if (attrtype == MSG_boot_dflt) {
2578 if (data->mbr->bootsec == mb->sector+mp->mbrp_start) 2587 if (data->mbr->bootsec == mb->sector+mp->mbrp_start)
2579 data->mbr->bootsec = 0; 2588 data->mbr->bootsec = 0;
2580 else 2589 else
2581 data->mbr->bootsec = mb->sector+mp->mbrp_start; 2590 data->mbr->bootsec = mb->sector+mp->mbrp_start;
2582 return true; 2591 return true;
2583#endif 2592#endif
2584 } 2593 }
2585 2594
2586 return false; 2595 return false;
2587} 2596}
2588 2597
2589static bool 2598static bool
2590mbr_custom_attribute_format(const struct disk_partitions *arg, 2599mbr_custom_attribute_format(const struct disk_partitions *arg,
2591 part_id id, size_t attr_no, const struct disk_part_info *info, 2600 part_id id, size_t attr_no, const struct disk_part_info *info,
2592 char *res, size_t space) 2601 char *res, size_t space)
2593{ 2602{
2594 const struct mbr_disk_partitions *parts = 2603 const struct mbr_disk_partitions *parts =
2595 (const struct mbr_disk_partitions*)arg; 2604 (const struct mbr_disk_partitions*)arg;
2596 struct part_attr_fmt_data data; 2605 struct part_attr_fmt_data data;
2597 2606
2598 data.str = res; 2607 data.str = res;
2599 data.avail_space = space; 2608 data.avail_space = space;
2600 data.attr_no = attr_no; 2609 data.attr_no = attr_no;
2601 data.parts = parts; 2610 data.parts = parts;
2602 data.info = info; 2611 data.info = info;
2603 2612
2604 return mbr_part_apply(arg, id, part_attr_fornat_str, &data); 2613 return mbr_part_apply(arg, id, part_attr_fornat_str, &data);
2605} 2614}
2606 2615
2607static bool 2616static bool
2608mbr_custom_attribute_toggle(struct disk_partitions *arg, 2617mbr_custom_attribute_toggle(struct disk_partitions *arg,
2609 part_id id, size_t attr_no) 2618 part_id id, size_t attr_no)
2610{ 2619{
2611 struct mbr_disk_partitions *parts = 2620 struct mbr_disk_partitions *parts =
2612 (struct mbr_disk_partitions*)arg; 2621 (struct mbr_disk_partitions*)arg;
2613 struct part_attr_set_data data; 2622 struct part_attr_set_data data;
2614 2623
2615 data.attr_no = attr_no; 2624 data.attr_no = attr_no;
2616 data.parts = parts; 2625 data.parts = parts;
2617 data.str = NULL; 2626 data.str = NULL;
2618#ifdef BOOTSEL 2627#ifdef BOOTSEL
2619 data.mbr = &parts->mbr; 2628 data.mbr = &parts->mbr;
2620#endif 2629#endif
2621 2630
2622 return mbr_part_apply(arg, id, part_attr_toggle, &data); 2631 return mbr_part_apply(arg, id, part_attr_toggle, &data);
2623} 2632}
2624 2633
2625static bool 2634static bool
2626mbr_custom_attribute_set_str(struct disk_partitions *arg, 2635mbr_custom_attribute_set_str(struct disk_partitions *arg,
2627 part_id id, size_t attr_no, const char *new_val) 2636 part_id id, size_t attr_no, const char *new_val)
2628{ 2637{
2629 struct mbr_disk_partitions *parts = 2638 struct mbr_disk_partitions *parts =
2630 (struct mbr_disk_partitions*)arg; 2639 (struct mbr_disk_partitions*)arg;
2631 struct part_attr_set_data data; 2640 struct part_attr_set_data data;
2632 2641
2633 data.attr_no = attr_no; 2642 data.attr_no = attr_no;
2634 data.parts = parts; 2643 data.parts = parts;
2635 data.str = new_val; 2644 data.str = new_val;
2636#ifdef BOOTSEL 2645#ifdef BOOTSEL
2637 data.mbr = &parts->mbr; 2646 data.mbr = &parts->mbr;
2638#endif 2647#endif
2639 2648
2640 return mbr_part_apply(arg, id, part_attr_set_str, &data); 2649 return mbr_part_apply(arg, id, part_attr_set_str, &data);
2641} 2650}
2642 2651
2643static daddr_t 2652static daddr_t
2644mbr_part_alignment(const struct disk_partitions *arg) 2653mbr_part_alignment(const struct disk_partitions *arg)
2645{ 2654{
2646 const struct mbr_disk_partitions *parts = 2655 const struct mbr_disk_partitions *parts =
2647 (const struct mbr_disk_partitions*)arg; 2656 (const struct mbr_disk_partitions*)arg;
2648 2657
2649 return parts->ptn_alignment; 2658 return parts->ptn_alignment;
2650} 2659}
2651 2660
2652static bool 2661static bool
2653is_custom_attribute_writable(const struct disk_partitions *arg, part_id id, 2662is_custom_attribute_writable(const struct disk_partitions *arg, part_id id,
2654 const mbr_info_t *mb, int i, bool primary, 2663 const mbr_info_t *mb, int i, bool primary,
2655 const struct mbr_partition *mp, void *cookie) 2664 const struct mbr_partition *mp, void *cookie)
2656{ 2665{
2657 const struct mbr_disk_partitions *parts = 2666 const struct mbr_disk_partitions *parts =
2658 (const struct mbr_disk_partitions*)arg; 2667 (const struct mbr_disk_partitions*)arg;
2659 struct part_attr_set_data *data = cookie; 2668 struct part_attr_set_data *data = cookie;
2660 const char *attrtype = parts->dp.pscheme 2669 const char *attrtype = parts->dp.pscheme
2661 ->custom_attributes[data->attr_no].label; 2670 ->custom_attributes[data->attr_no].label;
2662 2671
2663 if (attrtype == MSG_ptn_active) 2672 if (attrtype == MSG_ptn_active)
2664 /* Only 'normal' partitions can be 'Active' */ 2673 /* Only 'normal' partitions can be 'Active' */
2665 return primary && !MBR_IS_EXTENDED(mp->mbrp_type); 2674 return primary && !MBR_IS_EXTENDED(mp->mbrp_type);
2666#ifdef BOOTSEL 2675#ifdef BOOTSEL
2667 else if (attrtype == MSG_boot_dflt) 2676 else if (attrtype == MSG_boot_dflt)
2668 /* Only partitions with bootmenu names can be default */ 2677 /* Only partitions with bootmenu names can be default */
2669 return mb->mbrb.mbrbs_nametab[i][0] != 0; 2678 return mb->mbrb.mbrbs_nametab[i][0] != 0;
2670 else if (attrtype == MSG_bootmenu) 2679 else if (attrtype == MSG_bootmenu)
2671 /* The extended partition isn't bootable */ 2680 /* The extended partition isn't bootable */
2672 return !MBR_IS_EXTENDED(mp->mbrp_type); 2681 return !MBR_IS_EXTENDED(mp->mbrp_type);
2673#endif 2682#endif
2674 2683
2675 return false; 2684 return false;
2676} 2685}
2677 2686
2678static bool 2687static bool
2679mbr_custom_attribute_writable(const struct disk_partitions *arg, 2688mbr_custom_attribute_writable(const struct disk_partitions *arg,
2680 part_id id, size_t attr_no) 2689 part_id id, size_t attr_no)
2681{ 2690{
2682 const struct mbr_disk_partitions *parts = 2691 const struct mbr_disk_partitions *parts =
2683 (const struct mbr_disk_partitions*)arg; 2692 (const struct mbr_disk_partitions*)arg;
2684 struct part_attr_set_data data; 2693 struct part_attr_set_data data;
2685 2694