chiark / gitweb /
libvolume_id: recognize swap partitions with a tuxonice hibernate image
[elogind.git] / extras / volume_id / lib / lvm.c
1 /*
2  * volume_id - reads filesystem label and uuid
3  *
4  * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
5  *
6  *      This program is free software; you can redistribute it and/or modify it
7  *      under the terms of the GNU General Public License as published by the
8  *      Free Software Foundation version 2 of the License.
9  */
10
11 #ifndef _GNU_SOURCE
12 #define _GNU_SOURCE 1
13 #endif
14
15 #ifdef HAVE_CONFIG_H
16 #  include <config.h>
17 #endif
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <ctype.h>
25
26 #include "libvolume_id.h"
27 #include "util.h"
28
29 struct lvm1_super_block {
30         uint8_t id[2];
31 } PACKED;
32
33 struct lvm2_super_block {
34         uint8_t         id[8];
35         uint64_t        sector_xl;
36         uint32_t        crc_xl;
37         uint32_t        offset_xl;
38         uint8_t         type[8];
39 } PACKED;
40
41 struct lvm2_pv_header {
42         uint8_t         id[32];
43         uint64_t        devsize_xl;
44 } PACKED;
45
46 #define LVM1_SB_OFF                     0x400
47 #define LVM1_MAGIC                      "HM"
48
49 int volume_id_probe_lvm1(struct volume_id *id, uint64_t off, uint64_t size)
50 {
51         const uint8_t *buf;
52         struct lvm1_super_block *lvm;
53
54         info("probing at offset 0x%llx\n", (unsigned long long) off);
55
56         buf = volume_id_get_buffer(id, off + LVM1_SB_OFF, 0x800);
57         if (buf == NULL)
58                 return -1;
59
60         lvm = (struct lvm1_super_block *) buf;
61
62         if (memcmp(lvm->id, LVM1_MAGIC, 2) != 0)
63                 return -1;
64
65         volume_id_set_usage(id, VOLUME_ID_RAID);
66         id->type = "LVM1_member";
67
68         return 0;
69 }
70
71 #define LVM2_LABEL_ID                   "LABELONE"
72 #define LVM2LABEL_SCAN_SECTORS          4
73
74 int volume_id_probe_lvm2(struct volume_id *id, uint64_t off, uint64_t size)
75 {
76         const uint8_t *buf;
77         unsigned int soff;
78         struct lvm2_super_block *lvm;
79         struct lvm2_pv_header *pvhdr;
80
81         dbg("probing at offset 0x%llx\n", (unsigned long long) off);
82
83         buf = volume_id_get_buffer(id, off, LVM2LABEL_SCAN_SECTORS * 0x200);
84         if (buf == NULL)
85                 return -1;
86
87
88         for (soff = 0; soff < LVM2LABEL_SCAN_SECTORS * 0x200; soff += 0x200) {
89                 lvm = (struct lvm2_super_block *) &buf[soff];
90
91                 if (memcmp(lvm->id, LVM2_LABEL_ID, 8) == 0)
92                         goto found;
93         }
94
95         return -1;
96
97 found:
98         dbg("found at offset 0x%x (pv hdr offset 0x%x)\n",
99             soff, cpu_to_le32(lvm->offset_xl));
100         soff += cpu_to_le32(lvm->offset_xl);
101         pvhdr = (struct lvm2_pv_header *) &buf[soff];
102         memcpy(id->type_version, lvm->type, 8);
103         volume_id_set_usage(id, VOLUME_ID_RAID);
104         volume_id_set_uuid(id, pvhdr->id, 0, UUID_LVM);
105         id->type = "LVM2_member";
106
107         return 0;
108 }