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