X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=extras%2Fvolume_id%2Fvolume_id.c;h=e28c7303267782f10d2f022a880815e32196bd94;hb=240ce551799c78c6e77362e7b7feaaf09b72309b;hp=99aed6c96b608ba97192f2b10f346380d02bb0d8;hpb=9e8a3a095d955538acbdf28dba02582f6b2330e5;p=elogind.git diff --git a/extras/volume_id/volume_id.c b/extras/volume_id/volume_id.c index 99aed6c96..e28c73032 100644 --- a/extras/volume_id/volume_id.c +++ b/extras/volume_id/volume_id.c @@ -78,7 +78,7 @@ /* size of superblock buffer, reiserfs block is at 64k */ #define SB_BUFFER_SIZE 0x11000 /* size of seek buffer 4k */ -#define SEEK_BUFFER_SIZE 0x1000 +#define SEEK_BUFFER_SIZE 0x10000 static void set_label_raw(struct volume_id *id, @@ -221,8 +221,10 @@ static __u8 *get_buffer(struct volume_id *id, __u64 off, unsigned int len) return &(id->sbbuf[off]); } else { - if (len > SEEK_BUFFER_SIZE) - len = SEEK_BUFFER_SIZE; + if (len > SEEK_BUFFER_SIZE) { + dbg("seek buffer too small %d", SEEK_BUFFER_SIZE); + return NULL; + } /* get seek buffer */ if (id->seekbuf == NULL) { @@ -232,8 +234,7 @@ static __u8 *get_buffer(struct volume_id *id, __u64 off, unsigned int len) } /* check if we need to read */ - if ((off < id->seekbuf_off) || - ((off + len) > (id->seekbuf_off + id->seekbuf_len))) { + if ((off < id->seekbuf_off) || ((off + len) > (id->seekbuf_off + id->seekbuf_len))) { dbg("read seekbuf off:0x%llx len:0x%x", off, len); if (lseek(id->fd, off, SEEK_SET) == -1) return NULL; @@ -241,8 +242,10 @@ static __u8 *get_buffer(struct volume_id *id, __u64 off, unsigned int len) dbg("got 0x%x (%i) bytes", buf_len, buf_len); id->seekbuf_off = off; id->seekbuf_len = buf_len; - if (buf_len < len) + if (buf_len < len) { + dbg("requested 0x%x bytes, got only 0x%x bytes", len, buf_len); return NULL; + } } return &(id->seekbuf[off - id->seekbuf_off]); @@ -263,6 +266,36 @@ static void free_buffer(struct volume_id *id) } } +#define HPT37X_CONFIG_OFF 0x1200 +#define HPT37X_MAGIC_OK 0x5a7816f0 +#define HPT37X_MAGIC_BAD 0x5a7816fd +static int probe_highpoint_ataraid(struct volume_id *id, __u64 off) +{ + struct hpt37x { + __u8 filler1[32]; + __u32 magic; + __u32 magic_0; + __u32 magic_1; + } __attribute__((packed)) *hpt; + + const __u8 *buf; + + buf = get_buffer(id, off + HPT37X_CONFIG_OFF, 0x200); + if (buf == NULL) + return -1; + + hpt = (struct hpt37x *) buf; + + if (hpt->magic != HPT37X_MAGIC_OK && hpt->magic != HPT37X_MAGIC_BAD) + return -1; + + id->usage_id = VOLUME_ID_RAID; + id->type_id = VOLUME_ID_HPTRAID; + id->type = "hpt_ataraid_member"; + + return 0; +} + #define LVM1_SB_OFF 0x400 #define LVM1_MAGIC "HM" static int probe_lvm1(struct volume_id *id, __u64 off) @@ -321,7 +354,7 @@ static int probe_lvm2(struct volume_id *id, __u64 off) found: strncpy(id->type_version, lvm->type, 8); id->usage_id = VOLUME_ID_RAID; - id->type_id = VOLUME_ID_LVM1; + id->type_id = VOLUME_ID_LVM2; id->type = "LVM2_member"; return 0; @@ -461,6 +494,8 @@ static int probe_msdos_part_table(struct volume_id *id, __u64 off) p = &id->partitions[i]; + p->partition_type_raw = part[i].sys_ind; + if (is_extended(part[i].sys_ind)) { dbg("found extended partition at 0x%llx", poff); p->usage_id = VOLUME_ID_PARTITIONTABLE; @@ -535,8 +570,11 @@ static int probe_msdos_part_table(struct volume_id *id, __u64 off) p->off = current + poff; p->len = plen; id->partition_count++; + + p->partition_type_raw = part[i].sys_ind; + if (id->partition_count >= VOLUME_ID_PARTITIONS_MAX) { - dbg("to many partitions"); + dbg("too many partitions"); next = 0; } } @@ -734,7 +772,9 @@ static int probe_jfs(struct volume_id *id, __u64 off) #define FAT12_MAX 0xff5 #define FAT16_MAX 0xfff5 -#define FAT_ATTR_VOLUME 0x08 +#define FAT_ATTR_VOLUME_ID 0x08 +#define FAT_ATTR_DIR 0x10 +#define FAT_ENTRY_FREE 0xe5 static int probe_vfat(struct volume_id *id, __u64 off) { struct vfat_super_block { @@ -797,7 +837,7 @@ static int probe_vfat(struct volume_id *id, __u64 off) __u16 dir_entries; __u32 sect_count; __u16 reserved; - __u16 fat_size; + __u32 fat_size; __u32 root_cluster; __u32 dir_size; __u32 cluster_count; @@ -918,18 +958,19 @@ valid: for (i = 0; i <= root_dir_entries; i++) { /* end marker */ - if (dir[i].attr == 0x00) { + if (dir[i].name[0] == 0x00) { dbg("end of dir"); break; } /* empty entry */ - if (dir[i].attr == 0xe5) + if (dir[i].name[0] == FAT_ENTRY_FREE) continue; - if (dir[i].attr == FAT_ATTR_VOLUME) { - dbg("found ATTR_VOLUME id in root dir"); + if ((dir[i].attr & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) == FAT_ATTR_VOLUME_ID) { + dbg("found ATTR_VOLUME_ID id in root dir"); label = dir[i].name; + break; } dbg("skip dir entry"); @@ -976,17 +1017,17 @@ fat32: for (i = 0; i <= count; i++) { /* end marker */ - if (dir[i].attr == 0x00) { + if (dir[i].name[0] == 0x00) { dbg("end of dir"); goto fat32_label; } /* empty entry */ - if (dir[i].attr == 0xe5) + if (dir[i].name[0] == FAT_ENTRY_FREE) continue; - if (dir[i].attr == FAT_ATTR_VOLUME) { - dbg("found ATTR_VOLUME id in root dir"); + if ((dir[i].attr & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) == FAT_ATTR_VOLUME_ID) { + dbg("found ATTR_VOLUME_ID id in root dir"); label = dir[i].name; goto fat32_label; } @@ -1012,11 +1053,11 @@ fat32_label: if (label != NULL && strncmp(label, "NO NAME ", 11) != 0) { set_label_raw(id, label, 11); set_label_string(id, label, 11); - } else if (strncmp(vs->type.fat32.label, "NO NAME ", 11) == 0) { + } else if (strncmp(vs->type.fat32.label, "NO NAME ", 11) != 0) { set_label_raw(id, vs->type.fat32.label, 11); set_label_string(id, vs->type.fat32.label, 11); } - set_uuid(id, vs->type.fat32.serno, UUID_DCE); + set_uuid(id, vs->type.fat32.serno, UUID_DOS); found: id->usage_id = VOLUME_ID_FILESYSTEM; @@ -1179,6 +1220,12 @@ found: } #define ISO_SUPERBLOCK_OFFSET 0x8000 +#define ISO_SECTOR_SIZE 0x800 +#define ISO_VD_OFFSET (ISO_SUPERBLOCK_OFFSET + ISO_SECTOR_SIZE) +#define ISO_VD_PRIMARY 0x1 +#define ISO_VD_SUPPLEMENTARY 0x2 +#define ISO_VD_END 0xff +#define ISO_VD_MAX 16 static int probe_iso9660(struct volume_id *id, __u64 off) { union iso_super_block { @@ -1204,8 +1251,36 @@ static int probe_iso9660(struct volume_id *id, __u64 off) return -1; if (strncmp(is->iso.id, "CD001", 5) == 0) { - set_label_raw(id, is->iso.volume_id, 32); - set_label_string(id, is->iso.volume_id, 32); + int vd_offset; + int i; + int found_svd; + + found_svd = 0; + vd_offset = ISO_VD_OFFSET; + for (i = 0; i < ISO_VD_MAX; i++) { + is = (union iso_super_block *) + get_buffer (id, off + vd_offset, 0x200); + if (is == NULL || is->iso.type == ISO_VD_END) + break; + if (is->iso.type == ISO_VD_SUPPLEMENTARY) { + dbg("found ISO supplementary VD at offset 0x%llx", off + vd_offset); + found_svd = 1; + break; + } + vd_offset += ISO_SECTOR_SIZE; + } + + if (!found_svd) { + is = (union iso_super_block *) + get_buffer(id, off + ISO_SUPERBLOCK_OFFSET, 0x200); + if (is == NULL) + return -1; + set_label_raw(id, is->iso.volume_id, 32); + set_label_string(id, is->iso.volume_id, 32); + } else { + set_label_raw(id, is->iso.volume_id, 32); + set_label_unicode16(id, is->iso.volume_id, BE, 32); + } goto found; } if (strncmp(is->hs.id, "CDROM", 5) == 0) @@ -1943,21 +2018,37 @@ found: #define LARGEST_PAGESIZE 0x4000 static int probe_swap(struct volume_id *id, __u64 off) { - const __u8 *sig; + struct swap_header_v1_2 { + __u8 bootbits[1024]; + __u32 version; + __u32 last_page; + __u32 nr_badpages; + __u8 uuid[16]; + __u8 volume_name[16]; + } __attribute__((__packed__)) *sw; + + const __u8 *buf; unsigned int page; - /* huhh, the swap signature is on the end of the PAGE_SIZE */ + /* the swap signature is at the end of the PAGE_SIZE */ for (page = 0x1000; page <= LARGEST_PAGESIZE; page <<= 1) { - sig = get_buffer(id, off + page-10, 10); - if (sig == NULL) + buf = get_buffer(id, off + page-10, 10); + if (buf == NULL) return -1; - if (strncmp(sig, "SWAP-SPACE", 10) == 0) { + if (strncmp(buf, "SWAP-SPACE", 10) == 0) { strcpy(id->type_version, "1"); goto found; } - if (strncmp(sig, "SWAPSPACE2", 10) == 0) { + + if (strncmp(buf, "SWAPSPACE2", 10) == 0) { + sw = (struct swap_header_v1_2 *) get_buffer(id, off, sizeof(struct swap_header_v1_2)); + if (sw == NULL) + return -1; strcpy(id->type_version, "2"); + set_label_raw(id, sw->volume_name, 16); + set_label_string(id, sw->volume_name, 16); + set_uuid(id, sw->uuid, UUID_DCE); goto found; } } @@ -1979,6 +2070,8 @@ int volume_id_probe(struct volume_id *id, { int rc; + dbg("called with size=0x%llx", size); + if (id == NULL) return -EINVAL; @@ -2033,20 +2126,27 @@ int volume_id_probe(struct volume_id *id, case VOLUME_ID_LVM2: rc = probe_lvm2(id, off); break; + case VOLUME_ID_HPTRAID: + rc = probe_highpoint_ataraid(id, off); + break; case VOLUME_ID_ALL: default: + /* probe for raid first, cause fs probes may be successful on raid members */ rc = probe_linux_raid(id, off, size); if (rc == 0) break; - - /* signature in the first block */ - rc = probe_ntfs(id, off); + rc = probe_lvm1(id, off); if (rc == 0) break; - rc = probe_vfat(id, off); + rc = probe_lvm2(id, off); if (rc == 0) break; - rc = probe_msdos_part_table(id, off); + rc = probe_highpoint_ataraid(id, off); + if (rc == 0) + break; + + /* signature in the first block, only small buffer needed */ + rc = probe_vfat(id, off); if (rc == 0) break; rc = probe_mac_partition_map(id, off); @@ -2083,10 +2183,7 @@ int volume_id_probe(struct volume_id *id, rc = probe_ufs(id, off); if (rc == 0) break; - rc = probe_lvm1(id, off); - if (rc == 0) - break; - rc = probe_lvm2(id, off); + rc = probe_ntfs(id, off); if (rc == 0) break; @@ -2122,7 +2219,7 @@ struct volume_id *volume_id_open_node(const char *path) struct volume_id *id; int fd; - fd = open(path, O_RDONLY | O_NONBLOCK); + fd = open(path, O_RDONLY); if (fd < 0) { dbg("unable to open '%s'", path); return NULL;