| @@ -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 */ |
93 | const struct { | | 93 | const 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) */ |
119 | struct mbr_part_type_info { | | 119 | struct 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 | |
125 | const struct disk_partitioning_scheme mbr_parts; | | 125 | const struct disk_partitioning_scheme mbr_parts; |
126 | struct mbr_disk_partitions { | | 126 | struct 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 | |
133 | const struct disk_partitioning_scheme mbr_parts; | | 133 | const struct disk_partitioning_scheme mbr_parts; |
134 | | | 134 | |
135 | static size_t known_part_types = 0, last_added_part_type = 0; | | 135 | static size_t known_part_types = 0, last_added_part_type = 0; |
136 | static const size_t first_part_type = MBR_PTYPE_NETBSD; | | 136 | static 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) */ |
139 | struct mbr_part_type_info mbr_gen_type_desc[256]; | | 139 | struct mbr_part_type_info mbr_gen_type_desc[256]; |
140 | | | 140 | |
141 | const struct disk_partitioning_scheme disklabel_parts; | | 141 | const struct disk_partitioning_scheme disklabel_parts; |
142 | | | 142 | |
143 | static void convert_mbr_chs(int, int, int, uint8_t *, uint8_t *, | | 143 | static 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 |
185 | static void | | 185 | static void |
186 | dump_mbr(mbr_info_t *m, const char *label) | | 186 | dump_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 | |
224 | static void | | 224 | static void |
225 | free_mbr_info(mbr_info_t *m) | | 225 | free_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 | */ |
238 | bool | | 238 | bool |
239 | set_bios_geom_with_mbr_guess(struct disk_partitions *parts) | | 239 | set_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 | |
253 | static void | | 253 | static void |
254 | mbr_init_chs(struct mbr_disk_partitions *parts, int ncyl, int nhead, int nsec) | | 254 | mbr_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 | */ |
269 | void | | 269 | void |
270 | set_bios_geom(struct disk_partitions *parts, int cyl, int head, int sec) | | 270 | set_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 | |
303 | static int | | 303 | static int |
304 | find_mbr_space(const struct mbr_info_t *mbrs, uint *start, uint *size, | | 304 | find_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 |
399 | static int | | 399 | static int |
400 | validate_and_set_names(mbr_info_t *mbri, const struct mbr_bootsel *src, | | 400 | validate_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 | |
437 | static void | | 437 | static void |
438 | free_mbr(mbr_info_t *mbri) | | 438 | free_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 | |
450 | static int | | 450 | static int |
451 | valid_mbr(struct mbr_sector *mbrs) | | 451 | valid_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 | |
457 | static int | | 457 | static int |
458 | read_mbr(const char *disk, mbr_info_t *mbri) | | 458 | read_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 | |
586 | static int | | 586 | static int |
587 | write_mbr(const char *disk, mbr_info_t *mbri, int bsec, int bhead, int bcyl) | | 587 | write_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 | |
705 | static void | | 705 | static void |
706 | convert_mbr_chs(int cyl, int head, int sec, | | 706 | convert_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 | */ |
736 | int | | 736 | int |
737 | guess_biosgeom_from_parts(struct disk_partitions *parts, | | 737 | guess_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 | |
769 | static int | | 769 | static int |
770 | mbr_comp_part_entry(const void *a, const void *b) | | 770 | mbr_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 | |
786 | static void | | 786 | static void |
787 | mbr_sort_main_mbr(struct mbr_sector *m) | | 787 | mbr_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 | |
793 | static void | | 793 | static void |
794 | mbr_init_default_alignments(struct mbr_disk_partitions *parts, uint track) | | 794 | mbr_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 | |
817 | static struct disk_partitions * | | 817 | static struct disk_partitions * |
818 | mbr_create_new(const char *disk, daddr_t start, daddr_t len, daddr_t total, | | 818 | mbr_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 | |
846 | static void | | 846 | static void |
847 | mbr_calc_free_space(struct mbr_disk_partitions *parts) | | 847 | mbr_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 | |
881 | static struct disk_partitions * | | 881 | static struct disk_partitions * |
882 | mbr_read_from_disk(const char *disk, daddr_t start, daddr_t len) | | 882 | mbr_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 | |
913 | static bool | | 913 | static bool |
914 | mbr_write_to_disk(struct disk_partitions *new_state) | | 914 | mbr_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 | |
933 | static bool | | 933 | static bool |
934 | mbr_change_disk_geom(struct disk_partitions *arg, int ncyl, int nhead, | | 934 | mbr_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 | |
970 | static size_t | | 970 | static size_t |
971 | mbr_type_from_gen_desc(const struct part_type_desc *desc) | | 971 | mbr_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 | |
980 | static enum part_type | | 980 | static enum part_type |
981 | mbr_map_part_type(unsigned int t) | | 981 | mbr_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 | |
999 | static void | | 999 | static void |
1000 | map_mbr_part_types(void) | | 1000 | map_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 | |
1020 | static size_t | | 1020 | static size_t |
1021 | mbr_get_part_type_count(void) | | 1021 | mbr_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 | |
1029 | static const struct part_type_desc * | | 1029 | static const struct part_type_desc * |
1030 | mbr_get_fs_part_type(unsigned fs_type, unsigned sub_type) | | 1030 | mbr_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 | |
1056 | static const struct part_type_desc * | | 1056 | static const struct part_type_desc * |
1057 | mbr_get_part_type(size_t index) | | 1057 | mbr_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 | |
1076 | static const struct part_type_desc * | | 1076 | static const struct part_type_desc * |
1077 | mbr_new_custom_part_type(unsigned int v) | | 1077 | mbr_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 | |
1095 | static const struct part_type_desc * | | 1095 | static const struct part_type_desc * |
1096 | mbr_custom_part_type(const char *custom, const char **err_msg) | | 1096 | mbr_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 | |
1117 | static const struct part_type_desc * | | 1117 | static const struct part_type_desc * |
1118 | mbr_get_gen_type_desc(unsigned int pt) | | 1118 | mbr_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 | |
1133 | static const struct part_type_desc * | | 1133 | static const struct part_type_desc * |
1134 | mbr_get_generic_part_type(enum part_type pt) | | 1134 | mbr_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 | |
1150 | static void | | 1150 | static void |
1151 | mbr_partition_to_info(const struct mbr_partition *mp, daddr_t start_off, | | 1151 | mbr_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 | |
1164 | static bool | | 1164 | static bool |
1165 | mbr_part_apply(const struct disk_partitions *arg, part_id id, | | 1165 | mbr_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 | |
1212 | static bool | | 1212 | static bool |
1213 | mbr_do_get_part_info(const struct disk_partitions *arg, part_id id, | | 1213 | mbr_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 | |
1227 | static bool | | 1227 | static bool |
1228 | mbr_get_part_info(const struct disk_partitions *arg, part_id id, | | 1228 | mbr_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 | |
1234 | static bool | | 1234 | static bool |
1235 | type_can_change(const struct disk_partitions *arg, part_id id, | | 1235 | type_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 | |
1248 | static bool | | 1248 | static bool |
1249 | mbr_part_type_can_change(const struct disk_partitions *arg, part_id id) | | 1249 | mbr_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 | |
1254 | struct part_get_str_data { | | 1254 | struct 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 | |
1261 | static bool | | 1261 | static bool |
1262 | mbr_get_part_table_str(const struct disk_partitions *arg, part_id id, | | 1262 | mbr_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 | |
1299 | static bool | | 1299 | static bool |
1300 | mbr_table_str(const struct disk_partitions *arg, part_id id, size_t col, | | 1300 | mbr_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 | |
1311 | static bool | | 1311 | static bool |
1312 | mbr_get_part_attr_str(const struct disk_partitions *arg, part_id id, | | 1312 | mbr_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 | |
1337 | static bool | | 1337 | static bool |
1338 | mbr_part_attr_str(const struct disk_partitions *arg, part_id id, | | 1338 | mbr_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 | |
1351 | static bool | | 1351 | static bool |
1352 | mbr_info_to_partitition(const struct disk_part_info *info, | | 1352 | mbr_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 | |
1369 | static bool | | 1369 | static bool |
1370 | inside_ext_part(mbr_info_t *m, daddr_t start) | | 1370 | inside_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 | |
1393 | static void | | 1393 | static void |
1394 | adjust_ext_part(mbr_info_t *m, daddr_t start, daddr_t size) | | 1394 | adjust_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 | |
1418 | static bool | | 1418 | static bool |
1419 | ext_part_good(mbr_info_t *m, daddr_t ext_start, daddr_t ext_size) | | 1419 | ext_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 | |
1442 | static bool | | 1442 | static bool |
1443 | mbr_set_part_info(struct disk_partitions *arg, part_id id, | | 1443 | mbr_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 | |
1510 | found: | | 1510 | found: |
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 | |
1569 | static bool | | 1569 | static bool |
1570 | mbr_find_netbsd(const struct mbr_info_t *m, uint start, | | 1570 | mbr_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 | |
1605 | static struct disk_partitions * | | 1605 | static struct disk_partitions * |
1606 | mbr_read_disklabel(struct disk_partitions *arg, daddr_t start) | | 1606 | mbr_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 | |
1640 | static int | | 1640 | static int |
1641 | get_mapping(struct mbr_partition *parts, int i, | | 1641 | get_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 | |
1668 | static bool | | 1668 | static bool |
1669 | mbr_delete_all(struct disk_partitions *arg) | | 1669 | mbr_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 | */ |
1695 | static void | | 1704 | static void |
1696 | mbr_fixup_ext_chain(mbr_info_t *primary, uint ext_start, uint ext_end) | | 1705 | mbr_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 | |
1716 | struct delete_part_args { | | 1725 | struct 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 | |
1722 | static bool | | 1731 | static bool |
1723 | mbr_do_delete_part(const struct disk_partitions *arg, part_id id, | | 1732 | mbr_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 | |
1819 | static bool | | 1828 | static bool |
1820 | mbr_delete_part(struct disk_partitions *arg, part_id pno, const char **err_msg) | | 1829 | mbr_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 | |
1849 | static struct mbr_partition * | | 1858 | static struct mbr_partition * |
1850 | mbr_ptr_from_start(mbr_info_t *m, daddr_t start) | | 1859 | mbr_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 | |
1874 | static uint8_t | | 1883 | static uint8_t |
1875 | mbr_type_from_start(const mbr_info_t *m, daddr_t start) | | 1884 | mbr_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 | |
1899 | static part_id | | 1908 | static part_id |
1900 | mbr_add_part(struct disk_partitions *arg, | | 1909 | mbr_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 | |
2156 | find_rval: | | 2165 | find_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 | |
2194 | static int | | 2203 | static int |
2195 | mbr_guess_geom(struct disk_partitions *arg, int *cyl, int *head, int *sec) | | 2204 | mbr_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 | |
2266 | static daddr_t | | 2275 | static daddr_t |
2267 | mbr_max_part_size(const struct disk_partitions *arg, daddr_t fp_start) | | 2276 | mbr_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 | |
2283 | static size_t | | 2292 | static size_t |
2284 | mbr_get_free_spaces(const struct disk_partitions *arg, | | 2293 | mbr_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 | |
2326 | static bool | | 2335 | static bool |
2327 | mbr_can_add_partition(const struct disk_partitions *arg) | | 2336 | mbr_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 | |
2358 | static void | | 2367 | static void |
2359 | mbr_free(struct disk_partitions *arg) | | 2368 | mbr_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 | |
2372 | static bool | | 2381 | static bool |
2373 | mbr_verify_for_update(struct disk_partitions *arg) | | 2382 | mbr_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 | |
2381 | static int | | 2390 | static int |
2382 | mbr_verify(struct disk_partitions *arg, bool quiet) | | 2391 | mbr_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 | |
2426 | static bool | | 2435 | static bool |
2427 | mbr_guess_root(const struct disk_partitions *arg, | | 2436 | mbr_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 | |
2476 | struct part_attr_fmt_data { | | 2485 | struct 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 | |
2483 | struct part_attr_set_data { | | 2492 | struct 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 | |
2490 | static bool | | 2499 | static bool |
2491 | part_attr_fornat_str(const struct disk_partitions *arg, part_id id, | | 2500 | part_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 | |
2522 | static bool | | 2531 | static bool |
2523 | part_attr_set_str(const struct disk_partitions *arg, part_id id, | | 2532 | part_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 | |
2552 | static bool | | 2561 | static bool |
2553 | part_attr_toggle(const struct disk_partitions *arg, part_id id, | | 2562 | part_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 | |
2589 | static bool | | 2598 | static bool |
2590 | mbr_custom_attribute_format(const struct disk_partitions *arg, | | 2599 | mbr_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 | |
2607 | static bool | | 2616 | static bool |
2608 | mbr_custom_attribute_toggle(struct disk_partitions *arg, | | 2617 | mbr_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 | |
2625 | static bool | | 2634 | static bool |
2626 | mbr_custom_attribute_set_str(struct disk_partitions *arg, | | 2635 | mbr_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 | |
2643 | static daddr_t | | 2652 | static daddr_t |
2644 | mbr_part_alignment(const struct disk_partitions *arg) | | 2653 | mbr_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 | |
2652 | static bool | | 2661 | static bool |
2653 | is_custom_attribute_writable(const struct disk_partitions *arg, part_id id, | | 2662 | is_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 | |
2678 | static bool | | 2687 | static bool |
2679 | mbr_custom_attribute_writable(const struct disk_partitions *arg, | | 2688 | mbr_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 | |