Back to index

lshw  02.16
partitions.cc
Go to the documentation of this file.
00001 /*
00002  * partitions.cc
00003  *
00004  * This scan tries to guess partitioning information by looking at on-disk
00005  * structures.
00006  * Recognised partitioning schemes:
00007  * - MS-DOS (sometimes called MBR or static disks)
00008  * - Apple partition map
00009  * - EFI
00010  * - raw (whole disk)
00011  *
00012  */
00013 
00014 #define _LARGEFILE_SOURCE
00015 #define _FILE_OFFSET_BITS 64
00016 
00017 #include "version.h"
00018 #include "partitions.h"
00019 #include "blockio.h"
00020 #include "lvm.h"
00021 #include "volumes.h"
00022 #include "osutils.h"
00023 #include <stdio.h>
00024 #include <sys/types.h>
00025 #include <sys/stat.h>
00026 #include <fcntl.h>
00027 #include <string.h>
00028 #include <stdlib.h>
00029 #include <unistd.h>
00030 #include <stdint.h>
00031 
00032 __ID("@(#) $Id: partitions.cc 2433 2012-01-10 22:01:30Z lyonel $");
00033 
00034 #define LIFBLOCKSIZE 256
00035 
00036 struct maptypes
00037 {
00038   const char * id;
00039   const char * description;
00040   bool (*detect)(source & s, hwNode & n);
00041 };
00042 
00043 static bool detect_dosmap(source & s, hwNode & n);
00044 static bool detect_macmap(source & s, hwNode & n);
00045 static bool detect_lif(source & s, hwNode & n);
00046 static bool detect_luks(source & s, hwNode & n);
00047 static bool detect_gpt(source & s, hwNode & n);
00048 
00049 static struct maptypes map_types[] =
00050 {
00051   {"bsd", "BSD disklabel", NULL},
00052   {"gpt", "GUID partition table", detect_gpt},
00053   {"dos", "MS-DOS partition table", detect_dosmap},
00054   {"mac", "Apple Macintosh partition map", detect_macmap},
00055   {"lif", "HP-UX LIF", detect_lif},
00056   {"luks", "Linux Unified Key Setup", detect_luks},
00057   {"solaris-x86", "Solaris disklabel", NULL},
00058   {"solaris-sparc", "Solaris disklabel", NULL},
00059   {"raid", "Linux RAID", NULL},
00060   {"lvm", "Linux LVM Physical Volume", NULL},
00061   {"atari", "Atari ST", NULL},
00062   {"amiga", "Amiga", NULL},
00063   { NULL, NULL, NULL }
00064 };
00065 
00066 struct efi_guid_t
00067 {
00068   uint32_t time_low;
00069   uint16_t time_mid;
00070   uint16_t time_hi_and_version;
00071   uint8_t  clock_seq_hi_and_reserved;
00072   uint8_t  clock_seq_low;
00073   uint8_t  node[6];
00074 };
00075 
00076 struct gpth
00077 {
00078   uint64_t Signature;                             /* offset: 0 */
00079   uint32_t Revision;                              /* 8 */
00080   uint32_t HeaderSize;                            /* 12 */
00081   uint32_t HeaderCRC32;                           /* 16 */
00082   uint32_t Reserved1;                             /* 20 */
00083   uint64_t MyLBA;                                 /* 24 */
00084   uint64_t AlternateLBA;                          /* 32 */
00085   uint64_t FirstUsableLBA;                        /* 40 */
00086   uint64_t LastUsableLBA;                         /* 48 */
00087   efi_guid_t DiskGUID;                            /* 56 */
00088   uint64_t PartitionEntryLBA;                     /* 72 */
00089   uint32_t NumberOfPartitionEntries;              /* 80 */
00090   uint32_t SizeOfPartitionEntry;                  /* 84 */
00091   uint32_t PartitionEntryArrayCRC32;              /* 88 */
00092 };
00093 
00094 struct efipartition
00095 {
00096   efi_guid_t PartitionTypeGUID;
00097   efi_guid_t PartitionGUID;
00098   uint64_t StartingLBA;
00099   uint64_t EndingLBA;
00100   uint64_t Attributes;
00101   string PartitionName;
00102 };
00103 
00104 #define GPT_PMBR_LBA 0
00105 #define GPT_PMBR_SECTORS 1
00106 #define GPT_PRIMARY_HEADER_LBA 1
00107 #define GPT_HEADER_SECTORS 1
00108 #define GPT_PRIMARY_PART_TABLE_LBA 2
00109 
00110 #define EFI_PMBR_OSTYPE_EFI 0xee
00111 #define GPT_HEADER_SIGNATURE 0x5452415020494645LL /* "EFI PART" */
00112 
00113 struct dospartition
00114 {
00115   unsigned long long start;
00116   unsigned long long size;
00117   unsigned char type;
00118   unsigned char flags;
00119 };
00120 
00121 /* DOS partition types (from util-linux's fdisk)*/
00122 struct systypes
00123 {
00124   const unsigned char type;
00125   const char * description;
00126   const char * id;
00127   const char * capabilities;
00128   const char * icon;
00129 };
00130 
00131 static struct systypes dos_sys_types[] =
00132 {
00133   {0x00, "Empty", "empty", "nofs", ""},
00134   {0x01, "FAT12", "fat12", "", ""},
00135   {0x02, "XENIX root", "xenix", "", ""},
00136   {0x03, "XENIX usr", "xenix", "", ""},
00137   {0x04, "FAT16 <32M", "fat16", "", ""},
00138   {                                               /* DOS 3.3+ extended partition */
00139     0x05, "Extended", "extended", "multi", ""
00140   },
00141   {                                               /* DOS 16-bit >=32M */
00142     0x06, "FAT16", "fat16", "", ""
00143   },
00144   {                                               /* OS/2 IFS, eg, HPFS or NTFS or QNX */
00145     0x07, "HPFS/NTFS", "ntfs", "", ""
00146   },
00147   {                                               /* AIX boot (AIX -- PS/2 port) or SplitDrive */
00148     0x08, "AIX", "", "", ""
00149   },
00150   {                                               /* AIX data or Coherent */
00151     0x09, "AIX bootable", "", "boot", ""
00152   },
00153   {                                               /* OS/2 Boot Manager */
00154     0x0a, "OS/2 Boot Manager", "", "boot,nofs", ""
00155   },
00156   {0x0b, "W95 FAT32", "fat32", "", ""},
00157   {                                               /* LBA really is `Extended Int 13h' */
00158     0x0c, "W95 FAT32 (LBA)", "fat32", "", ""
00159   },
00160   {0x0e, "W95 FAT16 (LBA)", "fat32", "", ""},
00161   {0x0f, "W95 Ext'd (LBA)", "fat32", "", ""},
00162   {0x10, "OPUS", "", "", ""},
00163   {0x11, "Hidden FAT12", "fat12", "hidden", ""},
00164   {0x12, "Compaq diagnostics", "", "boot", ""},
00165   {0x14, "Hidden FAT16 <32M", "", "hidden", ""},
00166   {0x16, "Hidden FAT16", "", "hidden", ""},
00167   {0x17, "Hidden HPFS/NTFS", "ntfs", "hidden", ""},
00168   {0x18, "AST SmartSleep", "", "nofs", ""},
00169   {0x1b, "Hidden W95 FAT32", "", "hidden", ""},
00170   {0x1c, "Hidden W95 FAT32 (LBA)", "", "hidden", ""},
00171   {0x1e, "Hidden W95 FAT16 (LBA)", "", "hidden", ""},
00172   {0x24, "NEC DOS", "", "", ""},
00173   {0x39, "Plan 9", "plan9", "", ""},
00174   {0x3c, "PartitionMagic recovery", "", "nofs", ""},
00175   {0x40, "Venix 80286", "", "", ""},
00176   {0x41, "PPC PReP Boot", "", "boot", ""},
00177   {0x42, "SFS", "", "", ""},
00178   {0x4d, "QNX4.x", "", "", ""},
00179   {0x4e, "QNX4.x 2nd part", "", "", ""},
00180   {0x4f, "QNX4.x 3rd part", "", "", ""},
00181   {0x50, "OnTrack DM", "", "", ""},
00182   {                                               /* (or Novell) */
00183     0x51, "OnTrack DM6 Aux1", "", "", ""
00184   },
00185   {                                               /* CP/M or Microport SysV/AT */
00186     0x52, "CP/M", "cpm", "", ""
00187   },
00188   {0x53, "OnTrack DM6 Aux3", "", "", ""},
00189   {0x54, "OnTrackDM6", "", "", ""},
00190   {0x55, "EZ-Drive", "", "", ""},
00191   {0x56, "Golden Bow", "", "", ""},
00192   {0x5c, "Priam Edisk", "", "", ""},
00193   {0x61, "SpeedStor", "", "", ""},
00194   {                                               /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
00195     0x63, "GNU HURD or SysV", "", "", ""
00196   },
00197   {0x64, "Novell Netware 286", "", "", ""},
00198   {0x65, "Novell Netware 386", "", "", ""},
00199   {0x70, "DiskSecure Multi-Boot", "", "boot", ""},
00200   {0x75, "PC/IX", "", "", ""},
00201   {                                               /* Minix 1.4a and earlier */
00202     0x80, "Old Minix", "minix", "", ""
00203   },
00204   {                                               /* Minix 1.4b and later */
00205     0x81, "Minix / old Linux", "minix", "", ""
00206   },
00207   {0x82, "Linux swap / Solaris", "swap", "nofs", ""},
00208   {0x83, "Linux filesystem", "linux", "", ""},
00209   {0x84, "OS/2 hidden C: drive", "", "hidden", ""},
00210   {0x85, "Linux extended", "", "multi", ""},
00211   {0x86, "NTFS volume set", "", "multi", "md"},
00212   {0x87, "NTFS volume set", "", "multi", "md"},
00213   {0x88, "Linux plaintext", "", "", ""},
00214   {0x8e, "Linux LVM Physical Volume", "lvm", "multi", "md"},
00215   {0x93, "Amoeba", "", "", ""},
00216   {                                               /* (bad block table) */
00217     0x94, "Amoeba BBT", "", "", ""
00218   },
00219   {                                               /* BSDI */
00220     0x9f, "BSD/OS", "bsdos", "", ""
00221   },
00222   {0xa0, "IBM Thinkpad hibernation", "", "nofs", ""},
00223   {                                               /* various BSD flavours */
00224     0xa5, "FreeBSD", "freebsd", "", ""
00225   },
00226   {0xa6, "OpenBSD", "openbsd", "", ""},
00227   {0xa7, "NeXTSTEP", "nextstep", "", ""},
00228   {0xa8, "Darwin/OS X UFS", "darwin", "", ""},
00229   {0xa9, "NetBSD", "netbsd", "", ""},
00230   {0xab, "Darwin/OS X boot", "", "boot,nofs", ""},
00231   {0xac, "Darwin/OS X RAID", "", "multi", "md"},
00232   {0xaf, "Darwin/OS X HFS+", "hfs", "", ""},
00233   {0xb7, "BSDI fs", "", "", ""},
00234   {0xb8, "BSDI swap", "", "nofs", ""},
00235   {0xbb, "Boot Wizard hidden", "", "boot,nofs", ""},
00236   {0xbe, "Solaris boot", "", "boot,nofs", ""},
00237   {0xbf, "Solaris", "", "", ""},
00238   {0xc1, "DRDOS/sec (FAT-12)", "", "", ""},
00239   {0xc4, "DRDOS/sec (FAT-16 < 32M)", "", "", ""},
00240   {0xc6, "DRDOS/sec (FAT-16)", "", "", ""},
00241   {0xc7, "Syrinx", "", "", ""},
00242   {0xda, "Non-FS data", "", "nofs", ""},
00243   {0xdb, "CP/M / CTOS / ...", "", "", ""},
00244 /* CP/M or Concurrent CP/M or
00245              Concurrent DOS or CTOS */
00246   {                                               /* Dell PowerEdge Server utilities */
00247     0xde, "Dell Utility", "", "", ""
00248   },
00249   {                                               /* BootIt EMBRM */
00250     0xdf, "BootIt", "", "boot,nofs", ""
00251   },
00252   {0xe1, "DOS access", "", "", ""},
00253 /* DOS access or SpeedStor 12-bit FAT
00254              extended partition */
00255   {                                               /* DOS R/O or SpeedStor */
00256     0xe3, "DOS R/O", "", "", ""
00257   },
00258   {0xe4, "SpeedStor", "", "", ""},
00259 /* SpeedStor 16-bit FAT extended
00260              partition < 1024 cyl. */
00261   {0xeb, "BeOS fs", "", "", ""},
00262   {                                               /* Intel EFI GUID Partition Table */
00263     0xee, "EFI GPT", "", "nofs", ""
00264   },
00265   {                                               /* Intel EFI System Partition */
00266     0xef, "EFI (FAT-12/16/32)", "", "boot", ""
00267   },
00268   {                                               /* Linux/PA-RISC boot loader */
00269     0xf0, "Linux/PA-RISC boot", "", "boot", ""
00270   },
00271   {0xf1, "SpeedStor", "", "", ""},
00272   {                                               /* SpeedStor large partition */
00273     0xf4, "SpeedStor", "", "", ""
00274   },
00275   {                                               /* DOS 3.3+ secondary */
00276     0xf2, "DOS secondary", "", "", ""
00277   },
00278   {0xfd, "Linux raid autodetect", "", "multi", "md"},
00279 /* New (2.2.x) raid partition with
00280                  autodetect using persistent
00281                  superblock */
00282   {                                               /* SpeedStor >1024 cyl. or LANstep */
00283     0xfe, "LANstep", "", "", ""
00284   },
00285   {                                               /* Xenix Bad Block Table */
00286     0xff, "BBT", "", "", ""
00287   },
00288   { 0, NULL, NULL, NULL }
00289 };
00290 
00291 static unsigned int lastlogicalpart = 5;
00292 
00293 static bool guess_logicalname(source & s, const hwNode & disk, unsigned int n, hwNode & partition)
00294 {
00295   struct stat buf;
00296   char name[10];
00297   int dev = 0;
00298 
00299   snprintf(name, sizeof(name), "%d", n);
00300   if(disk.getBusInfo()!="")
00301     partition.setBusInfo(disk.getBusInfo()+string(",")+string(name));
00302 
00303   if(fstat(s.fd, &buf)!=0) return false;
00304   if(!S_ISBLK(buf.st_mode)) return false;
00305 
00306   if(s.diskname!="")
00307     dev = open_dev(buf.st_rdev + n, s.diskname+string(name));
00308   else
00309     dev = open_dev(buf.st_rdev + n, disk.getLogicalName()+string(name));
00310 
00311   if(dev>=0)
00312   {
00313     source spart = s;
00314     unsigned char buffer1[BLOCKSIZE], buffer2[BLOCKSIZE];
00315 
00316     spart.offset = 0;
00317     spart.fd = dev;
00318     spart.diskname = "";
00319 
00320     // read the first sector
00321     if((readlogicalblocks(s, buffer1, 0, 1)!=1) ||
00322       (readlogicalblocks(spart, buffer2, 0, 1)!=1))
00323     {
00324       close(dev);
00325       return false;
00326     }
00327 
00328     close(dev);
00329 
00330     if(memcmp(buffer1, buffer2, BLOCKSIZE)==0)
00331     {
00332       partition.claim();
00333       if(s.diskname!="")
00334         partition.setLogicalName(s.diskname+string(name));
00335       else
00336         partition.setLogicalName(disk.getLogicalName()+string(name));
00337       return true;
00338     }
00339   }
00340 
00341   return false;
00342 }
00343 
00344 
00345 static bool is_extended(unsigned char type)
00346 {
00347   return (type == 0x5) || (type == 0xf) || (type == 0x85);
00348 }
00349 
00350 
00351 static bool read_dospartition(source & s, unsigned short i, dospartition & p)
00352 {
00353   static unsigned char buffer[BLOCKSIZE];
00354   unsigned char flags = 0;
00355 
00356   if(readlogicalblocks(s, buffer, 0, 1)!=1)       // read the first sector
00357     return false;
00358 
00359   if(le_short(buffer+510)!=0xaa55)                // wrong magic number
00360     return false;
00361 
00362   flags = buffer[446 + i*16];
00363   if(flags!=0 && flags!=0x80)
00364 // inconsistency: partition is either
00365     return false;                                 // bootable or non-bootable
00366 
00367   p.flags = flags;
00368   p.type = buffer[446 + i*16 + 4];
00369   p.start = s.blocksize*(unsigned long long)le_long(buffer + 446 + i*16 + 8);
00370   p.size = s.blocksize*(unsigned long long)le_long(buffer + 446 + i*16 + 12);
00371 
00372   return true;
00373 }
00374 
00375 
00376 static bool analyse_dospart(source & s,
00377 unsigned char flags,
00378 unsigned char type,
00379 hwNode & partition);
00380 
00381 static bool analyse_dosextpart(source & s,
00382 unsigned char flags,
00383 unsigned char type,
00384 hwNode & extpart)
00385 {
00386   source extendedpart = s;
00387   int i = 0;
00388   dospartition pte[2];                            // we only read entries #0 and #1
00389 
00390   if(!is_extended(type))                          // this is not an extended partition
00391     return false;
00392 
00393   extpart.setDescription("Extended partition");
00394   extpart.addCapability("extended", "Extended partition");
00395   extpart.addCapability("partitioned", "Partitioned disk");
00396   extpart.addCapability("partitioned:extended", "Extended partition");
00397   extpart.setSize(extpart.getCapacity());
00398 
00399   extpart.describeCapability("nofs", "No filesystem");
00400 
00401   do
00402   {
00403     for(i=0; i<2; i++)
00404       if(!read_dospartition(extendedpart, i, pte[i]))
00405         return false;
00406 
00407     if((pte[0].type == 0) || (pte[0].size == 0))
00408       return true;
00409     else
00410     {
00411       hwNode partition("logicalvolume", hw::volume);
00412       source spart = extendedpart;
00413 
00414       spart.offset = extendedpart.offset + pte[0].start;
00415       spart.size = pte[0].size;
00416 
00417       partition.setPhysId(lastlogicalpart);
00418       partition.setCapacity(spart.size);
00419 
00420       if(analyse_dospart(spart, pte[0].flags, pte[0].type, partition))
00421       {
00422         guess_logicalname(spart, extpart, lastlogicalpart, partition);
00423         extpart.addChild(partition);
00424         lastlogicalpart++;
00425       }
00426     }
00427 
00428     if((pte[1].type == 0) || (pte[1].size == 0))
00429       return true;
00430     else
00431     {
00432       extendedpart.offset = s.offset + pte[1].start;
00433       extendedpart.size = pte[1].size;
00434       if(!is_extended(pte[1].type))
00435         return false;
00436     }
00437   } while(true);
00438 
00439   return true;
00440 }
00441 
00442 
00443 static bool analyse_dospart(source & s,
00444 unsigned char flags,
00445 unsigned char type,
00446 hwNode & partition)
00447 {
00448   int i = 0;
00449 
00450   if(is_extended(type))
00451     return analyse_dosextpart(s, flags, type, partition);
00452 
00453   if(flags!=0 && flags!=0x80)                     // inconsistency: partition is either bootable or non-bootable
00454     return false;
00455 
00456   if(s.offset==0 || s.size==0)                    // unused entry
00457     return false;
00458 
00459   partition.setCapacity(s.size);
00460 
00461   if(flags == 0x80)
00462     partition.addCapability("bootable", "Bootable partition (active)");
00463 
00464   while(dos_sys_types[i].id)
00465   {
00466     if(dos_sys_types[i].type == type)
00467     {
00468       partition.setDescription(string(dos_sys_types[i].description)+" partition");
00469       if(lowercase(dos_sys_types[i].capabilities) != "")
00470       {
00471         vector<string> capabilities;
00472         splitlines(dos_sys_types[i].capabilities, capabilities, ',');
00473 
00474         for(unsigned j=0; j<capabilities.size(); j++)
00475           partition.addCapability(capabilities[j]);
00476       }
00477       if(lowercase(dos_sys_types[i].icon) != "")
00478         partition.addHint("icon", string(dos_sys_types[i].icon));
00479       else
00480         partition.addHint("icon", string("disc"));
00481       break;
00482     }
00483     i++;
00484   }
00485 
00486   partition.describeCapability("nofs", "No filesystem");
00487   partition.describeCapability("boot", "Contains boot code");
00488   partition.describeCapability("multi", "Multi-volumes");
00489   partition.describeCapability("hidden", "Hidden partition");
00490 
00491   scan_lvm(partition, s);
00492 
00493   return true;
00494 }
00495 
00496 
00497 #define UNUSED_ENTRY_GUID \
00498 ((efi_guid_t) \
00499 { \
00500   0x00000000, 0x0000, 0x0000, 0x00, 00, \
00501   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } \
00502 })
00503 
00504 #define PARTITION_PRECIOUS 1
00505 #define PARTITION_READONLY (1LL << 60)
00506 #define PARTITION_HIDDEN   (1LL << 62)
00507 #define PARTITION_NOMOUNT  (1LL << 63)
00508 
00509 /* returns the EFI-style CRC32 value for buf
00510  * Dec 5, 2000 Matt Domsch <Matt_Domsch@dell.com>
00511  * - Copied crc32.c from the linux/drivers/net/cipe directory.
00512  * - Now pass seed as an arg
00513  * - changed unsigned long to uint32_t, added #include<stdint.h>
00514  * - changed len to be an unsigned long
00515  * - changed crc32val to be a register
00516  * - License remains unchanged!  It's still GPL-compatable!
00517  */
00518 
00519 /* ============================================================= */
00520 /*  COPYRIGHT (C) 1986 Gary S. Brown.  You may use this program, or       */
00521 /*  code or tables extracted from it, as desired without restriction.     */
00522 /*                                                                        */
00523 /*  First, the polynomial itself and its table of feedback terms.  The    */
00524 /*  polynomial is                                                         */
00525 /*  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   */
00526 /*                                                                        */
00527 /*  Note that we take it "backwards" and put the highest-order term in    */
00528 /*  the lowest-order bit.  The X^32 term is "implied"; the LSB is the     */
00529 /*  X^31 term, etc.  The X^0 term (usually shown as "+1") results in      */
00530 /*  the MSB being 1.                                                      */
00531 /*                                                                        */
00532 /*  Note that the usual hardware shift register implementation, which     */
00533 /*  is what we're using (we're merely optimizing it by doing eight-bit    */
00534 /*  chunks at a time) shifts bits into the lowest-order term.  In our     */
00535 /*  implementation, that means shifting towards the right.  Why do we     */
00536 /*  do it this way?  Because the calculated CRC must be transmitted in    */
00537 /*  order from highest-order term to lowest-order term.  UARTs transmit   */
00538 /*  characters in order from LSB to MSB.  By storing the CRC this way,    */
00539 /*  we hand it to the UART in the order low-byte to high-byte; the UART   */
00540 /*  sends each low-bit to hight-bit; and the result is transmission bit   */
00541 /*  by bit from highest- to lowest-order term without requiring any bit   */
00542 /*  shuffling on our part.  Reception works similarly.                    */
00543 /*                                                                        */
00544 /*  The feedback terms table consists of 256, 32-bit entries.  Notes:     */
00545 /*                                                                        */
00546 /*      The table can be generated at runtime if desired; code to do so   */
00547 /*      is shown later.  It might not be obvious, but the feedback        */
00548 /*      terms simply represent the results of eight shift/xor opera-      */
00549 /*      tions for all combinations of data and CRC register values.       */
00550 /*                                                                        */
00551 /*      The values must be right-shifted by eight bits by the "updcrc"    */
00552 /*      logic; the shift must be unsigned (bring in zeroes).  On some     */
00553 /*      hardware you could probably optimize the shift in assembler by    */
00554 /*      using byte-swap instructions.                                     */
00555 /*      polynomial $edb88320                                              */
00556 /*                                                                        */
00557 /*  --------------------------------------------------------------------  */
00558 
00559 static uint32_t crc32_tab[] =
00560 {
00561   0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
00562   0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
00563   0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
00564   0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
00565   0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
00566   0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
00567   0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
00568   0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
00569   0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
00570   0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
00571   0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
00572   0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
00573   0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
00574   0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
00575   0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
00576   0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
00577   0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
00578   0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
00579   0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
00580   0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
00581   0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
00582   0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
00583   0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
00584   0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
00585   0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
00586   0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
00587   0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
00588   0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
00589   0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
00590   0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
00591   0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
00592   0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
00593   0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
00594   0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
00595   0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
00596   0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
00597   0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
00598   0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
00599   0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
00600   0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
00601   0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
00602   0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
00603   0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
00604   0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
00605   0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
00606   0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
00607   0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
00608   0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
00609   0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
00610   0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
00611   0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
00612   0x2d02ef8dL
00613 };
00614 
00615 /* Return a 32-bit CRC of the contents of the buffer. */
00616 
00617 uint32_t
00618 __efi_crc32(const void *buf, unsigned long len, uint32_t seed)
00619 {
00620   unsigned long i;
00621   register uint32_t crc32val;
00622   const unsigned char *s = (const unsigned char *)buf;
00623 
00624   crc32val = seed;
00625   for (i = 0;  i < len;  i ++)
00626   {
00627     crc32val =
00628       crc32_tab[(crc32val ^ s[i]) & 0xff] ^
00629       (crc32val >> 8);
00630   }
00631   return crc32val;
00632 }
00633 
00634 
00635 /*
00636  *      This function uses the crc32 function by Gary S. Brown,
00637  * but seeds the function with ~0, and xor's with ~0 at the end.
00638  */
00639 static inline uint32_t
00640 efi_crc32(const void *buf, unsigned long len)
00641 {
00642   return (__efi_crc32(buf, len, ~0L) ^ ~0L);
00643 }
00644 
00645 
00646 static efi_guid_t read_efi_guid(uint8_t *buffer)
00647 {
00648   efi_guid_t result;
00649 
00650   memset(&result, 0, sizeof(result));
00651 
00652   result.time_low = le_long(buffer);
00653   result.time_mid = le_short(buffer+4);
00654   result.time_hi_and_version = le_short(buffer+4+2);
00655   result.clock_seq_hi_and_reserved = *(buffer+4+2+2);
00656   result.clock_seq_low = *(buffer+4+2+2+1);
00657   memcpy(result.node, buffer+4+2+2+1+1, sizeof(result.node));
00658 
00659   return result;
00660 }
00661 
00662 
00663 bool operator ==(const efi_guid_t & guid1, const efi_guid_t & guid2)
00664 {
00665   return (guid1.time_low == guid2.time_low) &&
00666     (guid1.time_mid == guid2.time_mid) &&
00667     (guid1.time_hi_and_version == guid2.time_hi_and_version) &&
00668     (guid1.clock_seq_hi_and_reserved == guid2.clock_seq_hi_and_reserved) &&
00669     (guid1.clock_seq_low == guid2.clock_seq_low) &&
00670     (memcmp(guid1.node, guid2.node, sizeof(guid1.node))==0);
00671 }
00672 
00673 
00674 static string tostring(const efi_guid_t & guid)
00675 {
00676   char buffer[50];
00677 
00678   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]);
00679   return string(buffer);
00680 }
00681 
00682 bool operator ==(const efi_guid_t & guid1, const string & guid2)
00683 {
00684   return strcasecmp(tostring(guid1).c_str(), guid2.c_str()) == 0;
00685 }
00686 
00687 static bool detect_gpt(source & s, hwNode & n)
00688 {
00689   static uint8_t buffer[BLOCKSIZE];
00690   static gpth gpt_header;
00691   uint32_t i = 0;
00692   char gpt_version[8];
00693   uint8_t *partitions = NULL;
00694   uint8_t type;
00695 
00696   if(s.offset!=0)
00697     return false;                                 // partition tables must be at the beginning of the disk
00698 
00699                                                   // read the first sector
00700   if(readlogicalblocks(s, buffer, GPT_PMBR_LBA, 1)!=1)
00701     return false;
00702 
00703   if(le_short(buffer+510)!=0xaa55)                // wrong magic number
00704     return false;
00705 
00706   for(i=0; i<4; i++)
00707   {
00708     type = buffer[446 + i*16 + 4];
00709 
00710     if((type != 0) && (type != EFI_PMBR_OSTYPE_EFI))
00711       return false;                               // the EFI pseudo-partition must be the only partition
00712   }
00713 
00714                                                   // read the second sector
00715   if(readlogicalblocks(s, buffer, GPT_PRIMARY_HEADER_LBA, 1)!=1)
00716     return false;                                 // (partition table header)
00717 
00718   gpt_header.Signature = le_longlong(buffer);
00719   gpt_header.Revision = be_long(buffer + 0x8);    // big endian so that 1.0 -> 0x100
00720   gpt_header.HeaderSize = le_long(buffer + 0xc);
00721   gpt_header.HeaderCRC32 = le_long(buffer + 0x10);
00722   gpt_header.MyLBA = le_longlong(buffer + 0x18);
00723   gpt_header.AlternateLBA = le_longlong(buffer + 0x20);
00724   gpt_header.FirstUsableLBA = le_longlong(buffer + 0x28);
00725   gpt_header.LastUsableLBA = le_longlong(buffer + 0x30);
00726   gpt_header.DiskGUID = read_efi_guid(buffer + 0x38);
00727   gpt_header.PartitionEntryLBA = le_longlong(buffer + 0x48);
00728   gpt_header.NumberOfPartitionEntries = le_long(buffer + 0x50);
00729   gpt_header.SizeOfPartitionEntry = le_long(buffer + 0x54);
00730   gpt_header.PartitionEntryArrayCRC32 = le_long(buffer + 0x58);
00731 
00732                                                   // zero-out the CRC32 before re-calculating it
00733   memset(buffer + 0x10, 0, sizeof(gpt_header.HeaderCRC32));
00734   if(gpt_header.Signature != GPT_HEADER_SIGNATURE)
00735     return false;
00736 
00737   if(efi_crc32(buffer, 92) != gpt_header.HeaderCRC32)
00738     return false;                                 // check CRC32
00739 
00740   snprintf(gpt_version, sizeof(gpt_version), "%d.%02d", (gpt_header.Revision >> 8), (gpt_header.Revision & 0xff));
00741 
00742   n.addCapability("gpt-"+string(gpt_version), "GUID Partition Table version "+string(gpt_version));
00743   n.addHint("partitions", gpt_header.NumberOfPartitionEntries);
00744   n.setConfig("guid", tostring(gpt_header.DiskGUID));
00745   n.setHandle("GUID:" + tostring(gpt_header.DiskGUID));
00746   n.addHint("guid", tostring(gpt_header.DiskGUID));
00747 
00748   partitions = (uint8_t*)malloc(gpt_header.NumberOfPartitionEntries * gpt_header.SizeOfPartitionEntry + BLOCKSIZE);
00749   if(!partitions)
00750     return false;
00751   memset(partitions, 0, gpt_header.NumberOfPartitionEntries * gpt_header.SizeOfPartitionEntry + BLOCKSIZE);
00752   readlogicalblocks(s, partitions,
00753     gpt_header.PartitionEntryLBA,
00754     (gpt_header.NumberOfPartitionEntries * gpt_header.SizeOfPartitionEntry)/BLOCKSIZE + 1);
00755 
00756   for(i=0; i<gpt_header.NumberOfPartitionEntries; i++)
00757   {
00758     hwNode partition("volume", hw::volume);
00759     efipartition p;
00760 
00761     p.PartitionTypeGUID = read_efi_guid(partitions + gpt_header.SizeOfPartitionEntry * i);
00762     p.PartitionGUID = read_efi_guid(partitions + gpt_header.SizeOfPartitionEntry * i + 0x10);
00763     p.StartingLBA = le_longlong(partitions + gpt_header.SizeOfPartitionEntry * i + 0x20);
00764     p.EndingLBA = le_longlong(partitions + gpt_header.SizeOfPartitionEntry * i + 0x28);
00765     p.Attributes = le_longlong(partitions + gpt_header.SizeOfPartitionEntry * i + 0x30);
00766     for(int j=0; j<36; j++)
00767     {
00768       wchar_t c = le_short(partitions + gpt_header.SizeOfPartitionEntry * i + 0x38 + 2*j);
00769       if(!c)
00770         break;
00771       else
00772         p.PartitionName += utf8(c);
00773     }
00774 
00775     if(!(p.PartitionTypeGUID == UNUSED_ENTRY_GUID))
00776     {
00777       source spart = s;
00778       if(p.PartitionTypeGUID == "C12A7328-F81F-11D2-BA4B-00A0C93EC93B")
00779       {
00780         partition.setDescription("System partition");
00781         partition.setVendor("EFI");
00782         partition.addCapability("boot");
00783       }
00784       else
00785       if(p.PartitionTypeGUID == "024DEE41-33E7-11D3-9D69-0008C781F39F")
00786       {
00787         partition.setDescription("MBR partition scheme");
00788         partition.setVendor("EFI");
00789         partition.addCapability("nofs");
00790       }
00791       else
00792       if(p.PartitionTypeGUID == "21686148-6449-6E6F-744E-656564454649")
00793       {
00794         partition.setDescription("BIOS Boot partition");
00795         partition.setVendor("EFI");
00796         partition.addCapability("nofs");
00797       }
00798       else
00799       if(p.PartitionTypeGUID == "0657FD6D-A4AB-43C4-84E5-0933C84B4F4F")
00800       {
00801         partition.setDescription("swap partition");
00802         partition.setVendor("Linux");
00803         partition.addCapability("nofs");
00804       }
00805       else
00806       if(p.PartitionTypeGUID == "A19D880F-05FC-4D3B-A006-743F0F84911E")
00807       {
00808         partition.setDescription("RAID partition");
00809         partition.setVendor("Linux");
00810         partition.addCapability("multi");
00811       }
00812       else
00813       if(p.PartitionTypeGUID == "E6D6D379-F507-44C2-A23C-238F2A3DF928")
00814       {
00815         partition.setDescription("LVM Physical Volume");
00816         partition.setVendor("Linux");
00817         partition.addCapability("multi");
00818       }
00819       else
00820       if(p.PartitionTypeGUID == "8DA63339-0007-60C0-C436-083AC8230908")
00821       {
00822         partition.setDescription("reserved partition");
00823         partition.setVendor("Linux");
00824         partition.addCapability("nofs");
00825       }
00826       else
00827       if(p.PartitionTypeGUID == "75894C1E-3AEB-11D3-B7C1-7B03A0000000")
00828       {
00829         partition.setDescription("data partition");
00830         partition.setVendor("HP-UX");
00831       }
00832       else
00833       if(p.PartitionTypeGUID == "E2A1E728-32E3-11D6-A682-7B03A0000000")
00834       {
00835         partition.setDescription("service partition");
00836         partition.setVendor("HP-UX");
00837         partition.addCapability("nofs");
00838         partition.addCapability("boot");
00839       }
00840       else
00841       if(p.PartitionTypeGUID == "48465300-0000-11AA-AA11-00306543ECAC")
00842       {
00843         partition.setDescription("Apple HFS+ partition");
00844         partition.setVendor("Mac OS X");
00845       }
00846       else
00847       if(p.PartitionTypeGUID == "6A898CC3-1DD2-11B2-99A6-080020736631")
00848       {
00849         partition.setDescription("OS X ZFS partition or Solaris /usr partition");
00850         partition.setVendor("Solaris");
00851       }
00852       else
00853       if(p.PartitionTypeGUID == "52414944-0000-11AA-AA11-00306543ECAC")
00854       {
00855         partition.setDescription("RAID partition");
00856         partition.setVendor("Mac OS X");
00857         partition.addCapability("multi");
00858       }
00859       else
00860       if(p.PartitionTypeGUID == "52414944-5F4F-11AA-AA11-00306543ECAC")
00861       {
00862         partition.setDescription("RAID partition (offline)");
00863         partition.setVendor("Mac OS X");
00864         partition.addCapability("multi");
00865         partition.addCapability("offline");
00866       }
00867       else
00868       if(p.PartitionTypeGUID == "4C616265-6C00-11AA-AA11-00306543ECAC")
00869       {
00870         partition.setDescription("Apple label");
00871         partition.setVendor("Mac OS X");
00872         partition.addCapability("nofs");
00873       }
00874       else
00875       if(p.PartitionTypeGUID == "5265636F-7665-11AA-AA11-00306543ECAC")
00876       {
00877         partition.setDescription("recovery partition");
00878         partition.setVendor("Apple TV");
00879         partition.addCapability("nofs");
00880       }
00881       else
00882       if(p.PartitionTypeGUID == "53746F72-6167-11AA-AA11-00306543ECAC")
00883       {
00884         partition.setDescription("Apple Core Storage (File Vault)");
00885         partition.setVendor("Mac OS X");
00886         partition.addCapability("encrypted");
00887       }
00888       else
00889       if(p.PartitionTypeGUID == "426F6F74-0000-11AA-AA11-00306543ECAC")
00890       {
00891         partition.setDescription("boot partition");
00892         partition.setVendor("Mac OS X");
00893         partition.addCapability("boot");
00894       }
00895       else
00896       if(p.PartitionTypeGUID == "55465300-0000-11AA-AA11-00306543ECAC")
00897       {
00898         partition.setDescription("UFS partition");
00899         partition.setVendor("Mac OS X");
00900       }
00901       else
00902       if(p.PartitionTypeGUID == "516E7CB4-6ECF-11D6-8FF8-00022D09712B")
00903       {
00904         partition.setDescription("data partition");
00905         partition.setVendor("FreeBSD");
00906       }
00907       else
00908       if(p.PartitionTypeGUID == "516E7CB6-6ECF-11D6-8FF8-00022D09712B")
00909       {
00910         partition.setDescription("UFS partition");
00911         partition.setVendor("FreeBSD");
00912       }
00913       else
00914       if(p.PartitionTypeGUID == "516E7CBA-6ECF-11D6-8FF8-00022D09712B")
00915       {
00916         partition.setDescription("ZFS partition");
00917         partition.setVendor("FreeBSD");
00918       }
00919       else
00920       if(p.PartitionTypeGUID == "516E7CB8-6ECF-11D6-8FF8-00022D09712B")
00921       {
00922         partition.setDescription("Vinum Volume Manager partition");
00923         partition.setVendor("FreeBSD");
00924       }
00925       else
00926       if(p.PartitionTypeGUID == "516E7CB5-6ECF-11D6-8FF8-00022D09712B")
00927       {
00928         partition.setDescription("swap partition");
00929         partition.setVendor("FreeBSD");
00930         partition.addCapability("nofs");
00931       }
00932       else
00933       if(p.PartitionTypeGUID == "83BD6B9D-7F41-11DC-BE0B-001560B84F0F")
00934       {
00935         partition.setDescription("boot partition");
00936         partition.setVendor("FreeBSD");
00937         partition.addCapability("boot");
00938       }
00939       else
00940       if(p.PartitionTypeGUID == "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7")
00941       {
00942         partition.setDescription("data partition");
00943         partition.setVendor("Windows");
00944       }
00945       else
00946       if(p.PartitionTypeGUID == "DE94BBA4-06D1-4D40-A16A-BFD50179D6AC")
00947       {
00948         partition.setDescription("recovery environment");
00949         partition.setVendor("Windows");
00950         partition.addCapability("boot");
00951       }
00952       else
00953       if(p.PartitionTypeGUID == "37AFFC90-EF7D-4E96-91C3-2D7AE055B174")
00954       {
00955         partition.setDescription("IBM GPFS partition");
00956         partition.setVendor("Windows");
00957       }
00958       else
00959       if(p.PartitionTypeGUID == "5808C8AA-7E8F-42E0-85D2-E1E90434CFB3")
00960       {
00961         partition.setDescription("LDM configuration");
00962         partition.setVendor("Windows");
00963         partition.addCapability("nofs");
00964       }
00965       else
00966       if(p.PartitionTypeGUID == "AF9B60A0-1431-4F62-BC68-3311714A69AD")
00967       {
00968         partition.setDescription("LDM data partition");
00969         partition.setVendor("Windows");
00970         partition.addCapability("multi");
00971       }
00972       else
00973       if(p.PartitionTypeGUID == "E3C9E316-0B5C-4DB8-817D-F92DF00215AE")
00974       {
00975         partition.setDescription("reserved partition");
00976         partition.setVendor("Windows");
00977         partition.addCapability("nofs");
00978       }
00979       else
00980       if(p.PartitionTypeGUID == "FE3A2A5D-4F32-41A7-B725-ACCC3285A309")
00981       {
00982         partition.setDescription("kernel");
00983         partition.setVendor("ChromeOS");
00984       }
00985       else
00986       if(p.PartitionTypeGUID == "3CB8E202-3B7E-47DD-8A3C-7FF2A13CFCEC")
00987       {
00988         partition.setDescription("root filesystem");
00989         partition.setVendor("ChromeOS");
00990       }
00991       else
00992       if(p.PartitionTypeGUID == "2E0A753D-9E48-43B0-8337-B15192CB1B5E")
00993       {
00994         partition.setDescription("reserved");
00995         partition.setVendor("ChromeOS");
00996       }
00997       else
00998       if(p.PartitionTypeGUID == "6A82CB45-1DD2-11B2-99A6-080020736631")
00999       {
01000         partition.setDescription("boot partition");
01001         partition.setVendor("Solaris");
01002         partition.addCapability("boot");
01003       }
01004       else
01005       if(p.PartitionTypeGUID == "6A85CF4D-1DD2-11B2-99A6-080020736631")
01006       {
01007         partition.setDescription("root partition");
01008         partition.setVendor("Solaris");
01009       }
01010       else
01011       if(p.PartitionTypeGUID == "6A87C46F-1DD2-11B2-99A6-080020736631")
01012       {
01013         partition.setDescription("swap partition");
01014         partition.setVendor("Solaris");
01015         partition.addCapability("nofs");
01016       }
01017       else
01018       if(p.PartitionTypeGUID == "6A8B642B-1DD2-11B2-99A6-080020736631")
01019       {
01020         partition.setDescription("backup partition");
01021         partition.setVendor("Solaris");
01022       }
01023       else
01024       if(p.PartitionTypeGUID == "6A8EF2E9-1DD2-11B2-99A6-080020736631")
01025       {
01026         partition.setDescription("/var partition");
01027         partition.setVendor("Solaris");
01028       }
01029       else
01030       if(p.PartitionTypeGUID == "6A90BA39-1DD2-11B2-99A6-080020736631")
01031       {
01032         partition.setDescription("/home partition");
01033         partition.setVendor("Solaris");
01034       }
01035       else
01036       if(p.PartitionTypeGUID == "6A9283A5-1DD2-11B2-99A6-080020736631")
01037       {
01038         partition.setDescription("alternate sector");
01039         partition.setVendor("Solaris");
01040         partition.addCapability("nofs");
01041       }
01042       else
01043       if(p.PartitionTypeGUID == "6A945A3B-1DD2-11B2-99A6-080020736631" ||
01044          p.PartitionTypeGUID == "6A9630D1-1DD2-11B2-99A6-080020736631" ||
01045          p.PartitionTypeGUID == "6A980767-1DD2-11B2-99A6-080020736631" ||
01046          p.PartitionTypeGUID == "6A96237F-1DD2-11B2-99A6-080020736631" ||
01047          p.PartitionTypeGUID == "6A8D2AC7-1DD2-11B2-99A6-080020736631"
01048         )
01049       {
01050         partition.setDescription("reserved partition");
01051         partition.setVendor("Solaris");
01052       }
01053       else
01054       if(p.PartitionTypeGUID == "49F48D32-B10E-11DC-B99B-0019D1879648")
01055       {
01056         partition.setDescription("swap partition");
01057         partition.setVendor("NetBSD");
01058         partition.addCapability("nofs");
01059       }
01060       else
01061       if(p.PartitionTypeGUID == "49F48D5A-B10E-11DC-B99B-0019D1879648")
01062       {
01063         partition.setDescription("FFS partition");
01064         partition.setVendor("NetBSD");
01065       }
01066       else
01067       if(p.PartitionTypeGUID == "49F48D82-B10E-11DC-B99B-0019D1879648")
01068       {
01069         partition.setDescription("LFS partition");
01070         partition.setVendor("NetBSD");
01071       }
01072       else
01073       if(p.PartitionTypeGUID == "49F48DAA-B10E-11DC-B99B-0019D1879648")
01074       {
01075         partition.setDescription("RAID partition");
01076         partition.setVendor("NetBSD");
01077         partition.addCapability("multi");
01078       }
01079       else
01080       if(p.PartitionTypeGUID == "2DB519C4-B10F-11DC-B99B-0019D1879648")
01081       {
01082         partition.setDescription("concatenated partition");
01083         partition.setVendor("NetBSD");
01084         partition.addCapability("multi");
01085       }
01086       else
01087       if(p.PartitionTypeGUID == "2DB519EC-B10F-11DC-B99B-0019D1879648")
01088       {
01089         partition.setDescription("encrypted partition");
01090         partition.setVendor("NetBSD");
01091         partition.addCapability("encrypted");
01092       }
01093       else
01094       if(p.PartitionTypeGUID == "42465331-3ba3-10f1-802a-4861696b7521")             // is it really used ?
01095       {
01096         partition.setDescription("BeFS partition");
01097         partition.setVendor("Haiku");
01098       }
01099       else
01100         partition.setDescription("EFI partition");
01101       partition.setPhysId(i+1);
01102       partition.setCapacity(BLOCKSIZE * (p.EndingLBA - p.StartingLBA));
01103       partition.addHint("type", tostring(p.PartitionTypeGUID));
01104       partition.addHint("guid", tostring(p.PartitionGUID));
01105       partition.setSerial(tostring(p.PartitionGUID));
01106       partition.setHandle("GUID:" + tostring(p.PartitionGUID));
01107       partition.setConfig("name", p.PartitionName);
01108       if(p.Attributes && PARTITION_PRECIOUS)
01109         partition.addCapability("precious", "This partition is required for the platform to function");
01110       if(p.Attributes && PARTITION_READONLY)
01111         partition.addCapability("readonly", "Read-only partition");
01112       if(p.Attributes && PARTITION_HIDDEN)
01113         partition.addCapability("hidden");
01114       if(p.Attributes && PARTITION_NOMOUNT)
01115         partition.addCapability("nomount", "No automatic mount");
01116 
01117       partition.describeCapability("nofs", "No filesystem");
01118       partition.describeCapability("boot", "Contains boot code");
01119       partition.describeCapability("multi", "Multi-volumes");
01120       partition.describeCapability("hidden", "Hidden partition");
01121       partition.describeCapability("encrypted", "Contains encrypted data");
01122 
01123       spart.blocksize = s.blocksize;
01124       spart.offset = s.offset + p.StartingLBA*spart.blocksize;
01125       spart.size = (p.EndingLBA - p.StartingLBA)*spart.blocksize;
01126       guess_logicalname(spart, n, i+1, partition);
01127       scan_volume(partition, spart);
01128       n.addChild(partition);
01129     }
01130   }
01131 
01132   free(partitions);
01133 
01134   return true;
01135 }
01136 
01137 
01138 static bool detect_dosmap(source & s, hwNode & n)
01139 {
01140   static unsigned char buffer[BLOCKSIZE];
01141   int i = 0;
01142   unsigned char flags;
01143   unsigned char type;
01144   unsigned long long start, size;
01145   bool partitioned = false;
01146   unsigned long signature = 0;
01147 
01148   if(s.offset!=0)
01149     return false;                                 // partition tables must be at the beginning of the disk
01150 
01151   if(readlogicalblocks(s, buffer, 0, 1)!=1)       // read the first sector
01152     return false;
01153 
01154   if(le_short(buffer+510)!=0xaa55)                // wrong magic number
01155     return false;
01156 
01157   signature=le_long(buffer+440);
01158   if(signature == 0xffffffffL)
01159     signature = 0;
01160   if(signature)
01161   {
01162     char buffer[8+1];
01163     snprintf(buffer, sizeof(buffer), "%08lx", signature);
01164     n.setConfig("signature", buffer);
01165   }
01166 
01167   lastlogicalpart = 5;
01168 
01169   for(i=0; i<4; i++)
01170   {
01171     source spart = s;
01172     hwNode partition("volume", hw::volume);
01173 
01174     flags = buffer[446 + i*16];
01175     type = buffer[446 + i*16 + 4];
01176     start = le_long(buffer + 446 + i*16 + 8);
01177     size = le_long(buffer + 446 + i*16 + 12);
01178 
01179     if(flags!=0 && flags!=0x80)                   // inconsistency: partition is either bootable or non-bootable
01180       return false;
01181 
01182     spart.blocksize = s.blocksize;
01183     spart.offset = s.offset + start*spart.blocksize;
01184     spart.size = size*spart.blocksize;
01185 
01186     partition.setDescription("Primary partition");
01187     partition.addCapability("primary", "Primary partition");
01188     partition.setPhysId(i+1);
01189     partition.setCapacity(spart.size);
01190 
01191     if(analyse_dospart(spart, flags, type, partition))
01192     {
01193       guess_logicalname(spart, n, i+1, partition);
01194       scan_volume(partition, spart);
01195       n.addChild(partition);
01196       partitioned = true;
01197     }
01198   }
01199 
01200   return partitioned;
01201 }
01202 
01203 
01204 static bool detect_macmap(source & s, hwNode & n)
01205 {
01206   static unsigned char buffer[BLOCKSIZE];
01207   unsigned long count = 0, i = 0;
01208   unsigned long long start = 0, size = 0;
01209   string type = "";
01210 
01211   if(s.offset!=0)
01212     return false;                                 // partition maps must be at the beginning of the disk
01213 
01214   if(readlogicalblocks(s, buffer, 1, 1)!=1)       // read the second sector
01215     return false;
01216 
01217   if(be_short(buffer)!=0x504d)                    // wrong magic number
01218     return false;
01219 
01220   count = be_long(buffer+4);
01221 
01222   for (i = 1; i <= count; i++)
01223   {
01224     hwNode partition("volume", hw::volume);
01225 
01226     if((i>1) && readlogicalblocks(s, buffer, i, 1)!=1)
01227       return false;
01228 
01229     if(be_short(buffer)!=0x504d) continue;        // invalid map entry
01230 
01231     start = be_long(buffer + 8);
01232     size = be_long(buffer + 12);
01233     type = hw::strip(string((char*)buffer +  48, 32));
01234 
01235     partition.setPhysId(i);
01236     partition.setCapacity(size * s.blocksize);
01237     if(lowercase(type) == "apple_bootstrap")
01238       partition.addCapability("bootable", "Bootstrap partition");
01239 
01240     if(lowercase(type) == "linux_lvm")
01241     {
01242       partition.addHint("icon", string("md"));
01243       partition.addCapability("multi");
01244     }
01245     else
01246       partition.addHint("icon", string("disc"));
01247 
01248     for(unsigned int j=0; j<type.length(); j++)
01249       if(type[j] == '_') type[j] = ' ';
01250     partition.setDescription(type);
01251 
01252     if(true /*analyse_macpart(flags, type, start, size, partition)*/)
01253     {
01254       source spart = s;
01255 
01256       spart.blocksize = s.blocksize;
01257       spart.offset = s.offset + start*spart.blocksize;
01258       spart.size = size*spart.blocksize;
01259 
01260       guess_logicalname(spart, n, i, partition);
01261 
01262       scan_volume(partition, spart);
01263       n.addChild(partition);
01264     }
01265   }
01266 
01267   return true;
01268 }
01269 
01270 
01271 static bool detect_lif(source & s, hwNode & n)
01272 {
01273   static unsigned char buffer[LIFBLOCKSIZE];
01274   source lifvolume;
01275   unsigned long dir_start = 0, dir_length = 0;
01276   unsigned lif_version = 0;
01277   unsigned long ipl_addr = 0, ipl_length = 0, ipl_entry = 0;
01278 
01279   if(s.offset!=0)
01280     return false;                                 // LIF boot volumes must be at the beginning of the disk
01281 
01282   lifvolume = s;
01283   lifvolume.blocksize = LIFBLOCKSIZE;             // LIF blocks are 256 bytes long
01284 
01285                                                   // read the first block
01286   if(readlogicalblocks(lifvolume, buffer, 0, 1)!=1)
01287     return false;
01288 
01289   if(be_short(buffer)!=0x8000)                    // wrong magic number
01290     return false;
01291 
01292   dir_start = be_long(buffer+8);
01293   dir_length = be_long(buffer+16);
01294   lif_version = be_short(buffer+20);
01295 
01296   if(dir_start<2) return false;                   // blocks 0 and 1 are reserved
01297   if(dir_length<1) return false;                  // no directory to read from
01298   if(lif_version<1) return false;                 // weird LIF version
01299 
01300   ipl_addr = be_long(buffer+240);                 // byte address of IPL on media
01301   ipl_length = be_long(buffer+244);               // size of boot code
01302   ipl_entry = be_long(buffer+248);                // boot code entry point
01303 
01304 #if 0
01305   fprintf(stderr, "system: %x\n", be_short(buffer+12));
01306   fprintf(stderr, "start of directory: %ld\n", dir_start);
01307   fprintf(stderr, "length of directory: %ld\n", dir_length);
01308   fprintf(stderr, "lif version: %x\n", lif_version);
01309   fprintf(stderr, "tracks per surface: %ld\n", be_long(buffer+24));
01310   fprintf(stderr, "number of surfaces: %ld\n", be_long(buffer+28));
01311   fprintf(stderr, "blocks per track: %ld\n", be_long(buffer+32));
01312   fprintf(stderr, "ipl addr: %ld\n", ipl_addr);
01313   fprintf(stderr, "ipl length: %ld\n", ipl_length);
01314   fprintf(stderr, "ipl entry point: %lx\n", ipl_entry);
01315 #endif
01316 
01317   if((ipl_addr!=0) && (ipl_length>0)) n.addCapability("bootable", "Bootable disk");
01318 
01319   return true;
01320 }
01321 
01322 static bool detect_luks(source & s, hwNode & n)
01323 {
01324   static char buffer[BLOCKSIZE];
01325   source luksvolume;
01326   unsigned luks_version = 0;
01327 
01328   luksvolume = s;
01329   luksvolume.blocksize = BLOCKSIZE;
01330                                                   // read the first block
01331   if(readlogicalblocks(luksvolume, buffer, 0, 1)!=1)
01332     return false;
01333 
01334   if(memcmp(buffer, "LUKS", 4) != 0)                    // wrong magic number
01335     return false;
01336   if(be_short(buffer+4) != 0xbabe)
01337     return false;
01338 
01339   luks_version = be_short(buffer+6);
01340   if(luks_version<1)
01341     return false;                 // weird LUKS version
01342   else
01343   {
01344     hwNode partition("volume", hw::volume);
01345     scan_volume(partition, luksvolume);
01346     partition.setLogicalName(n.getLogicalName());
01347     n.addChild(partition);
01348   }
01349 
01350   return true;
01351 }
01352 
01353 bool scan_partitions(hwNode & n)
01354 {
01355   int i = 0;
01356   source s;
01357   int fd = open(n.getLogicalName().c_str(), O_RDONLY | O_NONBLOCK);
01358   hwNode * medium = NULL;
01359 
01360   if (fd < 0)
01361     return false;
01362 
01363   if(n.isCapable("removable"))
01364   {
01365     medium = n.addChild(hwNode("medium", hw::disk));
01366 
01367     medium->claim();
01368     medium->setSize(n.getSize());
01369     medium->setCapacity(n.getCapacity());
01370     medium->setLogicalName(n.getLogicalName());
01371   }
01372   else
01373     medium = &n;
01374 
01375   s.diskname = n.getLogicalName();
01376   s.fd = fd;
01377   s.offset = 0;
01378   s.blocksize = BLOCKSIZE;
01379   s.size = medium->getSize();
01380 
01381   while(map_types[i].id)
01382   {
01383     if(map_types[i].detect && map_types[i].detect(s, *medium))
01384     {
01385       medium->addCapability(string("partitioned"), "Partitioned disk");
01386       medium->addCapability(string("partitioned:") + string(map_types[i].id), string(map_types[i].description));
01387       break;
01388     }
01389     i++;
01390   }
01391 
01392   if(!medium->isCapable("partitioned"))
01393   {
01394     if(scan_volume(*medium, s))    // whole disk volume?
01395       medium->setClass(hw::volume);
01396   }
01397 
01398   close(fd);
01399 
01400 //if(medium != &n) free(medium);
01401 
01402   return false;
01403 }