1 /* $OpenBSD: part.c,v 1.50 2009/04/29 22:58:24 deraadt 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 <util.h> 30 #include <stdio.h> 31 #include <string.h> 32 #include <unistd.h> 33 #include <sys/fcntl.h> 34 #include <sys/types.h> 35 #include <sys/stat.h> 36 #include <sys/disklabel.h> 37 #include <machine/param.h> 38 #include "disk.h" 39 #include "misc.h" 40 #include "mbr.h" 41 42 int PRT_check_chs(prt_t *partn); 43 44 static const struct part_type { 45 int type; 46 char sname[14]; 47 } part_types[] = { 48 { 0x00, "unused "}, /* unused */ 49 { 0x01, "DOS FAT-12 "}, /* Primary DOS with 12 bit FAT */ 50 { 0x02, "XENIX / "}, /* XENIX / filesystem */ 51 { 0x03, "XENIX /usr "}, /* XENIX /usr filesystem */ 52 { 0x04, "DOS FAT-16 "}, /* Primary DOS with 16 bit FAT */ 53 { 0x05, "Extended DOS"}, /* Extended DOS */ 54 { 0x06, "DOS > 32MB "}, /* Primary 'big' DOS (> 32MB) */ 55 { 0x07, "NTFS "}, /* NTFS */ 56 { 0x08, "AIX fs "}, /* AIX filesystem */ 57 { 0x09, "AIX/Coherent"}, /* AIX boot partition or Coherent */ 58 { 0x0A, "OS/2 Bootmgr"}, /* OS/2 Boot Manager or OPUS */ 59 { 0x0B, "Win95 FAT-32"}, /* Primary Win95 w/ 32-bit FAT */ 60 { 0x0C, "Win95 FAT32L"}, /* Primary Win95 w/ 32-bit FAT LBA-mapped */ 61 { 0x0E, "DOS FAT-16 "}, /* Primary DOS w/ 16-bit FAT, CHS-mapped */ 62 { 0x0F, "Extended LBA"}, /* Extended DOS LBA-mapped */ 63 { 0x10, "OPUS "}, /* OPUS */ 64 { 0x11, "OS/2 hidden "}, /* OS/2 BM: hidden DOS 12-bit FAT */ 65 { 0x12, "Compaq Diag."}, /* Compaq Diagnostics */ 66 { 0x14, "OS/2 hidden "}, /* OS/2 BM: hidden DOS 16-bit FAT <32M or Novell DOS 7.0 bug */ 67 { 0x16, "OS/2 hidden "}, /* OS/2 BM: hidden DOS 16-bit FAT >=32M */ 68 { 0x17, "OS/2 hidden "}, /* OS/2 BM: hidden IFS */ 69 { 0x18, "AST swap "}, /* AST Windows swapfile */ 70 { 0x19, "Willowtech "}, /* Willowtech Photon coS */ 71 { 0x1C, "ThinkPad Rec"}, /* IBM ThinkPad recovery partition */ 72 { 0x20, "Willowsoft "}, /* Willowsoft OFS1 */ 73 { 0x24, "NEC DOS "}, /* NEC DOS */ 74 { 0x27, "Win Recovery"}, /* Windows hidden Recovery Partition */ 75 { 0x38, "Theos "}, /* Theos */ 76 { 0x39, "Plan 9 "}, /* Plan 9 */ 77 { 0x40, "VENIX 286 "}, /* VENIX 286 or LynxOS */ 78 { 0x41, "Lin/Minux DR"}, /* Linux/MINIX (sharing disk with DRDOS) or Personal RISC boot */ 79 { 0x42, "LinuxSwap DR"}, /* SFS or Linux swap (sharing disk with DRDOS) */ 80 { 0x43, "Linux DR "}, /* Linux native (sharing disk with DRDOS) */ 81 { 0x4D, "QNX 4.2 Pri "}, /* QNX 4.2 Primary */ 82 { 0x4E, "QNX 4.2 Sec "}, /* QNX 4.2 Secondary */ 83 { 0x4F, "QNX 4.2 Ter "}, /* QNX 4.2 Tertiary */ 84 { 0x50, "DM "}, /* DM (disk manager) */ 85 { 0x51, "DM "}, /* DM6 Aux1 (or Novell) */ 86 { 0x52, "CP/M or SysV"}, /* CP/M or Microport SysV/AT */ 87 { 0x53, "DM "}, /* DM6 Aux3 */ 88 { 0x54, "Ontrack "}, /* Ontrack */ 89 { 0x55, "EZ-Drive "}, /* EZ-Drive (disk manager) */ 90 { 0x56, "Golden Bow "}, /* Golden Bow (disk manager) */ 91 { 0x5C, "Priam "}, /* Priam Edisk (disk manager) */ 92 { 0x61, "SpeedStor "}, /* SpeedStor */ 93 { 0x63, "ISC, HURD, *"}, /* ISC, System V/386, GNU HURD or Mach */ 94 { 0x64, "NetWare 2.xx"}, /* Novell NetWare 2.xx */ 95 { 0x65, "NetWare 3.xx"}, /* Novell NetWare 3.xx */ 96 { 0x66, "NetWare 386 "}, /* Novell 386 NetWare */ 97 { 0x67, "Novell "}, /* Novell */ 98 { 0x68, "Novell "}, /* Novell */ 99 { 0x69, "Novell "}, /* Novell */ 100 { 0x70, "DiskSecure "}, /* DiskSecure Multi-Boot */ 101 { 0x75, "PCIX "}, /* PCIX */ 102 { 0x80, "Minix (old) "}, /* Minix 1.1 ... 1.4a */ 103 { 0x81, "Minix (new) "}, /* Minix 1.4b ... 1.5.10 */ 104 { 0x82, "Linux swap "}, /* Linux swap */ 105 { 0x83, "Linux files*"}, /* Linux filesystem */ 106 { 0x84, "OS/2 hidden "}, /* OS/2 hidden C: drive */ 107 { 0x85, "Linux ext. "}, /* Linux extended */ 108 { 0x86, "NT FAT VS "}, /* NT FAT volume set */ 109 { 0x87, "NTFS VS "}, /* NTFS volume set or HPFS mirrored */ 110 { 0x8E, "Linux LVM "}, /* Linux LVM */ 111 { 0x93, "Amoeba FS "}, /* Amoeba filesystem */ 112 { 0x94, "Amoeba BBT "}, /* Amoeba bad block table */ 113 { 0x99, "Mylex "}, /* Mylex EISA SCSI */ 114 { 0x9F, "BSDI "}, /* BSDI BSD/OS */ 115 { 0xA0, "NotebookSave"}, /* Phoenix NoteBIOS save-to-disk */ 116 { 0xA5, "FreeBSD "}, /* FreeBSD */ 117 { 0xA6, "OpenBSD "}, /* OpenBSD */ 118 { 0xA7, "NEXTSTEP "}, /* NEXTSTEP */ 119 { 0xA8, "MacOS X "}, /* MacOS X main partition */ 120 { 0xA9, "NetBSD "}, /* NetBSD */ 121 { 0xAB, "MacOS X boot"}, /* MacOS X boot partition */ 122 { 0xAF, "MacOS X HFS+"}, /* MacOS X HFS+ partition */ 123 { 0xB7, "BSDI filesy*"}, /* BSDI BSD/386 filesystem */ 124 { 0xB8, "BSDI swap "}, /* BSDI BSD/386 swap */ 125 { 0xBF, "Solaris "}, /* Solaris */ 126 { 0xC0, "CTOS "}, /* CTOS */ 127 { 0xC1, "DRDOSs FAT12"}, /* DRDOS/sec (FAT-12) */ 128 { 0xC4, "DRDOSs < 32M"}, /* DRDOS/sec (FAT-16, < 32M) */ 129 { 0xC6, "DRDOSs >=32M"}, /* DRDOS/sec (FAT-16, >= 32M) */ 130 { 0xC7, "HPFS Disbled"}, /* Syrinx (Cyrnix?) or HPFS disabled */ 131 { 0xDB, "CPM/C.DOS/C*"}, /* Concurrent CPM or C.DOS or CTOS */ 132 { 0xDE, "Dell Maint "}, /* Dell maintenance partition */ 133 { 0xE1, "SpeedStor "}, /* DOS access or SpeedStor 12-bit FAT extended partition */ 134 { 0xE3, "SpeedStor "}, /* DOS R/O or SpeedStor or Storage Dimensions */ 135 { 0xE4, "SpeedStor "}, /* SpeedStor 16-bit FAT extended partition < 1024 cyl. */ 136 { 0xEB, "BeOS/i386 "}, /* BeOS for Intel */ 137 { 0xEE, "EFI GPT "}, /* EFI Protective Partition */ 138 { 0xEF, "EFI Sys "}, /* EFI System Partition */ 139 { 0xF1, "SpeedStor "}, /* SpeedStor or Storage Dimensions */ 140 { 0xF2, "DOS 3.3+ Sec"}, /* DOS 3.3+ Secondary */ 141 { 0xF4, "SpeedStor "}, /* SpeedStor >1024 cyl. or LANstep or IBM PS/2 IML */ 142 { 0xFF, "Xenix BBT "}, /* Xenix Bad Block Table */ 143 }; 144 145 void 146 PRT_printall(void) 147 { 148 int i, idrows; 149 150 idrows = ((sizeof(part_types)/sizeof(struct part_type))+3)/4; 151 152 printf("Choose from the following Partition id values:\n"); 153 for (i = 0; i < idrows; i++) { 154 printf("%02X %s %02X %s %02X %s", 155 part_types[i].type, part_types[i].sname, 156 part_types[i+idrows].type, part_types[i+idrows].sname, 157 part_types[i+idrows*2].type, part_types[i+idrows*2].sname); 158 if ((i+idrows*3) < (sizeof(part_types)/sizeof(struct part_type))) { 159 printf(" %02X %s\n", 160 part_types[i+idrows*3].type, 161 part_types[i+idrows*3].sname); 162 } else 163 printf( "\n" ); 164 } 165 } 166 167 const char * 168 PRT_ascii_id(int id) 169 { 170 static char unknown[] = "<Unknown ID>"; 171 int i; 172 173 for (i = 0; i < sizeof(part_types)/sizeof(struct part_type); i++) { 174 if (part_types[i].type == id) 175 return (part_types[i].sname); 176 } 177 178 return (unknown); 179 } 180 181 void 182 PRT_parse(disk_t *disk, void *prt, off_t offset, off_t reloff, 183 prt_t *partn) 184 { 185 unsigned char *p = prt; 186 off_t off; 187 188 partn->flag = *p++; 189 partn->shead = *p++; 190 191 partn->ssect = (*p) & 0x3F; 192 partn->scyl = ((*p << 2) & 0xFF00) | (*(p+1)); 193 p += 2; 194 195 partn->id = *p++; 196 partn->ehead = *p++; 197 partn->esect = (*p) & 0x3F; 198 partn->ecyl = ((*p << 2) & 0xFF00) | (*(p+1)); 199 p += 2; 200 201 if ((partn->id == DOSPTYP_EXTEND) || (partn->id == DOSPTYP_EXTENDL)) 202 off = reloff; 203 else 204 off = offset; 205 206 partn->bs = getlong(p) + off; 207 partn->ns = getlong(p+4); 208 209 PRT_fix_CHS(disk, partn); 210 } 211 212 int 213 PRT_check_chs(prt_t *partn) 214 { 215 if ( (partn->shead > 255) || 216 (partn->ssect >63) || 217 (partn->scyl > 1023) || 218 (partn->ehead >255) || 219 (partn->esect >63) || 220 (partn->ecyl > 1023) ) 221 { 222 return 0; 223 } 224 return 1; 225 } 226 void 227 PRT_make(prt_t *partn, off_t offset, off_t reloff, void *prt) 228 { 229 unsigned char *p = prt; 230 int ecsave, scsave; 231 int modified = 0; 232 off_t off; 233 234 if ((partn->scyl > 1023) || (partn->ecyl > 1023)) { 235 scsave = partn->scyl; 236 ecsave = partn->ecyl; 237 partn->scyl = (partn->scyl > 1023)? 1023: partn->scyl; 238 partn->ecyl = (partn->ecyl > 1023)? 1023: partn->ecyl; 239 modified = 1; 240 } 241 if ((partn->id == DOSPTYP_EXTEND) || (partn->id == DOSPTYP_EXTENDL)) 242 off = reloff; 243 else 244 off = offset; 245 246 if (PRT_check_chs(partn)) { 247 *p++ = partn->flag & 0xFF; 248 249 *p++ = partn->shead & 0xFF; 250 *p++ = (partn->ssect & 0x3F) | ((partn->scyl & 0x300) >> 2); 251 *p++ = partn->scyl & 0xFF; 252 253 *p++ = partn->id & 0xFF; 254 255 *p++ = partn->ehead & 0xFF; 256 *p++ = (partn->esect & 0x3F) | ((partn->ecyl & 0x300) >> 2); 257 *p++ = partn->ecyl & 0xFF; 258 } else { 259 /* should this really keep flag, id and set others to 0xff? */ 260 *p++ = partn->flag & 0xFF; 261 *p++ = 0xFF; 262 *p++ = 0xFF; 263 *p++ = 0xFF; 264 *p++ = partn->id & 0xFF; 265 *p++ = 0xFF; 266 *p++ = 0xFF; 267 *p++ = 0xFF; 268 printf("Warning CHS values out of bounds only saving LBA values\n"); 269 } 270 271 putlong(p, partn->bs - off); 272 putlong(p+4, partn->ns); 273 if (modified) { 274 partn->scyl = scsave; 275 partn->ecyl = ecsave; 276 } 277 } 278 279 void 280 PRT_print(int num, prt_t *partn, char *units) 281 { 282 double size; 283 int i; 284 i = unit_lookup(units); 285 286 if (partn == NULL) { 287 printf(" Starting Ending LBA Info:\n"); 288 printf(" #: id C H S - C H S [ start: size ]\n"); 289 printf("-------------------------------------------------------------------------------\n"); 290 } else { 291 size = ((double)partn->ns * unit_types[SECTORS].conversion) / 292 unit_types[i].conversion; 293 printf("%c%1d: %.2X %6u %3u %3u - %6u %3u %3u [%12u:%12.0f%s] %s\n", 294 (partn->flag == 0x80)?'*':' ', 295 num, partn->id, 296 partn->scyl, partn->shead, partn->ssect, 297 partn->ecyl, partn->ehead, partn->esect, 298 partn->bs, size, 299 unit_types[i].abbr, 300 PRT_ascii_id(partn->id)); 301 } 302 } 303 304 void 305 PRT_fix_BN(disk_t *disk, prt_t *part, int pn) 306 { 307 u_int32_t spt, tpc, spc; 308 u_int32_t start = 0; 309 u_int32_t end = 0; 310 311 /* Zero out entry if not used */ 312 if (part->id == DOSPTYP_UNUSED ) { 313 memset(part, 0, sizeof(*part)); 314 return; 315 } 316 317 /* Disk metrics */ 318 spt = disk->real->sectors; 319 tpc = disk->real->heads; 320 spc = spt * tpc; 321 322 start += part->scyl * spc; 323 start += part->shead * spt; 324 start += part->ssect - 1; 325 326 end += part->ecyl * spc; 327 end += part->ehead * spt; 328 end += part->esect - 1; 329 330 /* XXX - Should handle this... */ 331 if (start > end) 332 warn("Start of partition #%d after end!", pn); 333 334 part->bs = start; 335 part->ns = (end - start) + 1; 336 } 337 338 void 339 PRT_fix_CHS(disk_t *disk, prt_t *part) 340 { 341 u_int32_t spt, tpc, spc; 342 u_int32_t start, end, size; 343 u_int32_t cyl, head, sect; 344 345 /* Zero out entry if not used */ 346 if (part->id == DOSPTYP_UNUSED ) { 347 memset(part, 0, sizeof(*part)); 348 return; 349 } 350 351 /* Disk metrics */ 352 spt = disk->real->sectors; 353 tpc = disk->real->heads; 354 spc = spt * tpc; 355 356 start = part->bs; 357 size = part->ns; 358 end = (start + size) - 1; 359 360 /* Figure out starting CHS values */ 361 cyl = (start / spc); start -= (cyl * spc); 362 head = (start / spt); start -= (head * spt); 363 sect = (start + 1); 364 365 part->scyl = cyl; 366 part->shead = head; 367 part->ssect = sect; 368 369 /* Figure out ending CHS values */ 370 cyl = (end / spc); end -= (cyl * spc); 371 head = (end / spt); end -= (head * spt); 372 sect = (end + 1); 373 374 part->ecyl = cyl; 375 part->ehead = head; 376 part->esect = sect; 377 } 378 379