Update to upstream util-linux 2.20.1
[framework/base/util-linux-ng.git] / libblkid / src / superblocks / lvm.c
1 /*
2  * Copyright (C) 1999 by Andries Brouwer
3  * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
4  * Copyright (C) 2001 by Andreas Dilger
5  * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
6  * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
7  *
8  * This file may be redistributed under the terms of the
9  * GNU Lesser General Public License.
10  */
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <string.h>
15 #include <stdint.h>
16
17 #include "superblocks.h"
18
19 #define LVM1_ID_LEN 128
20 #define LVM2_ID_LEN 32
21
22 struct lvm2_pv_label_header {
23         /* label_header */
24         uint8_t         id[8];          /* LABELONE */
25         uint64_t        sector_xl;      /* Sector number of this label */
26         uint32_t        crc_xl;         /* From next field to end of sector */
27         uint32_t        offset_xl;      /* Offset from start of struct to contents */
28         uint8_t         type[8];        /* LVM2 001 */
29         /* pv_header */
30         uint8_t         pv_uuid[LVM2_ID_LEN];
31 } __attribute__ ((packed));
32
33 struct lvm1_pv_label_header {
34         uint8_t id[2];                  /* HM */
35         uint16_t version;               /* version 1 or 2 */
36         uint32_t _notused[10];          /* lvm1 internals */
37         uint8_t pv_uuid[LVM1_ID_LEN];
38 } __attribute__ ((packed));
39
40 #define LVM2_LABEL_SIZE 512
41 static unsigned int lvm2_calc_crc(const void *buf, unsigned int size)
42 {
43         static const unsigned int crctab[] = {
44                 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
45                 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
46                 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
47                 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
48         };
49         unsigned int i, crc = 0xf597a6cf;
50         const uint8_t *data = (const uint8_t *) buf;
51
52         for (i = 0; i < size; i++) {
53                 crc ^= *data++;
54                 crc = (crc >> 4) ^ crctab[crc & 0xf];
55                 crc = (crc >> 4) ^ crctab[crc & 0xf];
56         }
57         return crc;
58 }
59
60 /* Length of real UUID is always LVM2_ID_LEN */
61 static void format_lvm_uuid(char *dst_uuid, char *src_uuid)
62 {
63         unsigned int i, b;
64
65         for (i = 0, b = 1; i < LVM2_ID_LEN; i++, b <<= 1) {
66                 if (b & 0x4444440)
67                         *dst_uuid++ = '-';
68                 *dst_uuid++ = *src_uuid++;
69         }
70         *dst_uuid = '\0';
71 }
72
73 static int probe_lvm2(blkid_probe pr, const struct blkid_idmag *mag)
74 {
75         int sector = mag->kboff << 1;
76         struct lvm2_pv_label_header *label;
77         char uuid[LVM2_ID_LEN + 7];
78         unsigned char *buf;
79
80         buf = blkid_probe_get_buffer(pr,
81                         mag->kboff << 10,
82                         512 + sizeof(struct lvm2_pv_label_header));
83         if (!buf)
84                 return -1;
85
86         /* buf is at 0k or 1k offset; find label inside */
87         if (memcmp(buf, "LABELONE", 8) == 0) {
88                 label = (struct lvm2_pv_label_header *) buf;
89         } else if (memcmp(buf + 512, "LABELONE", 8) == 0) {
90                 label = (struct lvm2_pv_label_header *)(buf + 512);
91                 sector++;
92         } else {
93                 return 1;
94         }
95
96         if (le64_to_cpu(label->sector_xl) != (unsigned) sector)
97                 return 1;
98
99         if (lvm2_calc_crc(&label->offset_xl, LVM2_LABEL_SIZE -
100                         ((char *) &label->offset_xl - (char *) label)) !=
101                         le32_to_cpu(label->crc_xl)) {
102                 DBG(DEBUG_PROBE,
103                     printf("LVM2: label checksum incorrect at sector %d\n",
104                            sector));
105                 return 1;
106         }
107
108         format_lvm_uuid(uuid, (char *) label->pv_uuid);
109         blkid_probe_sprintf_uuid(pr, label->pv_uuid, sizeof(label->pv_uuid),
110                         "%s", uuid);
111
112         /* the mag->magic is the same string as label->type,
113          * but zero terminated */
114         blkid_probe_set_version(pr, mag->magic);
115
116         /* LVM (pvcreate) wipes begin of the device -- let's remember this
117          * to resolve conflicts bettween LVM and partition tables, ...
118          */
119         blkid_probe_set_wiper(pr, 0, 8 * 1024);
120
121         return 0;
122 }
123
124 static int probe_lvm1(blkid_probe pr, const struct blkid_idmag *mag)
125 {
126         struct lvm1_pv_label_header *label;
127         char uuid[LVM2_ID_LEN + 7];
128         unsigned int version;
129
130         label = blkid_probe_get_sb(pr, mag, struct lvm1_pv_label_header);
131         if (!label)
132                 return -1;
133
134         version = le16_to_cpu(label->version);
135         if (version != 1 && version != 2)
136                 return 1;
137
138         format_lvm_uuid(uuid, (char *) label->pv_uuid);
139         blkid_probe_sprintf_uuid(pr, label->pv_uuid, sizeof(label->pv_uuid),
140                         "%s", uuid);
141
142         return 0;
143 }
144
145 /* NOTE: the original libblkid uses "lvm2pv" as a name */
146 const struct blkid_idinfo lvm2_idinfo =
147 {
148         .name           = "LVM2_member",
149         .usage          = BLKID_USAGE_RAID,
150         .probefunc      = probe_lvm2,
151         .magics         =
152         {
153                 { .magic = "LVM2 001", .len = 8, .sboff = 0x218 },
154                 { .magic = "LVM2 001", .len = 8, .sboff = 0x018 },
155                 { .magic = "LVM2 001", .len = 8, .kboff = 1, .sboff = 0x018 },
156                 { .magic = "LVM2 001", .len = 8, .kboff = 1, .sboff = 0x218 },
157                 { NULL }
158         }
159 };
160
161 const struct blkid_idinfo lvm1_idinfo =
162 {
163         .name           = "LVM1_member",
164         .usage          = BLKID_USAGE_RAID,
165         .probefunc      = probe_lvm1,
166         .magics         =
167         {
168                 { .magic = "HM", .len = 2 },
169                 { NULL }
170         }
171 };
172
173 const struct blkid_idinfo snapcow_idinfo =
174 {
175         .name           = "DM_snapshot_cow",
176         .usage          = BLKID_USAGE_OTHER,
177         .magics         =
178         {
179                 { .magic = "SnAp", .len = 4 },
180                 { NULL }
181         }
182 };