xref: /openbsd-src/sbin/fdisk/mbr.c (revision 614d0f2071fc86f1d5144ae7e56477c4d1e39d40)
1*614d0f20Skrw /*	$OpenBSD: mbr.c,v 1.124 2023/05/17 12:59:37 krw Exp $	*/
2a1705421Sweingart 
3a1705421Sweingart /*
4a1705421Sweingart  * Copyright (c) 1997 Tobias Weingartner
5a1705421Sweingart  *
610a68084Skrw  * Permission to use, copy, modify, and distribute this software for any
710a68084Skrw  * purpose with or without fee is hereby granted, provided that the above
810a68084Skrw  * copyright notice and this permission notice appear in all copies.
9a1705421Sweingart  *
1010a68084Skrw  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1110a68084Skrw  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1210a68084Skrw  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1310a68084Skrw  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1410a68084Skrw  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1510a68084Skrw  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1610a68084Skrw  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17a1705421Sweingart  */
18a1705421Sweingart 
19b9fc9a72Sderaadt #include <sys/param.h>	/* DEV_BSIZE */
20a7568474Sderaadt #include <sys/ioctl.h>
21a7568474Sderaadt #include <sys/disklabel.h>
22a7568474Sderaadt #include <sys/dkio.h>
23729290c0Skrw 
24605b5690Skrw #include <err.h>
25729290c0Skrw #include <stdio.h>
26729290c0Skrw #include <stdlib.h>
27bdf84265Skrw #include <string.h>
28abc6f793Skrw 
29a5472107Skrw #include "part.h"
30199eafeaSkrw #include "disk.h"
31a1705421Sweingart #include "misc.h"
32a1705421Sweingart #include "mbr.h"
3379bcacc5Skrw #include "gpt.h"
34108d94f1Sweingart 
35f43a9f23Skrw struct dos_mbr		default_dmbr;
36f43a9f23Skrw 
37f43a9f23Skrw void		mbr_to_dos_mbr(const struct mbr *, struct dos_mbr *);
38f43a9f23Skrw void		dos_mbr_to_mbr(const struct dos_mbr *, const uint64_t,
39f43a9f23Skrw     const uint64_t, struct mbr *);
409317a2ddSkrw 
411f546e5fSjsing void
MBR_init(struct mbr * mbr)42ac519580Skrw MBR_init(struct mbr *mbr)
434ed7cd7eSrahnds {
44d349feebSkrw 	struct dos_partition	dp;
453f3ade34Skrw 	struct prt		bootprt, obsdprt;
4608d01326Skrw 	daddr_t			daddr;
471f546e5fSjsing 
48dfcac45eSkrw 	memset(&gmbr, 0, sizeof(gmbr));
494d692ca3Skrw 	memset(&gh, 0, sizeof(gh));
504d692ca3Skrw 	memset(&gp, 0, sizeof(gp));
514d692ca3Skrw 
52f43a9f23Skrw 	if (mbr->mbr_lba_self != 0) {
53f43a9f23Skrw 		/* Extended MBR - save lba's, set sig, zap everything else. */
54f43a9f23Skrw 		memset(mbr->mbr_code, 0, sizeof(mbr->mbr_code));
55f43a9f23Skrw 		memset(mbr->mbr_prt, 0, sizeof(mbr->mbr_prt));
56f43a9f23Skrw 		mbr->mbr_signature = DOSMBR_SIGNATURE;
57f43a9f23Skrw 		return;
58f43a9f23Skrw 	}
59f43a9f23Skrw 
603f3ade34Skrw 	memset(&obsdprt, 0, sizeof(obsdprt));
613f3ade34Skrw 	memset(&bootprt, 0, sizeof(bootprt));
6207626630Skrw 
63354eded8Skrw 	if (disk.dk_bootprt.prt_ns > 0) {
64354eded8Skrw 		bootprt = disk.dk_bootprt;
65354eded8Skrw 	} else {
663f3ade34Skrw 		memcpy(&dp, &default_dmbr.dmbr_parts[0], sizeof(dp));
67*614d0f20Skrw 		PRT_dp_to_prt(&dp, 0, 0, &bootprt);
68354eded8Skrw 	}
693f3ade34Skrw 
703220ebedSkrw 	if (bootprt.prt_ns > 0) {
713220ebedSkrw 		/* Start OpenBSD partition immediately after bootprt. */
72d8f1450dSkrw 		obsdprt.prt_bs = bootprt.prt_bs + bootprt.prt_ns;
733220ebedSkrw 	} else if (disk.dk_heads > 1 || disk.dk_cylinders > 1) {
743220ebedSkrw 		/*
753220ebedSkrw 		 * Start OpenBSD partition on power of 2 block number
763220ebedSkrw 		 * after the first track.
773220ebedSkrw 		 */
7808d01326Skrw 		daddr = 1;
793220ebedSkrw 		while (daddr < DL_SECTOBLK(&dl, disk.dk_sectors))
8008d01326Skrw 			daddr *= 2;
81dd3db818Skrw 		obsdprt.prt_bs = DL_BLKTOSEC(&dl, daddr);
823220ebedSkrw 	} else {
833220ebedSkrw 		/* Start OpenBSD partition immediately after MBR. */
843220ebedSkrw 		obsdprt.prt_bs = 1;
853220ebedSkrw 	}
86bad58a6dSkrw 
874707d017Skrw 	if (obsdprt.prt_bs >= disk.dk_size) {
88bad58a6dSkrw 		memset(&obsdprt, 0, sizeof(obsdprt));
89bad58a6dSkrw 	} else {
904707d017Skrw 		obsdprt.prt_ns = disk.dk_size - obsdprt.prt_bs;
91bad58a6dSkrw 		obsdprt.prt_id = DOSPTYP_OPENBSD;
92bad58a6dSkrw 		if (bootprt.prt_flag != DOSACTIVE)
93bad58a6dSkrw 			obsdprt.prt_flag = DOSACTIVE;
94bad58a6dSkrw 	}
95561952b1Skrw 
963f3ade34Skrw 	memset(mbr, 0, sizeof(*mbr));
973f3ade34Skrw 	memcpy(mbr->mbr_code, default_dmbr.dmbr_boot, sizeof(mbr->mbr_code));
983f3ade34Skrw 	mbr->mbr_prt[0] = bootprt;
993f3ade34Skrw 	mbr->mbr_prt[3] = obsdprt;
1003f3ade34Skrw 	mbr->mbr_signature = DOSMBR_SIGNATURE;
1014ed7cd7eSrahnds }
102a1705421Sweingart 
103a1705421Sweingart void
dos_mbr_to_mbr(const struct dos_mbr * dmbr,const uint64_t lba_self,const uint64_t lba_firstembr,struct mbr * mbr)104f43a9f23Skrw dos_mbr_to_mbr(const struct dos_mbr *dmbr, const uint64_t lba_self,
1050cd9e2afSkrw     const uint64_t lba_firstembr, struct mbr *mbr)
106a1705421Sweingart {
1073dbb6cecSkrw 	struct dos_partition	dos_parts[NDOSPART];
1083d40667eSkrw 	uint8_t			*p;
1093d40667eSkrw 	unsigned int		 i;
1103d40667eSkrw 
1113d40667eSkrw 	p = (uint8_t *)dmbr;
1123d40667eSkrw 	mbr->mbr_dmbrzeros = 0;
1133d40667eSkrw 	for (i = 0; i < sizeof(struct dos_mbr) && *p == 0; i++, p++)
1143d40667eSkrw 		mbr->mbr_dmbrzeros++;
115a1705421Sweingart 
116f43a9f23Skrw 	memcpy(mbr->mbr_code, dmbr->dmbr_boot, sizeof(mbr->mbr_code));
117061e6e0aSkrw 	mbr->mbr_lba_self = lba_self;
118061e6e0aSkrw 	mbr->mbr_lba_firstembr = lba_firstembr;
119f43a9f23Skrw 	mbr->mbr_signature = letoh16(dmbr->dmbr_sign);
120a1705421Sweingart 
121f43a9f23Skrw 	memcpy(dos_parts, dmbr->dmbr_parts, sizeof(dos_parts));
1223dbb6cecSkrw 
123c5431474Skrw 	for (i = 0; i < nitems(mbr->mbr_prt); i++) {
124c5431474Skrw 		memset(&mbr->mbr_prt[i], 0, sizeof(mbr->mbr_prt[i]));
125c5431474Skrw 		if (i < nitems(dmbr->dmbr_parts))
126*614d0f20Skrw 			PRT_dp_to_prt(&dos_parts[i], lba_self, lba_firstembr,
127061e6e0aSkrw 			    &mbr->mbr_prt[i]);
12853f15ebcSkrw 	}
129c5431474Skrw }
130a1705421Sweingart 
131a1705421Sweingart void
mbr_to_dos_mbr(const struct mbr * mbr,struct dos_mbr * dos_mbr)132f43a9f23Skrw mbr_to_dos_mbr(const struct mbr *mbr, struct dos_mbr *dos_mbr)
133a1705421Sweingart {
13453f15ebcSkrw 	struct dos_partition	dos_partition;
135c5431474Skrw 	unsigned int		i;
136a1705421Sweingart 
137061e6e0aSkrw 	memcpy(dos_mbr->dmbr_boot, mbr->mbr_code, sizeof(dos_mbr->dmbr_boot));
13853f15ebcSkrw 	dos_mbr->dmbr_sign = htole16(DOSMBR_SIGNATURE);
139a1705421Sweingart 
140c5431474Skrw 	for (i = 0; i < nitems(dos_mbr->dmbr_parts); i++) {
141c5431474Skrw 		memset(&dos_partition, 0, sizeof(dos_partition));
142c5431474Skrw 		if (i < nitems(mbr->mbr_prt)) {
143*614d0f20Skrw 			PRT_prt_to_dp(&mbr->mbr_prt[i], mbr->mbr_lba_self,
14499e0469cSkrw 			    mbr->mbr_lba_firstembr, &dos_partition);
145c5431474Skrw 		}
14653f15ebcSkrw 		memcpy(&dos_mbr->dmbr_parts[i], &dos_partition,
14753f15ebcSkrw 		    sizeof(dos_mbr->dmbr_parts[i]));
14853f15ebcSkrw 	}
149a1705421Sweingart }
150a1705421Sweingart 
151a1705421Sweingart void
MBR_print(const struct mbr * mbr,const char * units)152859be6c9Skrw MBR_print(const struct mbr *mbr, const char *units)
153a1705421Sweingart {
1545f7fe693Skrw 	unsigned int		i;
155a1705421Sweingart 
1566c51fc53Skrw 	DISK_printgeometry("s");
157fba7235cSkrw 
158530f0457Skrw 	printf("Offset: %llu\t", mbr->mbr_lba_self);
159061e6e0aSkrw 	printf("Signature: 0x%X\n", (int)mbr->mbr_signature);
1607b70791fSkrw 	PRT_print_parthdr();
161a1705421Sweingart 
1625f7fe693Skrw 	for (i = 0; i < nitems(mbr->mbr_prt); i++)
1637b70791fSkrw 		PRT_print_part(i, &mbr->mbr_prt[i], units);
164a1705421Sweingart }
165a1705421Sweingart 
166a1705421Sweingart int
MBR_read(const uint64_t lba_self,const uint64_t lba_firstembr,struct mbr * mbr)1671429e715Skrw MBR_read(const uint64_t lba_self, const uint64_t lba_firstembr, struct mbr *mbr)
168a1705421Sweingart {
1691429e715Skrw 	struct dos_mbr		 dos_mbr;
170a1705421Sweingart 
171adf35c80Skrw 	if (DISK_readbytes(&dos_mbr, lba_self, sizeof(dos_mbr)))
1722a536aa2Skrw 		return -1;
173d1f880e6Skrw 
174f43a9f23Skrw 	dos_mbr_to_mbr(&dos_mbr, lba_self, lba_firstembr, mbr);
1751429e715Skrw 
1762a536aa2Skrw 	return 0;
177a1705421Sweingart }
178a1705421Sweingart 
179a1705421Sweingart int
MBR_write(const struct mbr * mbr)180e79775dbSkrw MBR_write(const struct mbr *mbr)
181a1705421Sweingart {
182e79775dbSkrw 	struct dos_mbr		 dos_mbr;
183d1f880e6Skrw 
184f43a9f23Skrw 	mbr_to_dos_mbr(mbr, &dos_mbr);
185e79775dbSkrw 
186adf35c80Skrw 	if (DISK_writebytes(&dos_mbr, mbr->mbr_lba_self, sizeof(dos_mbr)))
187605b5690Skrw 		return -1;
18834be3939Skrw 
18934be3939Skrw 	/* Refresh in-kernel disklabel from the updated disk information. */
190605b5690Skrw 	if (ioctl(disk.dk_fd, DIOCRLDINFO, 0) == -1)
191605b5690Skrw 		warn("DIOCRLDINFO");
1923f4f9081Skrw 
1932a536aa2Skrw 	return 0;
194a1705421Sweingart }
1959ba61043Skrw 
1969ba61043Skrw int
MBR_valid_prt(const struct mbr * mbr)1979ba61043Skrw MBR_valid_prt(const struct mbr *mbr)
1989ba61043Skrw {
1999ba61043Skrw 	uint64_t		bs, ns;
2009ba61043Skrw 	unsigned int		i, nprt;
2019ba61043Skrw 	unsigned char		id;
2029ba61043Skrw 
2033d40667eSkrw 	if (mbr->mbr_dmbrzeros == sizeof(struct dos_mbr))
2043d40667eSkrw 		return 1;	/* All zeros struct dos_mbr is editable. */
2053d40667eSkrw 
2069ba61043Skrw 	nprt = 0;
2075f7fe693Skrw 	for (i = 0; i < nitems(mbr->mbr_prt); i++) {
2089ba61043Skrw 		bs = mbr->mbr_prt[i].prt_bs;
2099ba61043Skrw 		ns = mbr->mbr_prt[i].prt_ns;
2109ba61043Skrw 		id = mbr->mbr_prt[i].prt_id;
2119ba61043Skrw 		if ((bs == 0 && ns == 0 && id == 0) ||
2129ba61043Skrw 		    (bs < DL_GETDSIZE(&dl) && ns > 0 && ns <= DL_GETDSIZE(&dl)))
2139ba61043Skrw 			nprt++;
2149ba61043Skrw 	}
2159ba61043Skrw 
2169ba61043Skrw 	return nprt > 0 && mbr->mbr_signature == DOSMBR_SIGNATURE;
2179ba61043Skrw }
218