1 /* $NetBSD: fdisk.c,v 1.129 2009/12/22 21:55:12 dsl Exp $ */
4 * Mach Operating System
5 * Copyright (c) 1992 Carnegie Mellon University
8 * Permission to use, copy, modify and distribute this software and its
9 * documentation is hereby granted, provided that both the copyright
10 * notice and this permission notice appear in all copies of the
11 * software, derivative works or modified versions, and any portions
12 * thereof, and that both notices appear in supporting documentation.
14 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
15 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18 * Carnegie Mellon requests users of this software to return to
20 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
21 * School of Computer Science
22 * Carnegie Mellon University
23 * Pittsburgh PA 15213-3890
25 * any improvements or extensions that they make and grant Carnegie Mellon
26 * the rights to redistribute these changes.
30 * 14-Dec-89 Robert Baron (rvb) at Carnegie-Mellon University
31 * Copyright (c) 1989 Robert. V. Baron
35 #if HAVE_NBTOOL_CONFIG_H
36 #include "nbtool_config.h"
39 #include <sys/cdefs.h>
42 __RCSID("$NetBSD: fdisk.c,v 1.129 2009/12/22 21:55:12 dsl Exp $");
46 #include <sys/types.h>
47 #include <sys/param.h>
62 #if !HAVE_NBTOOL_CONFIG_H
63 #include <sys/disklabel.h>
64 #include <sys/disklabel_gpt.h>
65 #include <sys/bootblock.h>
66 #include <sys/ioctl.h>
67 #include <sys/sysctl.h>
72 #include <nbinclude/sys/disklabel.h>
73 #include <nbinclude/sys/disklabel_gpt.h>
74 #include <nbinclude/sys/bootblock.h>
75 #include "../../include/disktab.h"
76 /* We enforce -F, so none of these possibly undefined items can be needed */
77 #define opendisk(path, fl, buf, buflen, cooked) (-1)
79 #define DIOCGDEFLABEL 0
87 #endif /* HAVE_NBTOOL_CONFIG_H */
89 #define DEFAULT_BOOTDIR "/usr/mdec"
91 #define LE_MBR_MAGIC htole16(MBR_MAGIC)
92 #define LE_MBR_BS_MAGIC htole16(MBR_BS_MAGIC)
94 #if defined(__i386__) || defined(__x86_64__)
95 #if !HAVE_NBTOOL_CONFIG_H
96 #include <machine/cpu.h>
97 #endif /* !HAVE_NBTOOL_CONFIG_H */
103 #define DEFAULT_BOOTCODE "mbr"
104 #define DEFAULT_BOOTSELCODE "mbr_bootsel"
105 #define DEFAULT_BOOTEXTCODE "mbr_ext"
107 /* Scan values for the various keys we use, as returned by the BIOS */
108 #define SCAN_ENTER 0x1c
113 #define MAX_BIOS_DISKS 16 /* Going beyond F12 is hard though! */
115 /* We same the dflt 'boot partition' as a disk block, with some magic values. */
116 #define DEFAULT_ACTIVE (~(daddr_t)0)
117 #define DEFAULT_DISK(n) (DEFAULT_ACTIVE - MAX_BIOS_DISKS + (n))
121 #define GPT_TYPE(offs) ((offs) == GPT_HDR_BLKNO ? "primary" : "secondary")
124 #define PRIdaddr PRId64
127 #ifndef _PATH_DEFDISK
128 #define _PATH_DEFDISK "/dev/rwd0d"
132 struct mbr_sector
*ptn
; /* array of pbrs */
133 daddr_t base
; /* first sector of ext. ptn */
134 daddr_t limit
; /* last sector of ext. ptn */
135 int num_ptn
; /* number of contained partitions */
136 int ptn_id
; /* entry in mbr */
137 int is_corrupt
; /* 1 if extended chain illegal */
141 static char lbuf
[LBUF
];
143 const char *disk
= _PATH_DEFDISK
;
145 struct disklabel disklabel
; /* disk parameters */
147 struct mbr_sector mboot
;
149 const char *boot_dir
= DEFAULT_BOOTDIR
;
150 char *boot_path
= 0; /* name of file we actually opened */
153 #define BOOTSEL_OPTIONS "B"
155 #define BOOTSEL_OPTIONS
156 #define change_part(e, p, id, st, sz, bm) change__part(e, p, id, st, sz)
158 #define OPTIONS BOOTSEL_OPTIONS "0123FSafiluvA:b:c:E:r:s:w:"
161 * Disk geometry and partition alignment.
163 * Modern disks do not have a fixed geomery and will always give a 'faked'
164 * geometry that matches the ATA standard - max 16 heads and 256 sec/track.
165 * The ATA geometry allows access to 2^28 sectors (as does LBA mode).
167 * The BIOS calls originally used an 8bit register for cylinder, head and
168 * sector. Later 2 bits were stolen from the sector number and added to
169 * cylinder number. The BIOS will translate this faked geometry either to
170 * the geometry reported by the disk, or do LBA reads (possibly LBA48).
171 * BIOS CHS reads have all sorts of limits, but 2^24 is absolute.
172 * For historic reasons the BIOS geometry is the called the dos geometry!
174 * If you know the disks real geometry it is usually worth aligning
175 * disk partitions to cylinder boundaries (certainly traditional!).
176 * For 'mbr' disks this has always been done with the BIOS geometry.
177 * The first track (typically 63 sectors) is reserved because the first
178 * sector is used for boot code. Similarly the data partition in an
179 * extended partition will start one track in. If an extended partition
180 * starts at the beginning of the disk you lose 2 tracks.
182 * However non-magnetic media in particular has physical sectors that are
183 * not the same size as those reported, so has to do read modify write
184 * sequences for misaligned transfers. The alignment of partitions to
185 * cylinder boundaries makes this happen all the time.
187 * It is thus sensible to align partitions on a sensible sector boundary.
188 * For instance 1MB (2048 sectors).
189 * Common code can do this by using a geometry with 1 head and 2048
193 /* Disks reported geometry and overall size from device driver */
194 unsigned int cylinders
, sectors
, heads
;
196 #define cylindersectors (heads * sectors)
198 /* Geometry from the BIOS */
199 unsigned int dos_cylinders
;
200 unsigned int dos_heads
;
201 unsigned int dos_sectors
;
202 daddr_t dos_disksectors
;
203 #define dos_cylindersectors (dos_heads * dos_sectors)
204 #define dos_totalsectors (dos_heads * dos_sectors * dos_cylinders)
206 #define DOSSECT(s,c) (((s) & 0x3f) | (((c) >> 2) & 0xc0))
207 #define DOSCYL(c) ((c) & 0xff)
208 #define SEC_IN_1M (1024 * 1024 / 512)
209 #define SEC_TO_MB(sec) ((unsigned int)(((sec) + SEC_IN_1M / 2) / SEC_IN_1M))
210 #define SEC_TO_CYL(sec) (((sec) + dos_cylindersectors/2) / dos_cylindersectors)
212 #define MAXCYL 1024 /* Usual limit is 1023 */
213 #define MAXHEAD 256 /* Usual limit is 255 */
217 /* Alignment of partition, and offset if first sector unusable */
218 unsigned int ptn_alignment
; /* default dos_cylindersectors */
219 unsigned int ptn_0_offset
; /* default dos_sectors */
221 int fd
= -1, wfd
= -1, *rfd
= &fd
;
222 char *disk_file
= NULL
;
223 char *disk_type
= NULL
;
225 int a_flag
; /* set active partition */
226 int i_flag
; /* init bootcode */
227 int u_flag
; /* update partition data */
228 int v_flag
; /* more verbose */
229 int sh_flag
; /* Output data as shell defines */
230 int f_flag
; /* force --not interactive */
231 int s_flag
; /* set id,offset,size */
232 int b_flag
; /* Set cyl, heads, secs (as c/h/s) */
233 int B_flag
; /* Edit/install bootselect code */
234 int E_flag
; /* extended partition number */
235 int b_cyl
, b_head
, b_sec
; /* b_flag values. */
237 #if !HAVE_NBTOOL_CONFIG_H
240 /* Tool - force 'file' mode to avoid unsupported functions and ioctls */
244 struct gpt_hdr gpt1
, gpt2
; /* GUID partition tables */
246 struct mbr_sector bootcode
[8192 / sizeof (struct mbr_sector
)];
247 int bootsize
; /* actual size of bootcode */
248 int boot_installed
; /* 1 if we've copied code into the mbr */
250 #if (defined(__i386__) || defined(__x86_64__)) && !HAVE_NBTOOL_CONFIG_H
256 #define KNOWN_SYSIDS (sizeof(mbr_ptypes)/sizeof(mbr_ptypes[0]))
260 void print_part(struct mbr_sector
*, int, daddr_t
);
261 void print_mbr_partition(struct mbr_sector
*, int, daddr_t
, daddr_t
, int);
262 void print_pbr(daddr_t
, int, uint8_t);
263 int is_all_zero(const unsigned char *, size_t);
264 void printvis(int, const char *, const char *, size_t);
265 int read_boot(const char *, void *, size_t, int);
266 void init_sector0(int);
267 void intuit_translated_geometry(void);
268 void get_bios_geometry(void);
269 void get_extended_ptn(void);
270 static void get_ptn_alignmemt(void);
271 #if defined(USE_DISKLIST)
272 void get_diskname(const char *, char *, size_t);
274 int change_part(int, int, int, daddr_t
, daddr_t
, char *);
275 void print_geometry(void);
276 int first_active(void);
277 void change_active(int);
278 void change_bios_geometry(void);
279 void dos(int, unsigned char *, unsigned char *, unsigned char *);
281 int read_disk(daddr_t
, void *);
282 int write_disk(daddr_t
, void *);
283 int get_params(void);
284 int read_s0(daddr_t
, struct mbr_sector
*);
286 int read_gpt(daddr_t
, struct gpt_hdr
*);
287 int delete_gpt(struct gpt_hdr
*);
288 int yesno(const char *, ...);
289 int64_t decimal(const char *, int64_t, int, int64_t, int64_t);
290 #define DEC_SEC 1 /* asking for a sector number */
291 #define DEC_RND 2 /* round to end of first track */
292 #define DEC_RND_0 4 /* convert 0 to size of a track */
293 #define DEC_RND_DOWN 8 /* subtract 1 track */
294 #define DEC_RND_DOWN_2 16 /* subtract 2 tracks */
295 void string(const char *, int, char *);
296 int ptn_id(const char *, int *);
297 int type_match(const void *, const void *);
298 const char *get_type(int);
299 int get_mapping(int, unsigned int *, unsigned int *, unsigned int *, unsigned long *);
301 daddr_t
configure_bootsel(daddr_t
);
302 void install_bootsel(int);
303 daddr_t
get_default_boot(void);
304 void set_default_boot(daddr_t
);
308 initvar_disk(const char **diskp
)
310 #if !HAVE_NBTOOL_CONFIG_H
316 mib
[1] = KERN_ROOT_DEVICE
;
317 if (sysctl(mib
, 2, NULL
, &len
, NULL
, 0) == -1 ||
318 (root_device
= malloc(len
)) == NULL
||
319 sysctl(mib
, 2, root_device
, &len
, NULL
, 0) == -1)
322 *diskp
= root_device
;
323 #endif /* HAVE_NBTOOL_CONFIG_H */
327 main(int argc
, char *argv
[])
335 daddr_t default_ptn
; /* start sector of default ptn */
339 int csysid
; /* For the s_flag. */
340 unsigned int cstart
, csize
;
341 a_flag
= u_flag
= sh_flag
= f_flag
= s_flag
= b_flag
= 0;
345 csysid
= cstart
= csize
= 0;
346 while ((ch
= getopt(argc
, argv
, OPTIONS
)) != -1) {
360 case 'E': /* Extended partition number */
362 partition
= strtoul(optarg
, &cp
, 0);
363 if (*cp
|| partition
< 0)
364 errx(1, "Bad partition number -E %s.", optarg
);
367 case 'B': /* Bootselect parameters */
371 case 'F': /* device argument is really a file */
374 case 'S': /* Output as shell variables */
377 case 'a': /* Set active partition */
380 case 'f': /* Non interactive */
383 case 'i': /* Always update bootcode */
386 case 'l': /* List known partition types */
387 for (len
= 0; len
< KNOWN_SYSIDS
; len
++)
388 printf("%03d %s\n", mbr_ptypes
[len
].id
,
389 mbr_ptypes
[len
].name
);
391 case 'u': /* Update partition details */
394 case 'v': /* Be verbose */
397 case 's': /* Partition details */
399 if (sscanf(optarg
, "%d/%u/%u%n", &csysid
, &cstart
,
404 if (optarg
[n
] == '/') {
405 cbootmenu
= optarg
+ n
+ 1;
410 errx(1, "Bad argument to the -s flag.");
412 case 'b': /* BIOS geometry */
414 if (sscanf(optarg
, "%d/%d/%d%n", &b_cyl
, &b_head
,
415 &b_sec
, &n
) != 3 || optarg
[n
] != 0)
416 errx(1, "Bad argument to the -b flag.");
420 case 'A': /* Partition alignment[/offset] */
421 if (sscanf(optarg
, "%u/%u%n", &ptn_alignment
,
422 &ptn_0_offset
, &n
) < 1
424 || ptn_0_offset
> ptn_alignment
)
425 errx(1, "Bad argument to the -A flag.");
426 if (ptn_0_offset
== 0)
427 ptn_0_offset
= ptn_alignment
;
429 case 'c': /* file/directory containing boot code */
430 if (strchr(optarg
, '/') != NULL
&&
431 stat(optarg
, &sb
) == 0 &&
432 (sb
.st_mode
& S_IFMT
) == S_IFDIR
) {
436 bootsize
= read_boot(optarg
, bootcode
,
440 case 'r': /* read data from disk_file (not raw disk) */
443 case 'w': /* write data to disk_file */
447 if (setdisktab(optarg
) == -1)
448 errx(EXIT_FAILURE
, "bad disktab");
460 if (disk_type
!= NULL
&& getdiskbyname(disk_type
) == NULL
)
461 errx(EXIT_FAILURE
, "bad disktype");
463 if (sh_flag
&& (a_flag
|| i_flag
|| u_flag
|| f_flag
|| s_flag
))
466 if (B_flag
&& f_flag
) {
467 warnx("Bootselector may only be configured interactively");
471 if (f_flag
&& u_flag
&& !s_flag
) {
472 warnx("Partition data not specified");
476 if (s_flag
&& partition
== -1) {
477 warnx("-s flag requires a partition selected.");
487 /* Default to boot device */
491 if (!F_flag
&& stat(disk
, &sb
) == 0 && S_ISREG(sb
.st_mode
))
494 if (open_disk(B_flag
|| a_flag
|| i_flag
|| u_flag
) < 0)
497 if (read_s0(0, &mboot
))
498 /* must have been a blank disk */
501 read_gpt(GPT_HDR_BLKNO
, &gpt1
);
502 read_gpt(disksectors
- 1, &gpt2
);
505 dos_cylinders
= b_cyl
;
512 if (ptn_alignment
== 0)
518 default_ptn
= get_default_boot();
521 if (E_flag
&& !u_flag
&& partition
>= ext
.num_ptn
)
522 errx(1, "Extended partition %d is not defined.", partition
);
524 /* Do the update stuff! */
526 if (!f_flag
&& !b_flag
)
527 change_bios_geometry();
530 change_part(E_flag
, partition
, csysid
, cstart
, csize
,
533 int part
= partition
, chg_ext
= E_flag
, prompt
= 1;
541 "Which partition do you want to change?",
545 prompt
= change_part(chg_ext
, part
, 0, 0, 0, 0);
546 } while (partition
== -1);
549 if (!i_flag
&& !B_flag
) {
555 if (a_flag
&& !E_flag
)
556 change_active(partition
);
559 if (B_flag
|| u_flag
|| i_flag
)
560 /* Ensure the mbr code supports this configuration */
563 default_ptn
= configure_bootsel(default_ptn
);
564 set_default_boot(default_ptn
);
570 if (u_flag
|| a_flag
|| i_flag
|| B_flag
) {
572 printf("\nWe haven't written the MBR back to disk "
573 "yet. This is your last chance.\n");
576 if (gpt1
.hdr_size
!= 0 || gpt2
.hdr_size
!= 0)
577 printf("\nWARNING: The disk is carrying "
578 "GUID Partition Tables.\n"
580 "GPT headers will be deleted.\n\n");
581 if (yesno("Should we write new partition table?")) {
587 if (delete_gpt(&gpt1
) > 0)
588 warnx("Primary GPT header was deleted");
589 if (delete_gpt(&gpt2
) > 0)
590 warnx("Secondary GPT header was deleted");
601 int indent
= 7 + (int)strlen(getprogname()) + 1;
603 (void)fprintf(stderr
, "usage: %s [-afiluvBS] "
604 "[-A ptn_alignment[/ptn_0_offset]] \\\n"
605 "%*s[-b cylinders/heads/sectors] \\\n"
606 "%*s[-0123 | -E num "
607 "[-s id/start/size[/bootmenu]]] \\\n"
608 "%*s[-t disktab] [-T disktype] \\\n"
610 "[-r|-w file] [device]\n"
611 "\t-a change active partition\n"
612 "\t-f force - not interactive\n"
613 "\t-i initialise MBR code\n"
614 "\t-l list partition types\n"
615 "\t-u update partition data\n"
616 "\t-v verbose output, -v -v more verbose still\n"
617 "\t-B update bootselect options\n"
618 "\t-F treat device as a regular file\n"
619 "\t-S output as shell defines\n"
620 "\t-r and -w access 'file' for non-destructive testing\n",
621 getprogname(), indent
, "", indent
, "", indent
, "", indent
, "");
628 daddr_t offset
= ext
.base
;
631 offset
+= le32toh(ext
.ptn
[part
- 1].mbr_parts
[1].mbrp_start
);
642 printf("Partition table:\n");
643 for (part
= 0; part
< MBR_PART_COUNT
; part
++) {
645 printf("%d: ", part
);
646 print_part(&mboot
, part
, 0);
650 printf("Extended partition table is corrupt\n");
652 if (ext
.num_ptn
!= 0)
653 printf("Extended partition table:\n");
655 for (part
= 0; part
< ext
.num_ptn
; part
++) {
657 printf("E%d: ", part
);
658 print_part(&ext
.ptn
[part
], 0, ext_offset(part
));
659 if (!sh_flag
&& v_flag
>= 2) {
661 print_mbr_partition(&ext
.ptn
[part
], 1,
662 ext_offset(part
), ext
.base
, 0);
666 if (!sh_flag
&& mboot
.mbr_bootsel_magic
== LE_MBR_BS_MAGIC
) {
669 printf("Bootselector ");
670 if (mboot
.mbr_bootsel
.mbrbs_flags
& MBR_BS_ACTIVE
) {
672 tmo
= le16toh(mboot
.mbr_bootsel
.mbrbs_timeo
);
674 printf(", infinite timeout");
676 printf(", timeout %d seconds",
677 (10 * tmo
+ 9) / 182);
684 int active
= first_active();
685 if (active
== MBR_PART_COUNT
)
686 printf("No active partition.\n");
688 printf("First active partition: %d\n", active
);
690 if (!sh_flag
&& mboot
.mbr_dsn
!= 0)
691 printf("Drive serial number: %"PRIu32
" (0x%08x)\n",
692 le32toh(mboot
.mbr_dsn
),
693 le32toh(mboot
.mbr_dsn
));
699 printf("Extended partition E%d:\n", which
);
700 if (which
> ext
.num_ptn
)
701 printf("Undefined\n");
703 print_part(&ext
.ptn
[which
], 0, ext_offset(which
));
706 printf("Partition %d:\n", which
);
707 print_part(&mboot
, which
, 0);
712 print_part(struct mbr_sector
*boot
, int part
, daddr_t offset
)
714 struct mbr_partition
*partp
;
718 print_mbr_partition(boot
, part
, offset
, 0, 0);
722 partp
= &boot
->mbr_parts
[part
];
723 if (boot
!= &mboot
) {
724 part
= boot
- ext
.ptn
;
729 if (partp
->mbrp_type
== 0) {
730 printf("PART%s%dSIZE=0\n", e
, part
);
734 printf("PART%s%dID=%d\n", e
, part
, partp
->mbrp_type
);
735 printf("PART%s%dSIZE=%u\n", e
, part
, le32toh(partp
->mbrp_size
));
736 printf("PART%s%dSTART=%"PRIdaddr
"\n", e
, part
,
737 offset
+ le32toh(partp
->mbrp_start
));
738 printf("PART%s%dFLAG=0x%x\n", e
, part
, partp
->mbrp_flag
);
739 printf("PART%s%dBCYL=%d\n", e
, part
,
740 MBR_PCYL(partp
->mbrp_scyl
, partp
->mbrp_ssect
));
741 printf("PART%s%dBHEAD=%d\n", e
, part
, partp
->mbrp_shd
);
742 printf("PART%s%dBSEC=%d\n", e
, part
, MBR_PSECT(partp
->mbrp_ssect
));
743 printf("PART%s%dECYL=%d\n", e
, part
,
744 MBR_PCYL(partp
->mbrp_ecyl
, partp
->mbrp_esect
));
745 printf("PART%s%dEHEAD=%d\n", e
, part
, partp
->mbrp_ehd
);
746 printf("PART%s%dESEC=%d\n", e
, part
, MBR_PSECT(partp
->mbrp_esect
));
750 pr_cyls(daddr_t sector
, int is_end
)
752 unsigned long cyl
, head
, sect
;
753 cyl
= sector
/ dos_cylindersectors
;
754 sect
= sector
- cyl
* dos_cylindersectors
;
755 head
= sect
/ dos_sectors
;
756 sect
-= head
* dos_sectors
;
761 if (head
== dos_heads
- 1 && sect
== dos_sectors
- 1)
764 if (head
== 0 && sect
== 0)
768 printf("/%lu/%lu", head
, sect
+ 1);
772 print_mbr_partition(struct mbr_sector
*boot
, int part
,
773 daddr_t offset
, daddr_t exoffset
, int indent
)
777 struct mbr_partition
*partp
= &boot
->mbr_parts
[part
];
778 struct mbr_sector eboot
;
780 static int dumped
= 0;
782 if (partp
->mbrp_type
== 0 && v_flag
< 2) {
783 printf("<UNUSED>\n");
787 start
= le32toh(partp
->mbrp_start
);
788 size
= le32toh(partp
->mbrp_size
);
789 if (MBR_IS_EXTENDED(partp
->mbrp_type
))
794 printf("%s (sysid %d)\n", get_type(partp
->mbrp_type
), partp
->mbrp_type
);
796 if (boot
->mbr_bootsel_magic
== LE_MBR_BS_MAGIC
&&
797 boot
->mbr_bootsel
.mbrbs_nametab
[part
][0])
798 printf("%*s bootmenu: %s\n", indent
, "",
799 boot
->mbr_bootsel
.mbrbs_nametab
[part
]);
802 printf("%*s start %"PRIdaddr
", size %"PRIdaddr
,
803 indent
, "", start
, size
);
805 printf(" (%u MB, Cyls ", SEC_TO_MB(size
));
806 if (v_flag
== 0 && le32toh(partp
->mbrp_start
) == ptn_0_offset
)
807 pr_cyls(start
- ptn_0_offset
, 0);
811 pr_cyls(start
+ size
- 1, 1);
815 switch (partp
->mbrp_flag
) {
818 case MBR_PFLAG_ACTIVE
:
822 printf(", flag 0x%x", partp
->mbrp_flag
);
828 printf("%*s beg: cylinder %4d, head %3d, sector %2d\n",
830 MBR_PCYL(partp
->mbrp_scyl
, partp
->mbrp_ssect
),
831 partp
->mbrp_shd
, MBR_PSECT(partp
->mbrp_ssect
));
832 printf("%*s end: cylinder %4d, head %3d, sector %2d\n",
834 MBR_PCYL(partp
->mbrp_ecyl
, partp
->mbrp_esect
),
835 partp
->mbrp_ehd
, MBR_PSECT(partp
->mbrp_esect
));
838 if (partp
->mbrp_type
== 0 && start
== 0 && v_flag
< 3)
841 if (! MBR_IS_EXTENDED(partp
->mbrp_type
))
842 print_pbr(start
, indent
+ 8, partp
->mbrp_type
);
844 if (!MBR_IS_EXTENDED(partp
->mbrp_type
) ||
845 (v_flag
<= 2 && !ext
.is_corrupt
))
849 * Recursive dump extended table,
850 * This is read from the disk - so is wrong during editing.
851 * Just ensure we only show it once.
856 printf("%*s Extended partition table:\n", indent
, "");
858 if (read_s0(start
, &eboot
) == -1)
860 for (p
= 0; p
< MBR_PART_COUNT
; p
++) {
861 printf("%*s%d: ", indent
, "", p
);
862 print_mbr_partition(&eboot
, p
, start
,
863 exoffset
? exoffset
: start
, indent
);
870 /* Print a line with a label and a vis-encoded string */
872 printvis(int indent
, const char *label
, const char *buf
, size_t size
)
876 if ((visbuf
= malloc(size
* 4 + 1)) == NULL
)
877 err(1, "Malloc failed");
878 strsvisx(visbuf
, buf
, size
, VIS_TAB
|VIS_NL
|VIS_OCTAL
, "\"");
879 printf("%*s%s: \"%s\"\n",
885 /* Check whether a buffer contains all bytes zero */
887 is_all_zero(const unsigned char *p
, size_t size
)
898 * Report on the contents of a PBR sector.
900 * We first perform several sanity checks. If vflag >= 2, we report all
901 * failing tests, but for smaller values of v_flag we stop after the
902 * first failing test. Tests are ordered in an attempt to get the most
903 * useful error message from the first failing test.
905 * If v_flag >= 2, we also report some decoded values from the PBR.
906 * These results may be meaningless, if the PBR doesn't follow common
909 * Trying to decode anything more than the magic number in the last
910 * two bytes is a layering violation, but it can be very useful in
911 * diagnosing boot failures.
914 print_pbr(daddr_t sector
, int indent
, uint8_t part_type
)
916 struct mbr_sector pboot
;
917 unsigned char *p
, *endp
;
922 #define PBR_ERROR(...) \
925 printf("%*s%s: ", indent, "", \
926 (v_flag < 2 ? "PBR is not bootable" : "Not bootable")); \
927 printf(__VA_ARGS__); \
930 } while (/*CONSTCOND*/ 0)
933 printf("%*sInformation from PBR:\n",
938 if (read_disk(sector
, &pboot
) == -1) {
939 PBR_ERROR("Sector %"PRIdaddr
" is unreadable (%s)\n",
940 sector
, strerror(errno
));
944 /* all bytes identical? */
945 p
= (unsigned char *)&pboot
;
946 endp
= p
+ sizeof(pboot
);
949 for (; p
< endp
; p
++) {
956 PBR_ERROR("All bytes are identical (0x%02x)\n", val
);
958 if (pboot
.mbr_magic
!= LE_MBR_MAGIC
)
959 PBR_ERROR("Bad magic number (0x%04x)\n",
960 le16toh(pboot
.mbr_magic
));
963 /* Some i386 OS might fail this test. All non-i386 will fail. */
964 if (pboot
.mbr_jmpboot
[0] != 0xE9
965 && pboot
.mbr_jmpboot
[0] != 0xEB) {
966 PBR_ERROR("Does not begin with i386 JMP instruction"
967 " (0x%02x 0x%02x0 0x%02x)\n",
968 pboot
.mbr_jmpboot
[0], pboot
.mbr_jmpboot
[1],
969 pboot
.mbr_jmpboot
[2]);
973 if (v_flag
> 0 && errcount
== 0)
974 printf("%*sPBR appears to be bootable\n",
979 if (! is_all_zero(pboot
.mbr_oemname
, sizeof(pboot
.mbr_oemname
))) {
980 printvis(indent
, "OEM name", (char *)pboot
.mbr_oemname
,
981 sizeof(pboot
.mbr_oemname
));
984 if (pboot
.mbr_bpb
.bpb16
.bsBootSig
== 0x29)
985 printf("%*sBPB FAT16 boot signature found\n",
987 if (pboot
.mbr_bpb
.bpb32
.bsBootSig
== 0x29)
988 printf("%*sBPB FAT32 boot signature found\n",
995 read_boot(const char *name
, void *buf
, size_t len
, int err_exit
)
1000 if (boot_path
!= NULL
)
1002 if (strchr(name
, '/') == 0)
1003 asprintf(&boot_path
, "%s/%s", boot_dir
, name
);
1005 boot_path
= strdup(name
);
1006 if (boot_path
== NULL
)
1007 err(1, "Malloc failed");
1009 if ((bfd
= open(boot_path
, O_RDONLY
)) < 0 || fstat(bfd
, &st
) == -1) {
1010 warn("%s", boot_path
);
1014 if (st
.st_size
> (off_t
)len
) {
1015 warnx("%s: bootcode too large", boot_path
);
1020 warnx("%s: bootcode too small", boot_path
);
1023 if (read(bfd
, buf
, len
) != ret
) {
1024 warn("%s", boot_path
);
1029 * Do some sanity checking here
1031 if (((struct mbr_sector
*)buf
)->mbr_magic
!= LE_MBR_MAGIC
) {
1032 warnx("%s: invalid magic", boot_path
);
1037 ret
= (ret
+ 0x1ff) & ~0x1ff;
1049 init_sector0(int zappart
)
1052 int copy_size
= offsetof(struct mbr_sector
, mbr_dsn
);
1054 #ifdef DEFAULT_BOOTCODE
1056 bootsize
= read_boot(DEFAULT_BOOTCODE
, bootcode
,
1057 sizeof bootcode
, 0);
1060 if (mboot
.mbr_bootsel_magic
== LE_MBR_BS_MAGIC
1061 && bootcode
[0].mbr_bootsel_magic
== LE_MBR_BS_MAGIC
)
1062 copy_size
= MBR_BS_OFFSET
;
1065 if (bootsize
!= 0) {
1067 memcpy(&mboot
, bootcode
, copy_size
);
1068 mboot
.mbr_bootsel_magic
= bootcode
[0].mbr_bootsel_magic
;
1070 mboot
.mbr_magic
= LE_MBR_MAGIC
;
1074 for (i
= 0; i
< MBR_PART_COUNT
; i
++)
1075 memset(&mboot
.mbr_parts
[i
], 0, sizeof(mboot
.mbr_parts
[i
]));
1079 get_extended_ptn(void)
1081 struct mbr_partition
*mp
;
1082 struct mbr_sector
*boot
;
1084 struct mbr_sector
*nptn
;
1086 /* find first (there should only be one) extended partition */
1087 for (mp
= mboot
.mbr_parts
; !MBR_IS_EXTENDED(mp
->mbrp_type
); mp
++)
1088 if (mp
>= &mboot
.mbr_parts
[MBR_PART_COUNT
])
1092 * The extended partition should be structured as a linked list
1093 * (even though it appears, at first glance, to be a tree).
1095 ext
.base
= le32toh(mp
->mbrp_start
);
1096 ext
.limit
= ext
.base
+ le32toh(mp
->mbrp_size
);
1097 ext
.ptn_id
= mp
- mboot
.mbr_parts
;
1098 for (offset
= 0;; offset
= le32toh(boot
->mbr_parts
[1].mbrp_start
)) {
1099 nptn
= realloc(ext
.ptn
, (ext
.num_ptn
+ 1) * sizeof *ext
.ptn
);
1101 err(1, "Malloc failed");
1103 boot
= ext
.ptn
+ ext
.num_ptn
;
1104 if (read_s0(offset
+ ext
.base
, boot
) == -1)
1106 /* expect p0 to be valid and p1 to be another extended ptn */
1107 if (MBR_IS_EXTENDED(boot
->mbr_parts
[0].mbrp_type
))
1109 if (boot
->mbr_parts
[1].mbrp_type
!= 0 &&
1110 !MBR_IS_EXTENDED(boot
->mbr_parts
[1].mbrp_type
))
1112 /* p2 and p3 should be unallocated */
1113 if (boot
->mbr_parts
[2].mbrp_type
!= 0 ||
1114 boot
->mbr_parts
[3].mbrp_type
!= 0)
1116 /* data ptn inside extended one */
1117 if (boot
->mbr_parts
[0].mbrp_type
!= 0 &&
1118 offset
+ le32toh(boot
->mbr_parts
[0].mbrp_start
)
1119 + le32toh(boot
->mbr_parts
[0].mbrp_size
) > ext
.limit
)
1124 if (boot
->mbr_parts
[1].mbrp_type
== 0)
1125 /* end of extended partition chain */
1127 /* must be in sector order */
1128 if (offset
>= le32toh(boot
->mbr_parts
[1].mbrp_start
))
1132 warnx("Extended partition table is corrupt\n");
1137 #if defined(USE_DISKLIST)
1139 get_diskname(const char *fullname
, char *diskname
, size_t size
)
1144 p
= strrchr(fullname
, '/');
1151 strlcpy(diskname
, fullname
, size
);
1158 for (p2
= p
; *p2
!= 0; p2
++)
1159 if (isdigit((unsigned char)*p2
))
1162 /* XXX invalid diskname? */
1163 strlcpy(diskname
, fullname
, size
);
1166 while (isdigit((unsigned char)*p2
))
1172 strlcpy(diskname
, fullname
, size
);
1176 memcpy(diskname
, p
, len
);
1182 get_ptn_alignmemt(void)
1184 struct mbr_partition
*partp
= &mboot
.mbr_parts
[0];
1185 uint32_t ptn_0_base
, ptn_0_limit
;
1187 /* Default to using 'traditional' cylinder alignment */
1188 ptn_alignment
= dos_cylindersectors
;
1189 ptn_0_offset
= dos_sectors
;
1191 if (partp
->mbrp_type
!= 0) {
1192 /* Try to copy alignment of first partition */
1193 ptn_0_base
= le32toh(partp
->mbrp_start
);
1194 ptn_0_limit
= ptn_0_base
+ le32toh(partp
->mbrp_size
);
1195 if (!(ptn_0_limit
& 2047)) {
1196 /* Partition ends on a 1MB boundary, align to 1MB */
1197 ptn_alignment
= 2048;
1198 if (ptn_0_base
<= 2048
1199 && !(ptn_0_base
& (ptn_0_base
- 1))) {
1200 /* ptn_base is a power of 2, use it */
1201 ptn_0_offset
= ptn_0_base
;
1205 /* Use 1MB alignment for large disks */
1206 if (disksectors
> 2048 * 1024 * 128) {
1207 ptn_alignment
= 2048;
1208 ptn_0_offset
= 2048;
1214 get_bios_geometry(void)
1216 #if defined(USE_DISKLIST)
1219 struct biosdisk_info
*bip
;
1220 struct nativedisk_info
*nip
;
1223 mib
[0] = CTL_MACHDEP
;
1224 mib
[1] = CPU_DISKINFO
;
1225 if (sysctl(mib
, 2, NULL
, &len
, NULL
, 0) < 0) {
1228 dl
= (struct disklist
*) malloc(len
);
1230 err(1, "Malloc failed");
1231 if (sysctl(mib
, 2, dl
, &len
, NULL
, 0) < 0) {
1237 get_diskname(disk
, diskname
, sizeof diskname
);
1239 for (i
= 0; i
< dl
->dl_nnativedisks
; i
++) {
1240 nip
= &dl
->dl_nativedisks
[i
];
1241 if (strcmp(diskname
, nip
->ni_devname
))
1244 * XXX listing possible matches is better. This is ok for
1245 * now because the user has a chance to change it later.
1246 * Also, if all the disks have the same parameters then we can
1247 * just use them, we don't need to know which disk is which.
1249 if (nip
->ni_nmatches
!= 0) {
1250 bip
= &dl
->dl_biosdisks
[nip
->ni_biosmatches
[0]];
1251 dos_cylinders
= bip
->bi_cyl
;
1252 dos_heads
= bip
->bi_head
;
1253 dos_sectors
= bip
->bi_sec
;
1254 if (bip
->bi_lbasecs
)
1255 dos_disksectors
= bip
->bi_lbasecs
;
1261 /* Allright, allright, make a stupid guess.. */
1262 intuit_translated_geometry();
1267 get_default_boot(void)
1272 if (mboot
.mbr_bootsel_magic
!= LE_MBR_BS_MAGIC
)
1273 /* default to first active partition */
1274 return DEFAULT_ACTIVE
;
1276 id
= mboot
.mbr_bootsel
.mbrbs_defkey
;
1278 if (mboot
.mbr_bootsel
.mbrbs_flags
& MBR_BS_ASCII
) {
1279 /* Keycode is ascii */
1281 return DEFAULT_ACTIVE
;
1282 /* '1'+ => allocated partition id, 'a'+ => disk 0+ */
1283 if (id
>= 'a' && id
< 'a' + MAX_BIOS_DISKS
)
1284 return DEFAULT_DISK(id
- 'a');
1287 /* keycode is PS/2 keycode */
1288 if (id
== SCAN_ENTER
)
1289 return DEFAULT_ACTIVE
;
1290 /* 1+ => allocated partition id, F1+ => disk 0+ */
1291 if (id
>= SCAN_F1
&& id
< SCAN_F1
+ MAX_BIOS_DISKS
)
1292 return DEFAULT_DISK(id
- SCAN_F1
);
1296 /* Convert partition index to the invariant start sector number */
1298 for (p
= 0; p
< MBR_PART_COUNT
; p
++) {
1299 if (mboot
.mbr_parts
[p
].mbrp_type
== 0)
1301 if (mboot
.mbr_bootsel
.mbrbs_nametab
[p
][0] == 0)
1304 return le32toh(mboot
.mbr_parts
[p
].mbrp_start
);
1307 for (p
= 0; p
< ext
.num_ptn
; p
++) {
1308 if (ext
.ptn
[p
].mbr_parts
[0].mbrp_type
== 0)
1310 if (ext
.ptn
[p
].mbr_bootsel
.mbrbs_nametab
[0][0] == 0)
1313 return ext_offset(p
)
1314 + le32toh(ext
.ptn
[p
].mbr_parts
[0].mbrp_start
);
1317 return DEFAULT_ACTIVE
;
1321 set_default_boot(daddr_t default_ptn
)
1324 static const unsigned char key_list
[] = { SCAN_ENTER
, SCAN_F1
, SCAN_1
,
1326 const unsigned char *key
= key_list
;
1328 if (mboot
.mbr_bootsel_magic
!= LE_MBR_BS_MAGIC
)
1332 if (mboot
.mbr_bootsel
.mbrbs_flags
& MBR_BS_ASCII
)
1333 /* Use ascii values */
1336 if (default_ptn
== DEFAULT_ACTIVE
) {
1337 mboot
.mbr_bootsel
.mbrbs_defkey
= key
[0];
1341 if (default_ptn
>= DEFAULT_DISK(0)
1342 && default_ptn
< DEFAULT_DISK(MAX_BIOS_DISKS
)) {
1343 mboot
.mbr_bootsel
.mbrbs_defkey
= key
[1]
1344 + default_ptn
- DEFAULT_DISK(0);
1348 mboot
.mbr_bootsel
.mbrbs_defkey
= key
[2];
1349 for (p
= 0; p
< MBR_PART_COUNT
; p
++) {
1350 if (mboot
.mbr_parts
[p
].mbrp_type
== 0)
1352 if (mboot
.mbr_bootsel
.mbrbs_nametab
[p
][0] == 0)
1354 if (le32toh(mboot
.mbr_parts
[p
].mbrp_start
) == default_ptn
)
1356 mboot
.mbr_bootsel
.mbrbs_defkey
++;
1359 if (mboot
.mbr_bootsel
.mbrbs_flags
& MBR_BS_EXTLBA
) {
1360 for (p
= 0; p
< ext
.num_ptn
; p
++) {
1361 if (ext
.ptn
[p
].mbr_parts
[0].mbrp_type
== 0)
1363 if (ext
.ptn
[p
].mbr_bootsel
.mbrbs_nametab
[0][0] == 0)
1365 if (le32toh(ext
.ptn
[p
].mbr_parts
[0].mbrp_start
) +
1366 ext_offset(p
) == default_ptn
)
1368 mboot
.mbr_bootsel
.mbrbs_defkey
++;
1372 /* Default to first active partition */
1373 mboot
.mbr_bootsel
.mbrbs_defkey
= key
[0];
1377 install_bootsel(int needed
)
1379 struct mbr_bootsel
*mbs
= &mboot
.mbr_bootsel
;
1384 needed
|= MBR_BS_NEWMBR
; /* need new bootsel code */
1386 /* Work out which boot code we need for this configuration */
1387 for (p
= 0; p
< MBR_PART_COUNT
; p
++) {
1388 if (mboot
.mbr_parts
[p
].mbrp_type
== 0)
1390 if (mboot
.mbr_bootsel_magic
!= LE_MBR_BS_MAGIC
)
1392 if (mbs
->mbrbs_nametab
[p
][0] == 0)
1394 needed
|= MBR_BS_ACTIVE
;
1395 if (le32toh(mboot
.mbr_parts
[p
].mbrp_start
) >= dos_totalsectors
)
1396 ext13
= MBR_BS_EXTINT13
;
1399 for (p
= 0; p
< ext
.num_ptn
; p
++) {
1400 if (ext
.ptn
[p
].mbr_bootsel_magic
!= LE_MBR_BS_MAGIC
)
1402 if (ext
.ptn
[p
].mbr_parts
[0].mbrp_type
== 0)
1404 if (ext
.ptn
[p
].mbr_bootsel
.mbrbs_nametab
[p
][0] == 0)
1406 needed
|= MBR_BS_EXTLBA
| MBR_BS_ACTIVE
;
1410 needed
|= MBR_BS_ACTIVE
;
1412 /* Is the installed code good enough ? */
1413 if (!i_flag
&& (needed
== 0 ||
1414 (mboot
.mbr_bootsel_magic
== LE_MBR_BS_MAGIC
1415 && (mbs
->mbrbs_flags
& needed
) == needed
))) {
1416 /* yes - just set flags */
1417 mbs
->mbrbs_flags
|= ext13
;
1421 /* ok - we need to replace the bootcode */
1423 if (f_flag
&& !(i_flag
|| B_flag
)) {
1424 warnx("Installed bootfile doesn't support required options.");
1428 if (!f_flag
&& bootsize
== 0 && !i_flag
)
1429 /* Output an explanation for the 'update bootcode' prompt. */
1431 "Installed bootfile doesn't support required options.");
1433 /* Were we told a specific file ? (which we have already read) */
1434 /* If so check that it supports what we need. */
1435 if (bootsize
!= 0 && needed
!= 0
1436 && (bootcode
[0].mbr_bootsel_magic
!= LE_MBR_BS_MAGIC
1437 || ((bootcode
[0].mbr_bootsel
.mbrbs_flags
& needed
) != needed
))) {
1438 /* No it doesn't... */
1440 warnx("Bootfile %s doesn't support "
1441 "required bootsel options", boot_path
);
1442 /* But install it anyway */
1444 if (yesno("Bootfile %s doesn't support the required "
1445 "options,\ninstall default bootfile instead?",
1450 if (bootsize
== 0) {
1451 /* Get name of bootfile that supports the required facilities */
1452 code
= DEFAULT_BOOTCODE
;
1453 if (needed
& MBR_BS_ACTIVE
)
1454 code
= DEFAULT_BOOTSELCODE
;
1455 #ifdef DEFAULT_BOOTEXTCODE
1456 if (needed
& MBR_BS_EXTLBA
)
1457 code
= DEFAULT_BOOTEXTCODE
;
1460 bootsize
= read_boot(code
, bootcode
, sizeof bootcode
, 0);
1462 /* The old bootcode is better than no bootcode at all */
1464 if ((bootcode
[0].mbr_bootsel
.mbrbs_flags
& needed
) != needed
)
1465 warnx("Default bootfile %s doesn't support required "
1466 "options. Got flags 0x%x, wanted 0x%x\n",
1467 boot_path
, bootcode
[0].mbr_bootsel
.mbrbs_flags
,
1471 if (!f_flag
&& !yesno("Update the bootcode from %s?", boot_path
))
1476 if (mboot
.mbr_bootsel_magic
== LE_MBR_BS_MAGIC
)
1477 mbs
->mbrbs_flags
= bootcode
[0].mbr_bootsel
.mbrbs_flags
| ext13
;
1481 configure_bootsel(daddr_t default_ptn
)
1483 struct mbr_bootsel
*mbs
= &mboot
.mbr_bootsel
;
1489 #if defined(USE_DISKLIST)
1491 num_bios_disks
= dl
->dl_nbiosdisks
;
1492 if (num_bios_disks
> MAX_BIOS_DISKS
)
1493 num_bios_disks
= MAX_BIOS_DISKS
;
1496 num_bios_disks
= MAX_BIOS_DISKS
;
1498 printf("\nBoot selector configuration:\n");
1500 /* The timeout value is in ticks, ~18.2 Hz. Avoid using floats.
1501 * Ticks are nearly 64k/3600 - so our long timers are sligtly out!
1502 * Newer bootcode always waits for 1 tick, so treats 0xffff
1505 tmo
= le16toh(mbs
->mbrbs_timeo
);
1506 tmo
= tmo
== 0xffff ? -1 : (10 * tmo
+ 9) / 182;
1507 tmo
= decimal("Timeout value (0 to 3600 seconds, -1 => never)",
1509 mbs
->mbrbs_timeo
= htole16(tmo
== -1 ? 0xffff : (tmo
* 182) / 10);
1511 off
= calloc(1 + MBR_PART_COUNT
+ ext
.num_ptn
+ num_bios_disks
, sizeof *off
);
1513 err(1, "Malloc failed");
1515 printf("Select the default boot option. Options are:\n\n");
1518 off
[opt
] = DEFAULT_ACTIVE
;
1519 printf("%d: The first active partition\n", opt
);
1520 for (i
= 0; i
< MBR_PART_COUNT
; i
++) {
1521 if (mboot
.mbr_parts
[i
].mbrp_type
== 0)
1523 if (mbs
->mbrbs_nametab
[i
][0] == 0)
1525 printf("%d: %s\n", ++opt
, &mbs
->mbrbs_nametab
[i
][0]);
1526 off
[opt
] = le32toh(mboot
.mbr_parts
[i
].mbrp_start
);
1527 if (off
[opt
] == default_ptn
)
1530 if (mbs
->mbrbs_flags
& MBR_BS_EXTLBA
) {
1531 for (i
= 0; i
< ext
.num_ptn
; i
++) {
1532 if (ext
.ptn
[i
].mbr_parts
[0].mbrp_type
== 0)
1534 if (ext
.ptn
[i
].mbr_bootsel
.mbrbs_nametab
[0][0] == 0)
1537 ++opt
, ext
.ptn
[i
].mbr_bootsel
.mbrbs_nametab
[0]);
1538 off
[opt
] = ext_offset(i
) +
1539 le32toh(ext
.ptn
[i
].mbr_parts
[0].mbrp_start
);
1540 if (off
[opt
] == default_ptn
)
1544 for (i
= 0; i
< num_bios_disks
; i
++) {
1545 printf("%d: Harddisk %d\n", ++opt
, i
);
1546 off
[opt
] = DEFAULT_DISK(i
);
1547 if (DEFAULT_DISK(i
) == default_ptn
)
1551 item
= decimal("Default boot option", item
, 0, 0, opt
);
1553 default_ptn
= off
[item
];
1557 #endif /* BOOTSEL */
1560 /* Prerequisite: the disklabel parameters and master boot record must
1561 * have been read (i.e. dos_* and mboot are meaningful).
1562 * Specification: modifies dos_cylinders, dos_heads, dos_sectors, and
1563 * dos_cylindersectors to be consistent with what the
1564 * partition table is using, if we can find a geometry
1565 * which is consistent with all partition table entries.
1566 * We may get the number of cylinders slightly wrong (in
1567 * the conservative direction). The idea is to be able
1568 * to create a NetBSD partition on a disk we don't know
1569 * the translated geometry of.
1570 * This routine is only used for non-x86 systems or when we fail to
1571 * get the BIOS geometry from the kernel.
1574 intuit_translated_geometry(void)
1576 uint32_t xcylinders
;
1577 int xheads
= -1, xsectors
= -1, i
, j
;
1578 unsigned int c1
, h1
, s1
, c2
, h2
, s2
;
1579 unsigned long a1
, a2
;
1580 uint64_t num
, denom
;
1583 * The physical parameters may be invalid as bios geometry.
1584 * If we cannot determine the actual bios geometry, we are
1585 * better off picking a likely 'faked' geometry than leaving
1586 * the invalid physical one.
1589 if (dos_cylinders
> MAXCYL
|| dos_heads
> MAXHEAD
||
1590 dos_sectors
> MAXSECTOR
) {
1593 #if defined(USE_DISKLIST)
1595 /* BIOS may use 256 heads or 1024 cylinders */
1596 for (i
= 0; i
< dl
->dl_nbiosdisks
; i
++) {
1597 if (h1
< (unsigned int)dl
->dl_biosdisks
[i
].bi_head
)
1598 h1
= dl
->dl_biosdisks
[i
].bi_head
;
1599 if (c1
< (unsigned int)dl
->dl_biosdisks
[i
].bi_cyl
)
1600 c1
= dl
->dl_biosdisks
[i
].bi_cyl
;
1604 dos_sectors
= MAXSECTOR
;
1606 dos_cylinders
= disklabel
.d_secperunit
/ (MAXSECTOR
* h1
);
1607 if (dos_cylinders
> c1
)
1611 /* Try to deduce the number of heads from two different mappings. */
1612 for (i
= 0; i
< MBR_PART_COUNT
* 2 - 1; i
++) {
1613 if (get_mapping(i
, &c1
, &h1
, &s1
, &a1
) < 0)
1616 for (j
= i
+ 1; j
< MBR_PART_COUNT
* 2; j
++) {
1617 if (get_mapping(j
, &c2
, &h2
, &s2
, &a2
) < 0)
1620 num
= (uint64_t)h1
* a2
- (uint64_t)h2
* a1
;
1621 denom
= (uint64_t)c2
* a1
- (uint64_t)c1
* a2
;
1622 if (denom
!= 0 && num
!= 0 && num
% denom
== 0) {
1623 xheads
= num
/ denom
;
1624 xsectors
= a1
/ (c1
* xheads
+ h1
);
1633 warnx("Cannot determine the number of heads");
1637 if (xsectors
== -1) {
1638 warnx("Cannot determine the number of sectors");
1642 /* Estimate the number of cylinders. */
1643 xcylinders
= disklabel
.d_secperunit
/ xheads
/ xsectors
;
1644 if (disklabel
.d_secperunit
> xcylinders
* xheads
* xsectors
)
1648 * Now verify consistency with each of the partition table entries.
1649 * Be willing to shove cylinders up a little bit to make things work,
1650 * but translation mismatches are fatal.
1652 for (i
= 0; i
< MBR_PART_COUNT
* 2; i
++) {
1653 if (get_mapping(i
, &c1
, &h1
, &s1
, &a1
) < 0)
1655 if (c1
>= MAXCYL
- 2)
1657 if (xsectors
* (c1
* xheads
+ h1
) + s1
!= a1
)
1662 /* Everything checks out.
1663 * Reset the geometry to use for further calculations.
1664 * But cylinders cannot be > 1024.
1666 if (xcylinders
> MAXCYL
)
1667 dos_cylinders
= MAXCYL
;
1669 dos_cylinders
= xcylinders
;
1671 dos_sectors
= xsectors
;
1675 * For the purposes of intuit_translated_geometry(), treat the partition
1676 * table as a list of eight mapping between (cylinder, head, sector)
1677 * triplets and absolute sectors. Get the relevant geometry triplet and
1678 * absolute sectors for a given entry, or return -1 if it isn't present.
1679 * Note: for simplicity, the returned sector is 0-based.
1682 get_mapping(int i
, unsigned int *cylinder
, unsigned int *head
, unsigned int *sector
,
1683 unsigned long *absolute
)
1685 struct mbr_partition
*part
= &mboot
.mbr_parts
[i
/ 2];
1687 if (part
->mbrp_type
== 0)
1690 *cylinder
= MBR_PCYL(part
->mbrp_scyl
, part
->mbrp_ssect
);
1691 *head
= part
->mbrp_shd
;
1692 *sector
= MBR_PSECT(part
->mbrp_ssect
);
1693 *absolute
= le32toh(part
->mbrp_start
);
1695 *cylinder
= MBR_PCYL(part
->mbrp_ecyl
, part
->mbrp_esect
);
1696 *head
= part
->mbrp_ehd
;
1697 *sector
= MBR_PSECT(part
->mbrp_esect
);
1698 *absolute
= le32toh(part
->mbrp_start
)
1699 + le32toh(part
->mbrp_size
) - 1;
1701 /* Sanity check the data against all zeroes */
1702 if ((*cylinder
== 0) && (*sector
== 0) && (*head
== 0))
1704 /* sector numbers in the MBR partition table start at 1 */
1705 *sector
= *sector
- 1;
1706 /* Sanity check the data against max values */
1707 if ((((*cylinder
* MAXHEAD
) + *head
) * MAXSECTOR
+ *sector
) < *absolute
)
1708 /* cannot be a CHS mapping */
1714 delete_ptn(int part
)
1716 if (part
== ext
.ptn_id
) {
1717 /* forget all about the extended partition */
1719 memset(&ext
, 0, sizeof ext
);
1722 mboot
.mbr_parts
[part
].mbrp_type
= 0;
1726 delete_ext_ptn(int part
)
1730 ext
.ptn
[0].mbr_parts
[0].mbrp_type
= 0;
1733 ext
.ptn
[part
- 1].mbr_parts
[1] = ext
.ptn
[part
].mbr_parts
[1];
1734 memmove(&ext
.ptn
[part
], &ext
.ptn
[part
+ 1],
1735 (ext
.num_ptn
- part
- 1) * sizeof ext
.ptn
[0]);
1740 add_ext_ptn(daddr_t start
, daddr_t size
)
1743 struct mbr_partition
*partp
;
1744 struct mbr_sector
*nptn
;
1746 nptn
= realloc(ext
.ptn
, (ext
.num_ptn
+ 1) * sizeof *ext
.ptn
);
1750 for (part
= 0; part
< ext
.num_ptn
; part
++)
1751 if (ext_offset(part
) > start
)
1753 /* insert before 'part' - make space... */
1754 memmove(&ext
.ptn
[part
+ 1], &ext
.ptn
[part
],
1755 (ext
.num_ptn
- part
) * sizeof ext
.ptn
[0]);
1756 memset(&ext
.ptn
[part
], 0, sizeof ext
.ptn
[0]);
1757 ext
.ptn
[part
].mbr_magic
= LE_MBR_MAGIC
;
1758 /* we will be 'part' */
1760 /* link us to 'next' */
1761 partp
= &ext
.ptn
[0].mbr_parts
[1];
1762 /* offset will be fixed by caller */
1763 partp
->mbrp_size
= htole32(
1764 le32toh(ext
.ptn
[1].mbr_parts
[0].mbrp_start
) +
1765 le32toh(ext
.ptn
[1].mbr_parts
[0].mbrp_size
));
1767 /* link us to prev's next */
1768 partp
= &ext
.ptn
[part
- 1].mbr_parts
[1];
1769 ext
.ptn
[part
].mbr_parts
[1] = *partp
;
1770 /* and prev onto us */
1771 partp
->mbrp_start
= htole32(start
- ptn_0_offset
- ext
.base
);
1772 partp
->mbrp_size
= htole32(size
+ ptn_0_offset
);
1774 partp
->mbrp_type
= 5; /* as used by win98 */
1775 partp
->mbrp_flag
= 0;
1776 /* wallop in some CHS values - win98 doesn't saturate them */
1777 dos(le32toh(partp
->mbrp_start
),
1778 &partp
->mbrp_scyl
, &partp
->mbrp_shd
, &partp
->mbrp_ssect
);
1779 dos(le32toh(partp
->mbrp_start
) + le32toh(partp
->mbrp_size
) - 1,
1780 &partp
->mbrp_ecyl
, &partp
->mbrp_ehd
, &partp
->mbrp_esect
);
1787 check_overlap(int part
, int sysid
, daddr_t start
, daddr_t size
, int fix
)
1790 unsigned int p_s
, p_e
;
1794 return "Sector zero is reserved for the MBR";
1796 if (start
< ptn_0_offset
)
1797 /* This is just a convention, not a requirement */
1798 return "Track zero is reserved for the BIOS";
1800 if (start
+ size
> disksectors
)
1801 return "Partition exceeds size of disk";
1802 for (p
= 0; p
< MBR_PART_COUNT
; p
++) {
1803 if (p
== part
|| mboot
.mbr_parts
[p
].mbrp_type
== 0)
1805 p_s
= le32toh(mboot
.mbr_parts
[p
].mbrp_start
);
1806 p_e
= p_s
+ le32toh(mboot
.mbr_parts
[p
].mbrp_size
);
1807 if (start
+ size
<= p_s
|| start
>= p_e
)
1814 return "Overlaps another partition";
1818 /* Are we trying to create an extended partition */
1819 if (!MBR_IS_EXTENDED(mboot
.mbr_parts
[part
].mbrp_type
)) {
1820 /* this wasn't the extended partition */
1821 if (!MBR_IS_EXTENDED(sysid
))
1823 /* making an extended partition */
1824 if (ext
.base
!= 0) {
1826 return "There cannot be 2 extended partitions";
1828 delete_ptn(ext
.ptn_id
);
1831 /* allocate a new extended partition */
1832 ext
.ptn
= calloc(1, sizeof ext
.ptn
[0]);
1833 if (ext
.ptn
== NULL
)
1834 err(1, "Malloc failed");
1835 ext
.ptn
[0].mbr_magic
= LE_MBR_MAGIC
;
1838 ext
.limit
= start
+ size
;
1844 /* Check we haven't cut space allocated to an extended ptn */
1846 if (!MBR_IS_EXTENDED(sysid
)) {
1847 /* no longer an extended partition */
1849 /* Kill all memory of the extended partitions */
1853 if (ext
.num_ptn
== 0 ||
1854 (ext
.num_ptn
== 1 && ext
.ptn
[0].mbr_parts
[0].mbrp_type
== 0))
1855 /* nothing in extended partition */
1859 if (yesno("Do you really want to delete all the extended partitions?"))
1861 return "Extended partition busy";
1864 if (le32toh(mboot
.mbr_parts
[part
].mbrp_start
) != ext
.base
)
1865 /* maybe impossible, but an extra sanity check */
1868 for (p
= ext
.num_ptn
; --p
>= 0;) {
1869 if (ext
.ptn
[p
].mbr_parts
[0].mbrp_type
== 0)
1871 p_s
= ext_offset(p
);
1872 p_e
= p_s
+ le32toh(ext
.ptn
[p
].mbr_parts
[0].mbrp_start
)
1873 + le32toh(ext
.ptn
[p
].mbr_parts
[0].mbrp_size
);
1874 if (p_s
>= start
&& p_e
<= start
+ size
)
1877 return "Extended partition outside main partition";
1882 if (fix
&& start
!= ext
.base
) {
1883 /* The internal offsets need to be fixed up */
1884 for (p
= 0; p
< ext
.num_ptn
- 1; p
++)
1885 ext
.ptn
[p
].mbr_parts
[1].mbrp_start
= htole32(
1886 le32toh(ext
.ptn
[p
].mbr_parts
[1].mbrp_start
)
1887 + ext
.base
- start
);
1888 /* and maybe an empty partition at the start */
1889 if (ext
.ptn
[0].mbr_parts
[0].mbrp_type
== 0) {
1890 if (le32toh(ext
.ptn
[0].mbr_parts
[1].mbrp_start
) == 0) {
1891 /* don't need the empty slot */
1892 memmove(&ext
.ptn
[0], &ext
.ptn
[1],
1893 (ext
.num_ptn
- 1) * sizeof ext
.ptn
[0]);
1897 /* must create an empty slot */
1898 add_ext_ptn(start
, ptn_0_offset
);
1899 ext
.ptn
[0].mbr_parts
[1].mbrp_start
= htole32(ext
.base
1905 ext
.limit
= start
+ size
;
1911 check_ext_overlap(int part
, int sysid
, daddr_t start
, daddr_t size
, int fix
)
1914 unsigned int p_s
, p_e
;
1919 if (MBR_IS_EXTENDED(sysid
))
1920 return "Nested extended partitions are not allowed";
1922 /* allow one track at start for extended partition header */
1923 start
-= ptn_0_offset
;
1924 size
+= ptn_0_offset
;
1925 if (start
< ext
.base
|| start
+ size
> ext
.limit
)
1926 return "Outside bounds of extended partition";
1931 for (p
= ext
.num_ptn
; --p
>= 0;) {
1932 if (p
== part
|| ext
.ptn
[p
].mbr_parts
[0].mbrp_type
== 0)
1934 p_s
= ext_offset(p
);
1935 p_e
= p_s
+ le32toh(ext
.ptn
[p
].mbr_parts
[0].mbrp_start
)
1936 + le32toh(ext
.ptn
[p
].mbr_parts
[0].mbrp_size
);
1938 p_s
+= le32toh(ext
.ptn
[p
].mbr_parts
[0].mbrp_start
)
1940 if (start
< p_e
&& start
+ size
> p_s
) {
1942 return "Overlaps another extended partition";
1947 /* must not change numbering yet */
1948 ext
.ptn
[p
].mbr_parts
[0].mbrp_type
= 0;
1956 change_part(int extended
, int part
, int sysid
, daddr_t start
, daddr_t size
,
1959 struct mbr_partition
*partp
;
1960 struct mbr_sector
*boot
;
1967 const char *errtext
;
1969 char tmp_bootmenu
[MBR_PART_COUNT
* (MBR_BS_PARTNAMESIZE
+ 1)];
1970 int bootmenu_len
= (extended
? MBR_PART_COUNT
: 1) * (MBR_BS_PARTNAMESIZE
+ 1);
1974 if (part
!= -1 && part
< ext
.num_ptn
) {
1975 boot
= &ext
.ptn
[part
];
1976 partp
= &boot
->mbr_parts
[0];
1977 offset
= ext_offset(part
);
1988 partp
= &boot
->mbr_parts
[part
];
1993 if (!f_flag
&& part
!= -1) {
1994 printf("The data for partition %s%d is:\n", e
, part
);
1995 print_part(boot
, upart
, offset
);
1999 if (bootmenu
!= NULL
)
2000 strlcpy(tmp_bootmenu
, bootmenu
, bootmenu_len
);
2002 if (boot
!= NULL
&& boot
->mbr_bootsel_magic
== LE_MBR_BS_MAGIC
)
2003 strlcpy(tmp_bootmenu
,
2004 boot
->mbr_bootsel
.mbrbs_nametab
[upart
],
2007 tmp_bootmenu
[0] = 0;
2010 if (!s_flag
&& partp
!= NULL
) {
2011 /* values not specified, default to current ones */
2012 sysid
= partp
->mbrp_type
;
2013 start
= offset
+ le32toh(partp
->mbrp_start
);
2014 size
= le32toh(partp
->mbrp_size
);
2017 /* creating a new partition, default to free space */
2018 if (!s_flag
&& sysid
== 0 && extended
) {
2019 /* non-extended partition */
2021 for (p
= 0; p
< ext
.num_ptn
; p
++) {
2022 if (ext
.ptn
[p
].mbr_parts
[0].mbrp_type
== 0)
2024 n_s
= ext_offset(p
);
2025 if (n_s
> start
+ ptn_0_offset
)
2027 start
= ext_offset(p
)
2028 + le32toh(ext
.ptn
[p
].mbr_parts
[0].mbrp_start
)
2029 + le32toh(ext
.ptn
[p
].mbr_parts
[0].mbrp_size
);
2031 if (ext
.limit
- start
<= ptn_0_offset
) {
2032 printf("No space in extended partition\n");
2035 start
+= ptn_0_offset
;
2038 if (!s_flag
&& sysid
== 0 && !extended
) {
2039 /* same for non-extended partition */
2040 /* first see if old start is free */
2041 if (start
< ptn_0_offset
)
2043 for (p
= 0; start
!= 0 && p
< MBR_PART_COUNT
; p
++) {
2044 if (mboot
.mbr_parts
[p
].mbrp_type
== 0)
2046 n_s
= le32toh(mboot
.mbr_parts
[p
].mbrp_start
);
2048 start
< n_s
+ le32toh(mboot
.mbr_parts
[p
].mbrp_size
))
2052 /* Look for first gap */
2053 start
= ptn_0_offset
;
2054 for (p
= 0; p
< MBR_PART_COUNT
; p
++) {
2055 if (mboot
.mbr_parts
[p
].mbrp_type
== 0)
2057 n_s
= le32toh(mboot
.mbr_parts
[p
].mbrp_start
);
2058 n_e
= n_s
+ le32toh(mboot
.mbr_parts
[p
].mbrp_size
);
2059 if (start
>= n_s
&& start
< n_e
) {
2064 if (start
>= disksectors
) {
2065 printf("No free space\n");
2072 /* request new values from user */
2075 sysid
= decimal("sysid", sysid
, 0, 0, 255);
2076 if (sysid
== 0 && !v_flag
) {
2080 tmp_bootmenu
[0] = 0;
2083 daddr_t old
= start
;
2084 daddr_t lim
= extended
? ext
.limit
: disksectors
;
2085 start
= decimal("start", start
,
2086 DEC_SEC
| DEC_RND_0
| (extended
? DEC_RND
: 0),
2087 extended
? ext
.base
: 0, lim
);
2088 /* Adjust 'size' so that end doesn't move when 'start'
2089 * is only changed slightly.
2091 if (size
> start
- old
)
2092 size
-= start
- old
;
2095 /* Find end of available space from this start point */
2097 for (p
= 0; p
< ext
.num_ptn
; p
++) {
2100 if (ext
.ptn
[p
].mbr_parts
[0].mbrp_type
== 0)
2102 n_s
= ext_offset(p
);
2103 if (n_s
> start
&& n_s
< lim
)
2105 if (start
>= n_s
&& start
< n_s
2106 + le32toh(ext
.ptn
[p
].mbr_parts
[0].mbrp_start
)
2107 + le32toh(ext
.ptn
[p
].mbr_parts
[0].mbrp_size
)) {
2113 for (p
= 0; p
< MBR_PART_COUNT
; p
++) {
2116 if (mboot
.mbr_parts
[p
].mbrp_type
== 0)
2118 n_s
= le32toh(mboot
.mbr_parts
[p
].mbrp_start
);
2119 if (n_s
> start
&& n_s
< lim
)
2121 if (start
>= n_s
&& start
< n_s
2122 + le32toh(mboot
.mbr_parts
[p
].mbrp_size
)) {
2130 printf("Start sector already allocated\n");
2133 if (size
== 0 || size
> lim
)
2136 if (start
% ptn_alignment
== ptn_0_offset
)
2138 if (start
== 2 * ptn_0_offset
)
2139 fl
|= DEC_RND_DOWN
| DEC_RND_DOWN_2
;
2140 size
= decimal("size", size
, fl
, 0, lim
);
2142 #ifndef DEFAULT_BOOTEXTCODE
2145 string("bootmenu", bootmenu_len
, tmp_bootmenu
);
2151 * Before we write these away, we must verify that nothing
2152 * untoward has been requested.
2156 errtext
= check_ext_overlap(part
, sysid
, start
, size
, 0);
2158 errtext
= check_overlap(part
, sysid
, start
, size
, 0);
2159 if (errtext
!= NULL
) {
2161 errx(2, "%s\n", errtext
);
2162 printf("%s\n", errtext
);
2167 * Before proceeding, delete any overlapped partitions.
2168 * This can only happen if '-f' was supplied on the command line.
2169 * Just hope the caller knows what they are doing.
2170 * This also fixes the base of each extended partition if the
2171 * partition itself has moved.
2175 errtext
= check_ext_overlap(part
, sysid
, start
, size
, 1);
2177 errtext
= check_overlap(part
, sysid
, start
, size
, 1);
2180 errx(1, "%s\n", errtext
);
2183 /* delete this partition - save info though */
2185 /* must have been trying to create an extended ptn */
2187 if (start
== 0 && size
== 0)
2188 memset(partp
, 0, sizeof *partp
);
2190 if (boot
->mbr_bootsel_magic
== LE_MBR_BS_MAGIC
)
2191 memset(boot
->mbr_bootsel
.mbrbs_nametab
[upart
], 0,
2192 sizeof boot
->mbr_bootsel
.mbrbs_nametab
[0]);
2195 delete_ext_ptn(part
);
2204 delete_ext_ptn(part
);
2205 if (start
== ext
.base
+ ptn_0_offset
)
2206 /* First one must have been free */
2209 part
= add_ext_ptn(start
, size
);
2211 /* These must be re-calculated because of the realloc */
2212 boot
= &ext
.ptn
[part
];
2213 partp
= &boot
->mbr_parts
[0];
2214 offset
= ext_offset(part
);
2217 partp
->mbrp_type
= sysid
;
2218 partp
->mbrp_start
= htole32( start
- offset
);
2219 partp
->mbrp_size
= htole32( size
);
2220 dos(start
, &partp
->mbrp_scyl
, &partp
->mbrp_shd
, &partp
->mbrp_ssect
);
2221 dos(start
+ size
- 1,
2222 &partp
->mbrp_ecyl
, &partp
->mbrp_ehd
, &partp
->mbrp_esect
);
2225 boot
->mbr_bootsel_magic
= LE_MBR_BS_MAGIC
;
2226 strncpy(boot
->mbr_bootsel
.mbrbs_nametab
[upart
], tmp_bootmenu
,
2229 /* We need to bootselect code installed in order to have
2230 * somewhere to safely write the menu tag.
2232 if (boot
->mbr_bootsel_magic
!= LE_MBR_BS_MAGIC
) {
2234 yesno("The bootselect code is not installed, "
2235 "do you want to install it now?"))
2236 install_bootsel(MBR_BS_ACTIVE
);
2238 if (boot
->mbr_bootsel_magic
== LE_MBR_BS_MAGIC
) {
2239 strncpy(boot
->mbr_bootsel
.mbrbs_nametab
[upart
],
2240 tmp_bootmenu
, bootmenu_len
);
2245 if (v_flag
&& !f_flag
&& yesno("Explicitly specify beg/end address?")) {
2246 /* this really isn't a good idea.... */
2247 int tsector
, tcylinder
, thead
;
2249 tcylinder
= MBR_PCYL(partp
->mbrp_scyl
, partp
->mbrp_ssect
);
2250 thead
= partp
->mbrp_shd
;
2251 tsector
= MBR_PSECT(partp
->mbrp_ssect
);
2252 tcylinder
= decimal("beginning cylinder",
2253 tcylinder
, 0, 0, dos_cylinders
- 1);
2254 thead
= decimal("beginning head",
2255 thead
, 0, 0, dos_heads
- 1);
2256 tsector
= decimal("beginning sector",
2257 tsector
, 0, 1, dos_sectors
);
2258 partp
->mbrp_scyl
= DOSCYL(tcylinder
);
2259 partp
->mbrp_shd
= thead
;
2260 partp
->mbrp_ssect
= DOSSECT(tsector
, tcylinder
);
2262 tcylinder
= MBR_PCYL(partp
->mbrp_ecyl
, partp
->mbrp_esect
);
2263 thead
= partp
->mbrp_ehd
;
2264 tsector
= MBR_PSECT(partp
->mbrp_esect
);
2265 tcylinder
= decimal("ending cylinder",
2266 tcylinder
, 0, 0, dos_cylinders
- 1);
2267 thead
= decimal("ending head",
2268 thead
, 0, 0, dos_heads
- 1);
2269 tsector
= decimal("ending sector",
2270 tsector
, 0, 1, dos_sectors
);
2271 partp
->mbrp_ecyl
= DOSCYL(tcylinder
);
2272 partp
->mbrp_ehd
= thead
;
2273 partp
->mbrp_esect
= DOSSECT(tsector
, tcylinder
);
2276 /* If we had to mark an extended partition as deleted because
2277 * another request would have overlapped it, now is the time
2278 * to do the actual delete.
2280 if (extended
&& f_flag
) {
2281 for (p
= ext
.num_ptn
; --p
>= 0;)
2282 if (ext
.ptn
[p
].mbr_parts
[0].mbrp_type
== 0)
2289 print_geometry(void)
2293 printf("DISK=%s\n", disk
);
2294 printf("DLCYL=%d\nDLHEAD=%d\nDLSEC=%d\nDLSIZE=%"PRIdaddr
"\n",
2295 cylinders
, heads
, sectors
, disksectors
);
2296 printf("BCYL=%d\nBHEAD=%d\nBSEC=%d\nBDLSIZE=%"PRIdaddr
"\n",
2297 dos_cylinders
, dos_heads
, dos_sectors
, dos_disksectors
);
2298 printf("NUMEXTPTN=%d\n", ext
.num_ptn
);
2303 printf("Disk: %s\n", disk
);
2304 printf("NetBSD disklabel disk geometry:\n");
2305 printf("cylinders: %d, heads: %d, sectors/track: %d "
2306 "(%d sectors/cylinder)\ntotal sectors: %"PRIdaddr
"\n\n",
2307 cylinders
, heads
, sectors
, cylindersectors
, disksectors
);
2308 printf("BIOS disk geometry:\n");
2309 printf("cylinders: %d, heads: %d, sectors/track: %d "
2310 "(%d sectors/cylinder)\ntotal sectors: %"PRIdaddr
"\n\n",
2311 dos_cylinders
, dos_heads
, dos_sectors
, dos_cylindersectors
,
2313 printf("Partitions aligned to %d sector boundaries, offset %d\n\n",
2314 ptn_alignment
, ptn_0_offset
);
2317 /* Find the first active partition, else return MBR_PART_COUNT */
2321 struct mbr_partition
*partp
= &mboot
.mbr_parts
[0];
2324 for (part
= 0; part
< MBR_PART_COUNT
; part
++)
2325 if (partp
[part
].mbrp_flag
& MBR_PFLAG_ACTIVE
)
2327 return MBR_PART_COUNT
;
2331 change_active(int which
)
2333 struct mbr_partition
*partp
;
2335 int active
= MBR_PART_COUNT
;
2337 partp
= &mboot
.mbr_parts
[0];
2339 if (a_flag
&& which
!= -1)
2342 active
= first_active();
2344 if (yesno("Do you want to change the active partition?")) {
2345 printf ("Choosing %d will make no partition active.\n",
2348 active
= decimal("active partition",
2349 active
, 0, 0, MBR_PART_COUNT
);
2350 } while (!yesno("Are you happy with this choice?"));
2354 if (active
!= MBR_PART_COUNT
)
2355 printf ("Making partition %d active.\n", active
);
2357 for (part
= 0; part
< MBR_PART_COUNT
; part
++)
2358 partp
[part
].mbrp_flag
&= ~MBR_PFLAG_ACTIVE
;
2359 if (active
< MBR_PART_COUNT
)
2360 partp
[active
].mbrp_flag
|= MBR_PFLAG_ACTIVE
;
2364 change_bios_geometry(void)
2367 if (!yesno("Do you want to change our idea of what BIOS thinks?"))
2370 #if defined(USE_DISKLIST)
2372 struct biosdisk_info
*bip
;
2375 for (i
= 0; i
< dl
->dl_nbiosdisks
; i
++) {
2377 printf("\nGeometries of known disks:\n");
2378 bip
= &dl
->dl_biosdisks
[i
];
2379 printf("Disk %d: cylinders %u, heads %u, sectors %u"
2380 " (%"PRIdaddr
" sectors, %dMB)\n",
2381 i
, bip
->bi_cyl
, bip
->bi_head
, bip
->bi_sec
,
2382 bip
->bi_lbasecs
, SEC_TO_MB(bip
->bi_lbasecs
));
2389 dos_cylinders
= decimal("BIOS's idea of #cylinders",
2390 dos_cylinders
, 0, 0, MAXCYL
);
2391 dos_heads
= decimal("BIOS's idea of #heads",
2392 dos_heads
, 0, 0, MAXHEAD
);
2393 dos_sectors
= decimal("BIOS's idea of #sectors",
2394 dos_sectors
, 0, 1, MAXSECTOR
);
2396 } while (!yesno("Are you happy with this choice?"));
2400 /***********************************************\
2401 * Change real numbers into strange dos numbers *
2402 \***********************************************/
2404 dos(int sector
, unsigned char *cylinderp
, unsigned char *headp
,
2405 unsigned char *sectorp
)
2409 cylinder
= sector
/ dos_cylindersectors
;
2410 sector
-= cylinder
* dos_cylindersectors
;
2412 head
= sector
/ dos_sectors
;
2413 sector
-= head
* dos_sectors
;
2414 if (cylinder
> 1023)
2417 *cylinderp
= DOSCYL(cylinder
);
2419 *sectorp
= DOSSECT(sector
+ 1, cylinder
);
2423 open_disk(int update
)
2425 static char namebuf
[MAXPATHLEN
+ 1];
2426 int flags
= update
&& disk_file
== NULL
? O_RDWR
: O_RDONLY
;
2429 fd
= opendisk(disk
, flags
, namebuf
, sizeof(namebuf
), 0);
2431 if (errno
== ENODEV
)
2432 warnx("%s is not a character device", namebuf
);
2434 warn("cannot opendisk %s", namebuf
);
2439 fd
= open(disk
, flags
, 0);
2441 warn("cannot open %s", disk
);
2446 if (get_params() == -1) {
2451 if (disk_file
!= NULL
) {
2452 /* for testing: read/write data from a disk file */
2453 wfd
= open(disk_file
, update
? O_RDWR
|O_CREAT
: O_RDONLY
, 0777);
2455 warn("%s", disk_file
);
2466 read_disk(daddr_t sector
, void *buf
)
2470 errx(1, "read_disk(); fd == -1");
2471 if (lseek(*rfd
, sector
* (off_t
)512, 0) == -1)
2473 return (read(*rfd
, buf
, 512));
2477 write_disk(daddr_t sector
, void *buf
)
2481 errx(1, "write_disk(); wfd == -1");
2482 if (lseek(wfd
, sector
* (off_t
)512, 0) == -1)
2484 return (write(wfd
, buf
, 512));
2488 guess_geometry(daddr_t _sectors
)
2490 dos_sectors
= MAXSECTOR
;
2491 dos_heads
= MAXHEAD
- 1; /* some BIOS might use 256 */
2492 dos_cylinders
= _sectors
/ (MAXSECTOR
* (MAXHEAD
- 1));
2493 if (dos_cylinders
< 1)
2495 else if (dos_cylinders
> MAXCYL
- 1)
2496 dos_cylinders
= MAXCYL
- 1;
2502 if (disk_type
!= NULL
) {
2503 struct disklabel
*tmplabel
;
2505 if ((tmplabel
= getdiskbyname(disk_type
)) == NULL
) {
2506 warn("bad disktype");
2509 disklabel
= *tmplabel
;
2510 } else if (F_flag
) {
2512 if (fstat(fd
, &st
) == -1) {
2516 if (st
.st_size
% 512 != 0) {
2517 warnx("%s size (%lld) is not divisible "
2518 "by sector size (%d)", disk
, (long long)st
.st_size
,
2521 disklabel
.d_secperunit
= st
.st_size
/ 512;
2522 guess_geometry(disklabel
.d_secperunit
);
2523 disklabel
.d_ncylinders
= dos_cylinders
;
2524 disklabel
.d_ntracks
= dos_heads
;
2525 disklabel
.d_nsectors
= dos_sectors
;
2526 } else if (ioctl(fd
, DIOCGDEFLABEL
, &disklabel
) == -1) {
2527 warn("DIOCGDEFLABEL");
2528 if (ioctl(fd
, DIOCGDINFO
, &disklabel
) == -1) {
2534 disksectors
= disklabel
.d_secperunit
;
2535 cylinders
= disklabel
.d_ncylinders
;
2536 heads
= disklabel
.d_ntracks
;
2537 sectors
= disklabel
.d_nsectors
;
2539 /* pick up some defaults for the BIOS sizes */
2540 if (sectors
<= MAXSECTOR
) {
2541 dos_cylinders
= cylinders
;
2543 dos_sectors
= sectors
;
2545 /* guess - has to better than the above */
2546 guess_geometry(disksectors
);
2548 dos_disksectors
= disksectors
;
2555 * Rather unfortunately the bootsel 'magic' number is at the end of the
2556 * the structure, and there is no checksum. So when other operating
2557 * systems install mbr code by only writing the length of their code they
2558 * can overwrite part of the structure but keeping the magic number intact.
2559 * This code attempts to empirically detect this problem.
2562 validate_bootsel(struct mbr_bootsel
*mbs
)
2564 unsigned int key
= mbs
->mbrbs_defkey
;
2572 * Check default key is sane
2573 * - this is the most likely field to be stuffed
2574 * 16 disks and 16 bootable partitions seems enough!
2575 * (the keymap decode starts falling apart at that point)
2577 if (mbs
->mbrbs_flags
& MBR_BS_ASCII
) {
2578 if (key
!= 0 && !(key
== '\r'
2579 || (key
>= '1' && key
< '1' + MAX_BIOS_DISKS
)
2580 || (key
>= 'a' && key
< 'a' + MAX_BIOS_DISKS
)))
2583 if (key
!= 0 && !(key
== SCAN_ENTER
2584 || (key
>= SCAN_1
&& key
< SCAN_1
+ MAX_BIOS_DISKS
)
2585 || (key
>= SCAN_F1
&& key
< SCAN_F1
+ MAX_BIOS_DISKS
)))
2589 /* Checking the flags will lead to breakage... */
2591 /* Timeout value is expected to be a multiple of a second */
2592 tmo
= htole16(mbs
->mbrbs_timeo
);
2593 if (tmo
!= 0 && tmo
!= 0xffff && tmo
!= (10 * tmo
+ 9) / 182 * 182 / 10)
2596 /* Check the menu strings are printable */
2597 /* Unfortunately they aren't zero filled... */
2598 for (i
= 0; i
< sizeof(mbs
->mbrbs_nametab
); i
++) {
2599 int c
= (uint8_t)mbs
->mbrbs_nametab
[0][i
];
2600 if (c
== 0 || isprint(c
))
2610 read_s0(daddr_t offset
, struct mbr_sector
*boot
)
2612 const char *tabletype
= offset
? "extended" : "primary";
2614 static int reported
;
2617 if (read_disk(offset
, boot
) == -1) {
2618 warn("Can't read %s partition table", tabletype
);
2621 if (boot
->mbr_magic
!= LE_MBR_MAGIC
) {
2622 warnx("%s partition table invalid, "
2623 "no magic in sector %"PRIdaddr
, tabletype
, offset
);
2628 if (boot
->mbr_bootsel_magic
== LE_MBR_BS_MAGIC
) {
2629 /* mbr_bootsel in new location */
2630 if (validate_bootsel(&boot
->mbr_bootsel
)) {
2631 warnx("removing corrupt bootsel information");
2632 boot
->mbr_bootsel_magic
= 0;
2636 if (boot
->mbr_bootsel_magic
!= LE_MBR_MAGIC
)
2639 /* mbr_bootsel in old location */
2641 warnx("%s partition table: using old-style bootsel information",
2644 if (validate_bootsel((void *)((uint8_t *)boot
+ MBR_BS_OFFSET
+ 4))) {
2645 warnx("%s bootsel information corrupt - ignoring", tabletype
);
2648 memmove((uint8_t *)boot
+ MBR_BS_OFFSET
,
2649 (uint8_t *)boot
+ MBR_BS_OFFSET
+ 4,
2650 sizeof(struct mbr_bootsel
));
2651 if ( ! (boot
->mbr_bootsel
.mbrbs_flags
& MBR_BS_NEWMBR
)) {
2652 /* old style default key */
2654 /* F1..F4 => ptn 0..3, F5+ => disk 0+ */
2655 id
= boot
->mbr_bootsel
.mbrbs_defkey
;
2657 if (id
>= MBR_PART_COUNT
)
2658 id
-= MBR_PART_COUNT
; /* Use number of disk */
2659 else if (mboot
.mbr_parts
[id
].mbrp_type
!= 0)
2660 id
= le32toh(boot
->mbr_parts
[id
].mbrp_start
);
2662 id
= DEFAULT_ACTIVE
;
2663 boot
->mbr_bootsel
.mbrbs_defkey
= id
;
2665 boot
->mbr_bootsel_magic
= LE_MBR_BS_MAGIC
;
2666 /* highlight that new bootsel code is necessary */
2667 boot
->mbr_bootsel
.mbrbs_flags
&= ~MBR_BS_NEWMBR
;
2668 #endif /* BOOTSEL */
2680 * write enable label sector before write (if necessary),
2681 * disable after writing.
2682 * needed if the disklabel protected area also protects
2683 * sector 0. (e.g. empty disk)
2686 if (wfd
== fd
&& F_flag
== 0 && ioctl(wfd
, DIOCWLABEL
, &flag
) < 0)
2688 if (write_disk(0, &mboot
) == -1) {
2689 warn("Can't write fdisk partition table");
2693 for (i
= bootsize
; (i
-= 0x200) > 0;)
2694 if (write_disk(i
/ 0x200, &bootcode
[i
/ 0x200]) == -1) {
2695 warn("Can't write bootcode");
2698 for (offset
= 0, i
= 0; i
< ext
.num_ptn
; i
++) {
2699 if (write_disk(ext
.base
+ offset
, ext
.ptn
+ i
) == -1) {
2700 warn("Can't write %dth extended partition", i
);
2703 offset
= le32toh(ext
.ptn
[i
].mbr_parts
[1].mbrp_start
);
2708 if (wfd
== fd
&& F_flag
== 0 && ioctl(wfd
, DIOCWLABEL
, &flag
) < 0)
2714 yesno(const char *str
, ...)
2724 first
= ch
= getchar();
2725 while (ch
!= '\n' && ch
!= EOF
)
2729 return (first
== 'y' || first
== 'Y');
2733 decimal(const char *prompt
, int64_t dflt
, int flags
, int64_t minval
, int64_t maxval
)
2741 if (flags
& DEC_SEC
) {
2742 printf("%s: [%" PRId64
"..%" PRId64
"cyl default: %" PRId64
", %" PRId64
"cyl, %uMB] ",
2743 prompt
, SEC_TO_CYL(minval
), SEC_TO_CYL(maxval
),
2744 dflt
, SEC_TO_CYL(dflt
), SEC_TO_MB(dflt
));
2746 printf("%s: [%" PRId64
"..%" PRId64
" default: %" PRId64
"] ",
2747 prompt
, minval
, maxval
, dflt
);
2749 if (!fgets(lbuf
, LBUF
, stdin
))
2753 cp
+= strspn(cp
, " \t");
2757 if (cp
[0] == '$' && cp
[1] == '\n')
2760 if (isdigit((unsigned char)*cp
) || *cp
== '-') {
2761 acc
= strtoll(lbuf
, &cp
, 10);
2762 len
= strcspn(cp
, " \t\n");
2764 if (len
!= 0 && (flags
& DEC_SEC
)) {
2765 if (!strncasecmp(cp
, "gb", len
)) {
2769 if (valid
|| !strncasecmp(cp
, "mb", len
)) {
2771 /* round to whole number of cylinders */
2772 acc
+= ptn_alignment
/ 2;
2773 acc
/= ptn_alignment
;
2776 if (valid
|| !strncasecmp(cp
, "cyl", len
)) {
2777 acc
*= ptn_alignment
;
2778 /* adjustments for cylinder boundary */
2779 if (acc
== 0 && flags
& DEC_RND_0
)
2780 acc
+= ptn_0_offset
;
2781 if (flags
& DEC_RND
)
2782 acc
+= ptn_0_offset
;
2783 if (flags
& DEC_RND_DOWN
)
2784 acc
-= ptn_0_offset
;
2785 if (flags
& DEC_RND_DOWN_2
)
2786 acc
-= ptn_0_offset
;
2792 cp
+= strspn(cp
, " \t");
2794 lbuf
[strlen(lbuf
) - 1] = 0;
2795 printf("%s is not a valid %s number.\n", lbuf
,
2796 flags
& DEC_SEC
? "sector" : "decimal");
2800 if (acc
>= minval
&& acc
<= maxval
)
2802 printf("%" PRId64
" is not between %" PRId64
" and %" PRId64
".\n", acc
, minval
, maxval
);
2807 ptn_id(const char *prompt
, int *extended
)
2809 unsigned int acc
= 0;
2812 for (;; printf("%s is not a valid partition number.\n", lbuf
)) {
2813 printf("%s: [none] ", prompt
);
2815 if (!fgets(lbuf
, LBUF
, stdin
))
2817 lbuf
[strlen(lbuf
)-1] = '\0';
2820 cp
+= strspn(cp
, " \t");
2825 if (*cp
== 'E' || *cp
== 'e') {
2830 acc
= strtoul(cp
, &cp
, 10);
2832 cp
+= strspn(cp
, " \t");
2836 if (*extended
|| acc
< MBR_PART_COUNT
)
2843 string(const char *prompt
, int length
, char *buf
)
2848 printf("%s: [%.*s] ", prompt
, length
, buf
);
2850 if (!fgets(lbuf
, LBUF
, stdin
))
2854 /* unchanged if just <enter> */
2856 /* now strip trailing spaces, <space><enter> deletes string */
2859 while (len
!= 0 && lbuf
[len
- 1] == ' ');
2862 printf("'%s' is longer than %d characters.\n",
2865 strncpy(buf
, lbuf
, length
);
2870 type_match(const void *key
, const void *item
)
2872 const int *idp
= key
;
2873 const struct mbr_ptype
*ptr
= item
;
2885 struct mbr_ptype
*ptr
;
2887 ptr
= bsearch(&type
, mbr_ptypes
, KNOWN_SYSIDS
,
2888 sizeof(mbr_ptypes
[0]), type_match
);
2895 read_gpt(daddr_t offset
, struct gpt_hdr
*gptp
)
2898 struct gpt_hdr
*hdr
= (void *)buf
;
2899 const char *tabletype
= GPT_TYPE(offset
);
2901 if (read_disk(offset
, buf
) == -1) {
2902 warn("Can't read %s GPT header", tabletype
);
2905 (void)memcpy(gptp
, buf
, GPT_HDR_SIZE
);
2907 /* GPT CRC should be calculated with CRC field preset to zero */
2908 hdr
->hdr_crc_self
= 0;
2910 if (memcmp(gptp
->hdr_sig
, GPT_HDR_SIG
, sizeof(gptp
->hdr_sig
))
2911 || gptp
->hdr_lba_self
!= (uint64_t)offset
2912 || crc32(0, (void *)hdr
, gptp
->hdr_size
) != gptp
->hdr_crc_self
) {
2914 (void)memset(gptp
, 0, GPT_HDR_SIZE
);
2917 if (v_flag
&& gptp
->hdr_size
!= 0) {
2918 printf("Found %s GPT header CRC %"PRIu32
" "
2919 "at sector %"PRIdaddr
", backup at %"PRIdaddr
"\n",
2920 tabletype
, gptp
->hdr_crc_self
, offset
, gptp
->hdr_lba_alt
);
2922 return gptp
->hdr_size
;
2927 delete_gpt(struct gpt_hdr
*gptp
)
2930 struct gpt_hdr
*hdr
= (void *)buf
;
2932 if (gptp
->hdr_size
== 0)
2935 /* don't accidently overwrite something important */
2936 if (gptp
->hdr_lba_self
!= GPT_HDR_BLKNO
&&
2937 gptp
->hdr_lba_self
!= (uint64_t)disksectors
- 1) {
2938 warnx("given GPT header location doesn't seem correct");
2942 (void)memcpy(buf
, gptp
, GPT_HDR_SIZE
);
2944 * Don't really delete GPT, just "disable" it, so it can
2945 * be recovered later in case of mistake or something
2947 (void)memset(hdr
->hdr_sig
, 0, sizeof(gptp
->hdr_sig
));
2948 if (write_disk(gptp
->hdr_lba_self
, hdr
) == -1) {
2949 warn("can't delete %s GPT header",
2950 GPT_TYPE(gptp
->hdr_lba_self
));
2953 (void)memset(gptp
, 0, GPT_HDR_SIZE
);