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