xref: /openbsd/sbin/fdisk/mbr.c (revision 8932bfb7)
1 /*	$OpenBSD: mbr.c,v 1.27 2011/06/20 19:10:41 krw Exp $	*/
2 
3 /*
4  * Copyright (c) 1997 Tobias Weingartner
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <err.h>
29 #include <errno.h>
30 #include <util.h>
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34 #include <memory.h>
35 #include <sys/fcntl.h>
36 #include <sys/ioctl.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <sys/disklabel.h>
40 #include <sys/dkio.h>
41 #include <machine/param.h>
42 #include "disk.h"
43 #include "misc.h"
44 #include "mbr.h"
45 #include "part.h"
46 
47 
48 void
49 MBR_init(disk_t *disk, mbr_t *mbr)
50 {
51 	daddr64_t i;
52 	int adj;
53 
54 	/* Fix up given mbr for this disk */
55 	mbr->part[0].flag = 0;
56 	mbr->part[1].flag = 0;
57 	mbr->part[2].flag = 0;
58 
59 	mbr->part[3].flag = DOSACTIVE;
60 	mbr->signature = DOSMBR_SIGNATURE;
61 
62 	/* Use whole disk, save for first head, on first cyl. */
63 	mbr->part[3].id = DOSPTYP_OPENBSD;
64 	mbr->part[3].scyl = 0;
65 	mbr->part[3].shead = 1;
66 	mbr->part[3].ssect = 1;
67 
68 	/* Go right to the end */
69 	mbr->part[3].ecyl = disk->real->cylinders - 1;
70 	mbr->part[3].ehead = disk->real->heads - 1;
71 	mbr->part[3].esect = disk->real->sectors;
72 
73 	/* Fix up start/length fields */
74 	PRT_fix_BN(disk, &mbr->part[3], 3);
75 
76 #if defined(__powerpc__) || defined(__mips__)
77 	/* Now fix up for the MS-DOS boot partition on PowerPC. */
78 	mbr->part[0].flag = DOSACTIVE;	/* Boot from dos part */
79 	mbr->part[3].flag = 0;
80 	mbr->part[3].ns += mbr->part[3].bs;
81 	mbr->part[3].bs = mbr->part[0].bs + mbr->part[0].ns;
82 	mbr->part[3].ns -= mbr->part[3].bs;
83 	PRT_fix_CHS(disk, &mbr->part[3]);
84 	if ((mbr->part[3].shead != 1) || (mbr->part[3].ssect != 1)) {
85 		/* align the partition on a cylinder boundary */
86 		mbr->part[3].shead = 0;
87 		mbr->part[3].ssect = 1;
88 		mbr->part[3].scyl += 1;
89 	}
90 	/* Fix up start/length fields */
91 	PRT_fix_BN(disk, &mbr->part[3], 3);
92 #endif
93 
94 	/* Start OpenBSD MBR partition on a power of 2 block number. */
95 	i = 1;
96 	while (i < DL_SECTOBLK(&dl, mbr->part[3].bs))
97 		i *= 2;
98 	i = DL_BLKTOSEC(&dl, i);
99 	adj = i - mbr->part[3].bs;
100 	mbr->part[3].bs += adj;
101 	mbr->part[3].ns -= adj;
102 	PRT_fix_CHS(disk, &mbr->part[3]);
103 }
104 
105 void
106 MBR_parse(disk_t *disk, char *mbr_buf, off_t offset, off_t reloff, mbr_t *mbr)
107 {
108 	int i;
109 
110 	memcpy(mbr->code, mbr_buf, MBR_CODE_SIZE);
111 	mbr->offset = offset;
112 	mbr->reloffset = reloff;
113 	mbr->signature = getshort(&mbr_buf[MBR_SIG_OFF]);
114 
115 	for (i = 0; i < NDOSPART; i++)
116 		PRT_parse(disk, &mbr_buf[MBR_PART_OFF + MBR_PART_SIZE * i],
117 		    offset, reloff, &mbr->part[i]);
118 }
119 
120 void
121 MBR_make(mbr_t *mbr, char *mbr_buf)
122 {
123 	int i;
124 
125 	memcpy(mbr_buf, mbr->code, MBR_CODE_SIZE);
126 	putshort(&mbr_buf[MBR_SIG_OFF], mbr->signature);
127 
128 	for (i = 0; i < NDOSPART; i++)
129 		PRT_make(&mbr->part[i], mbr->offset, mbr->reloffset,
130 		    &mbr_buf[MBR_PART_OFF + MBR_PART_SIZE * i]);
131 }
132 
133 void
134 MBR_print(mbr_t *mbr, char *units)
135 {
136 	int i;
137 
138 	/* Header */
139 	printf("Signature: 0x%X\n",
140 	    (int)mbr->signature);
141 	PRT_print(0, NULL, units);
142 
143 	/* Entries */
144 	for (i = 0; i < NDOSPART; i++)
145 		PRT_print(i, &mbr->part[i], units);
146 }
147 
148 int
149 MBR_read(int fd, off_t where, char *buf)
150 {
151 	const int secsize = unit_types[SECTORS].conversion;
152 	ssize_t len;
153 	off_t off;
154 	char *secbuf;
155 
156 	where *= secsize;
157 	off = lseek(fd, where, SEEK_SET);
158 	if (off != where)
159 		return (-1);
160 
161 	secbuf = malloc(secsize);
162 	if (secbuf == NULL)
163 		return (-1);
164 	bzero(secbuf, secsize);
165 
166 	len = read(fd, secbuf, secsize);
167 	bcopy(secbuf, buf, DEV_BSIZE);
168 	free(secbuf);
169 
170 	if (len == -1)
171 		return (-1);
172 	if (len < DEV_BSIZE) {
173 		/* short read */
174 		errno = EIO;
175 		return (-1);
176 	}
177 
178 	return (0);
179 }
180 
181 int
182 MBR_write(int fd, off_t where, char *buf)
183 {
184 	const int secsize = unit_types[SECTORS].conversion;
185 	ssize_t len;
186 	off_t off;
187 	char *secbuf;
188 
189 	/* Read the sector we want to store the MBR in. */
190 	where *= secsize;
191 	off = lseek(fd, where, SEEK_SET);
192 	if (off != where)
193 		return (-1);
194 
195 	secbuf = malloc(secsize);
196 	if (secbuf == NULL)
197 		return (-1);
198 	bzero(secbuf, secsize);
199 
200 	len = read(fd, secbuf, secsize);
201 	if (len == -1 || len != secsize)
202 		goto done;
203 
204 	/*
205 	 * Place the new MBR in the first DEV_BSIZE bytes of the sector and
206 	 * write the sector back to "disk".
207 	 */
208 	bcopy(buf, secbuf, DEV_BSIZE);
209 	off = lseek(fd, where, SEEK_SET);
210 	if (off == where)
211 		len = write(fd, secbuf, secsize);
212 	else
213 		len = -1;
214 
215 done:
216 	free(secbuf);
217 	if (len == -1)
218 		return (-1);
219 	if (len != secsize) {
220 		/* short read or write */
221 		errno = EIO;
222 		return (-1);
223 	}
224 
225 	ioctl(fd, DIOCRLDINFO, 0);
226 	return (0);
227 }
228 
229 /*
230  * Copy partition table from the disk indicated
231  * to the supplied mbr structure
232  */
233 void
234 MBR_pcopy(disk_t *disk, mbr_t *mbr)
235 {
236 	int i, fd, error, offset = 0, reloff = 0;
237 	mbr_t mbrd;
238 	char mbr_disk[DEV_BSIZE];
239 
240 	fd = DISK_open(disk->name, O_RDONLY);
241 	error = MBR_read(fd, offset, mbr_disk);
242 	close(fd);
243 	if (error == -1)
244 		return;
245 	MBR_parse(disk, mbr_disk, offset, reloff, &mbrd);
246 	for (i = 0; i < NDOSPART; i++) {
247 		PRT_parse(disk, &mbr_disk[MBR_PART_OFF +
248 		    MBR_PART_SIZE * i],
249 		    offset, reloff, &mbr->part[i]);
250 	}
251 }
252