1 /* $OpenBSD: part.c,v 1.80 2021/05/15 19:44:15 krw Exp $ */ 2 3 /* 4 * Copyright (c) 1997 Tobias Weingartner 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/disklabel.h> 21 22 #include <err.h> 23 #include <stdint.h> 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <uuid.h> 28 29 #include "disk.h" 30 #include "misc.h" 31 #include "part.h" 32 33 int PRT_check_chs(struct prt *partn); 34 35 static const struct part_type { 36 int type; 37 char sname[14]; 38 char guid[37]; 39 } part_types[] = { 40 { 0x00, "unused ", "00000000-0000-0000-0000-000000000000" }, 41 { 0x01, "FAT12 ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" }, 42 { 0x02, "XENIX / "}, /* XENIX / filesystem */ 43 { 0x03, "XENIX /usr "}, /* XENIX /usr filesystem */ 44 { 0x04, "FAT16S ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" }, 45 { 0x05, "Extended DOS"}, /* Extended DOS */ 46 { 0x06, "FAT16B ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" }, 47 { 0x07, "NTFS ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" }, 48 { 0x08, "AIX fs "}, /* AIX filesystem */ 49 { 0x09, "AIX/Coherent"}, /* AIX boot partition or Coherent */ 50 { 0x0A, "OS/2 Bootmgr"}, /* OS/2 Boot Manager or OPUS */ 51 { 0x0B, "FAT32 ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" }, 52 { 0x0C, "FAT32L ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" }, 53 { 0x0D, "BIOS Boot ", "21686148-6449-6e6f-744e-656564454649" }, 54 { 0x0E, "FAT16L ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" }, 55 { 0x0F, "Extended LBA"}, /* Extended DOS LBA-mapped */ 56 { 0x10, "OPUS "}, /* OPUS */ 57 { 0x11, "OS/2 hidden ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" }, 58 { 0x12, "Compaq Diag."}, /* Compaq Diagnostics */ 59 { 0x14, "OS/2 hidden ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" }, 60 { 0x16, "OS/2 hidden ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" }, 61 { 0x17, "OS/2 hidden ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" }, 62 { 0x18, "AST swap "}, /* AST Windows swapfile */ 63 { 0x19, "Willowtech "}, /* Willowtech Photon coS */ 64 { 0x1C, "ThinkPad Rec", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" }, 65 { 0x24, "NEC DOS "}, /* NEC DOS */ 66 { 0x27, "Win Recovery", "de94bba4-06d1-4d40-a16a-bfd50179d6ac" }, 67 { 0x20, "Willowsoft "}, /* Willowsoft OFS1 */ 68 { 0x38, "Theos "}, /* Theos */ 69 { 0x39, "Plan 9 "}, /* Plan 9 */ 70 { 0x40, "VENIX 286 "}, /* VENIX 286 or LynxOS */ 71 { 0x41, "Lin/Minux DR"}, /* Linux/MINIX (sharing disk with DRDOS) or Personal RISC boot */ 72 { 0x42, "LinuxSwap DR", "af9b60a0-1431-4f62-bc68-3311714a69ad" }, 73 { 0x43, "Linux DR "}, /* Linux native (sharing disk with DRDOS) */ 74 { 0x4D, "QNX 4.2 Pri "}, /* QNX 4.2 Primary */ 75 { 0x4E, "QNX 4.2 Sec "}, /* QNX 4.2 Secondary */ 76 { 0x4F, "QNX 4.2 Ter "}, /* QNX 4.2 Tertiary */ 77 { 0x50, "DM "}, /* DM (disk manager) */ 78 { 0x51, "DM "}, /* DM6 Aux1 (or Novell) */ 79 { 0x52, "CP/M or SysV"}, /* CP/M or Microport SysV/AT */ 80 { 0x53, "DM "}, /* DM6 Aux3 */ 81 { 0x54, "Ontrack "}, /* Ontrack */ 82 { 0x55, "EZ-Drive "}, /* EZ-Drive (disk manager) */ 83 { 0x56, "Golden Bow "}, /* Golden Bow (disk manager) */ 84 { 0x5C, "Priam "}, /* Priam Edisk (disk manager) */ 85 { 0x61, "SpeedStor "}, /* SpeedStor */ 86 { 0x63, "ISC, HURD, *"}, /* ISC, System V/386, GNU HURD or Mach */ 87 { 0x64, "NetWare 2.xx"}, /* Novell NetWare 2.xx */ 88 { 0x65, "NetWare 3.xx"}, /* Novell NetWare 3.xx */ 89 { 0x66, "NetWare 386 "}, /* Novell 386 NetWare */ 90 { 0x67, "Novell "}, /* Novell */ 91 { 0x68, "Novell "}, /* Novell */ 92 { 0x69, "Novell "}, /* Novell */ 93 { 0x70, "DiskSecure "}, /* DiskSecure Multi-Boot */ 94 { 0x75, "PCIX "}, /* PCIX */ 95 { 0x7f, "ChromeKernel", "fe3a2a5d-4f32-41a7-b725-accc3285a309" }, 96 { 0x80, "Minix (old) "}, /* Minix 1.1 ... 1.4a */ 97 { 0x81, "Minix (new) "}, /* Minix 1.4b ... 1.5.10 */ 98 { 0x82, "Linux swap ", "0657fd6d-a4ab-43c4-84e5-0933c84b4f4f" }, 99 { 0x83, "Linux files*", "0fc63daf-8483-4772-8e79-3d69d8477de4" }, 100 { 0x84, "OS/2 hidden "}, /* OS/2 hidden C: drive */ 101 { 0x85, "Linux ext. "}, /* Linux extended */ 102 { 0x86, "NT FAT VS "}, /* NT FAT volume set */ 103 { 0x87, "NTFS VS "}, /* NTFS volume set or HPFS mirrored */ 104 { 0x8E, "Linux LVM ", "e6d6d379-f507-44c2-a23c-238f2a3df928" }, 105 { 0x93, "Amoeba FS "}, /* Amoeba filesystem */ 106 { 0x94, "Amoeba BBT "}, /* Amoeba bad block table */ 107 { 0x99, "Mylex "}, /* Mylex EISA SCSI */ 108 { 0x9F, "BSDI "}, /* BSDI BSD/OS */ 109 { 0xA0, "NotebookSave"}, /* Phoenix NoteBIOS save-to-disk */ 110 { 0xA5, "FreeBSD ", "516e7cb4-6ecf-11d6-8ff8-00022d09712b" }, 111 { 0xA6, "OpenBSD ", "824cc7a0-36a8-11e3-890a-952519ad3f61" }, 112 { 0xA7, "NEXTSTEP "}, /* NEXTSTEP */ 113 { 0xA8, "MacOS X ", "55465300-0000-11aa-aa11-00306543ecac" }, 114 { 0xA9, "NetBSD ", "516e7cb4-6ecf-11d6-8ff8-00022d09712b" }, 115 { 0xAB, "MacOS X boot", "426f6f74-0000-11aa-aa11-00306543ecac" }, 116 { 0xAF, "MacOS X HFS+", "48465300-0000-11aa-aa11-00306543ecac" }, 117 { 0xB7, "BSDI filesy*"}, /* BSDI BSD/386 filesystem */ 118 { 0xB8, "BSDI swap "}, /* BSDI BSD/386 swap */ 119 { 0xBF, "Solaris ", "6a85cf4d-1dd2-11b2-99a6-080020736631" }, 120 { 0xC0, "CTOS "}, /* CTOS */ 121 { 0xC1, "DRDOSs FAT12"}, /* DRDOS/sec (FAT-12) */ 122 { 0xC4, "DRDOSs < 32M"}, /* DRDOS/sec (FAT-16, < 32M) */ 123 { 0xC6, "DRDOSs >=32M"}, /* DRDOS/sec (FAT-16, >= 32M) */ 124 { 0xC7, "HPFS Disbled"}, /* Syrinx (Cyrnix?) or HPFS disabled */ 125 { 0xDB, "CPM/C.DOS/C*"}, /* Concurrent CPM or C.DOS or CTOS */ 126 { 0xDE, "Dell Maint "}, /* Dell maintenance partition */ 127 { 0xE1, "SpeedStor "}, /* DOS access or SpeedStor 12-bit FAT extended partition */ 128 { 0xE3, "SpeedStor "}, /* DOS R/O or SpeedStor or Storage Dimensions */ 129 { 0xE4, "SpeedStor "}, /* SpeedStor 16-bit FAT extended partition < 1024 cyl. */ 130 { 0xEB, "BeOS/i386 ", "42465331-3ba3-10f1-802a-4861696b7521" }, 131 { 0xEE, "EFI GPT "}, /* EFI Protective Partition */ 132 { 0xEF, "EFI Sys ", "c12a7328-f81f-11d2-ba4b-00a0c93ec93b" }, 133 { 0xF1, "SpeedStor "}, /* SpeedStor or Storage Dimensions */ 134 { 0xF2, "DOS 3.3+ Sec"}, /* DOS 3.3+ Secondary */ 135 { 0xF4, "SpeedStor "}, /* SpeedStor >1024 cyl. or LANstep or IBM PS/2 IML */ 136 { 0xFF, "Xenix BBT "}, /* Xenix Bad Block Table */ 137 }; 138 139 void 140 PRT_printall(void) 141 { 142 int i, idrows; 143 144 idrows = ((sizeof(part_types)/sizeof(struct part_type))+3)/4; 145 146 printf("Choose from the following Partition id values:\n"); 147 for (i = 0; i < idrows; i++) { 148 printf("%02X %s %02X %s %02X %s", 149 part_types[i].type, part_types[i].sname, 150 part_types[i+idrows].type, part_types[i+idrows].sname, 151 part_types[i+idrows*2].type, part_types[i+idrows*2].sname); 152 if ((i+idrows*3) < (sizeof(part_types)/sizeof(struct part_type))) { 153 printf(" %02X %s\n", 154 part_types[i+idrows*3].type, 155 part_types[i+idrows*3].sname); 156 } else 157 printf( "\n" ); 158 } 159 } 160 161 const char * 162 PRT_ascii_id(int id) 163 { 164 static char unknown[] = "<Unknown ID>"; 165 int i; 166 167 for (i = 0; i < sizeof(part_types)/sizeof(struct part_type); i++) { 168 if (part_types[i].type == id) 169 return (part_types[i].sname); 170 } 171 172 return (unknown); 173 } 174 175 void 176 PRT_parse(struct dos_partition *prt, off_t offset, off_t reloff, 177 struct prt *partn) 178 { 179 off_t off; 180 uint32_t t; 181 182 partn->flag = prt->dp_flag; 183 partn->shead = prt->dp_shd; 184 185 partn->ssect = (prt->dp_ssect) & 0x3F; 186 partn->scyl = ((prt->dp_ssect << 2) & 0xFF00) | prt->dp_scyl; 187 188 partn->id = prt->dp_typ; 189 partn->ehead = prt->dp_ehd; 190 partn->esect = (prt->dp_esect) & 0x3F; 191 partn->ecyl = ((prt->dp_esect << 2) & 0xFF00) | prt->dp_ecyl; 192 193 if ((partn->id == DOSPTYP_EXTEND) || (partn->id == DOSPTYP_EXTENDL)) 194 off = reloff; 195 else 196 off = offset; 197 198 #if 0 /* XXX */ 199 partn->bs = letoh32(prt->dp_start) + off; 200 partn->ns = letoh32(prt->dp_size); 201 if (partn->id == DOSPTYP_EFI && partn == UINT32_MAX) 202 partn->ns = DL_GETDSIZE(&dl) - partn->bs; 203 #else 204 memcpy(&t, &prt->dp_start, sizeof(uint32_t)); 205 partn->bs = letoh32(t) + off; 206 memcpy(&t, &prt->dp_size, sizeof(uint32_t)); 207 partn->ns = letoh32(t); 208 if (partn->id == DOSPTYP_EFI && partn->ns == UINT32_MAX) 209 partn->ns = DL_GETDSIZE(&dl) - partn->bs; 210 #endif 211 212 PRT_fix_CHS(partn); 213 } 214 215 int 216 PRT_check_chs(struct prt *partn) 217 { 218 if ( (partn->shead > 255) || 219 (partn->ssect >63) || 220 (partn->scyl > 1023) || 221 (partn->ehead >255) || 222 (partn->esect >63) || 223 (partn->ecyl > 1023) ) 224 { 225 return (0); 226 } 227 return (1); 228 } 229 230 void 231 PRT_make(struct prt *partn, off_t offset, off_t reloff, 232 struct dos_partition *prt) 233 { 234 off_t off; 235 uint32_t ecsave, scsave; 236 uint64_t t; 237 238 /* Save (and restore below) cylinder info we may fiddle with. */ 239 scsave = partn->scyl; 240 ecsave = partn->ecyl; 241 242 if ((partn->scyl > 1023) || (partn->ecyl > 1023)) { 243 partn->scyl = (partn->scyl > 1023)? 1023: partn->scyl; 244 partn->ecyl = (partn->ecyl > 1023)? 1023: partn->ecyl; 245 } 246 if ((partn->id == DOSPTYP_EXTEND) || (partn->id == DOSPTYP_EXTENDL)) 247 off = reloff; 248 else 249 off = offset; 250 251 if (PRT_check_chs(partn)) { 252 prt->dp_shd = partn->shead & 0xFF; 253 prt->dp_ssect = (partn->ssect & 0x3F) | 254 ((partn->scyl & 0x300) >> 2); 255 prt->dp_scyl = partn->scyl & 0xFF; 256 prt->dp_ehd = partn->ehead & 0xFF; 257 prt->dp_esect = (partn->esect & 0x3F) | 258 ((partn->ecyl & 0x300) >> 2); 259 prt->dp_ecyl = partn->ecyl & 0xFF; 260 } else { 261 memset(prt, 0xFF, sizeof(*prt)); 262 } 263 264 prt->dp_flag = partn->flag & 0xFF; 265 prt->dp_typ = partn->id & 0xFF; 266 267 t = htole64(partn->bs - off); 268 memcpy(&prt->dp_start, &t, sizeof(uint32_t)); 269 if (partn->id == DOSPTYP_EFI && (partn->bs + partn->ns) > 270 DL_GETDSIZE(&dl)) 271 t = htole64(UINT32_MAX); 272 else 273 t = htole64(partn->ns); 274 memcpy(&prt->dp_size, &t, sizeof(uint32_t)); 275 276 partn->scyl = scsave; 277 partn->ecyl = ecsave; 278 } 279 280 void 281 PRT_print(int num, struct prt *partn, char *units) 282 { 283 const int secsize = unit_types[SECTORS].conversion; 284 double size; 285 int i; 286 287 i = unit_lookup(units); 288 289 if (partn == NULL) { 290 printf(" Starting Ending " 291 " LBA Info:\n"); 292 printf(" #: id C H S - C H S " 293 "[ start: size ]\n"); 294 printf("---------------------------------------" 295 "----------------------------------------\n"); 296 } else { 297 size = ((double)partn->ns * secsize) / unit_types[i].conversion; 298 printf("%c%1d: %.2X %6u %3u %3u - %6u %3u %3u " 299 "[%12llu:%12.0f%s] %s\n", 300 (partn->flag == DOSACTIVE)?'*':' ', 301 num, partn->id, 302 partn->scyl, partn->shead, partn->ssect, 303 partn->ecyl, partn->ehead, partn->esect, 304 partn->bs, size, 305 unit_types[i].abbr, 306 PRT_ascii_id(partn->id)); 307 } 308 } 309 310 void 311 PRT_fix_BN(struct prt *part, int pn) 312 { 313 uint32_t spt, tpc, spc; 314 uint32_t start = 0; 315 uint32_t end = 0; 316 317 /* Zero out entry if not used */ 318 if (part->id == DOSPTYP_UNUSED) { 319 memset(part, 0, sizeof(*part)); 320 return; 321 } 322 323 /* Disk geometry. */ 324 spt = disk.sectors; 325 tpc = disk.heads; 326 spc = spt * tpc; 327 328 start += part->scyl * spc; 329 start += part->shead * spt; 330 start += part->ssect - 1; 331 332 end += part->ecyl * spc; 333 end += part->ehead * spt; 334 end += part->esect - 1; 335 336 /* XXX - Should handle this... */ 337 if (start > end) 338 warnx("Start of partition #%d after end!", pn); 339 340 part->bs = start; 341 part->ns = (end - start) + 1; 342 } 343 344 void 345 PRT_fix_CHS(struct prt *part) 346 { 347 uint32_t spt, tpc, spc; 348 uint32_t start, end, size; 349 uint32_t cyl, head, sect; 350 351 /* Zero out entry if not used */ 352 if (part->id == DOSPTYP_UNUSED || part->ns == 0) { 353 memset(part, 0, sizeof(*part)); 354 return; 355 } 356 357 /* Disk geometry. */ 358 spt = disk.sectors; 359 tpc = disk.heads; 360 spc = spt * tpc; 361 362 start = part->bs; 363 size = part->ns; 364 end = (start + size) - 1; 365 366 /* Figure out starting CHS values */ 367 cyl = (start / spc); start -= (cyl * spc); 368 head = (start / spt); start -= (head * spt); 369 sect = (start + 1); 370 371 part->scyl = cyl; 372 part->shead = head; 373 part->ssect = sect; 374 375 /* Figure out ending CHS values */ 376 cyl = (end / spc); end -= (cyl * spc); 377 head = (end / spt); end -= (head * spt); 378 sect = (end + 1); 379 380 part->ecyl = cyl; 381 part->ehead = head; 382 part->esect = sect; 383 } 384 385 char * 386 PRT_uuid_to_typename(struct uuid *uuid) 387 { 388 static char partition_type[37]; /* Room for a GUID if needed. */ 389 char *uuidstr = NULL; 390 int i, entries, status; 391 392 memset(partition_type, 0, sizeof(partition_type)); 393 394 uuid_to_string(uuid, &uuidstr, &status); 395 if (status != uuid_s_ok) 396 goto done; 397 398 entries = sizeof(part_types) / sizeof(struct part_type); 399 400 for (i = 0; i < entries; i++) { 401 if (memcmp(part_types[i].guid, uuidstr, 402 sizeof(part_types[i].guid)) == 0) 403 break; 404 } 405 406 if (i < entries) 407 strlcpy(partition_type, part_types[i].sname, 408 sizeof(partition_type)); 409 else 410 strlcpy(partition_type, uuidstr, sizeof(partition_type)); 411 412 done: 413 free(uuidstr); 414 415 return (partition_type); 416 } 417 418 int 419 PRT_uuid_to_type(struct uuid *uuid) 420 { 421 char *uuidstr; 422 int entries, i, status, type; 423 424 type = 0; 425 426 uuid_to_string(uuid, &uuidstr, &status); 427 if (status != uuid_s_ok) 428 goto done; 429 430 entries = sizeof(part_types) / sizeof(struct part_type); 431 for (i = 0; i < entries; i++) { 432 if (memcmp(part_types[i].guid, uuidstr, 433 sizeof(part_types[i].guid)) == 0) { 434 type = part_types[i].type; 435 break; 436 } 437 } 438 439 done: 440 free(uuidstr); 441 return (type); 442 } 443 444 struct uuid * 445 PRT_type_to_uuid(int type) 446 { 447 static struct uuid guid; 448 int i, entries, status = uuid_s_ok; 449 450 memset(&guid, 0, sizeof(guid)); 451 452 entries = sizeof(part_types) / sizeof(struct part_type); 453 454 for (i = 0; i < entries; i++) { 455 if (part_types[i].type == type) 456 break; 457 } 458 if (i < entries) 459 uuid_from_string(part_types[i].guid, &guid, &status); 460 if (i == entries || status != uuid_s_ok) 461 uuid_from_string(part_types[0].guid, &guid, &status); 462 463 return (&guid); 464 } 465