hal/hald/linux/volume_id volume_id.c, 1.25, 1.26 volume_id.h, 1.13,
1.14
Kay Sievers
kay at freedesktop.org
Wed Aug 25 13:20:24 PDT 2004
Update of /cvs/hal/hal/hald/linux/volume_id
In directory gabe:/tmp/cvs-serv13758/hald/linux/volume_id
Modified Files:
volume_id.c volume_id.h
Log Message:
2004-08-25 Kay Sievers <kay.sievers at vrfy.org>
* hald/linux/block_class_device.c:
(set_volume_id_values), (get_first_valid_partition),
(volume_set_size), (detect_media), (block_class_pre_process): Add
"volume.is_part_of_raid" and pass the size of the volume down to
volume_id to be able to look for a raid superblock at the end of
the device.
* hald/linux/volume_id/volume_id.c:
(probe_linux_raid) : Add linux_raid detection with reading of the
raid set uuid
(probe_msdos_part_table): follow extended partiton while probing
(vfat_search_label_in_dir), (probe_vfat): Support reding of labels
stored in the directory of FAT32 and read the whole root directory
instead of only the first cluster
(probe_mac_partition_map): return UNUSED and PARTITIONTABLE types
for know Apple partitions
(volume_id_probe): Add raid detection, if volume_id is called with
the size of the volume.
Index: volume_id.c
===================================================================
RCS file: /cvs/hal/hal/hald/linux/volume_id/volume_id.c,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -d -r1.25 -r1.26
--- volume_id.c 23 Aug 2004 00:29:28 -0000 1.25
+++ volume_id.c 25 Aug 2004 20:20:22 -0000 1.26
@@ -249,13 +249,70 @@
}
}
+#define MD_RESERVED_BYTES (64 * 1024)
+#define MD_MAGIC 0xa92b4efc
+static int probe_linux_raid(struct volume_id *id, __u64 off, __u64 size)
+{
+ struct mdp_super_block {
+ __u32 md_magic;
+ __u32 major_version;
+ __u32 minor_version;
+ __u32 patch_version;
+ __u32 gvalid_words;
+ __u32 set_uuid0;
+ __u32 ctime;
+ __u32 level;
+ __u32 size;
+ __u32 nr_disks;
+ __u32 raid_disks;
+ __u32 md_minor;
+ __u32 not_persistent;
+ __u32 set_uuid1;
+ __u32 set_uuid2;
+ __u32 set_uuid3;
+ } __attribute__((packed)) *mdp;
+
+ const __u8 *buf;
+ __u64 sboff = (size & ~(MD_RESERVED_BYTES - 1)) - MD_RESERVED_BYTES;
+ __u8 uuid[16];
+
+ if (size == 0)
+ return -1;
+
+ buf = get_buffer(id, off + sboff, 0x800);
+ if (buf == NULL)
+ return -1;
+
+ mdp = (struct mdp_super_block *) buf;
+
+ if (le32_to_cpu(mdp->md_magic) != MD_MAGIC)
+ return -1;
+
+ memcpy(uuid, &mdp->set_uuid0, 4);
+ memcpy(&uuid[4], &mdp->set_uuid1, 12);
+ set_uuid(id, uuid, 16);
+
+ dbg("found raid signature");
+ id->type_id = VOLUME_ID_RAID;
+ id->format = "linux_raid";
+
+ return 0;
+}
+
#define MSDOS_MAGIC "\x55\xaa"
#define MSDOS_PARTTABLE_OFFSET 0x1be
-#define MSDOS_EOS_SIG 0x1FE
+#define MSDOS_SIG_OFF 0x1fe
#define BSIZE 0x200
#define DOS_EXTENDED_PARTITION 0x05
#define LINUX_EXTENDED_PARTITION 0x85
#define WIN98_EXTENDED_PARTITION 0x0f
+#define LINUX_RAID_PARTITION 0xfd
+#define is_extended(type) \
+ (type == DOS_EXTENDED_PARTITION || \
+ type == WIN98_EXTENDED_PARTITION || \
+ type == LINUX_EXTENDED_PARTITION)
+#define is_raid(type) \
+ (type == LINUX_RAID_PARTITION)
static int probe_msdos_part_table(struct volume_id *id, __u64 off)
{
struct msdos_partition_entry {
@@ -273,13 +330,20 @@
const __u8 *buf;
int i;
+ __u64 poff;
+ __u64 plen;
+ __u64 extended = 0;
+ __u64 current;
+ __u64 next;
+ int limit;
int empty = 1;
+ struct volume_id_partition *p;
buf = get_buffer(id, off, 0x200);
if (buf == NULL)
return -1;
- if (strncmp(&buf[MSDOS_EOS_SIG], MSDOS_MAGIC, 2) != 0)
+ if (strncmp(&buf[MSDOS_SIG_OFF], MSDOS_MAGIC, 2) != 0)
return -1;
/* check flags on all entries for a valid partition table */
@@ -297,36 +361,106 @@
if (id->partitions != NULL)
free(id->partitions);
- id->partitions = malloc(4 * sizeof(struct volume_id_partition));
+ id->partitions = malloc(VOLUME_ID_PARTITIONS_MAX *
+ sizeof(struct volume_id_partition));
if (id->partitions == NULL)
return -1;
- memset(id->partitions, 0x00, 4 * sizeof(struct volume_id_partition));
+ memset(id->partitions, 0x00,
+ VOLUME_ID_PARTITIONS_MAX * sizeof(struct volume_id_partition));
for (i = 0; i < 4; i++) {
- __u64 poff;
- __u64 plen;
-
poff = (__u64) le32_to_cpu(part[i].start_sect) * BSIZE;
plen = (__u64) le32_to_cpu(part[i].nr_sects) * BSIZE;
if (plen == 0)
continue;
- if (part[i].sys_ind == DOS_EXTENDED_PARTITION ||
- part[i].sys_ind == WIN98_EXTENDED_PARTITION ||
- part[i].sys_ind == LINUX_EXTENDED_PARTITION) {
+ p = &id->partitions[i];
+
+ if (is_extended(part[i].sys_ind)) {
dbg("found extended partition at 0x%llx", poff);
- id->partitions[i].type = VOLUME_ID_PARTITIONTABLE;
+ p->type_id = VOLUME_ID_PARTITIONTABLE;
+ p->format_id = VOLUME_ID_MSDOSEXTENDED;
+ p->format = "msdos_extended_partition";
+ if (extended == 0)
+ extended = off + poff;
} else {
dbg("found 0x%x data partition at 0x%llx, len 0x%llx",
part[i].sys_ind, poff, plen);
- id->partitions[i].type = VOLUME_ID_UNPROBED;
+
+ if (is_raid(part[i].sys_ind))
+ p->type_id = VOLUME_ID_RAID;
+ else
+ p->type_id = VOLUME_ID_UNPROBED;
}
- id->partitions[i].off = off + poff;
- id->partitions[i].len = off + plen;
+
+ p->off = off + poff;
+ p->len = plen;
id->partition_count = i+1;
}
+ next = extended;
+ current = extended;
+ limit = 50;
+
+ /* follow extended partition chain and add data partitions */
+ while (next != 0) {
+ if (limit-- == 0) {
+ dbg("extended chain limit reached");
+ break;
+ }
+
+ buf = get_buffer(id, current, 0x200);
+ if (buf == NULL)
+ break;
+
+ part = (struct msdos_partition_entry*) &buf[MSDOS_PARTTABLE_OFFSET];
+
+ if (strncmp(&buf[MSDOS_SIG_OFF], MSDOS_MAGIC, 2) != 0)
+ break;
+
+ next = 0;
+
+ for (i = 0; i < 4; i++) {
+ poff = (__u64) le32_to_cpu(part[i].start_sect) * BSIZE;
+ plen = (__u64) le32_to_cpu(part[i].nr_sects) * BSIZE;
+
+ if (plen == 0)
+ continue;
+
+ if (is_extended(part[i].sys_ind)) {
+ dbg("found extended partition at 0x%llx", poff);
+ if (next == 0)
+ next = extended + poff;
+ } else {
+ dbg("found 0x%x data partition at 0x%llx, len 0x%llx",
+ part[i].sys_ind, poff, plen);
+
+ /* we always start at the 5th entry */
+ while (id->partition_count < 4)
+ id->partitions[id->partition_count++].type_id =
+ VOLUME_ID_UNUSED;
+
+ p = &id->partitions[id->partition_count];
+
+ if (is_raid(part[i].sys_ind))
+ p->type_id = VOLUME_ID_RAID;
+ else
+ p->type_id = VOLUME_ID_UNPROBED;
+
+ p->off = current + poff;
+ p->len = plen;
+ id->partition_count++;
+ if (id->partition_count >= VOLUME_ID_PARTITIONS_MAX) {
+ dbg("to many partitions");
+ next = 0;
+ }
+ }
+ }
+
+ current = next;
+ }
+
id->type_id = VOLUME_ID_PARTITIONTABLE;
id->format_id = VOLUME_ID_MSDOSPARTTABLE;
id->format = "msdos_partition_table";
@@ -531,7 +665,7 @@
__u32 size;
} __attribute__((__packed__));
-static char *_search_label_in_dir_block(const __u8 *buf, __u16 size)
+static char *vfat_search_label_in_dir(const __u8 *buf, __u16 size)
{
struct vfat_dir_entry *dir;
int i;
@@ -553,7 +687,7 @@
continue;
if (dir[i].attr == FAT_ATTR_VOLUME) {
- dbg("found ATTR_VOLUME id root dir");
+ dbg("found ATTR_VOLUME id in root dir");
return dir[i].name;
}
@@ -618,11 +752,11 @@
__u32 fat_length;
__u64 root_start;
__u32 start_data_sect;
- __u32 root_cluster_sect_off;
__u16 root_dir_entries;
__u8 *buf;
__u32 buf_size;
__u8 *label = NULL;
+ __u32 next;
vs = (struct vfat_super_block *) get_buffer(id, off, 0x200);
if (vs == NULL)
@@ -715,17 +849,17 @@
goto fat32;
}
- /* the label may be a attribute in the root directory */
- root_start = (reserved + fat_size)* sector_size;
+ /* the label may be an attribute in the root directory */
+ root_start = (reserved + fat_size) * sector_size;
root_dir_entries = le16_to_cpu(vs->dir_entries);
dbg("root dir start 0x%x", root_start);
buf_size = root_dir_entries * sizeof(struct vfat_dir_entry);
- buf = get_buffer(id, root_start, buf_size);
+ buf = get_buffer(id, off + root_start, buf_size);
if (buf == NULL)
goto found;
- label = _search_label_in_dir_block(buf, buf_size);
+ label = vfat_search_label_in_dir(buf, buf_size);
if (label != NULL && strncmp(label, "NO NAME ", 11) != 0) {
set_label_raw(id, label, 11);
@@ -738,25 +872,43 @@
goto found;
fat32:
- /* the label may be a attribute in the root directory */
+ /* FAT32 root dir is a cluster chain like any other directory */
+ buf_size = vs->sectors_per_cluster * sector_size;
root_cluster = le32_to_cpu(vs->type.fat32.root_cluster);
- root_cluster_sect_off = (root_cluster - 2) * vs->sectors_per_cluster;
- start_data_sect = reserved + fat_size + dir_size;
- dbg("data area 0x%llx", (__u64) start_data_sect * sector_size);
- root_start = (start_data_sect + root_cluster_sect_off) * sector_size;
- dbg("root dir start 0x%x", root_start);
+ dbg("root dir cluster %u", root_cluster);
+ start_data_sect = reserved + fat_size;
- /* FIXME: on FAT32 the root dir is a cluster chain like any other
- * directory or a file, so we need to follow the chain, as the
- * label may be anywhere in the root directory. For now it's only
- * the first cluster.
- */
- buf_size = vs->sectors_per_cluster * sector_size;
- buf = get_buffer(id, root_start, buf_size);
- if (buf == NULL)
- goto found;
+ next = root_cluster;
+ while (1) {
+ __u32 next_sect_off;
+ __u64 next_off;
+ __u64 fat_entry_off;
- label = _search_label_in_dir_block(buf, buf_size);
+ dbg("next cluster %u", next);
+ next_sect_off = (next - 2) * vs->sectors_per_cluster;
+ next_off = (start_data_sect + next_sect_off) * sector_size;
+ dbg("cluster offset 0x%x", next_off);
+
+ /* get cluster */
+ buf = get_buffer(id, off + next_off, buf_size);
+ if (buf == NULL)
+ goto found;
+
+ label = vfat_search_label_in_dir(buf, buf_size);
+ if (label != NULL)
+ break;
+
+ /* get FAT entry */
+ fat_entry_off = (reserved * sector_size) + (next * sizeof(__u32));
+ buf = get_buffer(id, off + fat_entry_off, buf_size);
+ if (buf == NULL)
+ goto found;
+
+ /* set next cluster */
+ next = le32_to_cpu(*((__u32 *) buf) & 0x0fffffff);
+ if (next == 0)
+ break;
+ }
if (label != NULL && strncmp(label, "NO NAME ", 11) != 0) {
set_label_raw(id, label, 11);
@@ -1179,7 +1331,7 @@
part = (struct mac_partition *) buf;
if ((strncmp(part->signature, "PM", 2) == 0) &&
(strncmp(part->type, "Apple_partition_map", 19) == 0)) {
- /* linux creates a own subdevice for the map
+ /* linux creates an own subdevice for the map
* just return the type if the drive header is missing */
id->type_id = VOLUME_ID_PARTITIONTABLE;
id->format_id = VOLUME_ID_MACPARTMAP;
@@ -1236,6 +1388,15 @@
id->partitions[i].off = poff;
id->partitions[i].len = plen;
+
+ if (strncmp(part->type, "Apple_Free", 10) == 0) {
+ id->partitions[i].type_id = VOLUME_ID_UNUSED;
+ } else if (strncmp(part->type, "Apple_partition_map", 19) == 0) {
+ id->partitions[i].type_id = VOLUME_ID_PARTITIONTABLE;
+ id->partitions[i].format_id = VOLUME_ID_MACPARTMAP;
+ } else {
+ id->partitions[i].type_id = VOLUME_ID_UNPROBED;
+ }
}
id->type_id = VOLUME_ID_PARTITIONTABLE;
id->format_id = VOLUME_ID_MACPARTMAP;
@@ -1670,7 +1831,9 @@
/* probe volume for filesystem type and try to read label+uuid */
int volume_id_probe(struct volume_id *id,
- enum volume_id_type type, unsigned long long off)
+ enum volume_id_type type,
+ unsigned long long off,
+ unsigned long long size)
{
int rc;
@@ -1719,12 +1882,31 @@
case VOLUME_ID_SWAP:
rc = probe_swap(id, off);
break;
+ case VOLUME_ID_LINUX_RAID:
+ rc = probe_linux_raid(id, off, size);
+ break;
case VOLUME_ID_ALL:
default:
- /* read only minimal buffer, cause of the slow floppies */
+ rc = probe_linux_raid(id, off, size);
+ if (rc == 0)
+ break;
+
+ /* signature in the first block */
+ rc = probe_ntfs(id, off);
+ if (rc == 0)
+ break;
rc = probe_vfat(id, off);
if (rc == 0)
break;
+ rc = probe_msdos_part_table(id, off);
+ if (rc == 0)
+ break;
+ rc = probe_mac_partition_map(id, off);
+ if (rc == 0)
+ break;
+ rc = probe_xfs(id, off);
+ if (rc == 0)
+ break;
/* fill buffer with maximum */
get_buffer(id, 0, SB_BUFFER_SIZE);
@@ -1738,9 +1920,6 @@
rc = probe_reiserfs(id, off);
if (rc == 0)
break;
- rc = probe_xfs(id, off);
- if (rc == 0)
- break;
rc = probe_jfs(id, off);
if (rc == 0)
break;
@@ -1750,21 +1929,12 @@
rc = probe_iso9660(id, off);
if (rc == 0)
break;
- rc = probe_ntfs(id, off);
- if (rc == 0)
- break;
- rc = probe_mac_partition_map(id, off);
- if (rc == 0)
- break;
rc = probe_hfs_hfsplus(id, off);
if (rc == 0)
break;
rc = probe_ufs(id, off);
if (rc == 0)
break;
- rc = probe_msdos_part_table(id, off);
- if (rc == 0)
- break;
rc = -1;
}
Index: volume_id.h
===================================================================
RCS file: /cvs/hal/hal/hald/linux/volume_id/volume_id.h,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -d -r1.13 -r1.14
--- volume_id.h 23 Aug 2004 00:29:28 -0000 1.13
+++ volume_id.h 25 Aug 2004 20:20:22 -0000 1.14
@@ -21,25 +21,28 @@
#ifndef _VOLUME_ID_H_
#define _VOLUME_ID_H_
-#define VOLUME_ID_VERSION 015
+#define VOLUME_ID_VERSION 019
#define VOLUME_ID_LABEL_SIZE 64
#define VOLUME_ID_UUID_SIZE 16
#define VOLUME_ID_UUID_STRING_SIZE 37
#define VOLUME_ID_FORMAT_SIZE 32
#define VOLUME_ID_PATH_MAX 256
+#define VOLUME_ID_PARTITIONS_MAX 16
enum volume_id_type {
- VOLUME_ID_UNKNOWN,
+ VOLUME_ID_UNUSED,
VOLUME_ID_UNPROBED,
VOLUME_ID_OTHER,
VOLUME_ID_FILESYSTEM,
- VOLUME_ID_PARTITIONTABLE
+ VOLUME_ID_PARTITIONTABLE,
+ VOLUME_ID_RAID
};
enum volume_id_format {
VOLUME_ID_ALL,
VOLUME_ID_MSDOSPARTTABLE,
+ VOLUME_ID_MSDOSEXTENDED,
VOLUME_ID_SWAP,
VOLUME_ID_EXT2,
VOLUME_ID_EXT3,
@@ -53,13 +56,16 @@
VOLUME_ID_MACPARTMAP,
VOLUME_ID_HFS,
VOLUME_ID_HFSPLUS,
- VOLUME_ID_UFS
+ VOLUME_ID_UFS,
+ VOLUME_ID_LINUX_RAID
};
struct volume_id_partition {
- enum volume_id_type type;
- unsigned long long off;
- unsigned long long len;
+ enum volume_id_type type_id;
+ enum volume_id_format format_id;
+ char *format;
+ unsigned long long off;
+ unsigned long long len;
};
struct volume_id {
@@ -94,7 +100,7 @@
/* probe volume for filesystem type and try to read label/uuid */
extern int volume_id_probe(struct volume_id *id, enum volume_id_type type,
- unsigned long long off);
+ unsigned long long off, unsigned long long size);
/* free allocated device info */
extern void volume_id_close(struct volume_id *id);
More information about the hal-commit
mailing list