1 /* $NetBSD: mbr.c,v 1.81 2009/09/19 14:57:27 abs Exp $ */
4 * Copyright 1997 Piermont Information Systems Inc.
7 * Written by Philip A. Nelson for Piermont Information Systems Inc.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed for the NetBSD Project by
20 * Piermont Information Systems Inc.
21 * 4. The name of Piermont Information Systems Inc. may not be used to endorse
22 * or promote products derived from this software without specific prior
25 * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS''
26 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE
29 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
35 * THE POSSIBILITY OF SUCH DAMAGE.
40 * Following applies to the geometry guessing code
44 * Mach Operating System
45 * Copyright (c) 1992 Carnegie Mellon University
46 * All Rights Reserved.
48 * Permission to use, copy, modify and distribute this software and its
49 * documentation is hereby granted, provided that both the copyright
50 * notice and this permission notice appear in all copies of the
51 * software, derivative works or modified versions, and any portions
52 * thereof, and that both notices appear in supporting documentation.
54 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
55 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
56 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
58 * Carnegie Mellon requests users of this software to return to
60 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
61 * School of Computer Science
62 * Carnegie Mellon University
63 * Pittsburgh PA 15213-3890
65 * any improvements or extensions that they make and grant Carnegie Mellon
66 * the rights to redistribute these changes.
69 /* mbr.c -- DOS Master Boot Record editing code */
71 #include <sys/param.h>
72 #include <sys/types.h>
81 #include "menu_defs.h"
84 #define NO_BOOTMENU (-0x100)
86 #define MAXCYL 1023 /* Possibly 1024 */
87 #define MAXHEAD 255 /* Possibly 256 */
95 {MBR_PTYPE_NETBSD
, "NetBSD"},
96 {MBR_PTYPE_EXT_LBA
, "Extended partition, LBA"},
97 {MBR_PTYPE_386BSD
, "FreeBSD/386BSD"},
98 {MBR_PTYPE_OPENBSD
, "OpenBSD"},
99 {MBR_PTYPE_LNXEXT2
, "Linux native"},
100 {MBR_PTYPE_LNXSWAP
, "Linux swap"},
101 {MBR_PTYPE_FAT12
, "DOS FAT12"},
102 {MBR_PTYPE_FAT16S
, "DOS FAT16, <32M"},
103 {MBR_PTYPE_FAT16B
, "DOS FAT16, >32M"},
104 {MBR_PTYPE_FAT16L
, "Windows FAT16, LBA"},
105 {MBR_PTYPE_FAT32
, "Windows FAT32"},
106 {MBR_PTYPE_FAT32L
, "Windows FAT32, LBA"},
107 {MBR_PTYPE_NTFSVOL
, "NTFS volume set"},
108 {MBR_PTYPE_NTFS
, "NTFS"},
109 {MBR_PTYPE_PREP
, "PReP Boot"},
110 #ifdef MBR_PTYPE_SOLARIS
111 {MBR_PTYPE_SOLARIS
, "Solaris"},
116 static int get_mapping(struct mbr_partition
*, int, int *, int *, int *,
118 static void convert_mbr_chs(int, int, int, uint8_t *, uint8_t *,
119 uint8_t *, uint32_t);
122 * Notes on the extended partition editor.
124 * The extended partition structure is actually a singly linked list.
125 * Each of the 'mbr' sectors can only contain 2 items, the first describes
126 * a user partition (relative to that mbr sector), the second describes
127 * the following partition (relative to the start of the extended partition).
129 * The 'start' sector for the user partition is always the size of one
130 * track - very often 63. The extended partitions themselves should
131 * always start on a cylinder boundary using the BIOS geometry - often
132 * 16065 sectors per cylinder.
134 * The disk is also always described in increasing sector order.
136 * During editing we keep the mbr sectors accurate (it might have been
137 * easier to use absolute sector numbers though), and keep a copy of the
138 * entire sector - to preserve any information any other OS has tried
139 * to squirrel away in the (apparently) unused space.
141 * For simplicity we add entries for unused space. These should not
142 * get written to the disk.
144 * Typical disk (with some small numbers):
147 * b 100 1000 extended LBA (type 15)
149 * 100 -> a 63 37 user
150 * b 100 200 extended partiton (type 5)
152 * 200 -> a 63 37 user
153 * b 200 300 extended partiton (type 5)
155 * 300 -> a 63 37 user
156 * b 0 0 0 (end of chain)
158 * If there is a gap, the 'b' partition will start beyond the area
159 * described by the 'a' partition.
161 * While writing this comment, I can't remember what happens is there
162 * is space at the start of the extended partition.
165 #ifndef debug_extended
166 #define dump_mbr(mbr, msg)
169 dump_mbr(mbr_info_t
*mbr
, const char *msg
)
173 fprintf(stderr
, "%s: bsec %d\n", msg
, bsec
);
175 fprintf(stderr
, "%9p: %9d %9p %6.6s:",
176 mbr
, mbr
->sector
, mbr
->extended
,
177 mbr
->prev_ext
, mbr
->last_mounted
);
178 for (i
= 0; i
< 4; i
++)
179 fprintf(stderr
, " %*d %9d %9d %9d,\n",
181 mbr
->mbr
.mbr_parts
[i
].mbrp_type
,
182 mbr
->mbr
.mbr_parts
[i
].mbrp_start
,
183 mbr
->mbr
.mbr_parts
[i
].mbrp_size
,
184 mbr
->mbr
.mbr_parts
[i
].mbrp_start
+
185 mbr
->mbr
.mbr_parts
[i
].mbrp_size
);
186 } while ((mbr
= mbr
->extended
));
191 * To be used only on ports which cannot provide any bios geometry
194 set_bios_geom_with_mbr_guess(void)
199 read_mbr(diskdev
, &mbr
);
200 msg_display(MSG_nobiosgeom
, dlcyl
, dlhead
, dlsec
);
201 if (guess_biosgeom_from_mbr(&mbr
, &cyl
, &head
, &sec
) >= 0)
202 msg_display_add(MSG_biosguess
, cyl
, head
, sec
);
203 set_bios_geom(cyl
, head
, sec
);
204 return edit_mbr(&mbr
);
208 * get C/H/S geometry from user via menu interface and
212 set_bios_geom(int cyl
, int head
, int sec
)
216 msg_display_add(MSG_setbiosgeom
);
219 snprintf(res
, 80, "%d", sec
);
220 msg_prompt_add(MSG_sectors
, res
, res
, 80);
222 } while (bsec
<= 0 || bsec
> 63);
225 snprintf(res
, 80, "%d", head
);
226 msg_prompt_add(MSG_heads
, res
, res
, 80);
228 } while (bhead
<= 0 || bhead
> 256);
230 bcyl
= dlsize
/ bsec
/ bhead
;
231 if (dlsize
!= bcyl
* bsec
* bhead
)
240 msg_display_add(MSG_realgeom
, dlcyl
, dlhead
, dlsec
);
241 msg_display_add(MSG_biosgeom
, bcyl
, bhead
, bsec
);
247 * Then, the partition stuff...
251 * If we change the mbr partitioning, the we must remove any references
252 * in the netbsd disklabel to the part we changed.
255 remove_old_partitions(uint start
, int64_t size
)
270 for (p
= oldlabel
; p
< oldlabel
+ nelem(oldlabel
); p
++) {
271 if (p
->pi_offset
>= end
|| p
->pi_offset
+ p
->pi_size
<= start
)
273 memset(p
, 0, sizeof *p
);
278 find_mbr_space(struct mbr_sector
*mbrs
, uint
*start
, uint
*size
, uint from
, int ignore
)
286 for (i
= 0; i
< MBR_PART_COUNT
; i
++) {
289 s
= mbrs
->mbr_parts
[i
].mbrp_start
;
290 e
= s
+ mbrs
->mbr_parts
[i
].mbrp_size
;
291 if (s
<= from
&& e
> from
) {
295 if (s
> from
&& s
- from
< sz
)
307 static struct mbr_partition
*
308 get_mbrp(mbr_info_t
**mbrip
, int opt
)
310 mbr_info_t
*mbri
= *mbrip
;
312 if (opt
>= MBR_PART_COUNT
)
313 for (opt
-= MBR_PART_COUNT
- 1; opt
; opt
--)
314 mbri
= mbri
->extended
;
317 return &mbri
->mbr
.mbr_parts
[opt
];
321 err_msg_win(const char *errmsg
)
326 errmsg
= msg_string(errmsg
);
327 cont
= msg_string(MSG_Hit_enter_to_continue
);
334 msg_prompt_win("%s.\n%s", -1, 18, l
+ 5, 4,
335 NULL
, NULL
, 1, errmsg
, cont
);
340 set_mbr_type(menudesc
*m
, void *arg
)
342 mbr_info_t
*mbri
= arg
;
343 mbr_info_t
*ombri
= arg
;
345 struct mbr_partition
*mbrp
;
353 dump_mbr(ombri
, "set type");
355 mbrp
= get_mbrp(&mbri
, opt
);
356 if (opt
>= MBR_PART_COUNT
)
362 type
= part_ids
[type
- 1].id
;
364 snprintf(numbuf
, sizeof numbuf
, "%u", mbrp
->mbrp_type
);
365 msg_prompt_win(MSG_get_ptn_id
, -1, 18, 0, 0,
366 numbuf
, numbuf
, sizeof numbuf
);
367 type
= strtoul(numbuf
, &cp
, 0);
372 if (type
== mbrp
->mbrp_type
)
373 /* type not changed... */
376 mbri
->last_mounted
[opt
< MBR_PART_COUNT
? opt
: 0] = NULL
;
378 if (MBR_IS_EXTENDED(mbrp
->mbrp_type
)) {
379 /* deleting extended partition.... */
380 if (mbri
->sector
|| mbri
->extended
->extended
)
381 /* We should have stopped this happening... */
382 return err_msg_win("can't delete extended");
383 free(mbri
->extended
);
384 mbri
->extended
= NULL
;
388 /* Deleting partition */
390 /* Remove references to this space from the NetBSD label */
391 remove_old_partitions(mbri
->sector
+ mbrp
->mbrp_start
,
394 if (ombri
->bootsec
== mbri
->sector
+ mbrp
->mbrp_start
)
397 memset(mbri
->mbrb
.mbrbs_nametab
[opt
], 0,
398 sizeof mbri
->mbrb
.mbrbs_nametab
[opt
]);
400 if (mbri
->sector
== 0) {
401 /* A main partition */
402 memset(mbrp
, 0, sizeof *mbrp
);
406 /* Merge with previous and next free areas */
407 ext
= mbri
->prev_ext
;
408 if (ext
!= NULL
&& ext
->mbr
.mbr_parts
[0].mbrp_type
== 0) {
409 /* previous was free - back up one entry */
413 while ((ext
= mbri
->extended
)) {
414 if (ext
->mbr
.mbr_parts
[0].mbrp_type
!= 0)
416 sz
= ext
->mbr
.mbr_parts
[0].mbrp_start
+
417 ext
->mbr
.mbr_parts
[0].mbrp_size
;
418 /* Increase size of our (empty) partition */
419 mbri
->mbr
.mbr_parts
[0].mbrp_size
+= sz
;
420 /* Make us describe the next partition */
421 mbri
->mbr
.mbr_parts
[1] = ext
->mbr
.mbr_parts
[1];
422 /* fix list of extended partitions */
423 mbri
->extended
= ext
->extended
;
424 if (ext
->extended
!= NULL
)
425 ext
->extended
->prev_ext
= mbri
;
427 /* Make previous size cover all our ptn */
428 ext
= mbri
->prev_ext
;
430 ext
->mbr
.mbr_parts
[1].mbrp_size
+= sz
;
435 if (mbrp
->mbrp_start
== 0) {
436 /* Find first chunk of space... */
437 /* Must be in the main partition */
438 if (mbri
->sector
!= 0)
439 /* shouldn't be possible to have null start... */
440 return err_msg_win("main-extended mixup");
441 if (find_mbr_space(&mbri
->mbr
, &start
, &sz
, bsec
, -1) != 0)
443 return err_msg_win(MSG_No_free_space
);
444 mbrp
->mbrp_start
= start
;
445 mbrp
->mbrp_size
= sz
;
446 /* If there isn't an active partition mark this one active */
447 if (!MBR_IS_EXTENDED(type
)) {
448 for (i
= 0; i
< MBR_PART_COUNT
; i
++)
449 if (mbri
->mbr
.mbr_parts
[i
].mbrp_flag
!= 0)
451 if (i
== MBR_PART_COUNT
)
452 mbrp
->mbrp_flag
= MBR_PFLAG_ACTIVE
;
456 if (MBR_IS_EXTENDED(type
)) {
457 if (mbri
->sector
!= 0)
458 /* Can't set extended partition in an extended one */
459 return err_msg_win(MSG_Only_one_extended_ptn
);
461 /* Can't have two extended partitions */
462 return err_msg_win(MSG_Only_one_extended_ptn
);
463 /* Create new extended partition */
464 ext
= calloc(1, sizeof *mbri
->extended
);
467 mbri
->extended
= ext
;
468 ext
->sector
= mbrp
->mbrp_start
;
469 ext
->mbr
.mbr_parts
[0].mbrp_start
= bsec
;
470 ext
->mbr
.mbr_parts
[0].mbrp_size
= mbrp
->mbrp_size
- bsec
;
472 mbrp
->mbrp_type
= type
;
478 set_type_label(menudesc
*m
, int opt
, void *arg
)
482 wprintw(m
->mw
, msg_string(MSG_Dont_change
));
486 wprintw(m
->mw
, msg_string(MSG_Delete_partition
));
489 if (part_ids
[opt
- 1].id
== -1) {
490 wprintw(m
->mw
, msg_string(MSG_Other_kind
));
493 wprintw(m
->mw
, part_ids
[opt
- 1].name
);
497 edit_mbr_type(menudesc
*m
, void *arg
)
499 static menu_ent type_opts
[1 + nelem(part_ids
)];
500 static int type_menu
= -1;
503 if (type_menu
== -1) {
504 for (i
= 0; i
< nelem(type_opts
); i
++) {
505 type_opts
[i
].opt_menu
= OPT_NOMENU
;
506 type_opts
[i
].opt_action
= set_mbr_type
;
508 type_menu
= new_menu(NULL
, type_opts
, nelem(type_opts
),
510 MC_SUBMENU
| MC_SCROLL
| MC_NOEXITOPT
| MC_NOCLEAR
,
511 NULL
, set_type_label
, NULL
,
516 process_menu(type_menu
, arg
);
522 edit_mbr_start(menudesc
*m
, void *arg
)
524 mbr_info_t
*mbri
= arg
;
526 struct mbr_partition
*mbrp
;
529 uint new_r
, new, limit
, dflt_r
;
537 } freespace
[MBR_PART_COUNT
];
540 char prompt
[MBR_PART_COUNT
* 60];
544 if (opt
>= MBR_PART_COUNT
)
545 /* should not be able to get here... */
548 mbrp
= mbri
->mbr
.mbr_parts
+ opt
;
549 /* locate the start of all free areas */
551 for (start
= bsec
, i
= 0; i
< MBR_PART_COUNT
; start
+= sz
, i
++) {
552 if (find_mbr_space(&mbri
->mbr
, &start
, &sz
, start
, opt
))
554 if (MBR_IS_EXTENDED(mbrp
->mbrp_type
)) {
555 /* Only want the area that contains this partition */
556 if (mbrp
->mbrp_start
< start
||
557 mbrp
->mbrp_start
>= start
+ sz
)
559 i
= MBR_PART_COUNT
- 1;
561 freespace
[spaces
].start
= start
;
562 freespace
[spaces
].start_r
= start
/ sizemult
;
563 freespace
[spaces
].limit
= start
+ sz
;
564 if (++spaces
>= sizeof freespace
)
565 /* shouldn't happen... */
569 /* Add description of start/size to user prompt */
571 for (i
= 0; i
< spaces
; i
++) {
572 len
+= snprintf(prompt
+ len
, sizeof prompt
- len
,
573 msg_string(MSG_ptn_starts
),
574 freespace
[i
].start_r
,
575 freespace
[i
].limit
/ sizemult
, multname
,
576 freespace
[i
].limit
/ sizemult
- freespace
[i
].start_r
,
578 if (len
>= sizeof prompt
)
582 /* And loop until the user gives a sensible answer */
583 dflt_r
= mbrp
->mbrp_start
/ sizemult
;
586 snprintf(numbuf
, sizeof numbuf
, "%d", dflt_r
);
587 msg_prompt_win(MSG_get_ptn_start
, -1, 18, 60, spaces
+ 3,
588 numbuf
, numbuf
, sizeof numbuf
,
589 prompt
, msg_string(errmsg
), multname
);
590 new_r
= strtoul(numbuf
, &cp
, 0);
592 errmsg
= MSG_Invalid_numeric
;
599 * Check that the start address from the user is inside one
602 new = new_r
* sizemult
;
603 for (i
= 0; i
< spaces
; i
++) {
604 if (new_r
== freespace
[i
].start_r
) {
605 new = freespace
[i
].start
;
608 if (new >= freespace
[i
].start
&&
609 new < freespace
[i
].limit
)
613 errmsg
= MSG_Space_allocated
;
616 limit
= freespace
[i
].limit
;
618 * We can only increase the start of an extended partition
619 * if the corresponding space inside the partition isn't used.
621 if (new > mbrp
->mbrp_start
&&
622 MBR_IS_EXTENDED(mbrp
->mbrp_type
) &&
623 (mbri
->extended
->mbr
.mbr_parts
[0].mbrp_type
!= 0 ||
624 mbri
->extended
->mbr
.mbr_parts
[0].mbrp_size
<
625 new - mbrp
->mbrp_start
)) {
626 errmsg
= MSG_Space_allocated
;
632 if (new < mbrp
->mbrp_start
+ mbrp
->mbrp_size
&&
633 limit
> mbrp
->mbrp_start
)
634 /* Keep end of partition in the same place */
635 limit
= mbrp
->mbrp_start
+ mbrp
->mbrp_size
;
637 delta
= new - mbrp
->mbrp_start
;
638 if (MBR_IS_EXTENDED(mbrp
->mbrp_type
)) {
639 ext
= mbri
->extended
;
640 if (ext
->mbr
.mbr_parts
[0].mbrp_type
!= 0) {
641 /* allocate an extended ptn for the free item */
642 ext
= calloc(1, sizeof *ext
);
645 ext
->sector
= mbrp
->mbrp_start
;
646 ext
->extended
= mbri
->extended
;
647 mbri
->extended
->prev_ext
= ext
;
648 mbri
->extended
= ext
;
649 ext
->mbr
.mbr_parts
[0].mbrp_start
= bsec
;
650 ext
->mbr
.mbr_parts
[0].mbrp_size
= -bsec
;
651 ext
->mbr
.mbr_parts
[1].mbrp_type
= MBR_PTYPE_EXT
;
652 ext
->mbr
.mbr_parts
[1].mbrp_start
= 0;
653 ext
->mbr
.mbr_parts
[1].mbrp_size
=
654 ext
->extended
->mbr
.mbr_parts
[0].mbrp_start
+
655 ext
->extended
->mbr
.mbr_parts
[0].mbrp_size
;
657 /* adjust size of first free item */
658 ext
->mbr
.mbr_parts
[0].mbrp_size
-= delta
;
659 ext
->sector
+= delta
;
660 /* and the link of all extended partitions */
663 ext
->mbr
.mbr_parts
[1].mbrp_start
-= delta
;
664 while ((ext
= ext
->extended
));
666 remove_old_partitions(mbri
->sector
+ mbrp
->mbrp_start
, delta
);
668 /* finally set partition base and size */
669 mbrp
->mbrp_start
= new;
670 mbrp
->mbrp_size
= limit
- new;
671 mbri
->last_mounted
[opt
] = NULL
;
677 edit_mbr_size(menudesc
*m
, void *arg
)
679 mbr_info_t
*mbri
= arg
;
680 mbr_info_t
*ombri
= arg
;
682 struct mbr_partition
*mbrp
;
684 uint start
, max
, max_r
, dflt
, dflt_r
, new;
691 mbrp
= get_mbrp(&mbri
, opt
);
692 dflt
= mbrp
->mbrp_size
;
693 if (opt
< MBR_PART_COUNT
) {
695 find_mbr_space(&mbri
->mbr
, &start
, &max
, mbrp
->mbrp_start
, opt
);
696 if (start
!= mbrp
->mbrp_start
)
701 ext
= mbri
->extended
;
704 * If the next extended partition describes a free area,
705 * then merge it onto this area.
707 if (ext
!= NULL
&& ext
->mbr
.mbr_parts
[0].mbrp_type
== 0) {
709 ext
->extended
->prev_ext
= mbri
;
710 mbri
->extended
= ext
->extended
;
712 mbri
->prev_ext
->mbr
.mbr_parts
[1].mbrp_size
713 += mbri
->mbr
.mbr_parts
[1].mbrp_size
;
714 mbrp
->mbrp_size
+= mbri
->mbr
.mbr_parts
[1].mbrp_size
;
715 max
+= mbri
->mbr
.mbr_parts
[1].mbrp_size
;
716 mbri
->mbr
.mbr_parts
[1] = ext
->mbr
.mbr_parts
[1];
721 start
= mbri
->sector
+ mbrp
->mbrp_start
;
722 /* We need to keep both the unrounded and rounded (_r) max and dflt */
723 dflt_r
= (start
+ dflt
) / sizemult
- start
/ sizemult
;
727 max_r
= max
/ sizemult
;
728 for (errmsg
= "";;) {
729 snprintf(numbuf
, sizeof numbuf
, "%d", dflt_r
);
730 msg_prompt_win(MSG_get_ptn_size
, -1, 18, 0, 0,
731 numbuf
, numbuf
, sizeof numbuf
,
732 msg_string(errmsg
), max_r
, multname
);
733 new = strtoul(numbuf
, &cp
, 0);
735 errmsg
= MSG_Invalid_numeric
;
739 errmsg
= MSG_Too_large
;
743 /* Treat zero as a request for the maximum */
746 /* If unchanged, don't re-round size */
749 /* Round end to cylinder boundary */
752 new += rounddown(start
, current_cylsize
);
753 new = roundup(new, current_cylsize
);
756 new += current_cylsize
;
760 /* We rounded the value to above the max */
763 if (new == dflt
|| opt
>= MBR_PART_COUNT
764 || !MBR_IS_EXTENDED(mbrp
->mbrp_type
))
767 * We've been asked to change the size of the main extended
768 * partition. If this reduces the size, then that space
769 * must be unallocated. If it increases the size then
770 * we must add a description ofthe new free space.
772 /* Find last extended partition */
773 for (ext
= mbri
->extended
; ext
->extended
; ext
= ext
->extended
)
775 if ((new < dflt
&& (ext
->mbr
.mbr_parts
[0].mbrp_type
!= 0
776 || (mbrp
->mbrp_start
+ new < ext
->sector
+ bsec
777 && mbrp
->mbrp_start
+ new != ext
->sector
)))
778 || (new > dflt
&& ext
->mbr
.mbr_parts
[0].mbrp_type
!= 0
779 && new < dflt
+ bsec
)) {
780 errmsg
= MSG_Space_allocated
;
784 if (ext
->mbr
.mbr_parts
[0].mbrp_type
== 0) {
785 /* adjust size of last item (free space) */
786 if (mbrp
->mbrp_start
+ new == ext
->sector
) {
787 /* kill last extended ptn */
790 ext
->extended
= NULL
;
791 memset(&ext
->mbr
.mbr_parts
[1], 0,
792 sizeof ext
->mbr
.mbr_parts
[1]);
795 ext
->mbr
.mbr_parts
[0].mbrp_size
+= delta
;
798 ext
->mbr
.mbr_parts
[1].mbrp_size
+= delta
;
801 /* Joy of joys, we must allocate another extended ptn */
803 ext
= calloc(1, sizeof *ext
);
806 mbri
->extended
= ext
;
807 ext
->prev_ext
= mbri
;
808 ext
->mbr
.mbr_parts
[0].mbrp_start
= bsec
;
809 ext
->mbr
.mbr_parts
[0].mbrp_size
= delta
- bsec
;
810 ext
->sector
= mbri
->sector
+ mbri
->mbr
.mbr_parts
[0].mbrp_start
811 + mbri
->mbr
.mbr_parts
[0].mbrp_size
;
812 mbri
->mbr
.mbr_parts
[1].mbrp_start
= ext
->sector
- ombri
->extended
->sector
;
813 mbri
->mbr
.mbr_parts
[1].mbrp_type
= MBR_PTYPE_EXT
;
814 mbri
->mbr
.mbr_parts
[1].mbrp_size
= delta
;
818 if (opt
>= MBR_PART_COUNT
&& max
- new <= (uint32_t)bsec
)
819 /* Round up if not enough space for a header for free area */
822 if (new != mbrp
->mbrp_size
) {
823 /* Kill information about old partition from label */
824 mbri
->last_mounted
[opt
< MBR_PART_COUNT
? opt
: 0] = NULL
;
825 remove_old_partitions(mbri
->sector
+ mbrp
->mbrp_start
+
826 mbrp
->mbrp_size
, (int64_t)new - mbrp
->mbrp_size
);
829 mbrp
->mbrp_size
= new;
830 if (opt
< MBR_PART_COUNT
|| new == max
)
833 /* Add extended partition for the free space */
834 ext
= calloc(1, sizeof *ext
);
836 mbrp
->mbrp_size
= max
;
839 /* Link into our extended chain */
840 ext
->extended
= mbri
->extended
;
841 mbri
->extended
= ext
;
842 ext
->prev_ext
= mbri
;
843 if (ext
->extended
!= NULL
)
844 ext
->extended
->prev_ext
= ext
;
845 ext
->mbr
.mbr_parts
[1] = mbri
->mbr
.mbr_parts
[1];
846 freespace
= max
- new;
847 if (mbri
->prev_ext
!= NULL
)
848 mbri
->prev_ext
->mbr
.mbr_parts
[1].mbrp_size
-= freespace
;
850 ext
->mbr
.mbr_parts
[0].mbrp_start
= bsec
;
851 ext
->mbr
.mbr_parts
[0].mbrp_size
= freespace
- bsec
;
853 ext
->sector
= mbri
->sector
+ mbri
->mbr
.mbr_parts
[0].mbrp_start
854 + mbri
->mbr
.mbr_parts
[0].mbrp_size
;
855 mbri
->mbr
.mbr_parts
[1].mbrp_start
= ext
->sector
- ombri
->extended
->sector
;
856 mbri
->mbr
.mbr_parts
[1].mbrp_type
= MBR_PTYPE_EXT
;
857 mbri
->mbr
.mbr_parts
[1].mbrp_size
= freespace
;
863 edit_mbr_active(menudesc
*m
, void *arg
)
865 mbr_info_t
*mbri
= arg
;
869 if (mbri
->opt
>= MBR_PART_COUNT
)
873 /* Invert active flag */
874 fl
= &mbri
->mbr
.mbr_parts
[mbri
->opt
].mbrp_flag
;
875 if (*fl
== MBR_PFLAG_ACTIVE
) {
880 /* Ensure there is at most one active partition */
881 for (i
= 0; i
< MBR_PART_COUNT
; i
++)
882 mbri
->mbr
.mbr_parts
[i
].mbrp_flag
= 0;
883 *fl
= MBR_PFLAG_ACTIVE
;
889 edit_mbr_install(menudesc
*m
, void *arg
)
891 mbr_info_t
*mbri
= arg
;
892 mbr_info_t
*ombri
= arg
;
893 struct mbr_partition
*mbrp
;
897 mbrp
= get_mbrp(&mbri
, opt
);
898 if (opt
>= MBR_PART_COUNT
)
901 start
= mbri
->sector
+ mbrp
->mbrp_start
;
902 /* We just remember the start address of the partition... */
903 if (start
== ombri
->install
)
906 ombri
->install
= start
;
912 edit_mbr_bootmenu(menudesc
*m
, void *arg
)
914 mbr_info_t
*mbri
= arg
;
915 mbr_info_t
*ombri
= arg
;
916 struct mbr_partition
*mbrp
;
919 mbrp
= get_mbrp(&mbri
, opt
);
920 if (opt
>= MBR_PART_COUNT
)
923 msg_prompt_win(/* XXX translate? */ "bootmenu", -1, 18, 0, 0,
924 mbri
->mbrb
.mbrbs_nametab
[opt
],
925 mbri
->mbrb
.mbrbs_nametab
[opt
],
926 sizeof mbri
->mbrb
.mbrbs_nametab
[opt
]);
927 if (mbri
->mbrb
.mbrbs_nametab
[opt
][0] == ' ')
928 mbri
->mbrb
.mbrbs_nametab
[opt
][0] = 0;
929 if (mbri
->mbrb
.mbrbs_nametab
[opt
][0] == 0
930 && ombri
->bootsec
== mbri
->sector
+ mbrp
->mbrp_start
)
936 edit_mbr_bootdefault(menudesc
*m
, void *arg
)
938 mbr_info_t
*mbri
= arg
;
939 mbr_info_t
*ombri
= arg
;
940 struct mbr_partition
*mbrp
;
942 mbrp
= get_mbrp(&mbri
, mbri
->opt
);
944 ombri
->bootsec
= mbri
->sector
+ mbrp
->mbrp_start
;
949 static void set_ptn_label(menudesc
*m
, int line
, void *arg
);
950 static void set_ptn_header(menudesc
*m
, void *arg
);
953 edit_mbr_entry(menudesc
*m
, void *arg
)
955 mbr_info_t
*mbri
= arg
;
956 static int ptn_menu
= -1;
958 static menu_ent ptn_opts
[] = {
959 #define PTN_OPT_TYPE 0
960 {NULL
, OPT_NOMENU
, 0, edit_mbr_type
},
961 #define PTN_OPT_START 1
962 {NULL
, OPT_NOMENU
, 0, edit_mbr_start
},
963 #define PTN_OPT_SIZE 2
964 {NULL
, OPT_NOMENU
, 0, edit_mbr_size
},
965 #define PTN_OPT_END 3
966 {NULL
, OPT_NOMENU
, OPT_IGNORE
, NULL
}, /* display end */
967 #define PTN_OPT_ACTIVE 4
968 {NULL
, OPT_NOMENU
, 0, edit_mbr_active
},
969 #define PTN_OPT_INSTALL 5
970 {NULL
, OPT_NOMENU
, 0, edit_mbr_install
},
972 #define PTN_OPT_BOOTMENU 6
973 {NULL
, OPT_NOMENU
, 0, edit_mbr_bootmenu
},
974 #define PTN_OPT_BOOTDEFAULT 7
975 {NULL
, OPT_NOMENU
, 0, edit_mbr_bootdefault
},
977 {MSG_askunits
, MENU_sizechoice
, OPT_SUB
, NULL
},
981 ptn_menu
= new_menu(NULL
, ptn_opts
, nelem(ptn_opts
),
983 MC_SUBMENU
| MC_SCROLL
| MC_NOCLEAR
,
984 set_ptn_header
, set_ptn_label
, NULL
,
985 NULL
, MSG_Partition_OK
);
989 mbri
->opt
= m
->cursel
;
990 process_menu(ptn_menu
, mbri
);
995 set_ptn_label(menudesc
*m
, int line
, void *arg
)
997 mbr_info_t
*mbri
= arg
;
998 mbr_info_t
*ombri
= arg
;
999 struct mbr_partition
*mbrp
;
1001 static const char *yes
, *no
;
1004 yes
= msg_string(MSG_Yes
);
1005 no
= msg_string(MSG_No
);
1009 mbrp
= get_mbrp(&mbri
, opt
);
1010 if (opt
>= MBR_PART_COUNT
)
1015 wprintw(m
->mw
, msg_string(MSG_ptn_type
),
1016 get_partname(mbrp
->mbrp_type
));
1019 wprintw(m
->mw
, msg_string(MSG_ptn_start
),
1020 (mbri
->sector
+ mbrp
->mbrp_start
) / sizemult
, multname
);
1023 wprintw(m
->mw
, msg_string(MSG_ptn_size
),
1024 (mbri
->sector
+ mbrp
->mbrp_start
+ mbrp
->mbrp_size
) /
1026 (mbri
->sector
+ mbrp
->mbrp_start
) / sizemult
, multname
);
1029 wprintw(m
->mw
, msg_string(MSG_ptn_end
),
1030 (mbri
->sector
+ mbrp
->mbrp_start
+ mbrp
->mbrp_size
) /
1031 sizemult
, multname
);
1033 case PTN_OPT_ACTIVE
:
1034 wprintw(m
->mw
, msg_string(MSG_ptn_active
),
1035 mbrp
->mbrp_flag
== MBR_PFLAG_ACTIVE
? yes
: no
);
1037 case PTN_OPT_INSTALL
:
1038 wprintw(m
->mw
, msg_string(MSG_ptn_install
),
1039 mbri
->sector
+ mbrp
->mbrp_start
== ombri
->install
&&
1040 mbrp
->mbrp_type
== MBR_PTYPE_NETBSD
? yes
: no
);
1043 case PTN_OPT_BOOTMENU
:
1044 wprintw(m
->mw
, msg_string(MSG_bootmenu
),
1045 mbri
->mbrb
.mbrbs_nametab
[opt
]);
1047 case PTN_OPT_BOOTDEFAULT
:
1048 wprintw(m
->mw
, msg_string(MSG_boot_dflt
),
1049 ombri
->bootsec
== mbri
->sector
+ mbrp
->mbrp_start
? yes
1058 set_ptn_header(menudesc
*m
, void *arg
)
1060 mbr_info_t
*mbri
= arg
;
1061 struct mbr_partition
*mbrp
;
1062 int opt
= mbri
->opt
;
1065 mbrp
= get_mbrp(&mbri
, opt
);
1066 if (opt
>= MBR_PART_COUNT
)
1068 typ
= mbrp
->mbrp_type
;
1070 #define DISABLE(opt,cond) \
1072 m->opts[opt].opt_flags |= OPT_IGNORE; \
1074 m->opts[opt].opt_flags &= ~OPT_IGNORE;
1076 /* Can't change type of the extended partition unless it is empty */
1077 DISABLE(PTN_OPT_TYPE
, MBR_IS_EXTENDED(typ
) &&
1078 (mbri
->extended
->mbr
.mbr_parts
[0].mbrp_type
!= 0 ||
1079 mbri
->extended
->extended
!= NULL
));
1081 /* It is unnecessary to be able to change the base of an extended ptn */
1082 DISABLE(PTN_OPT_START
, mbri
->sector
|| typ
== 0);
1084 /* or the size of a free area */
1085 DISABLE(PTN_OPT_SIZE
, typ
== 0);
1087 /* Only 'normal' partitions can be 'Active' */
1088 DISABLE(PTN_OPT_ACTIVE
, mbri
->sector
!= 0 || MBR_IS_EXTENDED(typ
) || typ
== 0);
1090 /* Can only install into NetBSD partition */
1091 DISABLE(PTN_OPT_INSTALL
, typ
!= MBR_PTYPE_NETBSD
);
1094 /* The extended partition isn't bootable */
1095 DISABLE(PTN_OPT_BOOTMENU
, MBR_IS_EXTENDED(typ
) || typ
== 0);
1098 mbri
->mbrb
.mbrbs_nametab
[opt
][0] = 0;
1100 /* Only partitions with bootmenu names can be made the default */
1101 DISABLE(PTN_OPT_BOOTDEFAULT
, mbri
->mbrb
.mbrbs_nametab
[opt
][0] == 0);
1107 set_mbr_label(menudesc
*m
, int opt
, void *arg
)
1109 mbr_info_t
*mbri
= arg
;
1110 mbr_info_t
*ombri
= arg
;
1111 struct mbr_partition
*mbrp
;
1113 const char *name
, *cp
, *mounted
;
1116 mbrp
= get_mbrp(&mbri
, opt
);
1117 if (opt
>= MBR_PART_COUNT
)
1120 if (mbrp
->mbrp_type
== 0 && mbri
->sector
== 0) {
1121 len
= snprintf(0, 0, msg_string(MSG_part_row_used
), 0, 0, 0);
1122 wprintw(m
->mw
, "%*s", len
, "");
1124 rstart
= mbri
->sector
+ mbrp
->mbrp_start
;
1125 rend
= (rstart
+ mbrp
->mbrp_size
) / sizemult
;
1126 rstart
= rstart
/ sizemult
;
1127 wprintw(m
->mw
, msg_string(MSG_part_row_used
),
1128 rstart
, rend
- rstart
,
1129 mbrp
->mbrp_flag
== MBR_PFLAG_ACTIVE
? 'a' : ' ',
1131 ombri
->bootsec
== mbri
->sector
+ mbrp
->mbrp_start
? 'd' :
1134 mbri
->sector
+ mbrp
->mbrp_start
== ombri
->install
&&
1135 mbrp
->mbrp_type
== MBR_PTYPE_NETBSD
? 'I' : ' ');
1137 name
= get_partname(mbrp
->mbrp_type
);
1138 mounted
= mbri
->last_mounted
[opt
];
1140 cp
= strchr(name
, ',');
1143 if (mounted
&& *mounted
!= 0) {
1144 wprintw(m
->mw
, " %*s (%s)", len
, name
, mounted
);
1146 wprintw(m
->mw
, " %.*s", len
, name
);
1148 if (mbri
->mbrb
.mbrbs_nametab
[opt
][0] != 0) {
1150 if (opt
>= MBR_PART_COUNT
)
1157 wprintw(m
->mw
, "%*s %s", 53 - x
, "",
1158 mbri
->mbrb
.mbrbs_nametab
[opt
]);
1164 set_mbr_header(menudesc
*m
, void *arg
)
1166 mbr_info_t
*mbri
= arg
;
1167 static menu_ent
*opts
;
1168 static int num_opts
;
1174 msg_display(MSG_editparttable
);
1176 msg_table_add(MSG_part_header
, dlsize
/sizemult
, multname
, multname
,
1177 multname
, multname
);
1179 if (num_opts
== 0) {
1181 opts
= malloc(6 * sizeof *opts
);
1188 /* First four items are the main partitions */
1189 for (op
= opts
, i
= 0; i
< MBR_PART_COUNT
; op
++, i
++) {
1190 op
->opt_name
= NULL
;
1191 op
->opt_menu
= OPT_NOMENU
;
1192 op
->opt_flags
= OPT_SUB
;
1193 op
->opt_action
= edit_mbr_entry
;
1195 left
= num_opts
- MBR_PART_COUNT
;
1197 /* Followed by the extended partitions */
1198 for (ext
= mbri
->extended
; ext
; left
--, op
++, ext
= ext
->extended
) {
1200 menu_ent
*new = realloc(opts
,
1201 (num_opts
+ 4) * sizeof *opts
);
1206 op
= new + (op
- opts
);
1209 op
->opt_name
= NULL
;
1210 op
->opt_menu
= OPT_NOMENU
;
1212 op
->opt_action
= edit_mbr_entry
;
1215 /* and unit changer */
1216 op
->opt_name
= MSG_askunits
;
1217 op
->opt_menu
= MENU_sizechoice
;
1218 op
->opt_flags
= OPT_SUB
;
1219 op
->opt_action
= NULL
;
1223 m
->numopts
= op
- opts
;
1227 mbr_use_wholedisk(mbr_info_t
*mbri
)
1229 struct mbr_sector
*mbrs
= &mbri
->mbr
;
1231 struct mbr_partition
*part
;
1233 part
= &mbrs
->mbr_parts
[0];
1234 /* Set the partition information for full disk usage. */
1235 while ((ext
= mbri
->extended
)) {
1236 mbri
->extended
= ext
->extended
;
1239 memset(part
, 0, MBR_PART_COUNT
* sizeof *part
);
1241 memset(&mbri
->mbrb
, 0, sizeof mbri
->mbrb
);
1243 part
[0].mbrp_type
= MBR_PTYPE_NETBSD
;
1244 part
[0].mbrp_size
= dlsize
- bsec
;
1245 part
[0].mbrp_start
= bsec
;
1246 part
[0].mbrp_flag
= MBR_PFLAG_ACTIVE
;
1249 ptsize
= dlsize
- bsec
;
1254 * Let user change incore Master Boot Record partitions via menu.
1257 edit_mbr(mbr_info_t
*mbri
)
1259 struct mbr_sector
*mbrs
= &mbri
->mbr
;
1261 struct mbr_partition
*part
;
1267 uint bsdstart
, bsdsize
;
1272 part
= &mbrs
->mbr_parts
[0];
1273 msg_display(MSG_fullpart
, diskdev
);
1274 process_menu(MENU_fullpart
, &usefull
);
1276 /* DOS fdisk label checking and value setting. */
1278 /* Count nonempty, non-BSD partitions. */
1280 for (i
= 0; i
< MBR_PART_COUNT
; i
++) {
1281 j
= part
[i
].mbrp_type
;
1285 if (j
!= MBR_PTYPE_NETBSD
)
1289 /* Ask if we really want to blow away non-NetBSD stuff */
1291 msg_display(MSG_ovrwrite
);
1292 process_menu(MENU_noyes
, NULL
);
1295 (void)fprintf(logfp
, "User answered no to destroy other data, aborting.\n");
1299 return(md_mbr_use_wholedisk(mbri
));
1302 mbr_menu
= new_menu(NULL
, NULL
, 16, 0, -1, 15, 70,
1303 MC_NOBOX
| MC_ALWAYS_SCROLL
| MC_NOCLEAR
,
1304 set_mbr_header
, set_mbr_label
, NULL
,
1305 NULL
, MSG_Partition_table_ok
);
1309 /* Default to MB, and use bios geometry for cylinder size */
1310 set_sizemultname_meg();
1311 current_cylsize
= bhead
* bsec
;
1316 process_menu(mbr_menu
, mbri
);
1321 for (ext
= mbri
; ext
; ext
= ext
->extended
) {
1322 part
= ext
->mbr
.mbr_parts
;
1323 for (i
= 0; i
< MBR_PART_COUNT
; part
++, i
++) {
1324 if (part
->mbrp_flag
!= 0)
1326 if (part
->mbrp_type
!= MBR_PTYPE_NETBSD
)
1328 start
= ext
->sector
+ part
->mbrp_start
;
1329 if (start
== mbri
->install
) {
1330 ptstart
= mbri
->install
;
1331 ptsize
= part
->mbrp_size
;
1337 bsdsize
= part
->mbrp_size
;
1342 /* Install in only netbsd partition if none tagged */
1343 if (ptstart
== 0 && bsdstart
!= ~0u) {
1350 msg_display(MSG_nobsdpart
);
1352 msg_display(MSG_multbsdpart
, 0);
1353 msg_display_add(MSG_reeditpart
, 0);
1354 process_menu(MENU_yesno
, NULL
);
1360 if (activepart
== 0) {
1361 msg_display(MSG_noactivepart
);
1362 process_menu(MENU_yesno
, NULL
);
1366 /* the md_check_mbr function has 3 ret codes to deal with
1367 * the different possible states. 0, 1, >1
1369 j
= md_check_mbr(mbri
);
1378 free_menu(mbr_menu
);
1384 get_partname(int typ
)
1387 static char unknown
[32];
1389 for (j
= 0; part_ids
[j
].id
!= -1; j
++)
1390 if (part_ids
[j
].id
== typ
)
1391 return part_ids
[j
].name
;
1393 snprintf(unknown
, sizeof unknown
, "Unknown (%d)", typ
);
1398 read_mbr(const char *disk
, mbr_info_t
*mbri
)
1400 struct mbr_partition
*mbrp
;
1401 struct mbr_sector
*mbrs
= &mbri
->mbr
;
1402 mbr_info_t
*ext
= NULL
;
1403 char diskpath
[MAXPATHLEN
];
1405 uint32_t ext_base
= 0, next_ext
= 0, ext_size
= 0;
1408 mbr_info_t
*ombri
= mbri
;
1413 * Fake up a likely 'bios sectors per track' for any extended
1414 * partition headers we might have to produce.
1419 memset(mbri
, 0, sizeof *mbri
);
1421 /* Open the disk. */
1422 fd
= opendisk(disk
, O_RDONLY
, diskpath
, sizeof(diskpath
), 0);
1427 if (pread(fd
, mbrs
, sizeof *mbrs
,
1428 (ext_base
+ next_ext
) * (off_t
)MBR_SECSIZE
) - sizeof *mbrs
!= 0)
1431 if (!valid_mbr(mbrs
))
1434 mbrp
= &mbrs
->mbr_parts
[0];
1435 if (ext_base
!= 0) {
1436 /* sanity check extended chain */
1437 if (MBR_IS_EXTENDED(mbrp
[0].mbrp_type
))
1439 if (mbrp
[1].mbrp_type
!= 0 &&
1440 !MBR_IS_EXTENDED(mbrp
[1].mbrp_type
))
1442 if (mbrp
[2].mbrp_type
!= 0 || mbrp
[3].mbrp_type
!= 0)
1444 /* Looks ok, link into extended chain */
1445 mbri
->extended
= ext
;
1446 ext
->prev_ext
= next_ext
!= 0 ? mbri
: NULL
;
1447 ext
->extended
= NULL
;
1452 if (mbrs
->mbr_bootsel_magic
== htole16(MBR_MAGIC
)) {
1453 /* old bootsel, grab bootsel info */
1454 mbri
->mbrb
= *(struct mbr_bootsel
*)
1455 ((uint8_t *)mbrs
+ MBR_BS_OLD_OFFSET
);
1457 bootkey
= mbri
->mbrb
.mbrbs_defkey
- SCAN_1
;
1458 } else if (mbrs
->mbr_bootsel_magic
== htole16(MBR_BS_MAGIC
)) {
1460 mbri
->mbrb
= mbrs
->mbr_bootsel
;
1462 bootkey
= mbri
->mbrb
.mbrbs_defkey
- SCAN_1
;
1464 /* Save original flags for mbr code update tests */
1465 mbri
->oflags
= mbri
->mbrb
.mbrbs_flags
;
1467 mbri
->sector
= next_ext
+ ext_base
;
1470 for (i
= 0; i
< MBR_PART_COUNT
; mbrp
++, i
++) {
1471 if (mbrp
->mbrp_type
== 0) {
1472 /* type is unused, discard scum */
1473 memset(mbrp
, 0, sizeof *mbrp
);
1476 mbrp
->mbrp_start
= le32toh(mbrp
->mbrp_start
);
1477 mbrp
->mbrp_size
= le32toh(mbrp
->mbrp_size
);
1478 if (MBR_IS_EXTENDED(mbrp
->mbrp_type
)) {
1479 next_ext
= mbrp
->mbrp_start
;
1481 ext_size
= mbrp
->mbrp_size
;
1483 mbri
->last_mounted
[i
] = strdup(get_last_mounted(
1484 fd
, mbri
->sector
+ mbrp
->mbrp_start
, NULL
));
1486 if (ombri
->install
== 0 &&
1487 strcmp(mbri
->last_mounted
[i
], "/") == 0)
1488 ombri
->install
= mbri
->sector
+
1493 if (mbri
->mbrb
.mbrbs_nametab
[i
][0] != 0
1495 ombri
->bootsec
= mbri
->sector
+
1500 if (ext_base
!= 0) {
1501 /* Is there a gap before the next partition? */
1502 unsigned int limit
= next_ext
;
1506 mbrp
-= MBR_PART_COUNT
;
1507 base
=mbri
->sector
+ mbrp
->mbrp_start
+ mbrp
->mbrp_size
;
1508 if (mbrp
->mbrp_type
!= 0 && ext_base
+ limit
!= base
) {
1509 /* Mock up an extry for the space */
1510 ext
= calloc(1, sizeof *ext
);
1514 ext
->mbr
.mbr_magic
= htole16(MBR_MAGIC
);
1515 ext
->mbr
.mbr_parts
[1] = mbrp
[1];
1516 ext
->mbr
.mbr_parts
[0].mbrp_start
= bsec
;
1517 ext
->mbr
.mbr_parts
[0].mbrp_size
=
1518 ext_base
+ limit
- base
- bsec
;
1519 mbrp
[1].mbrp_type
= MBR_PTYPE_EXT
;
1520 mbrp
[1].mbrp_start
= base
- ext_base
;
1521 mbrp
[1].mbrp_size
= limit
- mbrp
[1].mbrp_start
;
1522 mbri
->extended
= ext
;
1523 ext
->prev_ext
= mbri
;
1524 ext
->extended
= NULL
;
1530 if (next_ext
== 0 || ext_base
+ next_ext
<= mbri
->sector
)
1532 if (ext_base
== 0) {
1533 ext_base
= next_ext
;
1536 ext
= calloc(sizeof *ext
, 1);
1547 memset(&mbrs
->mbr_parts
, 0, sizeof mbrs
->mbr_parts
);
1548 mbrs
->mbr_magic
= htole16(MBR_MAGIC
);
1550 dump_mbr(ombri
, "read");
1555 write_mbr(const char *disk
, mbr_info_t
*mbri
, int convert
)
1557 char diskpath
[MAXPATHLEN
];
1559 struct mbr_partition
*mbrp
;
1560 u_int32_t pstart
, psize
;
1562 struct mbr_sector
*mbrs
;
1564 struct mbr_sector mbrsec
;
1568 /* Open the disk. */
1569 fd
= opendisk(disk
, O_WRONLY
, diskpath
, sizeof(diskpath
), 0);
1575 * If the main boot code (appears to) contain the netbsd bootcode,
1576 * copy in all the menu strings and set the default keycode
1577 * to be that for the default partition.
1578 * Unfortunately we can't rely on the user having actually updated
1579 * to the new mbr code :-(
1581 if (mbri
->mbr
.mbr_bootsel_magic
== htole16(MBR_BS_MAGIC
)
1582 || mbri
->mbr
.mbr_bootsel_magic
== htole16(MBR_MAGIC
)) {
1583 int8_t key
= SCAN_1
;
1584 uint offset
= MBR_BS_OFFSET
;
1585 if (mbri
->mbr
.mbr_bootsel_magic
== htole16(MBR_MAGIC
))
1586 offset
= MBR_BS_OLD_OFFSET
;
1587 mbri
->mbrb
.mbrbs_defkey
= SCAN_ENTER
;
1588 if (mbri
->mbrb
.mbrbs_timeo
== 0)
1589 mbri
->mbrb
.mbrbs_timeo
= 182; /* 10 seconds */
1590 for (ext
= mbri
; ext
!= NULL
; ext
= ext
->extended
) {
1592 mbrp
= &mbrs
->mbr_parts
[0];
1593 /* Ensure marker is set in each sector */
1594 mbrs
->mbr_bootsel_magic
= mbri
->mbr
.mbr_bootsel_magic
;
1595 /* and copy in bootsel parameters */
1596 *(struct mbr_bootsel
*)((uint8_t *)mbrs
+ offset
) =
1598 for (i
= 0; i
< MBR_PART_COUNT
; i
++) {
1599 if (ext
->mbrb
.mbrbs_nametab
[i
][0] == 0)
1601 if (ext
->sector
+ mbrp
->mbrp_start
==
1603 mbri
->mbrb
.mbrbs_defkey
= key
;
1607 /* copy main data (again) since we've put the 'key' in */
1608 *(struct mbr_bootsel
*)((uint8_t *)&mbri
->mbr
+ offset
) =
1613 for (ext
= mbri
; ext
!= NULL
; ext
= ext
->extended
) {
1614 sector
= ext
->sector
;
1615 mbrsec
= ext
->mbr
; /* copy sector */
1616 mbrp
= &mbrsec
.mbr_parts
[0];
1618 if (sector
!= 0 && ext
->extended
!= NULL
1619 && ext
->extended
->mbr
.mbr_parts
[0].mbrp_type
== 0) {
1620 /* We are followed by an empty slot, collapse out */
1621 ext
= ext
->extended
;
1622 /* Make us describe the next non-empty partition */
1623 mbrp
[1] = ext
->mbr
.mbr_parts
[1];
1626 for (i
= 0; i
< MBR_PART_COUNT
; i
++) {
1627 if (mbrp
[i
].mbrp_start
== 0 && mbrp
[i
].mbrp_size
== 0) {
1628 mbrp
[i
].mbrp_scyl
= 0;
1629 mbrp
[i
].mbrp_shd
= 0;
1630 mbrp
[i
].mbrp_ssect
= 0;
1631 mbrp
[i
].mbrp_ecyl
= 0;
1632 mbrp
[i
].mbrp_ehd
= 0;
1633 mbrp
[i
].mbrp_esect
= 0;
1636 pstart
= mbrp
[i
].mbrp_start
;
1637 psize
= mbrp
[i
].mbrp_size
;
1638 mbrp
[i
].mbrp_start
= htole32(pstart
);
1639 mbrp
[i
].mbrp_size
= htole32(psize
);
1641 convert_mbr_chs(bcyl
, bhead
, bsec
,
1642 &mbrp
[i
].mbrp_scyl
, &mbrp
[i
].mbrp_shd
,
1643 &mbrp
[i
].mbrp_ssect
, pstart
);
1644 convert_mbr_chs(bcyl
, bhead
, bsec
,
1645 &mbrp
[i
].mbrp_ecyl
, &mbrp
[i
].mbrp_ehd
,
1646 &mbrp
[i
].mbrp_esect
, pstart
+ psize
- 1);
1650 mbrsec
.mbr_magic
= htole16(MBR_MAGIC
);
1651 if (pwrite(fd
, &mbrsec
, sizeof mbrsec
,
1652 sector
* (off_t
)MBR_SECSIZE
) < 0) {
1663 valid_mbr(struct mbr_sector
*mbrs
)
1666 return (le16toh(mbrs
->mbr_magic
) == MBR_MAGIC
);
1670 convert_mbr_chs(int cyl
, int head
, int sec
,
1671 uint8_t *cylp
, uint8_t *headp
, uint8_t *secp
,
1674 unsigned int tcyl
, temp
, thead
, tsec
;
1677 tcyl
= relsecs
/ temp
;
1678 relsecs
-= tcyl
* temp
;
1680 thead
= relsecs
/ sec
;
1681 tsec
= relsecs
- thead
* sec
+ 1;
1686 *cylp
= MBR_PUT_LSCYL(tcyl
);
1688 *secp
= MBR_PUT_MSCYLANDSEC(tcyl
, tsec
);
1692 * This function is ONLY to be used as a last resort to provide a
1693 * hint for the user. Ports should provide a more reliable way
1694 * of getting the BIOS geometry. The i386 code, for example,
1695 * uses the BIOS geometry as passed on from the bootblocks,
1696 * and only uses this as a hint to the user when that information
1697 * is not present, or a match could not be made with a NetBSD
1702 guess_biosgeom_from_mbr(mbr_info_t
*mbri
, int *cyl
, int *head
, daddr_t
*sec
)
1704 struct mbr_sector
*mbrs
= &mbri
->mbr
;
1705 struct mbr_partition
*parts
= &mbrs
->mbr_parts
[0];
1706 int xcylinders
, xheads
, i
, j
;
1708 int c1
, h1
, s1
, c2
, h2
, s2
;
1710 uint64_t num
, denom
;
1713 * The physical parameters may be invalid as bios geometry.
1714 * If we cannot determine the actual bios geometry, we are
1715 * better off picking a likely 'faked' geometry than leaving
1716 * the invalid physical one.
1722 if (xcylinders
> MAXCYL
|| xheads
> MAXHEAD
|| xsectors
> MAXSECTOR
) {
1723 xsectors
= MAXSECTOR
;
1725 xcylinders
= dlsize
/ (MAXSECTOR
* MAXHEAD
);
1726 if (xcylinders
> MAXCYL
)
1727 xcylinders
= MAXCYL
;
1735 /* Try to deduce the number of heads from two different mappings. */
1736 for (i
= 0; i
< MBR_PART_COUNT
* 2 - 1; i
++) {
1737 if (get_mapping(parts
, i
, &c1
, &h1
, &s1
, &a1
) < 0)
1740 for (j
= i
+ 1; j
< MBR_PART_COUNT
* 2; j
++) {
1741 if (get_mapping(parts
, j
, &c2
, &h2
, &s2
, &a2
) < 0)
1744 num
= (uint64_t)h1
* a2
- (quad_t
)h2
* a1
;
1745 denom
= (uint64_t)c2
* a1
- (quad_t
)c1
* a2
;
1746 if (num
!= 0 && denom
!= 0 && num
% denom
== 0) {
1747 xheads
= (int)(num
/ denom
);
1748 xsectors
= a1
/ (c1
* xheads
+ h1
);
1760 * Estimate the number of cylinders.
1761 * XXX relies on get_disks having been called.
1763 xcylinders
= dlsize
/ xheads
/ xsectors
;
1764 if (dlsize
!= xcylinders
* xheads
* xsectors
)
1768 * Now verify consistency with each of the partition table entries.
1769 * Be willing to shove cylinders up a little bit to make things work,
1770 * but translation mismatches are fatal.
1772 for (i
= 0; i
< MBR_PART_COUNT
* 2; i
++) {
1773 if (get_mapping(parts
, i
, &c1
, &h1
, &s1
, &a1
) < 0)
1775 if (c1
>= MAXCYL
- 1)
1776 /* Ignore anything that is near the CHS limit */
1778 if (xsectors
* (c1
* xheads
+ h1
) + s1
!= a1
)
1783 * Everything checks out. Reset the geometry to use for further
1786 *cyl
= MIN(xcylinders
, MAXCYL
);
1793 get_mapping(struct mbr_partition
*parts
, int i
,
1794 int *cylinder
, int *head
, int *sector
, daddr_t
*absolute
)
1796 struct mbr_partition
*apart
= &parts
[i
/ 2];
1798 if (apart
->mbrp_type
== 0)
1801 *cylinder
= MBR_PCYL(apart
->mbrp_scyl
, apart
->mbrp_ssect
);
1802 *head
= apart
->mbrp_shd
;
1803 *sector
= MBR_PSECT(apart
->mbrp_ssect
) - 1;
1804 *absolute
= le32toh(apart
->mbrp_start
);
1806 *cylinder
= MBR_PCYL(apart
->mbrp_ecyl
, apart
->mbrp_esect
);
1807 *head
= apart
->mbrp_ehd
;
1808 *sector
= MBR_PSECT(apart
->mbrp_esect
) - 1;
1809 *absolute
= le32toh(apart
->mbrp_start
)
1810 + le32toh(apart
->mbrp_size
) - 1;
1812 /* Sanity check the data against max values */
1813 if ((((*cylinder
* MAXHEAD
) + *head
) * (uint32_t)MAXSECTOR
+ *sector
) < *absolute
)
1814 /* cannot be a CHS mapping */