partitions.cc
1 /* 2 * partitions.cc 3 * 4 * This scan tries to guess partitioning information by looking at on-disk 5 * structures. 6 * Recognised partitioning schemes: 7 * - MS-DOS (sometimes called MBR or static disks) 8 * - Apple partition map 9 * - EFI 10 * - raw (whole disk) 11 * 12 */ 13 14 #define _LARGEFILE_SOURCE 15 #define _FILE_OFFSET_BITS 64 16 17 #include "version.h" 18 #include "partitions.h" 19 #include "blockio.h" 20 #include "lvm.h" 21 #include "volumes.h" 22 #include "osutils.h" 23 #include "options.h" 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <cstring> 27 #include <sys/types.h> 28 #include <sys/stat.h> 29 #include <fcntl.h> 30 #include <string.h> 31 #include <stdlib.h> 32 #include <unistd.h> 33 #include <stdint.h> 34 #include <ctype.h> 35 36 __ID("@(#) $Id$"); 37 38 #define LIFBLOCKSIZE 256 39 40 struct maptypes 41 { 42 const char * id; 43 const char * description; 44 bool (*detect)(source & s, hwNode & n); 45 }; 46 47 static bool detect_dosmap(source & s, hwNode & n); 48 static bool detect_macmap(source & s, hwNode & n); 49 static bool detect_lif(source & s, hwNode & n); 50 static bool detect_luks(source & s, hwNode & n); 51 static bool detect_gpt(source & s, hwNode & n); 52 53 static struct maptypes map_types[] = 54 { 55 {"bsd", "BSD disklabel", NULL}, 56 {"gpt", "GUID partition table", detect_gpt}, 57 {"dos", "MS-DOS partition table", detect_dosmap}, 58 {"mac", "Apple Macintosh partition map", detect_macmap}, 59 {"lif", "HP-UX LIF", detect_lif}, 60 {"luks", "Linux Unified Key Setup", detect_luks}, 61 {"solaris-x86", "Solaris disklabel", NULL}, 62 {"solaris-sparc", "Solaris disklabel", NULL}, 63 {"raid", "Linux RAID", NULL}, 64 {"lvm", "Linux LVM Physical Volume", NULL}, 65 {"atari", "Atari ST", NULL}, 66 {"amiga", "Amiga", NULL}, 67 { NULL, NULL, NULL } 68 }; 69 70 struct efi_guid_t 71 { 72 uint32_t time_low; 73 uint16_t time_mid; 74 uint16_t time_hi_and_version; 75 uint8_t clock_seq_hi_and_reserved; 76 uint8_t clock_seq_low; 77 uint8_t node[6]; 78 }; 79 80 struct gpth 81 { 82 uint64_t Signature; /* offset: 0 */ 83 uint32_t Revision; /* 8 */ 84 uint32_t HeaderSize; /* 12 */ 85 uint32_t HeaderCRC32; /* 16 */ 86 uint32_t Reserved1; /* 20 */ 87 uint64_t MyLBA; /* 24 */ 88 uint64_t AlternateLBA; /* 32 */ 89 uint64_t FirstUsableLBA; /* 40 */ 90 uint64_t LastUsableLBA; /* 48 */ 91 efi_guid_t DiskGUID; /* 56 */ 92 uint64_t PartitionEntryLBA; /* 72 */ 93 uint32_t NumberOfPartitionEntries; /* 80 */ 94 uint32_t SizeOfPartitionEntry; /* 84 */ 95 uint32_t PartitionEntryArrayCRC32; /* 88 */ 96 }; 97 98 struct efipartition 99 { 100 efi_guid_t PartitionTypeGUID; 101 efi_guid_t PartitionGUID; 102 uint64_t StartingLBA; 103 uint64_t EndingLBA; 104 uint64_t Attributes; 105 string PartitionName; 106 }; 107 108 #define GPT_PMBR_LBA 0 109 #define GPT_PMBR_SECTORS 1 110 #define GPT_PRIMARY_HEADER_LBA 1 111 #define GPT_HEADER_SECTORS 1 112 #define GPT_PRIMARY_PART_TABLE_LBA 2 113 114 #define EFI_PMBR_OSTYPE_EFI 0xee 115 #define GPT_HEADER_SIGNATURE 0x5452415020494645LL /* "EFI PART" */ 116 117 struct dospartition 118 { 119 unsigned long long start; 120 unsigned long long size; 121 unsigned char type; 122 unsigned char flags; 123 }; 124 125 /* DOS partition types (from util-linux's fdisk)*/ 126 struct systypes 127 { 128 const unsigned char type; 129 const char * description; 130 const char * id; 131 const char * capabilities; 132 const char * icon; 133 }; 134 135 static struct systypes dos_sys_types[] = 136 { 137 {0x00, "Empty", "empty", "nofs", ""}, 138 {0x01, "FAT12", "fat12", "", ""}, 139 {0x02, "XENIX root", "xenix", "", ""}, 140 {0x03, "XENIX usr", "xenix", "", ""}, 141 {0x04, "FAT16 <32M", "fat16", "", ""}, 142 { /* DOS 3.3+ extended partition */ 143 0x05, "Extended", "extended", "multi", "" 144 }, 145 { /* DOS 16-bit >=32M */ 146 0x06, "FAT16", "fat16", "", "" 147 }, 148 { /* OS/2 IFS, eg, HPFS or NTFS or QNX */ 149 0x07, "HPFS/NTFS", "ntfs", "", "" 150 }, 151 { /* AIX boot (AIX -- PS/2 port) or SplitDrive */ 152 0x08, "AIX", "", "", "" 153 }, 154 { /* AIX data or Coherent */ 155 0x09, "AIX bootable", "", "boot", "" 156 }, 157 { /* OS/2 Boot Manager */ 158 0x0a, "OS/2 Boot Manager", "", "boot,nofs", "" 159 }, 160 {0x0b, "W95 FAT32", "fat32", "", ""}, 161 { /* LBA really is `Extended Int 13h' */ 162 0x0c, "W95 FAT32 (LBA)", "fat32", "", "" 163 }, 164 {0x0e, "W95 FAT16 (LBA)", "fat32", "", ""}, 165 {0x0f, "W95 Ext'd (LBA)", "fat32", "", ""}, 166 {0x10, "OPUS", "", "", ""}, 167 {0x11, "Hidden FAT12", "fat12", "hidden", ""}, 168 {0x12, "Compaq diagnostics", "", "boot", ""}, 169 {0x14, "Hidden FAT16 <32M", "", "hidden", ""}, 170 {0x16, "Hidden FAT16", "", "hidden", ""}, 171 {0x17, "Hidden HPFS/NTFS", "ntfs", "hidden", ""}, 172 {0x18, "AST SmartSleep", "", "nofs", ""}, 173 {0x1b, "Hidden W95 FAT32", "", "hidden", ""}, 174 {0x1c, "Hidden W95 FAT32 (LBA)", "", "hidden", ""}, 175 {0x1e, "Hidden W95 FAT16 (LBA)", "", "hidden", ""}, 176 {0x24, "NEC DOS", "", "", ""}, 177 {0x39, "Plan 9", "plan9", "", ""}, 178 {0x3c, "PartitionMagic recovery", "", "nofs", ""}, 179 {0x40, "Venix 80286", "", "", ""}, 180 {0x41, "PPC PReP Boot", "", "boot", ""}, 181 {0x42, "SFS", "", "", ""}, 182 {0x4d, "QNX4.x", "", "", ""}, 183 {0x4e, "QNX4.x 2nd part", "", "", ""}, 184 {0x4f, "QNX4.x 3rd part", "", "", ""}, 185 {0x50, "OnTrack DM", "", "", ""}, 186 { /* (or Novell) */ 187 0x51, "OnTrack DM6 Aux1", "", "", "" 188 }, 189 { /* CP/M or Microport SysV/AT */ 190 0x52, "CP/M", "cpm", "", "" 191 }, 192 {0x53, "OnTrack DM6 Aux3", "", "", ""}, 193 {0x54, "OnTrackDM6", "", "", ""}, 194 {0x55, "EZ-Drive", "", "", ""}, 195 {0x56, "Golden Bow", "", "", ""}, 196 {0x5c, "Priam Edisk", "", "", ""}, 197 {0x61, "SpeedStor", "", "", ""}, 198 { /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */ 199 0x63, "GNU HURD or SysV", "", "", "" 200 }, 201 {0x64, "Novell Netware 286", "", "", ""}, 202 {0x65, "Novell Netware 386", "", "", ""}, 203 {0x70, "DiskSecure Multi-Boot", "", "boot", ""}, 204 {0x75, "PC/IX", "", "", ""}, 205 { /* Minix 1.4a and earlier */ 206 0x80, "Old Minix", "minix", "", "" 207 }, 208 { /* Minix 1.4b and later */ 209 0x81, "Minix / old Linux", "minix", "", "" 210 }, 211 {0x82, "Linux swap / Solaris", "swap", "nofs", ""}, 212 {0x83, "Linux filesystem", "linux", "", ""}, 213 {0x84, "OS/2 hidden C: drive", "", "hidden", ""}, 214 {0x85, "Linux extended", "", "multi", ""}, 215 {0x86, "NTFS volume set", "", "multi", "md"}, 216 {0x87, "NTFS volume set", "", "multi", "md"}, 217 {0x88, "Linux plaintext", "", "", ""}, 218 {0x8e, "Linux LVM Physical Volume", "lvm", "multi", "md"}, 219 {0x93, "Amoeba", "", "", ""}, 220 { /* (bad block table) */ 221 0x94, "Amoeba BBT", "", "", "" 222 }, 223 { /* BSDI */ 224 0x9f, "BSD/OS", "bsdos", "", "" 225 }, 226 {0xa0, "IBM Thinkpad hibernation", "", "nofs", ""}, 227 { /* various BSD flavours */ 228 0xa5, "FreeBSD", "freebsd", "", "" 229 }, 230 {0xa6, "OpenBSD", "openbsd", "", ""}, 231 {0xa7, "NeXTSTEP", "nextstep", "", ""}, 232 {0xa8, "Darwin/OS X UFS", "darwin", "", ""}, 233 {0xa9, "NetBSD", "netbsd", "", ""}, 234 {0xab, "Darwin/OS X boot", "", "boot,nofs", ""}, 235 {0xac, "Darwin/OS X RAID", "", "multi", "md"}, 236 {0xaf, "Darwin/OS X HFS+", "hfs", "", ""}, 237 {0xb7, "BSDI fs", "", "", ""}, 238 {0xb8, "BSDI swap", "", "nofs", ""}, 239 {0xbb, "Boot Wizard hidden", "", "boot,nofs", ""}, 240 {0xbe, "Solaris boot", "", "boot,nofs", ""}, 241 {0xbf, "Solaris", "", "", ""}, 242 {0xc1, "DRDOS/sec (FAT-12)", "", "", ""}, 243 {0xc4, "DRDOS/sec (FAT-16 < 32M)", "", "", ""}, 244 {0xc6, "DRDOS/sec (FAT-16)", "", "", ""}, 245 {0xc7, "Syrinx", "", "", ""}, 246 {0xda, "Non-FS data", "", "nofs", ""}, 247 {0xdb, "CP/M / CTOS / ...", "", "", ""}, 248 /* CP/M or Concurrent CP/M or 249 Concurrent DOS or CTOS */ 250 { /* Dell PowerEdge Server utilities */ 251 0xde, "Dell Utility", "", "", "" 252 }, 253 { /* BootIt EMBRM */ 254 0xdf, "BootIt", "", "boot,nofs", "" 255 }, 256 {0xe1, "DOS access", "", "", ""}, 257 /* DOS access or SpeedStor 12-bit FAT 258 extended partition */ 259 { /* DOS R/O or SpeedStor */ 260 0xe3, "DOS R/O", "", "", "" 261 }, 262 {0xe4, "SpeedStor", "", "", ""}, 263 /* SpeedStor 16-bit FAT extended 264 partition < 1024 cyl. */ 265 {0xeb, "BeOS fs", "", "", ""}, 266 { /* Intel EFI GUID Partition Table */ 267 0xee, "EFI GPT", "", "nofs", "" 268 }, 269 { /* Intel EFI System Partition */ 270 0xef, "EFI (FAT-12/16/32)", "", "boot", "" 271 }, 272 { /* Linux/PA-RISC boot loader */ 273 0xf0, "Linux/PA-RISC boot", "", "boot", "" 274 }, 275 {0xf1, "SpeedStor", "", "", ""}, 276 { /* SpeedStor large partition */ 277 0xf4, "SpeedStor", "", "", "" 278 }, 279 { /* DOS 3.3+ secondary */ 280 0xf2, "DOS secondary", "", "", "" 281 }, 282 {0xfd, "Linux raid autodetect", "", "multi", "md"}, 283 /* New (2.2.x) raid partition with 284 autodetect using persistent 285 superblock */ 286 { /* SpeedStor >1024 cyl. or LANstep */ 287 0xfe, "LANstep", "", "", "" 288 }, 289 { /* Xenix Bad Block Table */ 290 0xff, "BBT", "", "", "" 291 }, 292 { 0, NULL, NULL, NULL } 293 }; 294 295 static unsigned int lastlogicalpart = 5; 296 297 static string partitionname(string disk, unsigned int n) 298 { 299 if(isdigit(disk[disk.length()-1])) 300 return disk+"p"+tostring(n); 301 else 302 return disk+tostring(n); 303 } 304 305 static bool guess_logicalname(source & s, const hwNode & disk, unsigned int n, hwNode & partition) 306 { 307 struct stat buf; 308 int dev = 0; 309 310 if(disk.getBusInfo()!="") 311 partition.setBusInfo(disk.getBusInfo()+string(",")+tostring(n)); 312 313 if(fstat(s.fd, &buf)!=0) return false; 314 if(!S_ISBLK(buf.st_mode)) return false; 315 316 if(s.diskname!="") 317 dev = open_dev(buf.st_rdev + n, S_IFBLK, partitionname(s.diskname, n)); 318 else 319 dev = open_dev(buf.st_rdev + n, S_IFBLK, partitionname(disk.getLogicalName(), n)); 320 321 if(dev>=0) 322 { 323 source spart = s; 324 unsigned char buffer1[BLOCKSIZE], buffer2[BLOCKSIZE]; 325 326 spart.offset = 0; 327 spart.fd = dev; 328 spart.diskname = ""; 329 330 // read the first sector 331 if((readlogicalblocks(s, buffer1, 0, 1)!=1) || 332 (readlogicalblocks(spart, buffer2, 0, 1)!=1)) 333 { 334 close(dev); 335 return false; 336 } 337 338 close(dev); 339 340 if(memcmp(buffer1, buffer2, BLOCKSIZE)==0) 341 { 342 partition.claim(); 343 if(s.diskname!="") 344 partition.setLogicalName(partitionname(s.diskname,n)); 345 else 346 partition.setLogicalName(partitionname(disk.getLogicalName(),n)); 347 return true; 348 } 349 } 350 351 return false; 352 } 353 354 355 static bool is_extended(unsigned char type) 356 { 357 return (type == 0x5) || (type == 0xf) || (type == 0x85); 358 } 359 360 361 static bool read_dospartition(source & s, unsigned short i, dospartition & p) 362 { 363 static unsigned char buffer[BLOCKSIZE]; 364 unsigned char flags = 0; 365 366 if(readlogicalblocks(s, buffer, 0, 1)!=1) // read the first sector 367 return false; 368 369 if(le_short(buffer+510)!=0xaa55) // wrong magic number 370 return false; 371 372 flags = buffer[446 + i*16]; 373 if(flags!=0 && flags!=0x80) 374 // inconsistency: partition is either 375 return false; // bootable or non-bootable 376 377 p.flags = flags; 378 p.type = buffer[446 + i*16 + 4]; 379 p.start = s.blocksize*(unsigned long long)le_long(buffer + 446 + i*16 + 8); 380 p.size = s.blocksize*(unsigned long long)le_long(buffer + 446 + i*16 + 12); 381 382 return true; 383 } 384 385 386 static bool analyse_dospart(source & s, 387 unsigned char flags, 388 unsigned char type, 389 hwNode & partition); 390 391 static bool analyse_dosextpart(source & s, 392 unsigned char flags, 393 unsigned char type, 394 hwNode & extpart) 395 { 396 source extendedpart = s; 397 int i = 0; 398 dospartition pte[2]; // we only read entries #0 and #1 399 400 if(!is_extended(type)) // this is not an extended partition 401 return false; 402 403 extpart.setDescription("Extended partition"); 404 extpart.addCapability("extended", "Extended partition"); 405 extpart.addCapability("partitioned", "Partitioned disk"); 406 extpart.addCapability("partitioned:extended", "Extended partition"); 407 extpart.setSize(extpart.getCapacity()); 408 409 extpart.describeCapability("nofs", "No filesystem"); 410 411 do 412 { 413 for(i=0; i<2; i++) 414 if(!read_dospartition(extendedpart, i, pte[i])) 415 return false; 416 417 if((pte[0].type == 0) || (pte[0].size == 0)) 418 return true; 419 else 420 { 421 hwNode partition("logicalvolume", hw::volume); 422 source spart = extendedpart; 423 424 spart.offset = extendedpart.offset + pte[0].start; 425 spart.size = pte[0].size; 426 427 partition.setPhysId(lastlogicalpart); 428 partition.setCapacity(spart.size); 429 430 if(analyse_dospart(spart, pte[0].flags, pte[0].type, partition)) 431 { 432 guess_logicalname(spart, extpart, lastlogicalpart, partition); 433 scan_volume(partition, spart); 434 extpart.addChild(partition); 435 lastlogicalpart++; 436 } 437 } 438 439 if((pte[1].type == 0) || (pte[1].size == 0)) 440 return true; 441 else 442 { 443 extendedpart.offset = s.offset + pte[1].start; 444 extendedpart.size = pte[1].size; 445 if(!is_extended(pte[1].type)) 446 return false; 447 } 448 } while(true); 449 450 return true; 451 } 452 453 454 static bool analyse_dospart(source & s, 455 unsigned char flags, 456 unsigned char type, 457 hwNode & partition) 458 { 459 int i = 0; 460 461 if(is_extended(type)) 462 return analyse_dosextpart(s, flags, type, partition); 463 464 if(flags!=0 && flags!=0x80) // inconsistency: partition is either bootable or non-bootable 465 return false; 466 467 if(s.offset==0 || s.size==0) // unused entry 468 return false; 469 470 partition.setCapacity(s.size); 471 472 if(flags == 0x80) 473 partition.addCapability("bootable", "Bootable partition (active)"); 474 475 while(dos_sys_types[i].id) 476 { 477 if(dos_sys_types[i].type == type) 478 { 479 partition.setDescription(string(dos_sys_types[i].description)+" partition"); 480 if(lowercase(dos_sys_types[i].capabilities) != "") 481 { 482 vector<string> capabilities; 483 splitlines(dos_sys_types[i].capabilities, capabilities, ','); 484 485 for(unsigned j=0; j<capabilities.size(); j++) 486 partition.addCapability(capabilities[j]); 487 } 488 if(lowercase(dos_sys_types[i].icon) != "") 489 partition.addHint("icon", string(dos_sys_types[i].icon)); 490 else 491 partition.addHint("icon", string("disc")); 492 break; 493 } 494 i++; 495 } 496 497 partition.describeCapability("nofs", "No filesystem"); 498 partition.describeCapability("boot", "Contains boot code"); 499 partition.describeCapability("multi", "Multi-volumes"); 500 partition.describeCapability("hidden", "Hidden partition"); 501 502 scan_lvm(partition, s); 503 504 return true; 505 } 506 507 508 #define UNUSED_ENTRY_GUID \ 509 ((efi_guid_t) \ 510 { \ 511 0x00000000, 0x0000, 0x0000, 0x00, 00, \ 512 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } \ 513 }) 514 515 #define PARTITION_PRECIOUS 1 516 #define PARTITION_READONLY (1LL << 60) 517 #define PARTITION_HIDDEN (1LL << 62) 518 #define PARTITION_NOMOUNT (1LL << 63) 519 520 /* returns the EFI-style CRC32 value for buf 521 * Dec 5, 2000 Matt Domsch <Matt_Domsch@dell.com> 522 * - Copied crc32.c from the linux/drivers/net/cipe directory. 523 * - Now pass seed as an arg 524 * - changed unsigned long to uint32_t, added #include<stdint.h> 525 * - changed len to be an unsigned long 526 * - License remains unchanged! It's still GPL-compatable! 527 */ 528 529 /* ============================================================= */ 530 /* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or */ 531 /* code or tables extracted from it, as desired without restriction. */ 532 /* */ 533 /* First, the polynomial itself and its table of feedback terms. The */ 534 /* polynomial is */ 535 /* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ 536 /* */ 537 /* Note that we take it "backwards" and put the highest-order term in */ 538 /* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ 539 /* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ 540 /* the MSB being 1. */ 541 /* */ 542 /* Note that the usual hardware shift register implementation, which */ 543 /* is what we're using (we're merely optimizing it by doing eight-bit */ 544 /* chunks at a time) shifts bits into the lowest-order term. In our */ 545 /* implementation, that means shifting towards the right. Why do we */ 546 /* do it this way? Because the calculated CRC must be transmitted in */ 547 /* order from highest-order term to lowest-order term. UARTs transmit */ 548 /* characters in order from LSB to MSB. By storing the CRC this way, */ 549 /* we hand it to the UART in the order low-byte to high-byte; the UART */ 550 /* sends each low-bit to hight-bit; and the result is transmission bit */ 551 /* by bit from highest- to lowest-order term without requiring any bit */ 552 /* shuffling on our part. Reception works similarly. */ 553 /* */ 554 /* The feedback terms table consists of 256, 32-bit entries. Notes: */ 555 /* */ 556 /* The table can be generated at runtime if desired; code to do so */ 557 /* is shown later. It might not be obvious, but the feedback */ 558 /* terms simply represent the results of eight shift/xor opera- */ 559 /* tions for all combinations of data and CRC register values. */ 560 /* */ 561 /* The values must be right-shifted by eight bits by the "updcrc" */ 562 /* logic; the shift must be unsigned (bring in zeroes). On some */ 563 /* hardware you could probably optimize the shift in assembler by */ 564 /* using byte-swap instructions. */ 565 /* polynomial $edb88320 */ 566 /* */ 567 /* -------------------------------------------------------------------- */ 568 569 static uint32_t crc32_tab[] = 570 { 571 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 572 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, 573 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 574 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 575 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, 576 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 577 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 578 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, 579 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 580 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, 581 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 582 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 583 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, 584 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 585 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 586 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, 587 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 588 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, 589 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 590 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 591 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, 592 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 593 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 594 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, 595 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 596 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, 597 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 598 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 599 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, 600 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 601 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 602 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, 603 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 604 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, 605 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 606 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 607 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, 608 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 609 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 610 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, 611 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 612 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, 613 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 614 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 615 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, 616 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 617 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 618 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, 619 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 620 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, 621 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 622 0x2d02ef8dL 623 }; 624 625 /* Return a 32-bit CRC of the contents of the buffer. */ 626 627 uint32_t 628 __efi_crc32(const void *buf, unsigned long len, uint32_t seed) 629 { 630 unsigned long i; 631 uint32_t crc32val; 632 const unsigned char *s = (const unsigned char *)buf; 633 634 crc32val = seed; 635 for (i = 0; i < len; i ++) 636 { 637 crc32val = 638 crc32_tab[(crc32val ^ s[i]) & 0xff] ^ 639 (crc32val >> 8); 640 } 641 return crc32val; 642 } 643 644 645 /* 646 * This function uses the crc32 function by Gary S. Brown, 647 * but seeds the function with ~0, and xor's with ~0 at the end. 648 */ 649 static inline uint32_t 650 efi_crc32(const void *buf, unsigned long len) 651 { 652 return (__efi_crc32(buf, len, ~0L) ^ ~0L); 653 } 654 655 656 static efi_guid_t read_efi_guid(uint8_t *buffer) 657 { 658 efi_guid_t result; 659 660 memset(&result, 0, sizeof(result)); 661 662 result.time_low = le_long(buffer); 663 result.time_mid = le_short(buffer+4); 664 result.time_hi_and_version = le_short(buffer+4+2); 665 result.clock_seq_hi_and_reserved = *(buffer+4+2+2); 666 result.clock_seq_low = *(buffer+4+2+2+1); 667 memcpy(result.node, buffer+4+2+2+1+1, sizeof(result.node)); 668 669 return result; 670 } 671 672 673 bool operator ==(const efi_guid_t & guid1, const efi_guid_t & guid2) 674 { 675 return (guid1.time_low == guid2.time_low) && 676 (guid1.time_mid == guid2.time_mid) && 677 (guid1.time_hi_and_version == guid2.time_hi_and_version) && 678 (guid1.clock_seq_hi_and_reserved == guid2.clock_seq_hi_and_reserved) && 679 (guid1.clock_seq_low == guid2.clock_seq_low) && 680 (memcmp(guid1.node, guid2.node, sizeof(guid1.node))==0); 681 } 682 683 684 static string tostring(const efi_guid_t & guid) 685 { 686 char buffer[50]; 687 688 snprintf(buffer, sizeof(buffer), "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", guid.time_low, guid.time_mid,guid.time_hi_and_version,guid.clock_seq_hi_and_reserved,guid.clock_seq_low,guid.node[0],guid.node[1],guid.node[2],guid.node[3],guid.node[4],guid.node[5]); 689 return string(buffer); 690 } 691 692 bool operator ==(const efi_guid_t & guid1, const string & guid2) 693 { 694 return strcasecmp(tostring(guid1).c_str(), guid2.c_str()) == 0; 695 } 696 697 static bool detect_gpt(source & s, hwNode & n) 698 { 699 static uint8_t buffer[BLOCKSIZE]; 700 static gpth gpt_header; 701 uint32_t i = 0; 702 char gpt_version[13]; 703 uint8_t *partitions = NULL; 704 uint8_t type; 705 706 if(s.offset!=0) 707 return false; // partition tables must be at the beginning of the disk 708 709 // read the first sector 710 if(readlogicalblocks(s, buffer, GPT_PMBR_LBA, 1)!=1) 711 return false; 712 713 if(le_short(buffer+510)!=0xaa55) // wrong magic number 714 return false; 715 716 for(i=0; i<4; i++) 717 { 718 type = buffer[446 + i*16 + 4]; 719 720 if((type != 0) && (type != EFI_PMBR_OSTYPE_EFI)) 721 return false; // the EFI pseudo-partition must be the only partition 722 } 723 724 // read the second sector 725 if(readlogicalblocks(s, buffer, GPT_PRIMARY_HEADER_LBA, 1)!=1) 726 return false; // (partition table header) 727 728 gpt_header.Signature = le_longlong(buffer); 729 gpt_header.Revision = be_long(buffer + 0x8); // big endian so that 1.0 -> 0x100 730 gpt_header.HeaderSize = le_long(buffer + 0xc); 731 gpt_header.HeaderCRC32 = le_long(buffer + 0x10); 732 gpt_header.MyLBA = le_longlong(buffer + 0x18); 733 gpt_header.AlternateLBA = le_longlong(buffer + 0x20); 734 gpt_header.FirstUsableLBA = le_longlong(buffer + 0x28); 735 gpt_header.LastUsableLBA = le_longlong(buffer + 0x30); 736 gpt_header.DiskGUID = read_efi_guid(buffer + 0x38); 737 gpt_header.PartitionEntryLBA = le_longlong(buffer + 0x48); 738 gpt_header.NumberOfPartitionEntries = le_long(buffer + 0x50); 739 gpt_header.SizeOfPartitionEntry = le_long(buffer + 0x54); 740 gpt_header.PartitionEntryArrayCRC32 = le_long(buffer + 0x58); 741 742 // zero-out the CRC32 before re-calculating it 743 memset(buffer + 0x10, 0, sizeof(gpt_header.HeaderCRC32)); 744 if(gpt_header.Signature != GPT_HEADER_SIGNATURE) 745 return false; 746 747 if(efi_crc32(buffer, 92) != gpt_header.HeaderCRC32) 748 return false; // check CRC32 749 750 snprintf(gpt_version, sizeof(gpt_version), "%d.%02d", (gpt_header.Revision >> 8), (gpt_header.Revision & 0xff)); 751 752 n.addCapability("gpt-"+string(gpt_version), "GUID Partition Table version "+string(gpt_version)); 753 n.addHint("partitions", gpt_header.NumberOfPartitionEntries); 754 n.setConfig("guid",::enabled("output:sanitize")?REMOVED:tostring(gpt_header.DiskGUID)); 755 n.setHandle(::enabled("output:sanitize")?"GUID:":"GUID:" + tostring(gpt_header.DiskGUID)); 756 n.addHint("guid",::enabled("output:sanitize")?REMOVED:tostring(gpt_header.DiskGUID)); 757 758 partitions = (uint8_t*)malloc(gpt_header.NumberOfPartitionEntries * gpt_header.SizeOfPartitionEntry + BLOCKSIZE); 759 if(!partitions) 760 return false; 761 memset(partitions, 0, gpt_header.NumberOfPartitionEntries * gpt_header.SizeOfPartitionEntry + BLOCKSIZE); 762 readlogicalblocks(s, partitions, 763 gpt_header.PartitionEntryLBA, 764 (gpt_header.NumberOfPartitionEntries * gpt_header.SizeOfPartitionEntry)/BLOCKSIZE + 1); 765 766 for(i=0; i<gpt_header.NumberOfPartitionEntries; i++) 767 { 768 hwNode partition("volume", hw::volume); 769 efipartition p; 770 771 p.PartitionTypeGUID = read_efi_guid(partitions + gpt_header.SizeOfPartitionEntry * i); 772 p.PartitionGUID = read_efi_guid(partitions + gpt_header.SizeOfPartitionEntry * i + 0x10); 773 p.StartingLBA = le_longlong(partitions + gpt_header.SizeOfPartitionEntry * i + 0x20); 774 p.EndingLBA = le_longlong(partitions + gpt_header.SizeOfPartitionEntry * i + 0x28); 775 p.Attributes = le_longlong(partitions + gpt_header.SizeOfPartitionEntry * i + 0x30); 776 for(int j=0; j<36; j++) 777 { 778 wchar_t c = le_short(partitions + gpt_header.SizeOfPartitionEntry * i + 0x38 + 2*j); 779 if(!c) 780 break; 781 else 782 p.PartitionName += utf8(c); 783 } 784 785 if(!(p.PartitionTypeGUID == UNUSED_ENTRY_GUID)) 786 { 787 source spart = s; 788 if(p.PartitionTypeGUID == "C12A7328-F81F-11D2-BA4B-00A0C93EC93B") 789 { 790 partition.setDescription("System partition"); 791 partition.setVendor("EFI"); 792 partition.addCapability("boot"); 793 } 794 else 795 if(p.PartitionTypeGUID == "024DEE41-33E7-11D3-9D69-0008C781F39F") 796 { 797 partition.setDescription("MBR partition scheme"); 798 partition.setVendor("EFI"); 799 partition.addCapability("nofs"); 800 } 801 else 802 if(p.PartitionTypeGUID == "21686148-6449-6E6F-744E-656564454649") 803 { 804 partition.setDescription("BIOS Boot partition"); 805 partition.setVendor("EFI"); 806 partition.addCapability("nofs"); 807 } 808 else 809 if(p.PartitionTypeGUID == "0657FD6D-A4AB-43C4-84E5-0933C84B4F4F") 810 { 811 partition.setDescription("swap partition"); 812 partition.setVendor("Linux"); 813 partition.addCapability("nofs"); 814 } 815 else 816 if(p.PartitionTypeGUID == "A19D880F-05FC-4D3B-A006-743F0F84911E") 817 { 818 partition.setDescription("RAID partition"); 819 partition.setVendor("Linux"); 820 partition.addCapability("multi"); 821 } 822 else 823 if(p.PartitionTypeGUID == "E6D6D379-F507-44C2-A23C-238F2A3DF928") 824 { 825 partition.setDescription("LVM Physical Volume"); 826 partition.setVendor("Linux"); 827 partition.addCapability("multi"); 828 } 829 else 830 if(p.PartitionTypeGUID == "8DA63339-0007-60C0-C436-083AC8230908") 831 { 832 partition.setDescription("reserved partition"); 833 partition.setVendor("Linux"); 834 partition.addCapability("nofs"); 835 } 836 else 837 if(p.PartitionTypeGUID == "75894C1E-3AEB-11D3-B7C1-7B03A0000000") 838 { 839 partition.setDescription("data partition"); 840 partition.setVendor("HP-UX"); 841 } 842 else 843 if(p.PartitionTypeGUID == "E2A1E728-32E3-11D6-A682-7B03A0000000") 844 { 845 partition.setDescription("service partition"); 846 partition.setVendor("HP-UX"); 847 partition.addCapability("nofs"); 848 partition.addCapability("boot"); 849 } 850 else 851 if(p.PartitionTypeGUID == "48465300-0000-11AA-AA11-00306543ECAC") 852 { 853 partition.setDescription("Apple HFS+ partition"); 854 partition.setVendor("Mac OS X"); 855 } 856 else 857 if(p.PartitionTypeGUID == "7C3457EF-0000-11AA-AA11-00306543ECAC") 858 { 859 partition.setDescription("Apple APFS partition"); 860 partition.setVendor("Mac OS X"); 861 } 862 else 863 if(p.PartitionTypeGUID == "6A898CC3-1DD2-11B2-99A6-080020736631") 864 { 865 partition.setDescription("OS X ZFS partition or Solaris /usr partition"); 866 partition.setVendor("Solaris"); 867 } 868 else 869 if(p.PartitionTypeGUID == "52414944-0000-11AA-AA11-00306543ECAC") 870 { 871 partition.setDescription("RAID partition"); 872 partition.setVendor("Mac OS X"); 873 partition.addCapability("multi"); 874 } 875 else 876 if(p.PartitionTypeGUID == "52414944-5F4F-11AA-AA11-00306543ECAC") 877 { 878 partition.setDescription("RAID partition (offline)"); 879 partition.setVendor("Mac OS X"); 880 partition.addCapability("multi"); 881 partition.addCapability("offline"); 882 } 883 else 884 if(p.PartitionTypeGUID == "4C616265-6C00-11AA-AA11-00306543ECAC") 885 { 886 partition.setDescription("Apple label"); 887 partition.setVendor("Mac OS X"); 888 partition.addCapability("nofs"); 889 } 890 else 891 if(p.PartitionTypeGUID == "5265636F-7665-11AA-AA11-00306543ECAC") 892 { 893 partition.setDescription("recovery partition"); 894 partition.setVendor("Apple TV"); 895 partition.addCapability("nofs"); 896 } 897 else 898 if(p.PartitionTypeGUID == "53746F72-6167-11AA-AA11-00306543ECAC") 899 { 900 partition.setDescription("Apple Core Storage (File Vault)"); 901 partition.setVendor("Mac OS X"); 902 partition.addCapability("encrypted"); 903 } 904 else 905 if(p.PartitionTypeGUID == "426F6F74-0000-11AA-AA11-00306543ECAC") 906 { 907 partition.setDescription("boot partition"); 908 partition.setVendor("Mac OS X"); 909 partition.addCapability("boot"); 910 } 911 else 912 if(p.PartitionTypeGUID == "55465300-0000-11AA-AA11-00306543ECAC") 913 { 914 partition.setDescription("UFS partition"); 915 partition.setVendor("Mac OS X"); 916 } 917 else 918 if(p.PartitionTypeGUID == "516E7CB4-6ECF-11D6-8FF8-00022D09712B") 919 { 920 partition.setDescription("data partition"); 921 partition.setVendor("FreeBSD"); 922 } 923 else 924 if(p.PartitionTypeGUID == "516E7CB6-6ECF-11D6-8FF8-00022D09712B") 925 { 926 partition.setDescription("UFS partition"); 927 partition.setVendor("FreeBSD"); 928 } 929 else 930 if(p.PartitionTypeGUID == "516E7CBA-6ECF-11D6-8FF8-00022D09712B") 931 { 932 partition.setDescription("ZFS partition"); 933 partition.setVendor("FreeBSD"); 934 } 935 else 936 if(p.PartitionTypeGUID == "516E7CB8-6ECF-11D6-8FF8-00022D09712B") 937 { 938 partition.setDescription("Vinum Volume Manager partition"); 939 partition.setVendor("FreeBSD"); 940 } 941 else 942 if(p.PartitionTypeGUID == "516E7CB5-6ECF-11D6-8FF8-00022D09712B") 943 { 944 partition.setDescription("swap partition"); 945 partition.setVendor("FreeBSD"); 946 partition.addCapability("nofs"); 947 } 948 else 949 if(p.PartitionTypeGUID == "83BD6B9D-7F41-11DC-BE0B-001560B84F0F") 950 { 951 partition.setDescription("boot partition"); 952 partition.setVendor("FreeBSD"); 953 partition.addCapability("boot"); 954 } 955 else 956 if(p.PartitionTypeGUID == "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7") 957 { 958 partition.setDescription("data partition"); 959 partition.setVendor("Windows"); 960 } 961 else 962 if(p.PartitionTypeGUID == "DE94BBA4-06D1-4D40-A16A-BFD50179D6AC") 963 { 964 partition.setDescription("recovery environment"); 965 partition.setVendor("Windows"); 966 partition.addCapability("boot"); 967 } 968 else 969 if(p.PartitionTypeGUID == "37AFFC90-EF7D-4E96-91C3-2D7AE055B174") 970 { 971 partition.setDescription("IBM GPFS partition"); 972 partition.setVendor("Windows"); 973 } 974 else 975 if(p.PartitionTypeGUID == "5808C8AA-7E8F-42E0-85D2-E1E90434CFB3") 976 { 977 partition.setDescription("LDM configuration"); 978 partition.setVendor("Windows"); 979 partition.addCapability("nofs"); 980 } 981 else 982 if(p.PartitionTypeGUID == "AF9B60A0-1431-4F62-BC68-3311714A69AD") 983 { 984 partition.setDescription("LDM data partition"); 985 partition.setVendor("Windows"); 986 partition.addCapability("multi"); 987 } 988 else 989 if(p.PartitionTypeGUID == "E3C9E316-0B5C-4DB8-817D-F92DF00215AE") 990 { 991 partition.setDescription("reserved partition"); 992 partition.setVendor("Windows"); 993 partition.addCapability("nofs"); 994 } 995 else 996 if(p.PartitionTypeGUID == "FE3A2A5D-4F32-41A7-B725-ACCC3285A309") 997 { 998 partition.setDescription("kernel"); 999 partition.setVendor("ChromeOS"); 1000 } 1001 else 1002 if(p.PartitionTypeGUID == "3CB8E202-3B7E-47DD-8A3C-7FF2A13CFCEC") 1003 { 1004 partition.setDescription("root filesystem"); 1005 partition.setVendor("ChromeOS"); 1006 } 1007 else 1008 if(p.PartitionTypeGUID == "2E0A753D-9E48-43B0-8337-B15192CB1B5E") 1009 { 1010 partition.setDescription("reserved"); 1011 partition.setVendor("ChromeOS"); 1012 } 1013 else 1014 if(p.PartitionTypeGUID == "6A82CB45-1DD2-11B2-99A6-080020736631") 1015 { 1016 partition.setDescription("boot partition"); 1017 partition.setVendor("Solaris"); 1018 partition.addCapability("boot"); 1019 } 1020 else 1021 if(p.PartitionTypeGUID == "6A85CF4D-1DD2-11B2-99A6-080020736631") 1022 { 1023 partition.setDescription("root partition"); 1024 partition.setVendor("Solaris"); 1025 } 1026 else 1027 if(p.PartitionTypeGUID == "6A87C46F-1DD2-11B2-99A6-080020736631") 1028 { 1029 partition.setDescription("swap partition"); 1030 partition.setVendor("Solaris"); 1031 partition.addCapability("nofs"); 1032 } 1033 else 1034 if(p.PartitionTypeGUID == "6A8B642B-1DD2-11B2-99A6-080020736631") 1035 { 1036 partition.setDescription("backup partition"); 1037 partition.setVendor("Solaris"); 1038 } 1039 else 1040 if(p.PartitionTypeGUID == "6A8EF2E9-1DD2-11B2-99A6-080020736631") 1041 { 1042 partition.setDescription("/var partition"); 1043 partition.setVendor("Solaris"); 1044 } 1045 else 1046 if(p.PartitionTypeGUID == "6A90BA39-1DD2-11B2-99A6-080020736631") 1047 { 1048 partition.setDescription("/home partition"); 1049 partition.setVendor("Solaris"); 1050 } 1051 else 1052 if(p.PartitionTypeGUID == "6A9283A5-1DD2-11B2-99A6-080020736631") 1053 { 1054 partition.setDescription("alternate sector"); 1055 partition.setVendor("Solaris"); 1056 partition.addCapability("nofs"); 1057 } 1058 else 1059 if(p.PartitionTypeGUID == "6A945A3B-1DD2-11B2-99A6-080020736631" || 1060 p.PartitionTypeGUID == "6A9630D1-1DD2-11B2-99A6-080020736631" || 1061 p.PartitionTypeGUID == "6A980767-1DD2-11B2-99A6-080020736631" || 1062 p.PartitionTypeGUID == "6A96237F-1DD2-11B2-99A6-080020736631" || 1063 p.PartitionTypeGUID == "6A8D2AC7-1DD2-11B2-99A6-080020736631" 1064 ) 1065 { 1066 partition.setDescription("reserved partition"); 1067 partition.setVendor("Solaris"); 1068 } 1069 else 1070 if(p.PartitionTypeGUID == "49F48D32-B10E-11DC-B99B-0019D1879648") 1071 { 1072 partition.setDescription("swap partition"); 1073 partition.setVendor("NetBSD"); 1074 partition.addCapability("nofs"); 1075 } 1076 else 1077 if(p.PartitionTypeGUID == "49F48D5A-B10E-11DC-B99B-0019D1879648") 1078 { 1079 partition.setDescription("FFS partition"); 1080 partition.setVendor("NetBSD"); 1081 } 1082 else 1083 if(p.PartitionTypeGUID == "49F48D82-B10E-11DC-B99B-0019D1879648") 1084 { 1085 partition.setDescription("LFS partition"); 1086 partition.setVendor("NetBSD"); 1087 } 1088 else 1089 if(p.PartitionTypeGUID == "49F48DAA-B10E-11DC-B99B-0019D1879648") 1090 { 1091 partition.setDescription("RAID partition"); 1092 partition.setVendor("NetBSD"); 1093 partition.addCapability("multi"); 1094 } 1095 else 1096 if(p.PartitionTypeGUID == "2DB519C4-B10F-11DC-B99B-0019D1879648") 1097 { 1098 partition.setDescription("concatenated partition"); 1099 partition.setVendor("NetBSD"); 1100 partition.addCapability("multi"); 1101 } 1102 else 1103 if(p.PartitionTypeGUID == "2DB519EC-B10F-11DC-B99B-0019D1879648") 1104 { 1105 partition.setDescription("encrypted partition"); 1106 partition.setVendor("NetBSD"); 1107 partition.addCapability("encrypted"); 1108 } 1109 else 1110 if(p.PartitionTypeGUID == "42465331-3ba3-10f1-802a-4861696b7521") // is it really used ? 1111 { 1112 partition.setDescription("BeFS partition"); 1113 partition.setVendor("Haiku"); 1114 } 1115 else 1116 partition.setDescription("EFI partition"); 1117 partition.setPhysId(i+1); 1118 partition.setCapacity(BLOCKSIZE * (p.EndingLBA - p.StartingLBA)); 1119 partition.addHint("type", tostring(p.PartitionTypeGUID)); 1120 partition.addHint("guid", tostring(p.PartitionGUID)); 1121 partition.setSerial(tostring(p.PartitionGUID)); 1122 partition.setHandle("GUID:" + tostring(p.PartitionGUID)); 1123 partition.setConfig("name", p.PartitionName); 1124 if(p.Attributes & PARTITION_PRECIOUS) 1125 partition.addCapability("precious", "This partition is required for the platform to function"); 1126 if(p.Attributes & PARTITION_READONLY) 1127 partition.addCapability("readonly", "Read-only partition"); 1128 if(p.Attributes & PARTITION_HIDDEN) 1129 partition.addCapability("hidden"); 1130 if(p.Attributes & PARTITION_NOMOUNT) 1131 partition.addCapability("nomount", "No automatic mount"); 1132 1133 partition.describeCapability("nofs", "No filesystem"); 1134 partition.describeCapability("boot", "Contains boot code"); 1135 partition.describeCapability("multi", "Multi-volumes"); 1136 partition.describeCapability("hidden", "Hidden partition"); 1137 partition.describeCapability("encrypted", "Contains encrypted data"); 1138 1139 spart.blocksize = s.blocksize; 1140 spart.offset = s.offset + p.StartingLBA*spart.blocksize; 1141 spart.size = (p.EndingLBA - p.StartingLBA)*spart.blocksize; 1142 guess_logicalname(spart, n, i+1, partition); 1143 scan_volume(partition, spart); 1144 n.addChild(partition); 1145 } 1146 } 1147 1148 free(partitions); 1149 1150 return true; 1151 } 1152 1153 1154 static bool detect_dosmap(source & s, hwNode & n) 1155 { 1156 static unsigned char buffer[BLOCKSIZE]; 1157 int i = 0; 1158 unsigned char flags; 1159 unsigned char type; 1160 unsigned long long start, size; 1161 bool partitioned = false; 1162 unsigned long signature = 0; 1163 1164 if(s.offset!=0) 1165 return false; // partition tables must be at the beginning of the disk 1166 1167 if(readlogicalblocks(s, buffer, 0, 1)!=1) // read the first sector 1168 return false; 1169 1170 if(le_short(buffer+510)!=0xaa55) // wrong magic number 1171 return false; 1172 1173 signature=le_long(buffer+440); 1174 if(signature == 0xffffffffL) 1175 signature = 0; 1176 if(signature) 1177 { 1178 char buffer[16+1]; 1179 snprintf(buffer, sizeof(buffer), "%08lx", signature); 1180 n.setConfig("signature", buffer); 1181 } 1182 1183 lastlogicalpart = 5; 1184 1185 for(i=0; i<4; i++) 1186 { 1187 source spart = s; 1188 hwNode partition("volume", hw::volume); 1189 1190 flags = buffer[446 + i*16]; 1191 type = buffer[446 + i*16 + 4]; 1192 start = le_long(buffer + 446 + i*16 + 8); 1193 size = le_long(buffer + 446 + i*16 + 12); 1194 1195 if(flags!=0 && flags!=0x80) // inconsistency: partition is either bootable or non-bootable 1196 return false; 1197 1198 spart.blocksize = s.blocksize; 1199 spart.offset = s.offset + start*spart.blocksize; 1200 spart.size = size*spart.blocksize; 1201 1202 partition.setDescription("Primary partition"); 1203 partition.addCapability("primary", "Primary partition"); 1204 partition.setPhysId(i+1); 1205 partition.setCapacity(spart.size); 1206 1207 if(analyse_dospart(spart, flags, type, partition)) 1208 { 1209 guess_logicalname(spart, n, i+1, partition); 1210 scan_volume(partition, spart); 1211 n.addChild(partition); 1212 partitioned = true; 1213 } 1214 } 1215 1216 return partitioned; 1217 } 1218 1219 1220 static bool detect_macmap(source & s, hwNode & n) 1221 { 1222 static unsigned char buffer[BLOCKSIZE]; 1223 unsigned long count = 0, i = 0; 1224 unsigned long long start = 0, size = 0; 1225 string type = ""; 1226 1227 if(s.offset!=0) 1228 return false; // partition maps must be at the beginning of the disk 1229 1230 if(readlogicalblocks(s, buffer, 1, 1)!=1) // read the second sector 1231 return false; 1232 1233 if(be_short(buffer)!=0x504d) // wrong magic number 1234 return false; 1235 1236 count = be_long(buffer+4); 1237 1238 for (i = 1; i <= count; i++) 1239 { 1240 hwNode partition("volume", hw::volume); 1241 1242 if((i>1) && readlogicalblocks(s, buffer, i, 1)!=1) 1243 return false; 1244 1245 if(be_short(buffer)!=0x504d) continue; // invalid map entry 1246 1247 start = be_long(buffer + 8); 1248 size = be_long(buffer + 12); 1249 type = hw::strip(string((char*)buffer + 48, 32)); 1250 1251 partition.setPhysId(i); 1252 partition.setCapacity(size * s.blocksize); 1253 if(lowercase(type) == "apple_bootstrap") 1254 partition.addCapability("bootable", "Bootstrap partition"); 1255 1256 if(lowercase(type) == "linux_lvm") 1257 { 1258 partition.addHint("icon", string("md")); 1259 partition.addCapability("multi"); 1260 } 1261 else 1262 partition.addHint("icon", string("disc")); 1263 1264 for(unsigned int j=0; j<type.length(); j++) 1265 if(type[j] == '_') type[j] = ' '; 1266 partition.setDescription(type); 1267 1268 if(true /*analyse_macpart(flags, type, start, size, partition)*/) 1269 { 1270 source spart = s; 1271 1272 spart.blocksize = s.blocksize; 1273 spart.offset = s.offset + start*spart.blocksize; 1274 spart.size = size*spart.blocksize; 1275 1276 guess_logicalname(spart, n, i, partition); 1277 1278 scan_volume(partition, spart); 1279 n.addChild(partition); 1280 } 1281 } 1282 1283 return true; 1284 } 1285 1286 1287 static bool detect_lif(source & s, hwNode & n) 1288 { 1289 static unsigned char buffer[LIFBLOCKSIZE]; 1290 source lifvolume; 1291 unsigned long dir_start = 0, dir_length = 0; 1292 unsigned lif_version = 0; 1293 unsigned long ipl_addr = 0, ipl_length = 0; 1294 1295 if(s.offset!=0) 1296 return false; // LIF boot volumes must be at the beginning of the disk 1297 1298 lifvolume = s; 1299 lifvolume.blocksize = LIFBLOCKSIZE; // LIF blocks are 256 bytes long 1300 1301 // read the first block 1302 if(readlogicalblocks(lifvolume, buffer, 0, 1)!=1) 1303 return false; 1304 1305 if(be_short(buffer)!=0x8000) // wrong magic number 1306 return false; 1307 1308 dir_start = be_long(buffer+8); 1309 dir_length = be_long(buffer+16); 1310 lif_version = be_short(buffer+20); 1311 1312 if(dir_start<2) return false; // blocks 0 and 1 are reserved 1313 if(dir_length<1) return false; // no directory to read from 1314 if(lif_version<1) return false; // weird LIF version 1315 1316 ipl_addr = be_long(buffer+240); // byte address of IPL on media 1317 ipl_length = be_long(buffer+244); // size of boot code 1318 #if 0 1319 ipl_entry = be_long(buffer+248); // boot code entry point 1320 1321 fprintf(stderr, "system: %x\n", be_short(buffer+12)); 1322 fprintf(stderr, "start of directory: %ld\n", dir_start); 1323 fprintf(stderr, "length of directory: %ld\n", dir_length); 1324 fprintf(stderr, "lif version: %x\n", lif_version); 1325 fprintf(stderr, "tracks per surface: %ld\n", be_long(buffer+24)); 1326 fprintf(stderr, "number of surfaces: %ld\n", be_long(buffer+28)); 1327 fprintf(stderr, "blocks per track: %ld\n", be_long(buffer+32)); 1328 fprintf(stderr, "ipl addr: %ld\n", ipl_addr); 1329 fprintf(stderr, "ipl length: %ld\n", ipl_length); 1330 fprintf(stderr, "ipl entry point: %lx\n", ipl_entry); 1331 #endif 1332 1333 if((ipl_addr!=0) && (ipl_length>0)) n.addCapability("bootable", "Bootable disk"); 1334 1335 return true; 1336 } 1337 1338 static bool detect_luks(source & s, hwNode & n) 1339 { 1340 static char buffer[BLOCKSIZE]; 1341 source luksvolume; 1342 unsigned luks_version = 0; 1343 1344 luksvolume = s; 1345 luksvolume.blocksize = BLOCKSIZE; 1346 // read the first block 1347 if(readlogicalblocks(luksvolume, buffer, 0, 1)!=1) 1348 return false; 1349 1350 if(memcmp(buffer, "LUKS", 4) != 0) // wrong magic number 1351 return false; 1352 if(be_short(buffer+4) != 0xbabe) 1353 return false; 1354 1355 luks_version = be_short(buffer+6); 1356 if(luks_version<1) 1357 return false; // weird LUKS version 1358 else 1359 { 1360 hwNode partition("volume", hw::volume); 1361 scan_volume(partition, luksvolume); 1362 partition.setLogicalName(n.getLogicalName()); 1363 n.addChild(partition); 1364 } 1365 1366 return true; 1367 } 1368 1369 bool scan_partitions(hwNode & n) 1370 { 1371 int i = 0; 1372 source s; 1373 int fd = open(n.getLogicalName().c_str(), O_RDONLY | O_NONBLOCK); 1374 hwNode * medium = NULL; 1375 1376 if (fd < 0) 1377 return false; 1378 1379 if(n.isCapable("removable")) 1380 { 1381 medium = n.addChild(hwNode("medium", hw::disk)); 1382 1383 medium->claim(); 1384 medium->setSize(n.getSize()); 1385 medium->setCapacity(n.getCapacity()); 1386 medium->setLogicalName(n.getLogicalName()); 1387 } 1388 else 1389 medium = &n; 1390 1391 s.diskname = n.getLogicalName(); 1392 s.fd = fd; 1393 s.offset = 0; 1394 s.blocksize = BLOCKSIZE; 1395 s.size = medium->getSize(); 1396 1397 while(map_types[i].id) 1398 { 1399 if(map_types[i].detect && map_types[i].detect(s, *medium)) 1400 { 1401 medium->addCapability(string("partitioned"), "Partitioned disk"); 1402 medium->addCapability(string("partitioned:") + string(map_types[i].id), string(map_types[i].description)); 1403 break; 1404 } 1405 i++; 1406 } 1407 1408 if(!medium->isCapable("partitioned")) 1409 { 1410 if(scan_volume(*medium, s)) // whole disk volume? 1411 medium->setClass(hw::volume); 1412 } 1413 1414 close(fd); 1415 1416 //if(medium != &n) free(medium); 1417 1418 return false; 1419 }