GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/fdisk/mbr.c Lines: 0 113 0.0 %
Date: 2016-12-06 Branches: 0 48 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: mbr.c,v 1.65 2015/12/30 17:21:39 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
	u_int64_t sz;
58
59
	sz = DL_GETDSIZE(&dl);
60
61
	memset(&mbr->part, 0, sizeof(mbr->part));
62
63
	/* Use whole disk, starting after MBR. */
64
	mbr->part[0].id = DOSPTYP_EFI;
65
	mbr->part[0].bs = 1;
66
	if (sz > UINT32_MAX)
67
		mbr->part[0].ns = UINT32_MAX;
68
	else
69
		mbr->part[0].ns = sz - 1;
70
71
	/* Fix up start/length fields. */
72
	PRT_fix_CHS(&mbr->part[0]);
73
}
74
75
void
76
MBR_init(struct mbr *mbr)
77
{
78
	extern u_int32_t b_arg;
79
	u_int64_t adj;
80
	daddr_t i;
81
82
	/*
83
	 * XXX Do *NOT* zap all MBR parts! Some archs still read initmbr
84
	 * from disk!! Just mark them inactive until -b goodness spreads
85
	 * further.
86
	 */
87
	mbr->part[0].flag = 0;
88
	mbr->part[1].flag = 0;
89
	mbr->part[2].flag = 0;
90
91
	memset(&gh, 0, sizeof(gh));
92
	memset(&gp, 0, sizeof(gp));
93
94
	mbr->part[3].flag = DOSACTIVE;
95
	mbr->signature = DOSMBR_SIGNATURE;
96
97
	/* Use whole disk. Reserve first track, or first cyl, if possible. */
98
	mbr->part[3].id = DOSPTYP_OPENBSD;
99
	if (disk.heads > 1)
100
		mbr->part[3].shead = 1;
101
	else
102
		mbr->part[3].shead = 0;
103
	if (disk.heads < 2 && disk.cylinders > 1)
104
		mbr->part[3].scyl = 1;
105
	else
106
		mbr->part[3].scyl = 0;
107
	mbr->part[3].ssect = 1;
108
109
	/* Go right to the end */
110
	mbr->part[3].ecyl = disk.cylinders - 1;
111
	mbr->part[3].ehead = disk.heads - 1;
112
	mbr->part[3].esect = disk.sectors;
113
114
	/* Fix up start/length fields */
115
	PRT_fix_BN(&mbr->part[3], 3);
116
117
#if defined(__powerpc__) || defined(__mips__)
118
	/* Now fix up for the MS-DOS boot partition on PowerPC. */
119
	mbr->part[0].flag = DOSACTIVE;	/* Boot from dos part */
120
	mbr->part[3].flag = 0;
121
	mbr->part[3].ns += mbr->part[3].bs;
122
	mbr->part[3].bs = mbr->part[0].bs + mbr->part[0].ns;
123
	mbr->part[3].ns -= mbr->part[3].bs;
124
	PRT_fix_CHS(&mbr->part[3]);
125
	if ((mbr->part[3].shead != 1) || (mbr->part[3].ssect != 1)) {
126
		/* align the partition on a cylinder boundary */
127
		mbr->part[3].shead = 0;
128
		mbr->part[3].ssect = 1;
129
		mbr->part[3].scyl += 1;
130
	}
131
	/* Fix up start/length fields */
132
	PRT_fix_BN(&mbr->part[3], 3);
133
#endif
134
#if defined(__i386__) || defined(__amd64__)
135
	if (b_arg > 0) {
136
		/* Add an EFI system partition on i386/amd64. */
137
		mbr->part[0].id = DOSPTYP_EFISYS;
138
		mbr->part[0].bs = 64;
139
		mbr->part[0].ns = b_arg;
140
		PRT_fix_CHS(&mbr->part[0]);
141
		mbr->part[3].ns += mbr->part[3].bs;
142
		mbr->part[3].bs = mbr->part[0].bs + mbr->part[0].ns;
143
		mbr->part[3].ns -= mbr->part[3].bs;
144
		PRT_fix_CHS(&mbr->part[3]);
145
	}
146
#endif
147
148
	/* Start OpenBSD MBR partition on a power of 2 block number. */
149
	i = 1;
150
	while (i < DL_SECTOBLK(&dl, mbr->part[3].bs))
151
		i *= 2;
152
	adj = DL_BLKTOSEC(&dl, i) - mbr->part[3].bs;
153
	mbr->part[3].bs += adj;
154
	mbr->part[3].ns -= adj;
155
	PRT_fix_CHS(&mbr->part[3]);
156
}
157
158
void
159
MBR_parse(struct dos_mbr *dos_mbr, off_t offset, off_t reloff, struct mbr *mbr)
160
{
161
	struct dos_partition dos_parts[NDOSPART];
162
	int i;
163
164
	memcpy(mbr->code, dos_mbr->dmbr_boot, sizeof(mbr->code));
165
	mbr->offset = offset;
166
	mbr->reloffset = reloff;
167
	mbr->signature = letoh16(dos_mbr->dmbr_sign);
168
169
	memcpy(dos_parts, dos_mbr->dmbr_parts, sizeof(dos_parts));
170
171
	for (i = 0; i < NDOSPART; i++)
172
		PRT_parse(&dos_parts[i], offset, reloff, &mbr->part[i]);
173
}
174
175
void
176
MBR_make(struct mbr *mbr, struct dos_mbr *dos_mbr)
177
{
178
	struct dos_partition dos_partition;
179
	int i;
180
181
	memcpy(dos_mbr->dmbr_boot, mbr->code, sizeof(dos_mbr->dmbr_boot));
182
	dos_mbr->dmbr_sign = htole16(DOSMBR_SIGNATURE);
183
184
	for (i = 0; i < NDOSPART; i++) {
185
		PRT_make(&mbr->part[i], mbr->offset, mbr->reloffset,
186
		    &dos_partition);
187
		memcpy(&dos_mbr->dmbr_parts[i], &dos_partition,
188
		    sizeof(dos_mbr->dmbr_parts[i]));
189
	}
190
}
191
192
void
193
MBR_print(struct mbr *mbr, char *units)
194
{
195
	int i;
196
197
	DISK_printgeometry(NULL);
198
199
	/* Header */
200
	printf("Offset: %lld\t", (long long)mbr->offset);
201
	printf("Signature: 0x%X\n", (int)mbr->signature);
202
	PRT_print(0, NULL, units);
203
204
	/* Entries */
205
	for (i = 0; i < NDOSPART; i++)
206
		PRT_print(i, &mbr->part[i], units);
207
}
208
209
int
210
MBR_read(off_t where, struct dos_mbr *dos_mbr)
211
{
212
	char *secbuf;
213
214
	secbuf = DISK_readsector(where);
215
	if (secbuf == NULL)
216
		return (-1);
217
218
	memcpy(dos_mbr, secbuf, sizeof(*dos_mbr));
219
	free(secbuf);
220
221
	return (0);
222
}
223
224
int
225
MBR_write(off_t where, struct dos_mbr *dos_mbr)
226
{
227
	char *secbuf;
228
229
	secbuf = DISK_readsector(where);
230
	if (secbuf == NULL)
231
		return (-1);
232
233
	/*
234
	 * Place the new MBR at the start of the sector and
235
	 * write the sector back to "disk".
236
	 */
237
	memcpy(secbuf, dos_mbr, sizeof(*dos_mbr));
238
	DISK_writesector(secbuf, where);
239
240
	/* Refresh in-kernel disklabel from the updated disk information. */
241
	ioctl(disk.fd, DIOCRLDINFO, 0);
242
243
	free(secbuf);
244
245
	return (0);
246
}
247
248
/*
249
 * If *dos_mbr has a 0xee or 0xef partition, nothing needs to happen. If no
250
 * such partition is present but the first or last sector on the disk has a
251
 * GPT, zero the GPT to ensure the MBR takes priority and fewer BIOSes get
252
 * confused.
253
 */
