1/* 2 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 25/* 26 * Copyright (c) 1997 Tobias Weingartner 27 * All rights reserved. 28 * 29 * Redistribution and use in source and binary forms, with or without 30 * modification, are permitted provided that the following conditions 31 * are met: 32 * 1. Redistributions of source code must retain the above copyright 33 * notice, this list of conditions and the following disclaimer. 34 * 2. Redistributions in binary form must reproduce the above copyright 35 * notice, this list of conditions and the following disclaimer in the 36 * documentation and/or other materials provided with the distribution. 37 * 3. All advertising materials mentioning features or use of this software 38 * must display the following acknowledgement: 39 * This product includes software developed by Tobias Weingartner. 40 * 4. The name of the author may not be used to endorse or promote products 41 * derived from this software without specific prior written permission. 42 * 43 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 44 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 45 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 46 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 47 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 48 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 49 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 50 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 51 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 52 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 53 */ 54 55#include <err.h> 56#include <util.h> 57#include <stdio.h> 58#include <string.h> 59#include <unistd.h> 60#include <sys/fcntl.h> 61#include <sys/types.h> 62#include <sys/stat.h> 63#include <machine/param.h> 64#include "disk.h" 65#include "misc.h" 66#include "mbr.h" 67 68 69static const struct part_type { 70 int type; 71 char sname[14]; 72 char *lname; 73} part_types[] = { 74 { 0x00, "unused ", "unused"}, 75 { 0x01, "DOS FAT-12 ", "Primary DOS with 12 bit FAT"}, 76 { 0x02, "XENIX / ", "XENIX / filesystem"}, 77 { 0x03, "XENIX /usr ", "XENIX /usr filesystem"}, 78 { 0x04, "DOS FAT-16 ", "Primary DOS with 16 bit FAT"}, 79 { 0x05, "Extended DOS", "Extended DOS"}, 80 { 0x06, "DOS > 32MB ", "Primary 'big' DOS (> 32MB)"}, 81 { 0x07, "HPFS/QNX/AUX", "OS/2 HPFS, QNX-2 or Advanced UNIX"}, 82 { 0x08, "AIX fs ", "AIX filesystem"}, 83 { 0x09, "AIX/Coherent", "AIX boot partition or Coherent"}, 84 { 0x0A, "OS/2 Bootmgr", "OS/2 Boot Manager or OPUS"}, 85 { 0x0B, "Win95 FAT-32", "Primary Win95 w/ 32-bit FAT"}, 86 { 0x0C, "Win95 FAT32L", "Primary Win95 w/ 32-bit FAT LBA-mapped"}, 87 { 0x0E, "DOS FAT-16 ", "Primary DOS w/ 16-bit FAT, CHS-mapped"}, 88 { 0x0F, "Extended LBA", "Extended DOS LBA-mapped"}, 89 { 0x10, "OPUS ", "OPUS"}, 90 { 0x11, "OS/2 hidden ", "OS/2 BM: hidden DOS 12-bit FAT"}, 91 { 0x12, "Compaq Diag.", "Compaq Diagnostics"}, 92 { 0x14, "OS/2 hidden ", "OS/2 BM: hidden DOS 16-bit FAT <32M or Novell DOS 7.0 bug"}, 93 { 0x16, "OS/2 hidden ", "OS/2 BM: hidden DOS 16-bit FAT >=32M"}, 94 { 0x17, "OS/2 hidden ", "OS/2 BM: hidden IFS"}, 95 { 0x18, "AST swap ", "AST Windows swapfile"}, 96 { 0x19, "Willowtech ", "Willowtech Photon coS"}, 97 { 0x20, "Willowsoft ", "Willowsoft OFS1"}, 98 { 0x24, "NEC DOS ", "NEC DOS"}, 99 { 0x38, "Theos ", "Theos"}, 100 { 0x39, "Plan 9 ", "Plan 9"}, 101 { 0x40, "VENIX 286 ", "VENIX 286 or LynxOS"}, 102 { 0x41, "Lin/Minux DR", "Linux/MINIX (sharing disk with DRDOS) or Personal RISC boot"}, 103 { 0x42, "LinuxSwap DR", "SFS or Linux swap (sharing disk with DRDOS)"}, 104 { 0x43, "Linux DR ", "Linux native (sharing disk with DRDOS)"}, 105 { 0x4D, "QNX 4.2 Pri ", "QNX 4.2 Primary"}, 106 { 0x4E, "QNX 4.2 Sec ", "QNX 4.2 Secondary"}, 107 { 0x4F, "QNX 4.2 Ter ", "QNX 4.2 Tertiary"}, 108 { 0x50, "DM ", "DM (disk manager)"}, 109 { 0x51, "DM ", "DM6 Aux1 (or Novell)"}, 110 { 0x52, "CP/M or SysV", "CP/M or Microport SysV/AT"}, 111 { 0x53, "DM ", "DM6 Aux3"}, 112 { 0x54, "Ontrack ", "Ontrack"}, 113 { 0x55, "EZ-Drive ", "EZ-Drive (disk manager)"}, 114 { 0x56, "Golden Bow ", "Golden Bow (disk manager)"}, 115 { 0x5C, "Priam ", "Priam Edisk (disk manager)"}, 116 { 0x61, "SpeedStor ", "SpeedStor"}, 117 { 0x63, "ISC, HURD, *", "ISC, System V/386, GNU HURD or Mach"}, 118 { 0x64, "Netware 2.xx", "Novell Netware 2.xx"}, 119 { 0x65, "Netware 3.xx", "Novell Netware 3.xx"}, 120 { 0x66, "Netware 386 ", "Novell 386 Netware"}, 121 { 0x67, "Novell ", "Novell"}, 122 { 0x68, "Novell ", "Novell"}, 123 { 0x69, "Novell ", "Novell"}, 124 { 0x70, "DiskSecure ", "DiskSecure Multi-Boot"}, 125 { 0x75, "PCIX ", "PCIX"}, 126 { 0x80, "Minix (old) ", "Minix 1.1 ... 1.4a"}, 127 { 0x81, "Minix (new) ", "Minix 1.4b ... 1.5.10"}, 128 { 0x82, "Linux swap ", "Linux swap"}, 129 { 0x83, "Linux files*", "Linux filesystem"}, 130 { 0x93, "Amoeba file*", "Amoeba filesystem"}, 131 { 0x94, "Amoeba BBT ", "Amoeba bad block table"}, 132 { 0x84, "OS/2 hidden ", "OS/2 hidden C: drive"}, 133 { 0x85, "Linux ext. ", "Linux extended"}, 134 { 0x86, "NT FAT VS ", "NT FAT volume set"}, 135 { 0x87, "NTFS VS ", "NTFS volume set or HPFS mirrored"}, 136 { 0x93, "Amoeba FS ", "Amoeba filesystem"}, 137 { 0x94, "Amoeba BBT ", "Amoeba bad block table"}, 138 { 0x99, "Mylex ", "Mylex EISA SCSI"}, 139 { 0x9F, "BSDI ", "BSDI BSD/OS"}, 140 { 0xA0, "NotebookSave", "Phoenix NoteBIOS save-to-disk"}, 141 { 0xA5, "FreeBSD ", "FreeBSD"}, 142 { 0xA6, "OpenBSD ", "OpenBSD"}, 143 { 0xA7, "NEXTSTEP ", "NEXTSTEP"}, 144 { 0xA8, "Darwin UFS ", "Darwin UFS partition"}, 145 { 0xA9, "NetBSD ", "NetBSD"}, 146 { 0xAB, "Darwin Boot ", "Darwin boot partition"}, 147 { 0xAF, "HFS+ ", "Darwin HFS+ partition"}, 148 { 0xB7, "BSDI filesy*", "BSDI BSD/386 filesystem"}, 149 { 0xB8, "BSDI swap ", "BSDI BSD/386 swap"}, 150 { 0xC0, "CTOS ", "CTOS"}, 151 { 0xC1, "DRDOSs FAT12", "DRDOS/sec (FAT-12)"}, 152 { 0xC4, "DRDOSs < 32M", "DRDOS/sec (FAT-16, < 32M)"}, 153 { 0xC6, "DRDOSs >=32M", "DRDOS/sec (FAT-16, >= 32M)"}, 154 { 0xC7, "HPFS Disbled", "Syrinx (Cyrnix?) or HPFS disabled"}, 155 { 0xDB, "CPM/C.DOS/C*", "Concurrent CPM or C.DOS or CTOS"}, 156 { 0xE1, "SpeedStor ", "DOS access or SpeedStor 12-bit FAT extended partition"}, 157 { 0xE3, "SpeedStor ", "DOS R/O or SpeedStor or Storage Dimensions"}, 158 { 0xE4, "SpeedStor ", "SpeedStor 16-bit FAT extended partition < 1024 cyl."}, 159 { 0xEB, "BeOS/i386 ", "BeOS for Intel"}, 160 { 0xF1, "SpeedStor ", "SpeedStor or Storage Dimensions"}, 161 { 0xF2, "DOS 3.3+ Sec", "DOS 3.3+ Secondary"}, 162 { 0xF4, "SpeedStor ", "SpeedStor >1024 cyl. or LANstep or IBM PS/2 IML"}, 163 { 0xFF, "Xenix BBT ", "Xenix Bad Block Table"}, 164}; 165 166void 167PRT_printall() 168{ 169 int i, idrows; 170 171 idrows = ((sizeof(part_types)/sizeof(struct part_type))+3)/4; 172 173 printf("Choose from the following Partition id values:\n"); 174 for (i = 0; i < idrows; i++) { 175 printf("%02X %s %02X %s %02X %s" 176 , part_types[i ].type, part_types[i ].sname 177 , part_types[i+idrows ].type, part_types[i+idrows ].sname 178 , part_types[i+idrows*2].type, part_types[i+idrows*2].sname 179 ); 180 if ((i+idrows*3) < (sizeof(part_types)/sizeof(struct part_type))) { 181 printf(" %02X %s\n" 182 , part_types[i+idrows*3].type, part_types[i+idrows*3].sname ); 183 } 184 else 185 printf( "\n" ); 186 } 187} 188 189const char * 190PRT_ascii_id(id) 191 int id; 192{ 193 static char unknown[] = "<Unknown ID>"; 194 int i; 195 196 for (i = 0; i < sizeof(part_types)/sizeof(struct part_type); i++) { 197 if (part_types[i].type == id) 198 return (part_types[i].sname); 199 } 200 201 return (unknown); 202} 203 204void 205PRT_parse(disk, prt, offset, reloff, partn, pn) 206 disk_t *disk; 207 void *prt; 208 off_t offset; 209 off_t reloff; 210 prt_t *partn; 211 int pn; 212{ 213 unsigned char *p = prt; 214 off_t off; 215 216 partn->flag = *p++; 217 partn->shead = *p++; 218 219 partn->ssect = (*p) & 0x3F; 220 partn->scyl = ((*p << 2) & 0xFF00) | (*(p+1)); 221 p += 2; 222 223 partn->id = *p++; 224 partn->ehead = *p++; 225 partn->esect = (*p) & 0x3F; 226 partn->ecyl = ((*p << 2) & 0xFF00) | (*(p+1)); 227 p += 2; 228 229 if ((partn->id == DOSPTYP_EXTEND) || (partn->id == DOSPTYP_EXTENDL)) 230 off = reloff; 231 else 232 off = offset; 233 234 partn->bs = getlong(p) + off; 235 partn->ns = getlong(p+4); 236 237 238 /* Zero out entry if not used */ 239 if (partn->id == DOSPTYP_UNUSED ) { 240 memset(partn, 0, sizeof(*partn)); 241 } 242} 243 244int 245PRT_check_chs(partn) 246 prt_t *partn; 247{ 248 if ( (partn->shead > 255) || 249 (partn->ssect >63) || 250 (partn->scyl > 1023) || 251 (partn->ehead >255) || 252 (partn->esect >63) || 253 (partn->ecyl > 1023) ) 254 { 255 return 0; 256 } 257 return 1; 258} 259void 260PRT_make(partn, offset, reloff, prt) 261 prt_t *partn; 262 off_t offset; 263 off_t reloff; 264 void *prt; 265{ 266 unsigned char *p = prt; 267 prt_t tmp; 268 off_t off; 269 270 tmp.shead = partn->shead; 271 tmp.ssect = partn->ssect; 272 tmp.scyl = (partn->scyl > 1023)? 1023: partn->scyl; 273 tmp.ehead = partn->ehead; 274 tmp.esect = partn->esect; 275 tmp.ecyl = (partn->ecyl > 1023)? 1023: partn->ecyl; 276 if (!PRT_check_chs(partn) && PRT_check_chs(&tmp)) { 277 partn->shead = tmp.shead; 278 partn->ssect = tmp.ssect; 279 partn->scyl = tmp.scyl; 280 partn->ehead = tmp.ehead; 281 partn->esect = tmp.esect; 282 partn->ecyl = tmp.ecyl; 283 printf("Cylinder values are modified to fit in CHS.\n"); 284 } 285 if ((partn->id == DOSPTYP_EXTEND) || (partn->id == DOSPTYP_EXTENDL)) 286 off = reloff; 287 else 288 off = offset; 289 290 if (PRT_check_chs(partn)) { 291 *p++ = partn->flag & 0xFF; 292 293 *p++ = partn->shead & 0xFF; 294 *p++ = (partn->ssect & 0x3F) | ((partn->scyl & 0x300) >> 2); 295 *p++ = partn->scyl & 0xFF; 296 297 *p++ = partn->id & 0xFF; 298 299 *p++ = partn->ehead & 0xFF; 300 *p++ = (partn->esect & 0x3F) | ((partn->ecyl & 0x300) >> 2); 301 *p++ = partn->ecyl & 0xFF; 302 } else { 303 /* should this really keep flag, id and set others to 0xff? */ 304 *p++ = partn->flag & 0xFF; 305 *p++ = 0xFF; 306 *p++ = 0xFF; 307 *p++ = 0xFF; 308 *p++ = partn->id & 0xFF; 309 *p++ = 0xFF; 310 *p++ = 0xFF; 311 *p++ = 0xFF; 312 printf("Warning CHS values out of bounds only saving LBA values\n"); 313 } 314 315 putlong(p, partn->bs - off); 316 putlong(p+4, partn->ns); 317} 318 319void 320PRT_print(num, partn) 321 int num; 322 prt_t *partn; 323{ 324 325 if (partn == NULL) { 326 printf(" Starting Ending\n"); 327 printf(" #: id cyl hd sec - cyl hd sec [ start - size]\n"); 328 printf("------------------------------------------------------------------------\n"); 329 } else { 330 printf("%c%1d: %.2X %4u %3u %3u - %4u %3u %3u [%10u - %10u] %s\n", 331 (partn->flag == 0x80)?'*':' ', 332 num + 1, partn->id, 333 partn->scyl, partn->shead, partn->ssect, 334 partn->ecyl, partn->ehead, partn->esect, 335 partn->bs, partn->ns, 336 PRT_ascii_id(partn->id)); 337 } 338} 339 340void 341PRT_fix_BN(disk, part, pn) 342 disk_t *disk; 343 prt_t *part; 344 int pn; 345{ 346 int spt, tpc, spc; 347 int start = 0; 348 int end = 0; 349 350 /* Zero out entry if not used */ 351 if (part->id == DOSPTYP_UNUSED ) { 352 memset(part, 0, sizeof(*part)); 353 return; 354 } 355 356 /* Disk metrics */ 357 spt = disk->real->sectors; 358 tpc = disk->real->heads; 359 spc = spt * tpc; 360 361 start += part->scyl * spc; 362 start += part->shead * spt; 363 start += part->ssect - 1; 364 365 end += part->ecyl * spc; 366 end += part->ehead * spt; 367 end += part->esect - 1; 368 369 /* XXX - Should handle this... */ 370 if (start > end) 371 warn("Start of partition #%d after end!", pn); 372 373 part->bs = start; 374 part->ns = (end - start) + 1; 375} 376 377void 378PRT_fix_CHS(disk, part, pn) 379 disk_t *disk; 380 prt_t *part; 381 int pn; 382{ 383 int spt, tpc, spc; 384 int start; 385 int cyl, head, sect; 386 387 /* Zero out entry if not used */ 388 if (part->id == DOSPTYP_UNUSED ) { 389 memset(part, 0, sizeof(*part)); 390 return; 391 } 392 393 /* Disk metrics */ 394 spt = disk->real->sectors; 395 tpc = disk->real->heads; 396 spc = spt * tpc; 397 398 start = part->bs; 399 400 if(start <= spt) { 401 /* Figure out "real" starting CHS values */ 402 cyl = (start / spc); start -= (cyl * spc); 403 head = (start / spt); start -= (head * spt); 404 sect = (start + 1); 405 } else { 406 cyl = 1023; 407 head = 254; 408 sect = 63; 409 } 410 411 part->scyl = cyl; 412 part->shead = head; 413 part->ssect = sect; 414 415 /* use fake geometry to trigger LBA mode */ 416 417 cyl = 1023; 418 head = 254; 419 sect = 63; 420 421 part->ecyl = cyl; 422 part->ehead = head; 423 part->esect = sect; 424} 425 426