Back to index

lshw  02.16
lvm.cc
Go to the documentation of this file.
00001 /*
00002  * lvm.cc
00003  *
00004  * This scan reports LVM-related information by looking for LVM2 structures
00005  * So far, the following information is reported:
00006  * - presence of LVM2 on-disk structures
00007  * - size of LVM2 physical volume
00008  * - UUID of LVM2 physical volume
00009  *
00010  */
00011 
00012 #include "version.h"
00013 #include "config.h"
00014 #include "lvm.h"
00015 #include "osutils.h"
00016 #include <string.h>
00017 
00018 __ID("@(#) $Id: lvm.cc 2433 2012-01-10 22:01:30Z lyonel $");
00019 
00020 #define LABEL_ID "LABELONE"
00021 #define LABEL_SIZE BLOCKSIZE                      /* Think very carefully before changing this */
00022 #define LABEL_SCAN_SECTORS 4L
00023 #define INITIAL_CRC 0xf597a6cf
00024 
00025 /* On disk - 32 bytes */
00026 struct label_header
00027 {
00028   uint8_t id[8];                                  /* LABELONE */
00029   uint64_t sector_xl;                             /* Sector number of this label */
00030   uint32_t crc_xl;                                /* From next field to end of sector */
00031   uint32_t offset_xl;                             /* Offset from start of struct to contents */
00032   uint8_t type[8];                                /* LVM2 001 */
00033 } __attribute__ ((packed));
00034 
00035 /* On disk */
00036 struct disk_locn
00037 {
00038   uint64_t offset;                                /* Offset in bytes to start sector */
00039   uint64_t size;                                  /* Bytes */
00040 } __attribute__ ((packed));
00041 
00042 #define ID_LEN 32
00043 
00044 /* Fields with the suffix _xl should be xlate'd wherever they appear */
00045 /* On disk */
00046 struct pv_header
00047 {
00048   uint8_t pv_uuid[ID_LEN];
00049 
00050 /* This size can be overridden if PV belongs to a VG */
00051   uint64_t device_size_xl;                        /* Bytes */
00052 
00053 /* NULL-terminated list of data areas followed by */
00054 /* NULL-terminated list of metadata area headers */
00055   struct disk_locn disk_areas_xl[0];              /* Two lists */
00056 } __attribute__ ((packed));
00057 
00058 /* In core */
00059 struct label
00060 {
00061   char type[8];
00062   uint64_t sector;
00063   struct labeller *labeller;
00064   void *info;
00065 };
00066 
00067 /* Calculate an endian-independent CRC of supplied buffer */
00068 uint32_t calc_crc(uint32_t initial, void *buf, uint32_t size)
00069 {
00070   static const uint32_t crctab[] =
00071   {
00072     0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
00073     0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
00074     0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
00075     0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
00076   };
00077   uint32_t i, crc = initial;
00078   uint8_t *data = (uint8_t *) buf;
00079 
00080   for(i = 0; i < size; i++)
00081   {
00082     crc ^= *data++;
00083     crc = (crc >> 4) ^ crctab[crc & 0xf];
00084     crc = (crc >> 4) ^ crctab[crc & 0xf];
00085   }
00086   return crc;
00087 }
00088 
00089 
00090 static const char *id = "@(#) $Id: lvm.cc 2433 2012-01-10 22:01:30Z lyonel $";
00091 
00092 static string uuid(void * s)
00093 {
00094   char * id = (char*)s;
00095 
00096   return string(id   ,6)+"-"+
00097     string(id+ 6,4)+"-"+
00098     string(id+10,4)+"-"+
00099     string(id+14,4)+"-"+
00100     string(id+18,4)+"-"+
00101     string(id+22,4)+"-"+
00102     string(id+26,6);
00103 }
00104 
00105 
00106 bool scan_lvm(hwNode & n, source & s)
00107 {
00108   uint8_t sector[BLOCKSIZE];
00109   label_header lh;
00110 
00111   if(s.blocksize != BLOCKSIZE)
00112     return false;
00113 
00114   for(uint32_t i=0; i<4; i++)
00115   {
00116     if(readlogicalblocks(s, sector, i, 1) != 1)
00117       return false;
00118     memcpy(&lh, sector, sizeof(lh));
00119     lh.sector_xl = le_longlong(sector+8);
00120     lh.crc_xl = le_long(sector+0x10);
00121     lh.offset_xl = le_long(sector+0x14);
00122 
00123     if((strncmp((char*)lh.id, LABEL_ID, sizeof(lh.id))==0) &&
00124       (lh.sector_xl==i) &&
00125       (lh.offset_xl < BLOCKSIZE) &&
00126       (calc_crc(INITIAL_CRC, sector+0x14, LABEL_SIZE-0x14)==lh.crc_xl))
00127     {
00128       pv_header pvh;
00129 
00130       memcpy(&pvh, sector+lh.offset_xl, sizeof(pvh));
00131       if(n.getDescription()=="")
00132         n.setDescription(_("Linux LVM Physical Volume"));
00133       n.addCapability("lvm2");
00134       n.setSerial(uuid(pvh.pv_uuid));
00135       if(n.getCapacity()==0)
00136         n.setCapacity(n.getSize());
00137       n.setSize(le_longlong(&pvh.device_size_xl));
00138       return true;
00139     }
00140   }
00141 
00142   (void) &id;                                     // avoid warning "id defined but not used"
00143 
00144   return false;
00145 }