254
void
255
MBR_zapgpt(struct dos_mbr *dos_mbr, uint64_t lastsec)
256
{
257
	struct dos_partition dos_parts[NDOSPART];
258
	char *secbuf;
259
	uint64_t sig;
260
	int i;
261
262
	memcpy(dos_parts, dos_mbr->dmbr_parts, sizeof(dos_parts));
263
264
	for (i = 0; i < NDOSPART; i++)
265
		if ((dos_parts[i].dp_typ == DOSPTYP_EFI) ||
266
		    (dos_parts[i].dp_typ == DOSPTYP_EFISYS))
267
			return;
268
269
	secbuf = DISK_readsector(GPTSECTOR);
270
	if (secbuf == NULL)
271
		return;
272
273
	memcpy(&sig, secbuf, sizeof(sig));
274
	if (letoh64(sig) == GPTSIGNATURE) {
275
		memset(secbuf, 0, sizeof(sig));
276
		DISK_writesector(secbuf, GPTSECTOR);
277
	}
278
	free(secbuf);
279
280
	secbuf = DISK_readsector(lastsec);
281
	if (secbuf == NULL)
282
		return;
283
284
	memcpy(&sig, secbuf, sizeof(sig));
285
	if (letoh64(sig) == GPTSIGNATURE) {
286
		memset(secbuf, 0, sizeof(sig));
287
		DISK_writesector(secbuf, lastsec);
288
	}
289
	free(secbuf);
290
}
291
292
/*
293
 * Returns 0 if the MBR with the provided partition array is a GPT protective
294
 * MBR, and returns 1 otherwise. A GPT protective MBR would have one and only
295
 * one MBR partition, an EFI partition that either covers the whole disk or as
296
 * much of it as is possible with a 32bit size field.
297
 *
298
 * Taken from kern/subr_disk.c.
299
 *
300
 * NOTE: MS always uses a size of UINT32_MAX for the EFI partition!**
301
 */
302
int
303
gpt_chk_mbr(struct dos_partition *dp, u_int64_t dsize)
304
{
305
	struct dos_partition *dp2;
306
	int efi, found, i;
307
	u_int32_t psize;
308
309
	found = efi = 0;
310
	for (dp2=dp, i=0; i < NDOSPART; i++, dp2++) {
311
		if (dp2->dp_typ == DOSPTYP_UNUSED)
312
			continue;
313
		found++;
314
		if (dp2->dp_typ != DOSPTYP_EFI)
315
			continue;
316
		psize = letoh32(dp2->dp_size);
317
		if (psize == (dsize - 1) ||
318
		    psize == UINT32_MAX) {
319
			if (letoh32(dp2->dp_start) == 1)
320
				efi++;
321
		}
322
	}
323
	if (found == 1 && efi == 1)
324
		return (0);
325
326
	return (1);
327
}
328