GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/fdisk/mbr.c Lines: 0 108 0.0 %
Date: 2017-11-13 Branches: 0 42 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: mbr.c,v 1.67 2016/09/01 16:17:46 krw Exp $	*/
2
3
/*
4
 * Copyright (c) 1997 Tobias Weingartner
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/param.h>	/* DEV_BSIZE */
20
#include <sys/ioctl.h>
21
#include <sys/disklabel.h>
22
#include <sys/dkio.h>
23
24
#include <stdint.h>
25
#include <stdio.h>
26
#include <stdlib.h>
27
#include <string.h>
28
29
#include "disk.h"
30
#include "part.h"
31
#include "misc.h"
32
#include "mbr.h"
33
#include "gpt.h"
34
35
struct mbr initial_mbr;
36
37
static int gpt_chk_mbr(struct dos_partition *, u_int64_t);
38
39
int
40
MBR_protective_mbr(struct mbr *mbr)
41
{
42
	struct dos_partition dp[NDOSPART], dos_partition;
43
	int i;
44
45
	for (i = 0; i < NDOSPART; i++) {
46
		PRT_make(&mbr->part[i], mbr->offset, mbr->reloffset,
47
		    &dos_partition);
48
		memcpy(&dp[i], &dos_partition, sizeof(dp[i]));
49
	}
50
51
	return (gpt_chk_mbr(dp, DL_GETDSIZE(&dl)));
52
}
53
54
void
55
MBR_init_GPT(struct mbr *mbr)
56
{
57
	memset(&mbr->part, 0, sizeof(mbr->part));
58
59
	/* Use whole disk, starting after MBR.
60
	 *
61
	 * Always set the partition size to UINT32_MAX (as MS does). EFI
62
	 * firmware has been encountered that lies in unpredictable ways
63
	 * about the size of the disk, thus making it impossible to boot
64
	 * such devices.
65
	 */
66
	mbr->part[0].id = DOSPTYP_EFI;
67
	mbr->part[0].bs = 1;
68
	mbr->part[0].ns = UINT32_MAX;
69
70
	/* Fix up start/length fields. */
71
	PRT_fix_CHS(&mbr->part[0]);
72
}
73
74
void
75
MBR_init(struct mbr *mbr)
76
{
77
	extern u_int32_t b_arg;
78
	u_int64_t adj;
79
	daddr_t i;
80
81
	/*
82
	 * XXX Do *NOT* zap all MBR parts! Some archs still read initmbr
83
	 * from disk!! Just mark them inactive until -b goodness spreads
84
	 * further.
85
	 */
86
	mbr->part[0].flag = 0;
87
	mbr->part[1].flag = 0;
88
	mbr->part[2].flag = 0;
89
90
	memset(&gh, 0, sizeof(gh));
91
	memset(&gp, 0, sizeof(gp));
92
93
	mbr->part[3].flag = DOSACTIVE;
94
	mbr->signature = DOSMBR_SIGNATURE;
95
96
	/* Use whole disk. Reserve first track, or first cyl, if possible. */
97
	mbr->part[3].id = DOSPTYP_OPENBSD;
98
	if (disk.heads > 1)
99
		mbr->part[3].shead = 1;
100
	else
101
		mbr->part[3].shead = 0;
102
	if (disk.heads < 2 && disk.cylinders > 1)
103
		mbr->part[3].scyl = 1;
104
	else
105
		mbr->part[3].scyl = 0;
106
	mbr->part[3].ssect = 1;
107
108
	/* Go right to the end */
109
	mbr->part[3].ecyl = disk.cylinders - 1;
110
	mbr->part[3].ehead = disk.heads - 1;
111
	mbr->part[3].esect = disk.sectors;
112
113
	/* Fix up start/length fields */
114
	PRT_fix_BN(&mbr->part[3], 3);
115
116
#if defined(__powerpc__) || defined(__mips__)
117
	/* Now fix up for the MS-DOS boot partition on PowerPC. */
118
	mbr->part[0].flag = DOSACTIVE;	/* Boot from dos part */
119
	mbr->part[3].flag = 0;
120
	mbr->part[3].ns += mbr->part[3].bs;
121
	mbr->part[3].bs = mbr->part[0].bs + mbr->part[0].ns;
122
	mbr->part[3].ns -= mbr->part[3].bs;
123
	PRT_fix_CHS(&mbr->part[3]);
124
	if ((mbr->part[3].shead != 1) || (mbr->part[3].ssect != 1)) {
125
		/* align the partition on a cylinder boundary */
126
		mbr->part[3].shead = 0;
127
		mbr->part[3].ssect = 1;
128
		mbr->part[3].scyl += 1;
129
	}
130
	/* Fix up start/length fields */
131
	PRT_fix_BN(&mbr->part[3], 3);
132
#endif
133
#if defined(__i386__) || defined(__amd64__)
134
	if (b_arg > 0) {
135
		/* Add an EFI system partition on i386/amd64. */
136
		mbr->part[0].id = DOSPTYP_EFISYS;
137
		mbr->part[0].bs = 64;
138
		mbr->part[0].ns = b_arg;
139
		PRT_fix_CHS(&mbr->part[0]);
140
		mbr->part[3].ns += mbr->part[3].bs;
141
		mbr->part[3].bs = mbr->part[0].bs + mbr->part[0].ns;
142
		mbr->part[3].ns -= mbr->part[3].bs;
143
		PRT_fix_CHS(&mbr->part[3]);
144
	}
145
#endif
146
147
	/* Start OpenBSD MBR partition on a power of 2 block number. */
148
	i = 1;
149
	while (i < DL_SECTOBLK(&dl, mbr->part[3].bs))
150
		i *= 2;
151
	adj = DL_BLKTOSEC(&dl, i) - mbr->part[3].bs;
152
	mbr->part[3].bs += adj;
153
	mbr->part[3].ns -= adj;
154
	PRT_fix_CHS(&mbr->part[3]);
155
}
156
157
void
158
MBR_parse(struct dos_mbr *dos_mbr, off_t offset, off_t reloff, struct mbr *mbr)
159
{
160
	struct dos_partition dos_parts[NDOSPART];
161
	int i;
162
163
	memcpy(mbr->code, dos_mbr->dmbr_boot, sizeof(mbr->code));
164
	mbr->offset = offset;
165
	mbr->reloffset = reloff;
166
	mbr->signature = letoh16(dos_mbr->dmbr_sign);
167
168
	memcpy(dos_parts, dos_mbr->dmbr_parts, sizeof(dos_parts));
169
170
	for (i = 0; i < NDOSPART; i++)
171
		PRT_parse(&dos_parts[i], offset, reloff, &mbr->part[i]);
172
}
173
174
void
175
MBR_make(struct mbr *mbr, struct dos_mbr *dos_mbr)
176
{
177
	struct dos_partition dos_partition;
178
	int i;
179
180
	memcpy(dos_mbr->dmbr_boot, mbr->code, sizeof(dos_mbr->dmbr_boot));
181
	dos_mbr->dmbr_sign = htole16(DOSMBR_SIGNATURE);
182
183
	for (i = 0; i < NDOSPART; i++) {
184
		PRT_make(&mbr->part[i], mbr->offset, mbr->reloffset,
185
		    &dos_partition);
186
		memcpy(&dos_mbr->dmbr_parts[i], &dos_partition,
187
		    sizeof(dos_mbr->dmbr_parts[i]));
188
	}
189
}
190
191
void
192
MBR_print(struct mbr *mbr, char *units)
193
{
194
	int i;
195
196
	DISK_printgeometry(NULL);
197
198
	/* Header */
199
	printf("Offset: %lld\t", (long long)mbr->offset);
200
	printf("Signature: 0x%X\n", (int)mbr->signature);
201
	PRT_print(0, NULL, units);
202
203
	/* Entries */
204
	for (i = 0; i < NDOSPART; i++)
205
		PRT_print(i, &mbr->part[i], units);
206
}
207
208
int
209
MBR_read(off_t where, struct dos_mbr *dos_mbr)
210
{
211
	char *secbuf;
212
213
	secbuf = DISK_readsector(where);
214
	if (secbuf == NULL)
215
		return (-1);
216
217
	memcpy(dos_mbr, secbuf, sizeof(*dos_mbr));
218
	free(secbuf);
219
220
	return (0);
221
}
222
223
int
224
MBR_write(off_t where, struct dos_mbr *dos_mbr)
225
{
226
	char *secbuf;
227
228
	secbuf = DISK_readsector(where);
229
	if (secbuf == NULL)
230
		return (-1);
231
232
	/*
233
	 * Place the new MBR at the start of the sector and
234
	 * write the sector back to "disk".
235
	 */
236
	memcpy(secbuf, dos_mbr, sizeof(*dos_mbr));
237
	DISK_writesector(secbuf, where);
238
239
	/* Refresh in-kernel disklabel from the updated disk information. */
240
	ioctl(disk.fd, DIOCRLDINFO, 0);
241
242
	free(secbuf);
243
244
	return (0);
245
}
246
247
/*
248
 * If *dos_mbr has a 0xee or 0xef partition, nothing needs to happen. If no
249
 * such partition is present but the first or last sector on the disk has a
250
 * GPT, zero the GPT to ensure the MBR takes priority and fewer BIOSes get
251
 * confused.
252
 */
