2 * volume_id - reads filesystem label and uuid
4 * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
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.
26 #include "volume_id.h"
31 struct msdos_partition_entry {
42 } __attribute__((packed));
44 #define MSDOS_MAGIC "\x55\xaa"
45 #define MSDOS_PARTTABLE_OFFSET 0x1be
46 #define MSDOS_SIG_OFF 0x1fe
48 #define DOS_EXTENDED_PARTITION 0x05
49 #define LINUX_EXTENDED_PARTITION 0x85
50 #define WIN98_EXTENDED_PARTITION 0x0f
51 #define LINUX_RAID_PARTITION 0xfd
52 #define is_extended(type) \
53 (type == DOS_EXTENDED_PARTITION || \
54 type == WIN98_EXTENDED_PARTITION || \
55 type == LINUX_EXTENDED_PARTITION)
56 #define is_raid(type) \
57 (type == LINUX_RAID_PARTITION)
59 int volume_id_probe_msdos_part_table(struct volume_id *id, uint64_t off)
65 uint64_t extended = 0;
70 struct msdos_partition_entry *part;
71 struct volume_id_partition *p;
73 dbg("probing at offset 0x%llx", (unsigned long long) off);
75 buf = volume_id_get_buffer(id, off, 0x200);
79 if (memcmp(&buf[MSDOS_SIG_OFF], MSDOS_MAGIC, 2) != 0)
82 /* check flags on all entries for a valid partition table */
83 part = (struct msdos_partition_entry*) &buf[MSDOS_PARTTABLE_OFFSET];
84 for (i = 0; i < 4; i++) {
85 if (part[i].boot_ind != 0 &&
86 part[i].boot_ind != 0x80)
89 if (le32_to_cpu(part[i].nr_sects) != 0)
95 if (id->partitions != NULL)
97 id->partitions = malloc(VOLUME_ID_PARTITIONS_MAX *
98 sizeof(struct volume_id_partition));
99 if (id->partitions == NULL)
101 memset(id->partitions, 0x00,
102 VOLUME_ID_PARTITIONS_MAX * sizeof(struct volume_id_partition));
104 for (i = 0; i < 4; i++) {
105 poff = (uint64_t) le32_to_cpu(part[i].start_sect) * BSIZE;
106 plen = (uint64_t) le32_to_cpu(part[i].nr_sects) * BSIZE;
111 p = &id->partitions[i];
113 p->partition_type_raw = part[i].sys_ind;
115 if (is_extended(part[i].sys_ind)) {
116 dbg("found extended partition at 0x%llx", (unsigned long long) poff);
117 volume_id_set_usage_part(p, VOLUME_ID_PARTITIONTABLE);
118 p->type = "msdos_extended_partition";
120 extended = off + poff;
122 dbg("found 0x%x data partition at 0x%llx, len 0x%llx",
123 part[i].sys_ind, (unsigned long long) poff, (unsigned long long) plen);
125 if (is_raid(part[i].sys_ind))
126 volume_id_set_usage_part(p, VOLUME_ID_RAID);
128 volume_id_set_usage_part(p, VOLUME_ID_UNPROBED);
133 id->partition_count = i+1;
140 /* follow extended partition chain and add data partitions */
143 dbg("extended chain limit reached");
147 buf = volume_id_get_buffer(id, current, 0x200);
151 part = (struct msdos_partition_entry*) &buf[MSDOS_PARTTABLE_OFFSET];
153 if (memcmp(&buf[MSDOS_SIG_OFF], MSDOS_MAGIC, 2) != 0)
158 for (i = 0; i < 4; i++) {
159 poff = (uint64_t) le32_to_cpu(part[i].start_sect) * BSIZE;
160 plen = (uint64_t) le32_to_cpu(part[i].nr_sects) * BSIZE;
165 if (is_extended(part[i].sys_ind)) {
166 dbg("found extended partition at 0x%llx", (unsigned long long) poff);
168 next = extended + poff;
170 dbg("found 0x%x data partition at 0x%llx, len 0x%llx",
171 part[i].sys_ind, (unsigned long long) poff, (unsigned long long) plen);
173 /* we always start at the 5th entry */
174 while (id->partition_count < 4)
175 volume_id_set_usage_part(&id->partitions[id->partition_count++], VOLUME_ID_UNUSED);
177 p = &id->partitions[id->partition_count];
179 if (is_raid(part[i].sys_ind))
180 volume_id_set_usage_part(p, VOLUME_ID_RAID);
182 volume_id_set_usage_part(p, VOLUME_ID_UNPROBED);
184 p->off = current + poff;
186 id->partition_count++;
188 p->partition_type_raw = part[i].sys_ind;
190 if (id->partition_count >= VOLUME_ID_PARTITIONS_MAX) {
191 dbg("too many partitions");
200 volume_id_set_usage(id, VOLUME_ID_PARTITIONTABLE);
201 id->type = "msdos_partition_table";