xref: /openbsd/sbin/fdisk/mbr.c (revision 404b540a)
1 /*	$OpenBSD: mbr.c,v 1.24 2009/02/08 18:03:18 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 	/* Fix up given mbr for this disk */
52 	mbr->part[0].flag = 0;
53 	mbr->part[1].flag = 0;
54 	mbr->part[2].flag = 0;
55 
56 	mbr->part[3].flag = DOSACTIVE;
57 	mbr->signature = DOSMBR_SIGNATURE;
58 
59 	/* Use whole disk, save for first head, on first cyl. */
60 	mbr->part[3].id = DOSPTYP_OPENBSD;
61 	mbr->part[3].scyl = 0;
62 	mbr->part[3].shead = 1;
63 	mbr->part[3].ssect = 1;
64 
65 	/* Go right to the end */
66 	mbr->part[3].ecyl = disk->real->cylinders - 1;
67 	mbr->part[3].ehead = disk->real->heads - 1;
68 	mbr->part[3].esect = disk->real->sectors;
69 
70 	/* Fix up start/length fields */
71 	PRT_fix_BN(disk, &mbr->part[3], 3);
72 
73 #if defined(__powerpc__) || defined(__mips__)
74 	/* Now fix up for the MS-DOS boot partition on PowerPC. */
75 	mbr->part[0].flag = DOSACTIVE;	/* Boot from dos part */
76 	mbr->part[3].flag = 0;
77 	mbr->part[3].ns += mbr->part[3].bs;
78 	mbr->part[3].bs = mbr->part[0].bs + mbr->part[0].ns;
79 	mbr->part[3].ns -= mbr->part[3].bs;
80 	PRT_fix_CHS(disk, &mbr->part[3]);
81 	if ((mbr->part[3].shead != 1) || (mbr->part[3].ssect != 1)) {
82 		/* align the partition on a cylinder boundary */
83 		mbr->part[3].shead = 0;
84 		mbr->part[3].ssect = 1;
85 		mbr->part[3].scyl += 1;
86 	}
87 	/* Fix up start/length fields */
88 	PRT_fix_BN(disk, &mbr->part[3], 3);
89 #endif
90 }
91 
92 void
93 MBR_parse(disk_t *disk, char *mbr_buf, off_t offset, off_t reloff, mbr_t *mbr)
94 {
95 	int i;
96 
97 	memcpy(mbr->code, mbr_buf, MBR_CODE_SIZE);
98 	mbr->offset = offset;
99 	mbr->reloffset = reloff;
100 	mbr->signature = getshort(&mbr_buf[MBR_SIG_OFF]);
101 
102 	for (i = 0; i < NDOSPART; i++)
103 		PRT_parse(disk, &mbr_buf[MBR_PART_OFF + MBR_PART_SIZE * i],
104 		    offset, reloff, &mbr->part[i]);
105 }
106 
107 void
108 MBR_make(mbr_t *mbr, char *mbr_buf)
109 {
110 	int i;
111 
112 	memcpy(mbr_buf, mbr->code, MBR_CODE_SIZE);
113 	putshort(&mbr_buf[MBR_SIG_OFF], mbr->signature);
114 
115 	for (i = 0; i < NDOSPART; i++)
116 		PRT_make(&mbr->part[i], mbr->offset, mbr->reloffset,
117 		    &mbr_buf[MBR_PART_OFF + MBR_PART_SIZE * i]);
118 }
119 
120 void
121 MBR_print(mbr_t *mbr, char *units)
122 {
123 	int i;
124 
125 	/* Header */
126 	printf("Signature: 0x%X\n",
127 	    (int)mbr->signature);
128 	PRT_print(0, NULL, units);
129 
130 	/* Entries */
131 	for (i = 0; i < NDOSPART; i++)
132 		PRT_print(i, &mbr->part[i], units);
133 }
134 
135 int
136 MBR_read(int fd, off_t where, char *buf)
137 {
138 	const int secsize = unit_types[SECTORS].conversion;
139 	ssize_t len;
140 	off_t off;
141 	char *secbuf;
142 
143 	where *= secsize;
144 	off = lseek(fd, where, SEEK_SET);
145 	if (off != where)
146 		return (-1);
147 
148 	secbuf = malloc(secsize);
149 	if (secbuf == NULL)
150 		return (-1);
151 	bzero(secbuf, secsize);
152 
153 	len = read(fd, secbuf, secsize);
154 	bcopy(secbuf, buf, DEV_BSIZE);
155 	free(secbuf);
156 
157 	if (len == -1)
158 		return (-1);
159 	if (len != secsize) {
160 		/* short read */
161 		errno = EIO;
162 		return (-1);
163 	}
164 
165 	return (0);
166 }
167 
168 int
169 MBR_write(int fd, off_t where, char *buf)
170 {
171 	const int secsize = unit_types[SECTORS].conversion;
172 	ssize_t len;
173 	off_t off;
174 	char *secbuf;
175 
176 	/* Read the sector we want to store the MBR in. */
177 	where *= secsize;
178 	off = lseek(fd, where, SEEK_SET);
179 	if (off != where)
180 		return (-1);
181 
182 	secbuf = malloc(secsize);
183 	if (secbuf == NULL)
184 		return (-1);
185 	bzero(secbuf, secsize);
186 
187 	len = read(fd, secbuf, secsize);
188 	if (len == -1 || len != secsize)
189 		goto done;
190 
191 	/*
192 	 * Place the new MBR in the first DEV_BSIZE bytes of the sector and
193 	 * write the sector back to "disk".
194 	 */
195 	bcopy(buf, secbuf, DEV_BSIZE);
196 	off = lseek(fd, where, SEEK_SET);
197 	if (off == where)
198 		len = write(fd, secbuf, secsize);
199 	else
200 		len = -1;
201 
202 done:
203 	free(secbuf);
204 	if (len == -1)
205 		return (-1);
206 	if (len != secsize) {
207 		/* short read or write */
208 		errno = EIO;
209 		return (-1);
210 	}
211 
212 	ioctl(fd, DIOCRLDINFO, 0);
213 	return (0);
214 }
215 
216 /*
217  * Copy partition table from the disk indicated
218  * to the supplied mbr structure
219  */
220 void
221 MBR_pcopy(disk_t *disk, mbr_t *mbr)
222 {
223 	int i, fd, offset = 0, reloff = 0;
224 	mbr_t mbrd;
225 	char mbr_disk[DEV_BSIZE];
226 
227 	fd = DISK_open(disk->name, O_RDONLY);
228 	MBR_read(fd, offset, mbr_disk);
229 	close(fd);
230 	MBR_parse(disk, mbr_disk, offset, reloff, &mbrd);
231 	for (i = 0; i < NDOSPART; i++) {
232 		PRT_parse(disk, &mbr_disk[MBR_PART_OFF +
233 		    MBR_PART_SIZE * i],
234 		    offset, reloff, &mbr->part[i]);
235 	}
236 }
237