253
void
254
MBR_zapgpt(struct dos_mbr *dos_mbr, uint64_t lastsec)
255
{
256
	struct dos_partition dos_parts[NDOSPART];
257
	char *secbuf;
258
	uint64_t sig;
259
	int i;
260
261
	memcpy(dos_parts, dos_mbr->dmbr_parts, sizeof(dos_parts));
262
263
	for (i = 0; i < NDOSPART; i++)
264
		if ((dos_parts[i].dp_typ == DOSPTYP_EFI) ||
265
		    (dos_parts[i].dp_typ == DOSPTYP_EFISYS))
266
			return;
267
268
	secbuf = DISK_readsector(GPTSECTOR);
269
	if (secbuf == NULL)
270
		return;
271
272
	memcpy(&sig, secbuf, sizeof(sig));
273
	if (letoh64(sig) == GPTSIGNATURE) {
274
		memset(secbuf, 0, sizeof(sig));
275
		DISK_writesector(secbuf, GPTSECTOR);
276
	}
277
	free(secbuf);
278
279
	secbuf = DISK_readsector(lastsec);
280
	if (secbuf == NULL)
281
		return;
282
283
	memcpy(&sig, secbuf, sizeof(sig));
284
	if (letoh64(sig) == GPTSIGNATURE) {
285
		memset(secbuf, 0, sizeof(sig));
286
		DISK_writesector(secbuf, lastsec);
287
	}
288
	free(secbuf);
289
}
290
291
/*
292
 * Returns 0 if the MBR with the provided partition array is a GPT protective
293
 * MBR, and returns 1 otherwise. A GPT protective MBR would have one and only
294
 * one MBR partition, an EFI partition that either covers the whole disk or as
295
 * much of it as is possible with a 32bit size field.
296
 *
297
 * Taken from kern/subr_disk.c.
298
 *
299
 * NOTE: MS always uses a size of UINT32_MAX for the EFI partition!**
300
 */
301
int
302
gpt_chk_mbr(struct dos_partition *dp, u_int64_t dsize)
303
{
304
	struct dos_partition *dp2;
305
	int efi, found, i;
306
	u_int32_t psize;
307
308
	found = efi = 0;
309
	for (dp2=dp, i=0; i < NDOSPART; i++, dp2++) {
310
		if (dp2->dp_typ == DOSPTYP_UNUSED)
311
			continue;
312
		found++;
313
		if (dp2->dp_typ != DOSPTYP_EFI)
314
			continue;
315
		psize = letoh32(dp2->dp_size);
316
		if (psize == (dsize - 1) ||
317
		    psize == UINT32_MAX) {
318
			if (letoh32(dp2->dp_start) == 1)
319
				efi++;
320
		}
321
	}
322
	if (found == 1 && efi == 1)
323
		return (0);
324
325
	return (1);
326
}
327