=== modified file 'Makefile.am' --- grub-0.97.orig/Makefile.am 2004-04-23 13:39:01 +0000 +++ grub-0.97/Makefile.am 2008-07-09 17:23:44 +0000 @@ -1,4 +1,9 @@ # Do not change this order if you don't know what you are doing. AUTOMAKE_OPTIONS = 1.7 gnu -SUBDIRS = netboot stage2 stage1 lib grub util docs +if UUID_SUPPORT +SUBDIRS = libvolume_id netboot stage2 stage1 lib grub util docs +else +SUBDIRS = netboot stage2 stage1 lib grub util docs +endif + EXTRA_DIST = BUGS MAINTENANCE === modified file 'configure.ac' --- grub-0.97.orig/configure.ac 2008-01-28 18:41:45 +0000 +++ grub-0.97/configure.ac 2008-07-09 17:23:44 +0000 @@ -605,6 +606,11 @@ [ --disable-serial disable serial terminal support]) AM_CONDITIONAL(SERIAL_SUPPORT, test "x$enable_serial" != xno) +dnl UUID scanning +AC_ARG_ENABLE(uuid, + [ --disable-uuid disable uuid scanning support]) +AM_CONDITIONAL(UUID_SUPPORT, test "x$enable_uuid" != xno) + dnl Simulation of the slowness of a serial device. AC_ARG_ENABLE(serial-speed-simulation, [ --enable-serial-speed-simulation @@ -666,5 +672,6 @@ docs/Makefile lib/Makefile util/Makefile \ grub/Makefile netboot/Makefile util/grub-image \ util/grub-install util/grub-md5-crypt \ - util/grub-terminfo util/grub-set-default]) + util/grub-terminfo util/grub-set-default \ + libvolume_id/Makefile]) AC_OUTPUT === modified file 'grub/Makefile.am' --- grub-0.97.orig/grub/Makefile.am 2005-02-02 20:40:05 +0000 +++ grub-0.97/grub/Makefile.am 2008-07-09 17:23:44 +0000 @@ -16,4 +16,9 @@ AM_CFLAGS = $(GRUB_CFLAGS) grub_SOURCES = main.c asmstub.c -grub_LDADD = ../stage2/libgrub.a ../lib/libcommon.a $(GRUB_LIBS) + +if UUID_SUPPORT +grub_LDADD = ../stage2/libgrub.a ../lib/libcommon.a ../libvolume_id/libvolume_id.a $(GRUB_LIBS) +else +grub_LDADD = ../stage2/libgrub.a ../lib/libcommon.a $(GRUB_LIBS) +endif === added directory 'libvolume_id' === added file 'libvolume_id/Makefile.am' --- grub-0.97.orig/libvolume_id/Makefile.am 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/Makefile.am 2008-07-15 12:31:43 +0000 @@ -0,0 +1,27 @@ +noinst_LIBRARIES = libvolume_id.a + +AM_CFLAGS = $(STAGE2_CFLAGS) -I$(top_srcdir)/stage2 -I$(top_srcdir)/stage1 + +LIBVOLUME_ID_FS_SUPPORTED = ext.c fat.c hfs.c jfs.c \ + luks.c ntfs.c ocfs.c reiserfs.c \ + xfs.c + +LIBVOLUME_ID_FS_UNSUPPORTED = cramfs.c gfs.c hpfs.c iso9660.c \ + lvm.c minix.c romfs.c squashfs.c \ + sysv.c udf.c ufs.c vxfs.c + +LIBVOLUME_ID_RAID_SUPPORTED = ddf_raid.c + +LIBVOLUME_ID_RAID_UNSUPPORTED = adaptec_raid.c highpoint.c isw_raid.c \ + jmicron_raid.c linux_raid.c lsi_raid.c \ + nvidia_raid.c promise_raid.c silicon_raid.c \ + via_raid.c + +LIBVOLUME_ID_MISC_UNSUPPORTED = linux_swap.c netware.c + +libvolume_id_a_SOURCES = $(LIBVOLUME_ID_FS_SUPPORTED) \ + $(LIBVOLUME_ID_RAID_SUPPORTED) \ + $(LIBVOLUME_ID_FS_UNSUPPORTED) \ + $(LIBVOLUME_ID_RAID_UNSUPPORTED) \ + volume_id.h volume_id.c util.c util.h misc.c + === added file 'libvolume_id/adaptec_raid.c' --- grub-0.97.orig/libvolume_id/adaptec_raid.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/adaptec_raid.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,107 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2006 Kay Sievers + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +struct adaptec_meta { + uint32_t b0idcode; + uint8_t lunsave[8]; + uint16_t sdtype; + uint16_t ssavecyl; + uint8_t ssavehed; + uint8_t ssavesec; + uint8_t sb0flags; + uint8_t jbodEnable; + uint8_t lundsave; + uint8_t svpdirty; + uint16_t biosInfo; + uint16_t svwbskip; + uint16_t svwbcln; + uint16_t svwbmax; + uint16_t res3; + uint16_t svwbmin; + uint16_t res4; + uint16_t svrcacth; + uint16_t svwcacth; + uint16_t svwbdly; + uint8_t svsdtime; + uint8_t res5; + uint16_t firmval; + uint16_t firmbln; + uint32_t firmblk; + uint32_t fstrsvrb; + uint16_t svBlockStorageTid; + uint16_t svtid; + uint8_t svseccfl; + uint8_t res6; + uint8_t svhbanum; + uint8_t resver; + uint32_t drivemagic; + uint8_t reserved[20]; + uint8_t testnum; + uint8_t testflags; + uint16_t maxErrorCount; + uint32_t count; + uint32_t startTime; + uint32_t interval; + uint8_t tstxt0; + uint8_t tstxt1; + uint8_t serNum[32]; + uint8_t res8[102]; + uint32_t fwTestMagic; + uint32_t fwTestSeqNum; + uint8_t fwTestRes[8]; + uint8_t smagic[4]; + uint32_t raidtbl; + uint16_t raidline; + uint8_t res9[0xF6]; +} PACKED; + +int volume_id_probe_adaptec_raid(struct volume_id *id, uint64_t off, uint64_t size) +{ + const uint8_t *buf; + uint64_t meta_off; + struct adaptec_meta *ad; + + info("probing at offset 0x%llx, size 0x%llx", + (unsigned long long) off, (unsigned long long) size); + + if (size < 0x10000) + return -1; + + meta_off = ((size / 0x200)-1) * 0x200; + buf = volume_id_get_buffer(id, off + meta_off, 0x200); + if (buf == NULL) + return -1; + + ad = (struct adaptec_meta *) buf; + if (memcmp((char*)ad->smagic, "DPTM", 4) != 0) + return -1; + + if (ad->b0idcode != be32_to_cpu(0x37FC4D1E)) + return -1; + + volume_id_set_usage(id, VOLUME_ID_RAID); + sprintf(id->type_version, "%u", ad->resver); + id->type = "adaptec_raid_member"; + + return 0; +} === added file 'libvolume_id/cramfs.c' --- grub-0.97.orig/libvolume_id/cramfs.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/cramfs.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,60 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +struct cramfs_super { + uint8_t magic[4]; + uint32_t size; + uint32_t flags; + uint32_t future; + uint8_t signature[16]; + struct cramfs_info { + uint32_t crc; + uint32_t edition; + uint32_t blocks; + uint32_t files; + } PACKED info; + uint8_t name[16]; +} PACKED; + +int volume_id_probe_cramfs(struct volume_id *id, uint64_t off, uint64_t size) +{ + struct cramfs_super *cs; + + info("probing at offset 0x%llx", (unsigned long long) off); + + cs = (struct cramfs_super *) volume_id_get_buffer(id, off, 0x200); + if (cs == NULL) + return -1; + + if (memcmp((char*)cs->magic, "\x45\x3d\xcd\x28", 4) == 0 || memcmp((char*)cs->magic, "\x28\xcd\x3d\x45", 4) == 0) { + volume_id_set_label_raw(id, cs->name, 16); + volume_id_set_label_string(id, cs->name, 16); + + volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); + id->type = "cramfs"; + return 0; + } + + return -1; +} === added file 'libvolume_id/ddf_raid.c' --- grub-0.97.orig/libvolume_id/ddf_raid.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/ddf_raid.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,60 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2007 Kay Sievers + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +/* http://www.snia.org/standards/home */ + +#define DDF_HEADER 0xDE11DE11 +#define DDF_GUID_LENGTH 24 +#define DDF_REV_LENGTH 8 + +static struct ddf_header { + uint32_t signature; + uint32_t crc; + uint8_t guid[DDF_GUID_LENGTH]; + uint8_t ddf_rev[DDF_REV_LENGTH]; +} PACKED *ddf; + +int volume_id_probe_ddf_raid(struct volume_id *id, uint64_t off, uint64_t size) +{ + uint64_t ddf_off = ((size / 0x200)-1) * 0x200; + const uint8_t *buf; + + info("probing at offset 0x%llx, size 0x%llx", + (unsigned long long) off, (unsigned long long) size); + if (size < 0x10000) + return -1; + + buf = volume_id_get_buffer(id, off + ddf_off, 0x200); + if (buf == NULL) + return -1; + ddf = (struct ddf_header *) buf; + + if (ddf->signature != cpu_to_be32(DDF_HEADER)) + return -1; + + volume_id_set_uuid(id, ddf->guid, DDF_GUID_LENGTH, UUID_STRING); + strcpy(id->type_version, (char*) ddf->ddf_rev); + volume_id_set_usage(id, VOLUME_ID_RAID); + id->type = "ddf_raid_member"; + return 0; +} === added file 'libvolume_id/ext.c' --- grub-0.97.orig/libvolume_id/ext.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/ext.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,129 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +struct ext2_super_block { + uint32_t s_inodes_count; + uint32_t s_blocks_count; + uint32_t s_r_blocks_count; + uint32_t s_free_blocks_count; + uint32_t s_free_inodes_count; + uint32_t s_first_data_block; + uint32_t s_log_block_size; + uint32_t s_log_frag_size; + uint32_t s_blocks_per_group; + uint32_t s_frags_per_group; + uint32_t s_inodes_per_group; + uint32_t s_mtime; + uint32_t s_wtime; + uint16_t s_mnt_count; + uint16_t s_max_mnt_count; + uint16_t s_magic; + uint16_t s_state; + uint16_t s_errors; + uint16_t s_minor_rev_level; + uint32_t s_lastcheck; + uint32_t s_checkinterval; + uint32_t s_creator_os; + uint32_t s_rev_level; + uint16_t s_def_resuid; + uint16_t s_def_resgid; + uint32_t s_first_ino; + uint16_t s_inode_size; + uint16_t s_block_group_nr; + uint32_t s_feature_compat; + uint32_t s_feature_incompat; + uint32_t s_feature_ro_compat; + uint8_t s_uuid[16]; + uint8_t s_volume_name[16]; +} PACKED; + +#define EXT_SUPER_MAGIC 0xEF53 +#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004 +#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 +#define EXT3_FEATURE_INCOMPAT_EXTENTS 0x0040 +#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080 +#define EXT4_FEATURE_INCOMPAT_MMP 0x0100 + +#define EXT_SUPERBLOCK_OFFSET 0x400 + +#define EXT3_MIN_BLOCK_SIZE 0x400 +#define EXT3_MAX_BLOCK_SIZE 0x1000 + +int volume_id_probe_ext(struct volume_id *id, uint64_t off, uint64_t size) +{ + struct ext2_super_block *es; + size_t bsize; + uint32_t feature_compat; + uint32_t feature_incompat; + + info("probing at offset 0x%llx", (unsigned long long) off); + + es = (struct ext2_super_block *) volume_id_get_buffer(id, off + EXT_SUPERBLOCK_OFFSET, 0x200); + if (es == NULL) + return -1; + + if (es->s_magic != cpu_to_le16(EXT_SUPER_MAGIC)) + return -1; + + bsize = 0x400 << le32_to_cpu(es->s_log_block_size); + dbg("ext blocksize 0x%zx", bsize); + if (bsize < EXT3_MIN_BLOCK_SIZE || bsize > EXT3_MAX_BLOCK_SIZE) { + dbg("invalid ext blocksize"); + return -1; + } + + volume_id_set_label_raw(id, es->s_volume_name, 16); + volume_id_set_label_string(id, es->s_volume_name, 16); + volume_id_set_uuid(id, es->s_uuid, 0, UUID_DCE); + sprintf(id->type_version, "%u.%u", + le32_to_cpu(es->s_rev_level), le16_to_cpu(es->s_minor_rev_level)); + + feature_compat = le32_to_cpu(es->s_feature_compat); + feature_incompat = le32_to_cpu(es->s_feature_incompat); + + /* check for external journal device */ + if ((feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) != 0) { + volume_id_set_usage(id, VOLUME_ID_OTHER); + id->type = "jbd"; + goto out; + } + + volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); + + if ((feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) != 0 || + (feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT) != 0 || + (feature_incompat & EXT4_FEATURE_INCOMPAT_MMP) != 0) { + id->type = "ext4"; + goto out; + } + + if ((feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) != 0) { + id->type = "ext3"; + goto out; + } + + id->type = "ext2"; + +out: + return 0; +} === added file 'libvolume_id/fat.c' --- grub-0.97.orig/libvolume_id/fat.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/fat.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,482 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004-2007 Kay Sievers + * Copyright (C) 2007 Ryan Lortie + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +#define FAT12_MAX 0xff5 +#define FAT16_MAX 0xfff5 +#define FAT_ATTR_VOLUME_ID 0x08 +#define FAT_ATTR_DIR 0x10 +#define FAT_ATTR_LONG_NAME 0x0f +#define FAT_ATTR_MASK 0x3f +#define FAT_ENTRY_FREE 0xe5 + +#define VFAT_LFN_SEQ_MASK 0x3f +#define VFAT_LFN_SEQ_LAST 0x40 +#define VFAT_LFN_SEQ_MAX 20 +#define VFAT_LFN_CHARS_PER_ENTRY (5 + 6 + 2) +#define VFAT_LOWERCASE_NAME 0x10 +#define VFAT_LOWERCASE_EXT 0x08 + +struct vfat_super_block { + uint8_t boot_jump[3]; + uint8_t sysid[8]; + uint16_t sector_size; + uint8_t sectors_per_cluster; + uint16_t reserved; + uint8_t fats; + uint16_t dir_entries; + uint16_t sectors; + uint8_t media; + uint16_t fat_length; + uint16_t secs_track; + uint16_t heads; + uint32_t hidden; + uint32_t total_sect; + union { + struct fat_super_block { + uint8_t unknown[3]; + uint8_t serno[4]; + uint8_t label[11]; + uint8_t magic[8]; + uint8_t dummy2[192]; + uint8_t pmagic[2]; + } PACKED fat; + struct fat32_super_block { + uint32_t fat32_length; + uint16_t flags; + uint8_t version[2]; + uint32_t root_cluster; + uint16_t fsinfo_sector; + uint16_t backup_boot; + uint16_t reserved2[6]; + uint8_t unknown[3]; + uint8_t serno[4]; + uint8_t label[11]; + uint8_t magic[8]; + uint8_t dummy2[164]; + uint8_t pmagic[2]; + } PACKED fat32; + } PACKED type; +} PACKED; + +struct fat32_fsinfo { + uint8_t signature1[4]; + uint32_t reserved1[120]; + uint8_t signature2[4]; + uint32_t free_clusters; + uint32_t next_cluster; + uint32_t reserved2[4]; +} PACKED; + +struct vfat_dir_entry { + uint8_t name[11]; + uint8_t attr; + uint8_t lowercase; + uint8_t fine_time_creat; + uint16_t time_creat; + uint16_t date_creat; + uint16_t date_acc; + uint16_t cluster_high; + uint16_t time_write; + uint16_t date_write; + uint16_t cluster_low; + uint32_t size; +} PACKED; + + +struct vfat_lfn_entry { + uint8_t seq; + uint16_t name0[5]; + uint8_t attr; + uint8_t reserved; + uint8_t cksum; + uint16_t name1[6]; + uint16_t cluster; + uint16_t name2[2]; +} PACKED; + +static uint8_t fat_lfn_checksum(const uint8_t name[11]) +{ + uint8_t cksum = 0; + int i; + + /* http://en.wikipedia.org/wiki/File_Allocation_Table */ + for (i = 0; i < 11; i++) + cksum = ((cksum & 1) ? 0x80 : 0) + (cksum >> 1) + name[i]; + + return cksum; +} + +static size_t fat_read_lfn(uint8_t *filename, size_t fnsize, + struct vfat_dir_entry *direntry, + struct vfat_dir_entry *entry) +{ + uint8_t buffer[VFAT_LFN_SEQ_MAX * VFAT_LFN_CHARS_PER_ENTRY * 2]; + uint8_t expected_seq = 1; + uint8_t cksum; + size_t len = 0; + size_t fnlen = 0; + + cksum = fat_lfn_checksum(entry->name); + + while (--entry >= direntry) { + struct vfat_lfn_entry *lfn = (struct vfat_lfn_entry *) entry; + + if (expected_seq > VFAT_LFN_SEQ_MAX) + break; + + if ((lfn->attr & FAT_ATTR_MASK) != FAT_ATTR_LONG_NAME) + break; + + if (lfn->cksum != cksum) + break; + + if ((lfn->seq & VFAT_LFN_SEQ_MASK) != expected_seq++) + break; + + if (lfn->cluster != 0) + break; + + /* extra paranoia -- should never happen */ + if (len + sizeof(lfn->name0) + sizeof(lfn->name1) + + sizeof(lfn->name2) > sizeof(buffer)) + break; + + memcpy (&buffer[len], lfn->name0, sizeof(lfn->name0)); + len += sizeof(lfn->name0); + memcpy (&buffer[len], lfn->name1, sizeof(lfn->name1)); + len += sizeof(lfn->name1); + memcpy (&buffer[len], lfn->name2, sizeof(lfn->name2)); + len += sizeof(lfn->name2); + + if (lfn->seq & VFAT_LFN_SEQ_LAST) { + fnlen = volume_id_set_unicode16(filename, fnsize, buffer, LE, len); + break; + } + } + + return fnlen; +} + +static size_t fat_read_filename(uint8_t *filename, size_t fnsize, + struct vfat_dir_entry *direntry, struct vfat_dir_entry *entry) +{ + size_t len; + int i; + + /* check if maybe we have LFN entries */ + len = fat_read_lfn(filename, fnsize, direntry, entry); + if (len > 0) + goto out; + + /* else, read the normal 8.3 name */ + for (i = 0; i < 11; i++) { + if (entry->lowercase & ((i < 8) ? VFAT_LOWERCASE_NAME : VFAT_LOWERCASE_EXT)) + filename[i] = tolower(entry->name[i]); + else + filename[i] = entry->name[i]; + } + len = 11; + +out: + filename[len] = '\0'; + return len; +} + +/* fills filename, returns string length */ +static size_t get_fat_attr_volume_id(uint8_t *filename, size_t fnsize, + struct vfat_dir_entry *direntry, unsigned int count) +{ + unsigned int i; + + for (i = 0; i < count; i++) { + /* end marker */ + if (direntry[i].name[0] == 0x00) { + dbg("end of dir"); + break; + } + + /* empty entry */ + if (direntry[i].name[0] == FAT_ENTRY_FREE) + continue; + + /* long name */ + if ((direntry[i].attr & FAT_ATTR_MASK) == FAT_ATTR_LONG_NAME) + continue; + + if ((direntry[i].attr & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) == FAT_ATTR_VOLUME_ID) { + /* labels do not have file data */ + if (direntry[i].cluster_high != 0 || direntry[i].cluster_low != 0) + continue; + + dbg("found ATTR_VOLUME_ID id in root dir"); + return fat_read_filename(filename, fnsize, direntry, &direntry[i]); + } + + dbg("skip dir entry"); + } + + return 0; +} + +int volume_id_probe_vfat(struct volume_id *id, uint64_t off, uint64_t size) +{ + uint8_t filename[255 * 3]; + struct vfat_super_block *vs; + struct vfat_dir_entry *direntry; + struct fat32_fsinfo *fsinfo; + uint16_t sector_size; + uint16_t dir_entries; + uint32_t sect_count; + uint16_t reserved; + uint32_t fat_size; + uint32_t root_cluster; + uint32_t dir_size; + uint32_t cluster_count; + uint16_t fat_length; + uint32_t fat32_length; + uint64_t root_start; + uint32_t start_data_sect; + uint16_t root_dir_entries; + uint16_t fsinfo_sect; + uint8_t *buf; + uint32_t buf_size; + uint32_t next; + int maxloop; + size_t fnlen; + + info("probing at offset 0x%llx", (unsigned long long) off); + + buf = volume_id_get_buffer(id, off, 0x400); + if (buf == NULL) + return -1; + + /* check signature */ + if (buf[510] != 0x55 || buf[511] != 0xaa) + return -1; + + vs = (struct vfat_super_block *) buf; + if (memcmp((char*)vs->sysid, "NTFS", 4) == 0) + return -1; + + /* believe only that's fat, don't trust the version */ + if (memcmp((char*)vs->type.fat32.magic, "MSWIN", 5) == 0) + goto magic; + + if (memcmp((char*)vs->type.fat32.magic, "FAT32 ", 8) == 0) + goto magic; + + if (memcmp((char*)vs->type.fat.magic, "FAT16 ", 8) == 0) + goto magic; + + if (memcmp((char*)vs->type.fat.magic, "MSDOS", 5) == 0) + goto magic; + + if (memcmp((char*)vs->type.fat.magic, "FAT12 ", 8) == 0) + goto magic; + + /* some old floppies don't have a magic, expect the boot jump address to match */ + if ((vs->boot_jump[0] != 0xeb || vs->boot_jump[2] != 0x90) && + vs->boot_jump[0] != 0xe9) + return -1; + +magic: + /* reserverd sector count */ + if (!vs->reserved) + return -1; + + /* fat count */ + if (!vs->fats) + return -1; + + /* media check */ + if (vs->media < 0xf8 && vs->media != 0xf0) + return -1; + + /* cluster size check */ + if (vs->sectors_per_cluster == 0 || + (vs->sectors_per_cluster & (vs->sectors_per_cluster-1))) + return -1; + + /* sector size check */ + sector_size = le16_to_cpu(vs->sector_size); + if (sector_size == 0 || ((sector_size & (sector_size-1)) != 0)) + return -1; + + dbg("sector_size 0x%x", sector_size); + dbg("sectors_per_cluster 0x%x", vs->sectors_per_cluster); + + dir_entries = le16_to_cpu(vs->dir_entries); + reserved = le16_to_cpu(vs->reserved); + dbg("reserved 0x%x", reserved); + + sect_count = le16_to_cpu(vs->sectors); + if (sect_count == 0) + sect_count = le32_to_cpu(vs->total_sect); + dbg("sect_count 0x%x", sect_count); + + fat_length = le16_to_cpu(vs->fat_length); + dbg("fat_length 0x%x", fat_length); + fat32_length = le32_to_cpu(vs->type.fat32.fat32_length); + dbg("fat32_length 0x%x", fat32_length); + + if (fat_length) + fat_size = fat_length * vs->fats; + else if (fat32_length) + fat_size = fat32_length * vs->fats; + else + return -1; + dbg("fat_size 0x%x", fat_size); + + dir_size = ((dir_entries * sizeof(struct vfat_dir_entry)) + + (sector_size-1)) / sector_size; + dbg("dir_size 0x%x", dir_size); + + cluster_count = sect_count - (reserved + fat_size + dir_size); + cluster_count /= vs->sectors_per_cluster; + dbg("cluster_count 0x%x", cluster_count); + + /* must be FAT32 */ + if (!fat_length && fat32_length) + goto fat32; + + /* cluster_count tells us the format */ + if (cluster_count < FAT12_MAX) + strcpy(id->type_version, "FAT12"); + else if (cluster_count < FAT16_MAX) + strcpy(id->type_version, "FAT16"); + else + goto fat32; + + /* the label may be an attribute in the root directory */ + root_start = (reserved + fat_size) * sector_size; + dbg("root dir start 0x%llx", (unsigned long long) root_start); + root_dir_entries = le16_to_cpu(vs->dir_entries); + dbg("expected entries 0x%x", root_dir_entries); + + buf_size = root_dir_entries * sizeof(struct vfat_dir_entry); + buf = volume_id_get_buffer(id, off + root_start, buf_size); + if (buf == NULL) + goto found; + + direntry = (struct vfat_dir_entry*) buf; + + fnlen = get_fat_attr_volume_id(filename, sizeof(filename), direntry, root_dir_entries); + + vs = (struct vfat_super_block *) volume_id_get_buffer(id, off, 0x200); + if (vs == NULL) + return -1; + + if (fnlen > 0 && memcmp((char*)filename, "NO NAME ", 11) != 0) { + volume_id_set_label_raw(id, filename, fnlen); + volume_id_set_label_string(id, filename, fnlen); + } else if (memcmp((char*)vs->type.fat.label, "NO NAME ", 11) != 0) { + volume_id_set_label_raw(id, vs->type.fat.label, 11); + volume_id_set_label_string(id, vs->type.fat.label, 11); + } + volume_id_set_uuid(id, vs->type.fat.serno, 0, UUID_DOS); + goto found; + +fat32: + /* FAT32 should have a valid signature in the fsinfo block */ + fsinfo_sect = le16_to_cpu(vs->type.fat32.fsinfo_sector); + buf = volume_id_get_buffer(id, off + (fsinfo_sect * sector_size), 0x200); + if (buf == NULL) + return -1; + fsinfo = (struct fat32_fsinfo *) buf; + if (memcmp((char*)fsinfo->signature1, "\x52\x52\x61\x41", 4) != 0) + return -1; + if (memcmp((char*)fsinfo->signature2, "\x72\x72\x41\x61", 4) != 0) + return -1 ; + + vs = (struct vfat_super_block *) volume_id_get_buffer(id, off, 0x200); + if (vs == NULL) + return -1; + + strcpy(id->type_version, "FAT32"); + + /* 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); + dbg("root dir cluster %u", root_cluster); + start_data_sect = reserved + fat_size; + + next = root_cluster; + maxloop = 100; + while (--maxloop) { + uint32_t next_sect_off; + uint64_t next_off; + uint64_t fat_entry_off; + int count; + + 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%llx", (unsigned long long) next_off); + + /* get cluster */ + buf = volume_id_get_buffer(id, off + next_off, buf_size); + if (buf == NULL) + goto found; + + direntry = (struct vfat_dir_entry*) buf; + count = buf_size / sizeof(struct vfat_dir_entry); + dbg("expected entries 0x%x", count); + + fnlen = get_fat_attr_volume_id(filename, sizeof(filename), direntry, count); + if (fnlen > 0) + break; + + /* get FAT entry */ + fat_entry_off = (reserved * sector_size) + (next * sizeof(uint32_t)); + buf = volume_id_get_buffer(id, off + fat_entry_off, buf_size); + if (buf == NULL) + goto found; + + /* set next cluster */ + next = le32_to_cpu(*((uint32_t *) buf)) & 0x0fffffff; + if (next < 2 || next >= 0x0ffffff0) + break; + } + if (maxloop == 0) + dbg("reached maximum follow count of root cluster chain, give up"); + + vs = (struct vfat_super_block *) volume_id_get_buffer(id, off, 0x200); + if (vs == NULL) + return -1; + + if (fnlen > 0 && memcmp((char*)filename, "NO NAME ", 11) != 0) { + volume_id_set_label_raw(id, filename, fnlen); + volume_id_set_label_string(id, filename, fnlen); + } else if (memcmp((char*)vs->type.fat32.label, "NO NAME ", 11) != 0) { + volume_id_set_label_raw(id, vs->type.fat32.label, 11); + volume_id_set_label_string(id, vs->type.fat32.label, 11); + } + volume_id_set_uuid(id, vs->type.fat32.serno, 0, UUID_DOS); + +found: + volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); + id->type = "vfat"; + + return 0; +} === added file 'libvolume_id/gfs.c' --- grub-0.97.orig/libvolume_id/gfs.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/gfs.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,115 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2006 Red Hat, Inc. + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +/* Common gfs/gfs2 constants: */ +#define GFS_MAGIC 0x01161970 +#define GFS_DEFAULT_BSIZE 4096 +#define GFS_SUPERBLOCK_OFFSET (0x10 * GFS_DEFAULT_BSIZE) +#define GFS_METATYPE_SB 1 +#define GFS_FORMAT_SB 100 +#define GFS_LOCKNAME_LEN 64 + +/* gfs1 constants: */ +#define GFS_FORMAT_FS 1309 +#define GFS_FORMAT_MULTI 1401 +/* gfs2 constants: */ +#define GFS2_FORMAT_FS 1801 +#define GFS2_FORMAT_MULTI 1900 + +struct gfs2_meta_header { + uint32_t mh_magic; + uint32_t mh_type; + uint64_t __pad0; /* Was generation number in gfs1 */ + uint32_t mh_format; + uint32_t __pad1; /* Was incarnation number in gfs1 */ +}; + +struct gfs2_inum { + uint64_t no_formal_ino; + uint64_t no_addr; +}; + +struct gfs2_sb { + struct gfs2_meta_header sb_header; + + uint32_t sb_fs_format; + uint32_t sb_multihost_format; + uint32_t __pad0; /* Was superblock flags in gfs1 */ + + uint32_t sb_bsize; + uint32_t sb_bsize_shift; + uint32_t __pad1; /* Was journal segment size in gfs1 */ + + struct gfs2_inum sb_master_dir; /* Was jindex dinode in gfs1 */ + struct gfs2_inum __pad2; /* Was rindex dinode in gfs1 */ + struct gfs2_inum sb_root_dir; + + char sb_lockproto[GFS_LOCKNAME_LEN]; + char sb_locktable[GFS_LOCKNAME_LEN]; + /* In gfs1, quota and license dinodes followed */ +} PACKED; + +static int volume_id_probe_gfs_generic(struct volume_id *id, uint64_t off, int vers) +{ + struct gfs2_sb *sbd; + + info("probing at offset 0x%llx", (unsigned long long) off); + + sbd = (struct gfs2_sb *) + volume_id_get_buffer(id, off + GFS_SUPERBLOCK_OFFSET, sizeof(struct gfs2_sb)); + if (sbd == NULL) + return -1; + + if (be32_to_cpu(sbd->sb_header.mh_magic) == GFS_MAGIC && + be32_to_cpu(sbd->sb_header.mh_type) == GFS_METATYPE_SB && + be32_to_cpu(sbd->sb_header.mh_format) == GFS_FORMAT_SB) { + if (vers == 1) { + if (be32_to_cpu(sbd->sb_fs_format) != GFS_FORMAT_FS || + be32_to_cpu(sbd->sb_multihost_format) != GFS_FORMAT_MULTI) + return -1; /* not gfs1 */ + id->type = "gfs"; + } + else if (vers == 2) { + if (be32_to_cpu(sbd->sb_fs_format) != GFS2_FORMAT_FS || + be32_to_cpu(sbd->sb_multihost_format) != GFS2_FORMAT_MULTI) + return -1; /* not gfs2 */ + id->type = "gfs2"; + } + else + return -1; + strcpy(id->type_version, "1"); + volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); + return 0; + } + return -1; +} + +int volume_id_probe_gfs(struct volume_id *id, uint64_t off, uint64_t size) +{ + return volume_id_probe_gfs_generic(id, off, 1); +} + +int volume_id_probe_gfs2(struct volume_id *id, uint64_t off, uint64_t size) +{ + return volume_id_probe_gfs_generic(id, off, 2); +} === added file 'libvolume_id/hfs.c' --- grub-0.97.orig/libvolume_id/hfs.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/hfs.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,318 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +struct hfs_finder_info{ + uint32_t boot_folder; + uint32_t start_app; + uint32_t open_folder; + uint32_t os9_folder; + uint32_t reserved; + uint32_t osx_folder; + uint8_t id[8]; +} PACKED; + +static struct hfs_mdb { + uint8_t signature[2]; + uint32_t cr_date; + uint32_t ls_Mod; + uint16_t atrb; + uint16_t nm_fls; + uint16_t vbm_st; + uint16_t alloc_ptr; + uint16_t nm_al_blks; + uint32_t al_blk_size; + uint32_t clp_size; + uint16_t al_bl_st; + uint32_t nxt_cnid; + uint16_t free_bks; + uint8_t label_len; + uint8_t label[27]; + uint32_t vol_bkup; + uint16_t vol_seq_num; + uint32_t wr_cnt; + uint32_t xt_clump_size; + uint32_t ct_clump_size; + uint16_t num_root_dirs; + uint32_t file_count; + uint32_t dir_count; + struct hfs_finder_info finder_info; + uint8_t embed_sig[2]; + uint16_t embed_startblock; + uint16_t embed_blockcount; +} PACKED *hfs; + +struct hfsplus_bnode_descriptor { + uint32_t next; + uint32_t prev; + uint8_t type; + uint8_t height; + uint16_t num_recs; + uint16_t reserved; +} PACKED; + +struct hfsplus_bheader_record { + uint16_t depth; + uint32_t root; + uint32_t leaf_count; + uint32_t leaf_head; + uint32_t leaf_tail; + uint16_t node_size; +} PACKED; + +struct hfsplus_catalog_key { + uint16_t key_len; + uint32_t parent_id; + uint16_t unicode_len; + uint8_t unicode[255 * 2]; +} PACKED; + +struct hfsplus_extent { + uint32_t start_block; + uint32_t block_count; +} PACKED; + +#define HFSPLUS_EXTENT_COUNT 8 +struct hfsplus_fork { + uint64_t total_size; + uint32_t clump_size; + uint32_t total_blocks; + struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT]; +} PACKED; + +static struct hfsplus_vol_header { + uint8_t signature[2]; + uint16_t version; + uint32_t attributes; + uint32_t last_mount_vers; + uint32_t reserved; + uint32_t create_date; + uint32_t modify_date; + uint32_t backup_date; + uint32_t checked_date; + uint32_t file_count; + uint32_t folder_count; + uint32_t blocksize; + uint32_t total_blocks; + uint32_t free_blocks; + uint32_t next_alloc; + uint32_t rsrc_clump_sz; + uint32_t data_clump_sz; + uint32_t next_cnid; + uint32_t write_count; + uint64_t encodings_bmp; + struct hfs_finder_info finder_info; + struct hfsplus_fork alloc_file; + struct hfsplus_fork ext_file; + struct hfsplus_fork cat_file; + struct hfsplus_fork attr_file; + struct hfsplus_fork start_file; +} PACKED *hfsplus; + +#define HFS_SUPERBLOCK_OFFSET 0x400 +#define HFS_NODE_LEAF 0xff +#define HFSPLUS_POR_CNID 1 + +static void hfsid_set_uuid(struct volume_id *id, const uint8_t *hfs_id) +{ +#if 0 + MD5_CTX md5c; + static const uint8_t hash_init[16] = { + 0xb3, 0xe2, 0x0f, 0x39, 0xf2, 0x92, 0x11, 0xd6, + 0x97, 0xa4, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac + }; + uint8_t uuid[16]; + + if (*((uint64_t *)hfs_id) == 0) + return; + + MD5_Init(&md5c); + MD5_Update(&md5c, &hash_init, 16); + MD5_Update(&md5c, hfs_id, 8); + MD5_Final(uuid, &md5c); + + uuid[6] = 0x30 | (uuid[6] & 0x0f); + uuid[8] = 0x80 | (uuid[8] & 0x3f); + volume_id_set_uuid(id, uuid, UUID_DCE); +#endif + + volume_id_set_uuid(id, hfs_id, 0, UUID_64BIT_BE); +} + +int volume_id_probe_hfs_hfsplus(struct volume_id *id, uint64_t off, uint64_t size) +{ + unsigned int blocksize; + unsigned int cat_block; + unsigned int ext_block_start; + unsigned int ext_block_count; + int ext; + unsigned int leaf_node_head; + unsigned int leaf_node_count; + unsigned int leaf_node_size; + unsigned int leaf_block; + uint64_t leaf_off; + unsigned int alloc_block_size; + unsigned int alloc_first_block; + unsigned int embed_first_block; + unsigned int record_count; + struct hfsplus_bnode_descriptor *descr; + struct hfsplus_bheader_record *bnode; + struct hfsplus_catalog_key *key; + unsigned int label_len; + struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT]; + const uint8_t *buf; + + info("probing at offset 0x%llx", (unsigned long long) off); + + buf = volume_id_get_buffer(id, off + HFS_SUPERBLOCK_OFFSET, 0x200); + if (buf == NULL) + return -1; + + hfs = (struct hfs_mdb *) buf; + if (memcmp((char *)hfs->signature, "BD", 2) != 0) + goto checkplus; + + /* it may be just a hfs wrapper for hfs+ */ + if (memcmp((char *)hfs->embed_sig, "H+", 2) == 0) { + alloc_block_size = be32_to_cpu(hfs->al_blk_size); + dbg("alloc_block_size 0x%x", alloc_block_size); + + alloc_first_block = be16_to_cpu(hfs->al_bl_st); + dbg("alloc_first_block 0x%x", alloc_first_block); + + embed_first_block = be16_to_cpu(hfs->embed_startblock); + dbg("embed_first_block 0x%x", embed_first_block); + + off += (alloc_first_block * 512) + + (embed_first_block * alloc_block_size); + dbg("hfs wrapped hfs+ found at offset 0x%llx", (unsigned long long) off); + + buf = volume_id_get_buffer(id, off + HFS_SUPERBLOCK_OFFSET, 0x200); + if (buf == NULL) + return -1; + goto checkplus; + } + + if (hfs->label_len > 0 && hfs->label_len < 28) { + volume_id_set_label_raw(id, hfs->label, hfs->label_len); + volume_id_set_label_string(id, hfs->label, hfs->label_len) ; + } + + hfsid_set_uuid(id, hfs->finder_info.id); + + volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); + id->type = "hfs"; + + return 0; + +checkplus: + hfsplus = (struct hfsplus_vol_header *) buf; + if (memcmp((char *)hfsplus->signature, "H+", 2) == 0) + goto hfsplus; + if (memcmp((char *)hfsplus->signature, "HX", 2) == 0) + goto hfsplus; + return -1; + +hfsplus: + hfsid_set_uuid(id, hfsplus->finder_info.id); + + blocksize = be32_to_cpu(hfsplus->blocksize); + dbg("blocksize %u", blocksize); + + memcpy(extents, hfsplus->cat_file.extents, sizeof(extents)); + cat_block = be32_to_cpu(extents[0].start_block); + dbg("catalog start block 0x%x", cat_block); + + buf = volume_id_get_buffer(id, off + (cat_block * blocksize), 0x2000); + if (buf == NULL) + goto found; + + bnode = (struct hfsplus_bheader_record *) + &buf[sizeof(struct hfsplus_bnode_descriptor)]; + + leaf_node_head = be32_to_cpu(bnode->leaf_head); + dbg("catalog leaf node 0x%x", leaf_node_head); + + leaf_node_size = be16_to_cpu(bnode->node_size); + dbg("leaf node size 0x%x", leaf_node_size); + + leaf_node_count = be32_to_cpu(bnode->leaf_count); + dbg("leaf node count 0x%x", leaf_node_count); + if (leaf_node_count == 0) + goto found; + + leaf_block = (leaf_node_head * leaf_node_size) / blocksize; + + /* get physical location */ + for (ext = 0; ext < HFSPLUS_EXTENT_COUNT; ext++) { + ext_block_start = be32_to_cpu(extents[ext].start_block); + ext_block_count = be32_to_cpu(extents[ext].block_count); + dbg("extent start block 0x%x, count 0x%x", ext_block_start, ext_block_count); + + if (ext_block_count == 0) + goto found; + + /* this is our extent */ + if (leaf_block < ext_block_count) + break; + + leaf_block -= ext_block_count; + } + if (ext == HFSPLUS_EXTENT_COUNT) + goto found; + dbg("found block in extent %i", ext); + + leaf_off = (ext_block_start + leaf_block) * blocksize; + + buf = volume_id_get_buffer(id, off + leaf_off, leaf_node_size); + if (buf == NULL) + goto found; + + descr = (struct hfsplus_bnode_descriptor *) buf; + dbg("descriptor type 0x%x", descr->type); + + record_count = be16_to_cpu(descr->num_recs); + dbg("number of records %u", record_count); + if (record_count == 0) + goto found; + + if (descr->type != HFS_NODE_LEAF) + goto found; + + key = (struct hfsplus_catalog_key *) + &buf[sizeof(struct hfsplus_bnode_descriptor)]; + + dbg("parent id 0x%x", be32_to_cpu(key->parent_id)); + if (be32_to_cpu(key->parent_id) != HFSPLUS_POR_CNID) + goto found; + + label_len = be16_to_cpu(key->unicode_len) * 2; + dbg("label unicode16 len %i", label_len); + volume_id_set_label_raw(id, key->unicode, label_len); + volume_id_set_label_unicode16(id, key->unicode, BE, label_len); + +found: + volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); + id->type = "hfsplus"; + + return 0; +} === added file 'libvolume_id/highpoint.c' --- grub-0.97.orig/libvolume_id/highpoint.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/highpoint.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,91 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +struct hpt37x_meta { + uint8_t filler1[32]; + uint32_t magic; +} PACKED; + +struct hpt45x_meta { + uint32_t magic; +} PACKED; + +#define HPT37X_CONFIG_OFF 0x1200 +#define HPT37X_MAGIC_OK 0x5a7816f0 +#define HPT37X_MAGIC_BAD 0x5a7816fd + +#define HPT45X_MAGIC_OK 0x5a7816f3 +#define HPT45X_MAGIC_BAD 0x5a7816fd + + +int volume_id_probe_highpoint_37x_raid(struct volume_id *id, uint64_t off, uint64_t size) +{ + const uint8_t *buf; + struct hpt37x_meta *hpt; + uint32_t magic; + + info("probing at offset 0x%llx", (unsigned long long) off); + + buf = volume_id_get_buffer(id, off + HPT37X_CONFIG_OFF, 0x200); + if (buf == NULL) + return -1; + + hpt = (struct hpt37x_meta *) buf; + magic = le32_to_cpu(hpt->magic); + if (magic != HPT37X_MAGIC_OK && magic != HPT37X_MAGIC_BAD) + return -1; + + volume_id_set_usage(id, VOLUME_ID_RAID); + id->type = "highpoint_raid_member"; + + return 0; +} + +int volume_id_probe_highpoint_45x_raid(struct volume_id *id, uint64_t off, uint64_t size) +{ + const uint8_t *buf; + struct hpt45x_meta *hpt; + uint64_t meta_off; + uint32_t magic; + + dbg("probing at offset 0x%llx, size 0x%llx", + (unsigned long long) off, (unsigned long long) size); + + if (size < 0x10000) + return -1; + + meta_off = ((size / 0x200)-11) * 0x200; + buf = volume_id_get_buffer(id, off + meta_off, 0x200); + if (buf == NULL) + return -1; + + hpt = (struct hpt45x_meta *) buf; + magic = le32_to_cpu(hpt->magic); + if (magic != HPT45X_MAGIC_OK && magic != HPT45X_MAGIC_BAD) + return -1; + + volume_id_set_usage(id, VOLUME_ID_RAID); + id->type = "highpoint_raid_member"; + + return 0; +} === added file 'libvolume_id/hpfs.c' --- grub-0.97.orig/libvolume_id/hpfs.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/hpfs.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,51 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2005 Kay Sievers + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +struct hpfs_super +{ + uint8_t magic[4]; + uint8_t version; +} PACKED; + +#define HPFS_SUPERBLOCK_OFFSET 0x2000 + +int volume_id_probe_hpfs(struct volume_id *id, uint64_t off, uint64_t size) +{ + struct hpfs_super *hs; + + info("probing at offset 0x%llx", (unsigned long long) off); + + hs = (struct hpfs_super *) volume_id_get_buffer(id, off + HPFS_SUPERBLOCK_OFFSET, 0x200); + if (hs == NULL) + return -1; + + if (memcmp((char *)hs->magic, "\x49\xe8\x95\xf9", 4) == 0) { + sprintf(id->type_version, "%u", hs->version); + + volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); + id->type = "hpfs"; + return 0; + } + + return -1; +} === added file 'libvolume_id/iso9660.c' --- grub-0.97.orig/libvolume_id/iso9660.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/iso9660.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,119 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +#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 + +struct iso_volume_descriptor { + uint8_t type; + uint8_t id[5]; + uint8_t version; + uint8_t flags; + uint8_t system_id[32]; + uint8_t volume_id[32]; + uint8_t unused[8]; + uint8_t space_size[8]; + uint8_t escape_sequences[8]; +} PACKED; + +struct high_sierra_volume_descriptor { + uint8_t foo[8]; + uint8_t type; + uint8_t id[5]; + uint8_t version; +} PACKED; + +int volume_id_probe_iso9660(struct volume_id *id, uint64_t off, uint64_t size) +{ + uint8_t *buf; + struct iso_volume_descriptor *is; + struct high_sierra_volume_descriptor *hs; + + info("probing at offset 0x%llx", (unsigned long long) off); + + buf = volume_id_get_buffer(id, off + ISO_SUPERBLOCK_OFFSET, 0x200); + if (buf == NULL) + return -1; + + is = (struct iso_volume_descriptor *) buf; + + if (memcmp((char*)is->id, "CD001", 5) == 0) { + int vd_offset; + int i; + + dbg("read label from PVD"); + volume_id_set_label_raw(id, is->volume_id, 32); + volume_id_set_label_string(id, is->volume_id, 32); + + dbg("looking for SVDs"); + vd_offset = ISO_VD_OFFSET; + for (i = 0; i < ISO_VD_MAX; i++) { + uint8_t svd_label[64]; + + is = (struct iso_volume_descriptor *) volume_id_get_buffer(id, off + vd_offset, 0x200); + if (is == NULL || is->type == ISO_VD_END) + break; + if (is->type != ISO_VD_SUPPLEMENTARY) + continue; + + dbg("found SVD at offset 0x%llx", (unsigned long long) (off + vd_offset)); + if (memcmp((char *)is->escape_sequences, "%/@", 3) == 0|| + memcmp((char *)is->escape_sequences, "%/C", 3) == 0|| + memcmp((char *)is->escape_sequences, "%/E", 3) == 0) { + dbg("Joliet extension found"); + volume_id_set_unicode16(svd_label, sizeof(svd_label), is->volume_id, BE, 32); + if (memcmp((char *)id->label, (char *)svd_label, 16) == 0) { + dbg("SVD label is identical, use the possibly longer PVD one"); + break; + } + + volume_id_set_label_raw(id, is->volume_id, 32); + volume_id_set_label_string(id, svd_label, 32); + strcpy(id->type_version, "Joliet Extension"); + goto found; + } + vd_offset += ISO_SECTOR_SIZE; + } + goto found; + } + + hs = (struct high_sierra_volume_descriptor *) buf; + + if (memcmp((char *)hs->id, "CDROM", 5) == 0) { + strcpy(id->type_version, "High Sierra"); + goto found; + } + + return -1; + +found: + volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); + id->type = "iso9660"; + + return 0; +} === added file 'libvolume_id/isw_raid.c' --- grub-0.97.orig/libvolume_id/isw_raid.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/isw_raid.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,61 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2005 Kay Sievers + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +struct isw_meta { + uint8_t sig[32]; + uint32_t check_sum; + uint32_t mpb_size; + uint32_t family_num; + uint32_t generation_num; +} PACKED; + +#define ISW_SIGNATURE "Intel Raid ISM Cfg Sig. " + + +int volume_id_probe_intel_software_raid(struct volume_id *id, uint64_t off, uint64_t size) +{ + const uint8_t *buf; + uint64_t meta_off; + struct isw_meta *isw; + + info("probing at offset 0x%llx, size 0x%llx", + (unsigned long long) off, (unsigned long long) size); + + if (size < 0x10000) + return -1; + + meta_off = ((size / 0x200)-2) * 0x200; + buf = volume_id_get_buffer(id, off + meta_off, 0x200); + if (buf == NULL) + return -1; + + isw = (struct isw_meta *) buf; + if (memcmp((char *)isw->sig, ISW_SIGNATURE, sizeof(ISW_SIGNATURE)-1) != 0) + return -1; + + volume_id_set_usage(id, VOLUME_ID_RAID); + memcpy(id->type_version, &isw->sig[sizeof(ISW_SIGNATURE)-1], 6); + id->type = "isw_raid_member"; + + return 0; +} === added file 'libvolume_id/jfs.c' --- grub-0.97.orig/libvolume_id/jfs.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/jfs.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,60 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +struct jfs_super_block { + uint8_t magic[4]; + uint32_t version; + uint64_t size; + uint32_t bsize; + uint32_t dummy1; + uint32_t pbsize; + uint32_t dummy2[27]; + uint8_t uuid[16]; + uint8_t label[16]; + uint8_t loguuid[16]; +} PACKED; + +#define JFS_SUPERBLOCK_OFFSET 0x8000 + +int volume_id_probe_jfs(struct volume_id *id, uint64_t off, uint64_t size) +{ + struct jfs_super_block *js; + + info("probing at offset 0x%llx", (unsigned long long) off); + + js = (struct jfs_super_block *) volume_id_get_buffer(id, off + JFS_SUPERBLOCK_OFFSET, 0x200); + if (js == NULL) + return -1; + + if (memcmp((char *)js->magic, "JFS1", 4) != 0) + return -1; + + volume_id_set_label_raw(id, js->label, 16); + volume_id_set_label_string(id, js->label, 16); + volume_id_set_uuid(id, js->uuid, 0, UUID_DCE); + + volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); + id->type = "jfs"; + + return 0; +} === added file 'libvolume_id/jmicron_raid.c' --- grub-0.97.orig/libvolume_id/jmicron_raid.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/jmicron_raid.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,57 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2006 Kay Sievers + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +struct jmicron_meta { + int8_t signature[2]; + uint8_t minor_version; + uint8_t major_version; + uint16_t checksum; +} PACKED; + +int volume_id_probe_jmicron_raid(struct volume_id *id, uint64_t off, uint64_t size) +{ + const uint8_t *buf; + uint64_t meta_off; + struct jmicron_meta *jm; + + info("probing at offset 0x%llx, size 0x%llx", + (unsigned long long) off, (unsigned long long) size); + + if (size < 0x10000) + return -1; + + meta_off = ((size / 0x200)-1) * 0x200; + buf = volume_id_get_buffer(id, off + meta_off, 0x200); + if (buf == NULL) + return -1; + + jm = (struct jmicron_meta *) buf; + if (memcmp((char *)jm->signature, "JM", 2) != 0) + return -1; + + volume_id_set_usage(id, VOLUME_ID_RAID); + sprintf(id->type_version, "%u.%u", jm->major_version, jm->minor_version); + id->type = "jmicron_raid_member"; + + return 0; +} === added file 'libvolume_id/linux_raid.c' --- grub-0.97.orig/libvolume_id/linux_raid.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/linux_raid.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,160 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +static struct mdp0_super_block { + uint32_t md_magic; + uint32_t major_version; + uint32_t minor_version; + uint32_t patch_version; + uint32_t gvalid_words; + uint32_t set_uuid0; + uint32_t ctime; + uint32_t level; + uint32_t size; + uint32_t nr_disks; + uint32_t raid_disks; + uint32_t md_minor; + uint32_t not_persistent; + uint32_t set_uuid1; + uint32_t set_uuid2; + uint32_t set_uuid3; +} PACKED *mdp0; + +struct mdp1_super_block { + uint32_t magic; + uint32_t major_version; + uint32_t feature_map; + uint32_t pad0; + uint8_t set_uuid[16]; + uint8_t set_name[32]; +} PACKED *mdp1; + +#define MD_RESERVED_BYTES 0x10000 +#define MD_SB_MAGIC 0xa92b4efc + +static int volume_id_probe_linux_raid0(struct volume_id *id, uint64_t off, uint64_t size) +{ + const uint8_t *buf; + union { + uint32_t ints[4]; + uint8_t bytes[16]; + } uuid; + + info("probing at offset 0x%llx, size 0x%llx", + (unsigned long long) off, (unsigned long long) size); + if (size < 0x10000) + return -1; + + buf = volume_id_get_buffer(id, off, 0x800); + if (buf == NULL) + return -1; + mdp0 = (struct mdp0_super_block *) buf; + + if (le32_to_cpu(mdp0->md_magic) == MD_SB_MAGIC) { + uuid.ints[0] = bswap_32(mdp0->set_uuid0); + if (le32_to_cpu(mdp0->minor_version >= 90)) { + uuid.ints[1] = bswap_32(mdp0->set_uuid1); + uuid.ints[2] = bswap_32(mdp0->set_uuid2); + uuid.ints[3] = bswap_32(mdp0->set_uuid3); + } else { + uuid.ints[1] = 0; + uuid.ints[2] = 0; + uuid.ints[3] = 0; + } + volume_id_set_uuid(id, uuid.bytes, 0, UUID_FOURINT); + sprintf(id->type_version, "%u.%u.%u", + le32_to_cpu(mdp0->major_version), + le32_to_cpu(mdp0->minor_version), + le32_to_cpu(mdp0->patch_version)); + } else if (be32_to_cpu(mdp0->md_magic) == MD_SB_MAGIC) { + uuid.ints[0] = mdp0->set_uuid0; + if (be32_to_cpu(mdp0->minor_version >= 90)) { + uuid.ints[1] = mdp0->set_uuid1; + uuid.ints[2] = mdp0->set_uuid2; + uuid.ints[3] = mdp0->set_uuid3; + } else { + uuid.ints[1] = 0; + uuid.ints[2] = 0; + uuid.ints[3] = 0; + } + volume_id_set_uuid(id, uuid.bytes, 0, UUID_FOURINT); + sprintf(id->type_version, "%u.%u.%u", + be32_to_cpu(mdp0->major_version), + be32_to_cpu(mdp0->minor_version), + be32_to_cpu(mdp0->patch_version)); + } else + return -1; + + volume_id_set_usage(id, VOLUME_ID_RAID); + id->type = "linux_raid_member"; + return 0; +} + +static int volume_id_probe_linux_raid1(struct volume_id *id, uint64_t off, uint64_t size) +{ + const uint8_t *buf; + + info("probing at offset 0x%llx, size 0x%llx", + (unsigned long long) off, (unsigned long long) size); + + buf = volume_id_get_buffer(id, off, 0x800); + if (buf == NULL) + return -1; + mdp1 = (struct mdp1_super_block *) buf; + + if (le32_to_cpu(mdp1->magic) != MD_SB_MAGIC) + return -1; + + volume_id_set_uuid(id, mdp1->set_uuid, 0, UUID_FOURINT); + volume_id_set_label_raw(id, mdp1->set_name, 32); + volume_id_set_label_string(id, mdp1->set_name, 32); + sprintf(id->type_version, "%u", le32_to_cpu(mdp1->major_version)); + volume_id_set_usage(id, VOLUME_ID_RAID); + id->type = "linux_raid_member"; + return 0; +} + +int volume_id_probe_linux_raid(struct volume_id *id, uint64_t off, uint64_t size) +{ + uint64_t sboff; + + /* version 0 at the end of the device */ + sboff = (size & ~(MD_RESERVED_BYTES - 1)) - MD_RESERVED_BYTES; + if (volume_id_probe_linux_raid0(id, off + sboff, size) == 0) + return 0; + + /* version 1.0 at the end of the device */ + sboff = (size & ~(0x1000 - 1)) - 0x2000; + if (volume_id_probe_linux_raid1(id, off + sboff, size) == 0) + return 0; + + /* version 1.1 at the start of the device */ + if (volume_id_probe_linux_raid1(id, off, size) == 0) + return 0; + + /* version 1.2 at 4k offset from the start */ + if (volume_id_probe_linux_raid1(id, off + 0x1000, size) == 0) + return 0; + + return -1; +} === added file 'libvolume_id/linux_swap.c' --- grub-0.97.orig/libvolume_id/linux_swap.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/linux_swap.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,85 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +struct swap_header_v1_2 { + uint8_t bootbits[1024]; + uint32_t version; + uint32_t last_page; + uint32_t nr_badpages; + uint8_t uuid[16]; + uint8_t volume_name[16]; +} PACKED; + +#define LARGEST_PAGESIZE 0x4000 + +int volume_id_probe_linux_swap(struct volume_id *id, uint64_t off, uint64_t size) +{ + const uint8_t *buf; + unsigned int page; + struct swap_header_v1_2 *sw; + + info("probing at offset 0x%llx", (unsigned long long) off); + + /* eek, the swap signature is at the end of the PAGE_SIZE */ + for (page = 0x1000; page <= LARGEST_PAGESIZE; page <<= 1) { + buf = volume_id_get_buffer(id, off + page-10, 10); + if (buf == NULL) + return -1; + + if (memcmp((char *)buf, "SWAP-SPACE", 10) == 0) { + strcpy(id->type_version, "1"); + goto found; + } + + if (memcmp((char *)buf, "SWAPSPACE2", 10) == 0) { + id->type = "swap"; + strcpy(id->type_version, "2"); + goto found_label; + } + + if (memcmp((char *)buf, "S1SUSPEND", 9) == 0) { + id->type = "suspend"; + strcpy(id->type_version, "s1suspend"); + goto found_label; + } + + if (memcmp((char *)buf, "ULSUSPEND", 9) == 0) { + id->type = "suspend"; + strcpy(id->type_version, "ulsuspend"); + goto found_label; + } + } + return -1; + +found_label: + sw = (struct swap_header_v1_2 *) volume_id_get_buffer(id, off, sizeof(struct swap_header_v1_2)); + if (sw != NULL) { + volume_id_set_label_raw(id, sw->volume_name, 16); + volume_id_set_label_string(id, sw->volume_name, 16); + volume_id_set_uuid(id, sw->uuid, 0, UUID_DCE); + } + +found: + volume_id_set_usage(id, VOLUME_ID_OTHER); + return 0; +} === added file 'libvolume_id/lsi_raid.c' --- grub-0.97.orig/libvolume_id/lsi_raid.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/lsi_raid.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,55 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2005 Kay Sievers + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +struct lsi_meta { + uint8_t sig[6]; +} PACKED; + +#define LSI_SIGNATURE "$XIDE$" + +int volume_id_probe_lsi_mega_raid(struct volume_id *id, uint64_t off, uint64_t size) +{ + const uint8_t *buf; + uint64_t meta_off; + struct lsi_meta *lsi; + + info("probing at offset 0x%llx, size 0x%llx", + (unsigned long long) off, (unsigned long long) size); + + if (size < 0x10000) + return -1; + + meta_off = ((size / 0x200)-1) * 0x200; + buf = volume_id_get_buffer(id, off + meta_off, 0x200); + if (buf == NULL) + return -1; + + lsi = (struct lsi_meta *) buf; + if (memcmp((char *)lsi->sig, LSI_SIGNATURE, sizeof(LSI_SIGNATURE)-1) != 0) + return -1; + + volume_id_set_usage(id, VOLUME_ID_RAID); + id->type = "lsi_mega_raid_member"; + + return 0; +} === added file 'libvolume_id/luks.c' --- grub-0.97.orig/libvolume_id/luks.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/luks.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,76 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2005 W. Michael Petullo + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +#define LUKS_SECTOR_SHIFT 9 +#define LUKS_SECTOR_SIZE (1 << LUKS_SECTOR_SHIFT) + +#define LUKS_CIPHERNAME_L 32 +#define LUKS_CIPHERMODE_L 32 +#define LUKS_HASHSPEC_L 32 +#define LUKS_DIGESTSIZE 20 +#define LUKS_SALTSIZE 32 +#define LUKS_NUMKEYS 8 + +#define LUKS_MAGIC_L 6 +#define LUKS_PHDR_SIZE (sizeof(struct luks_phdr)/LUKS_SECTOR_SIZE+1) +#define UUID_STRING_L 40 +static const uint8_t LUKS_MAGIC[] = {'L','U','K','S', 0xba, 0xbe}; + +struct luks_phdr { + uint8_t magic[LUKS_MAGIC_L]; + uint16_t version; + uint8_t cipherName[LUKS_CIPHERNAME_L]; + uint8_t cipherMode[LUKS_CIPHERMODE_L]; + uint8_t hashSpec[LUKS_HASHSPEC_L]; + uint32_t payloadOffset; + uint32_t keyBytes; + uint8_t mkDigest[LUKS_DIGESTSIZE]; + uint8_t mkDigestSalt[LUKS_SALTSIZE]; + uint32_t mkDigestIterations; + uint8_t uuid[UUID_STRING_L]; + struct { + uint32_t active; + uint32_t passwordIterations; + uint8_t passwordSalt[LUKS_SALTSIZE]; + uint32_t keyMaterialOffset; + uint32_t stripes; + } keyblock[LUKS_NUMKEYS]; +}; + +int volume_id_probe_luks(struct volume_id *id, uint64_t off, uint64_t size) +{ + struct luks_phdr *header; + + header = (struct luks_phdr*) volume_id_get_buffer(id, off, LUKS_PHDR_SIZE); + if (header == NULL) + return -1; + + if (memcmp((char *)header->magic, (char *)LUKS_MAGIC, LUKS_MAGIC_L)) + return -1; + + volume_id_set_usage(id, VOLUME_ID_CRYPTO); + volume_id_set_uuid(id, header->uuid, 36, UUID_HEX_STRING); + sprintf(id->type_version, "%u", le16_to_cpu(header->version)); + id->type = "crypto_LUKS"; + return 0; +} === added file 'libvolume_id/lvm.c' --- grub-0.97.orig/libvolume_id/lvm.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/lvm.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,92 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +struct lvm1_super_block { + uint8_t id[2]; +} PACKED; + +struct lvm2_super_block { + uint8_t id[8]; + uint64_t sector_xl; + uint32_t crc_xl; + uint32_t offset_xl; + uint8_t type[8]; +} PACKED; + +#define LVM1_SB_OFF 0x400 +#define LVM1_MAGIC "HM" + +int volume_id_probe_lvm1(struct volume_id *id, uint64_t off, uint64_t size) +{ + const uint8_t *buf; + struct lvm1_super_block *lvm; + + info("probing at offset 0x%llx", (unsigned long long) off); + + buf = volume_id_get_buffer(id, off + LVM1_SB_OFF, 0x800); + if (buf == NULL) + return -1; + + lvm = (struct lvm1_super_block *) buf; + + if (memcmp((char *)lvm->id, LVM1_MAGIC, 2) != 0) + return -1; + + volume_id_set_usage(id, VOLUME_ID_RAID); + id->type = "LVM1_member"; + + return 0; +} + +#define LVM2_LABEL_ID "LABELONE" +#define LVM2LABEL_SCAN_SECTORS 4 + +int volume_id_probe_lvm2(struct volume_id *id, uint64_t off, uint64_t size) +{ + const uint8_t *buf; + unsigned int soff; + struct lvm2_super_block *lvm; + + dbg("probing at offset 0x%llx", (unsigned long long) off); + + buf = volume_id_get_buffer(id, off, LVM2LABEL_SCAN_SECTORS * 0x200); + if (buf == NULL) + return -1; + + + for (soff = 0; soff < LVM2LABEL_SCAN_SECTORS * 0x200; soff += 0x200) { + lvm = (struct lvm2_super_block *) &buf[soff]; + + if (memcmp((char *)lvm->id, LVM2_LABEL_ID, 8) == 0) + goto found; + } + + return -1; + +found: + memcpy(id->type_version, lvm->type, 8); + volume_id_set_usage(id, VOLUME_ID_RAID); + id->type = "LVM2_member"; + + return 0; +} === added file 'libvolume_id/minix.c' --- grub-0.97.orig/libvolume_id/minix.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/minix.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,112 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2005-2007 Kay Sievers + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +#define MINIX_SUPERBLOCK_OFFSET 0x400 + +#define MINIX_SUPER_MAGIC 0x137F +#define MINIX_SUPER_MAGIC2 0x138F +#define MINIX2_SUPER_MAGIC 0x2468 +#define MINIX2_SUPER_MAGIC2 0x2478 +#define MINIX3_SUPER_MAGIC 0x4d5a + +struct minix_super_block +{ + uint16_t s_ninodes; + uint16_t s_nzones; + uint16_t s_imap_blocks; + uint16_t s_zmap_blocks; + uint16_t s_firstdatazone; + uint16_t s_log_zone_size; + uint32_t s_max_size; + uint16_t s_magic; + uint16_t s_state; + uint32_t s_zones; +} PACKED; + +struct minix3_super_block { + uint32_t s_ninodes; + uint16_t s_pad0; + uint16_t s_imap_blocks; + uint16_t s_zmap_blocks; + uint16_t s_firstdatazone; + uint16_t s_log_zone_size; + uint16_t s_pad1; + uint32_t s_max_size; + uint32_t s_zones; + uint16_t s_magic; + uint16_t s_pad2; + uint16_t s_blocksize; + uint8_t s_disk_version; +} PACKED; + +int volume_id_probe_minix(struct volume_id *id, uint64_t off, uint64_t size) +{ + uint8_t *buf; + struct minix_super_block *ms; + struct minix3_super_block *m3s; + + info("probing at offset 0x%llx", (unsigned long long) off); + + buf = volume_id_get_buffer(id, off + MINIX_SUPERBLOCK_OFFSET, 0x200); + if (buf == NULL) + return -1; + + ms = (struct minix_super_block *) buf; + + if (ms->s_magic == MINIX_SUPER_MAGIC || + ms->s_magic == bswap_16(MINIX_SUPER_MAGIC)) { + strcpy(id->type_version, "1"); + goto found; + } + if (ms->s_magic == MINIX_SUPER_MAGIC2 || + ms->s_magic == bswap_16(MINIX_SUPER_MAGIC2)) { + strcpy(id->type_version, "1"); + goto found; + } + if (ms->s_magic == MINIX2_SUPER_MAGIC || + ms->s_magic == bswap_16(MINIX2_SUPER_MAGIC)) { + strcpy(id->type_version, "2"); + goto found; + } + if (ms->s_magic == MINIX2_SUPER_MAGIC2 || + ms->s_magic == bswap_16(MINIX2_SUPER_MAGIC2)) { + strcpy(id->type_version, "2"); + goto found; + } + + m3s = (struct minix3_super_block *) buf; + if (m3s->s_magic == MINIX3_SUPER_MAGIC || + m3s->s_magic == bswap_16(MINIX3_SUPER_MAGIC)) { + strcpy(id->type_version, "3"); + goto found; + } + goto exit; + +found: + volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); + id->type = "minix"; + return 0; + +exit: + return -1; +} === added file 'libvolume_id/misc.c' --- grub-0.97.orig/libvolume_id/misc.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/misc.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,34 @@ +/* + * volume_id/misc.c + * + * Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ +#define _GNU_SOURCE +#include + +/* + * Misc auxiliary functions required for volume_id inside grub + */ +size_t strnlen(const char *s, size_t limit) +{ + size_t length = 0; + while ( (length < limit) && (*s++) ) + length++; + + return length; +} + +char *strchr (const char *s, int c) +{ + do { + if ( *s == c ) { + return (char*)s; + } + } while ( *s++ ); + + return 0; +} === added file 'libvolume_id/netware.c' --- grub-0.97.orig/libvolume_id/netware.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/netware.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,98 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2006 Kay Sievers + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +#define NW_SUPERBLOCK_OFFSET 0x1000 + +struct netware_super_block { + uint8_t SBH_Signature[4]; + uint16_t SBH_VersionMajor; + uint16_t SBH_VersionMinor; + uint16_t SBH_VersionMediaMajor; + uint16_t SBH_VersionMediaMinor; + uint32_t SBH_ItemsMoved; + uint8_t SBH_InternalID[16]; + uint32_t SBH_PackedSize; + uint32_t SBH_Checksum; + uint32_t supersyncid; + int64_t superlocation[4]; + uint32_t physSizeUsed; + uint32_t sizeUsed; + uint32_t superTimeStamp; + uint32_t reserved0[1]; + int64_t SBH_LoggedPoolDataBlk; + int64_t SBH_PoolDataBlk; + uint8_t SBH_OldInternalID[16]; + uint32_t SBH_PoolToLVStartUTC; + uint32_t SBH_PoolToLVEndUTC; + uint16_t SBH_VersionMediaMajorCreate; + uint16_t SBH_VersionMediaMinorCreate; + uint32_t SBH_BlocksMoved; + uint32_t SBH_TempBTSpBlk; + uint32_t SBH_TempFTSpBlk; + uint32_t SBH_TempFTSpBlk1; + uint32_t SBH_TempFTSpBlk2; + uint32_t nssMagicNumber; + uint32_t poolClassID; + uint32_t poolID; + uint32_t createTime; + int64_t SBH_LoggedVolumeDataBlk; + int64_t SBH_VolumeDataBlk; + int64_t SBH_SystemBeastBlkNum; + uint64_t totalblocks; + uint16_t SBH_Name[64]; + uint8_t SBH_VolumeID[16]; + uint8_t SBH_PoolID[16]; + uint8_t SBH_PoolInternalID[16]; + uint64_t SBH_Lsn; + uint32_t SBH_SS_Enabled; + uint32_t SBH_SS_CreateTime; + uint8_t SBH_SS_OriginalPoolID[16]; + uint8_t SBH_SS_OriginalVolumeID[16]; + uint8_t SBH_SS_Guid[16]; + uint16_t SBH_SS_OriginalName[64]; + uint32_t reserved2[64-(2+46)]; +} PACKED; + +int volume_id_probe_netware(struct volume_id *id, uint64_t off, uint64_t size) +{ + struct netware_super_block *nw; + + info("probing at offset 0x%llx", (unsigned long long) off); + + nw = (struct netware_super_block *) volume_id_get_buffer(id, off + NW_SUPERBLOCK_OFFSET, 0x200); + if (nw == NULL) + return -1; + + if (memcmp((char *)nw->SBH_Signature, "SPB5", 4) != 0) + return -1; + + volume_id_set_uuid(id, nw->SBH_PoolID, 0, UUID_DCE); + + sprintf(id->type_version, "%u.%02u", + le16_to_cpu(nw->SBH_VersionMediaMajor), le16_to_cpu(nw->SBH_VersionMediaMinor)); + + volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); + id->type = "nss"; + + return 0; +} === added file 'libvolume_id/ntfs.c' --- grub-0.97.orig/libvolume_id/ntfs.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/ntfs.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,192 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +static struct ntfs_super_block { + uint8_t jump[3]; + uint8_t oem_id[8]; + uint16_t bytes_per_sector; + uint8_t sectors_per_cluster; + uint16_t reserved_sectors; + uint8_t fats; + uint16_t root_entries; + uint16_t sectors; + uint8_t media_type; + uint16_t sectors_per_fat; + uint16_t sectors_per_track; + uint16_t heads; + uint32_t hidden_sectors; + uint32_t large_sectors; + uint16_t unused[2]; + uint64_t number_of_sectors; + uint64_t mft_cluster_location; + uint64_t mft_mirror_cluster_location; + int8_t cluster_per_mft_record; + uint8_t reserved1[3]; + int8_t cluster_per_index_record; + uint8_t reserved2[3]; + uint8_t volume_serial[8]; + uint16_t checksum; +} PACKED *ns; + +static struct master_file_table_record { + uint8_t magic[4]; + uint16_t usa_ofs; + uint16_t usa_count; + uint64_t lsn; + uint16_t sequence_number; + uint16_t link_count; + uint16_t attrs_offset; + uint16_t flags; + uint32_t bytes_in_use; + uint32_t bytes_allocated; +} PACKED *mftr; + +static struct file_attribute { + uint32_t type; + uint32_t len; + uint8_t non_resident; + uint8_t name_len; + uint16_t name_offset; + uint16_t flags; + uint16_t instance; + uint32_t value_len; + uint16_t value_offset; +} PACKED *attr; + +static struct volume_info { + uint64_t reserved; + uint8_t major_ver; + uint8_t minor_ver; +} PACKED *info; + +#define MFT_RECORD_VOLUME 3 +#define MFT_RECORD_ATTR_VOLUME_NAME 0x60 +#define MFT_RECORD_ATTR_VOLUME_INFO 0x70 +#define MFT_RECORD_ATTR_OBJECT_ID 0x40 +#define MFT_RECORD_ATTR_END 0xffffffffu + +#undef debug +#define debug grub_printf + +int volume_id_probe_ntfs(struct volume_id *id, uint64_t off, uint64_t size) +{ + unsigned int sector_size; + unsigned int cluster_size; + uint64_t mft_cluster; + uint64_t mft_off; + unsigned int mft_record_size; + unsigned int attr_type; + unsigned int attr_off; + unsigned int attr_len; + unsigned int val_off; + unsigned int val_len; + const uint8_t *buf; + const uint8_t *val; + + info("probing at offset 0x%llx", (unsigned long long) off); + + ns = (struct ntfs_super_block *) volume_id_get_buffer(id, off, 0x200); + if (ns == NULL) + return -1; + + if (memcmp((char *)ns->oem_id, "NTFS", 4) != 0) + return -1; + + volume_id_set_uuid(id, ns->volume_serial, 0, UUID_64BIT_LE); + + sector_size = le16_to_cpu(ns->bytes_per_sector); + if (sector_size < 0x200) + return -1; + + cluster_size = ns->sectors_per_cluster * sector_size; + mft_cluster = le64_to_cpu(ns->mft_cluster_location); + mft_off = mft_cluster * cluster_size; + + if (ns->cluster_per_mft_record < 0) + /* size = -log2(mft_record_size); normally 1024 Bytes */ + mft_record_size = 1 << -ns->cluster_per_mft_record; + else + mft_record_size = ns->cluster_per_mft_record * cluster_size; + + dbg("sectorsize 0x%x", sector_size); + dbg("clustersize 0x%x", cluster_size); + dbg("mftcluster %llu", (unsigned long long) mft_cluster); + dbg("mftoffset 0x%llx", (unsigned long long) mft_off); + dbg("cluster per mft_record %i", ns->cluster_per_mft_record); + dbg("mft record size %i", mft_record_size); + + buf = volume_id_get_buffer(id, off + mft_off + (MFT_RECORD_VOLUME * mft_record_size), + mft_record_size); + if (buf == NULL) + return -1; + + mftr = (struct master_file_table_record*) buf; + dbg("mftr->magic '%c%c%c%c'", mftr->magic[0], mftr->magic[1], mftr->magic[2], mftr->magic[3]); + if (memcmp((char *)mftr->magic, "FILE", 4) != 0) + return -1; + + attr_off = le16_to_cpu(mftr->attrs_offset); + dbg("file $Volume's attributes are at offset %i", attr_off); + + while (1) { + attr = (struct file_attribute*) &buf[attr_off]; + attr_type = le32_to_cpu(attr->type); + attr_len = le16_to_cpu(attr->len); + val_off = le16_to_cpu(attr->value_offset); + val_len = le32_to_cpu(attr->value_len); + attr_off += attr_len; + + if (attr_len == 0) + break; + + if (attr_off >= mft_record_size) + break; + + if (attr_type == MFT_RECORD_ATTR_END) + break; + + dbg("found attribute type 0x%x, len %i, at offset %i", + attr_type, attr_len, attr_off); + + if (attr_type == MFT_RECORD_ATTR_VOLUME_INFO) { + dbg("found info, len %i", val_len); + info = (struct volume_info*) (((uint8_t *) attr) + val_off); + sprintf(id->type_version, "%u.%u", info->major_ver, info->minor_ver); + } + + if (attr_type == MFT_RECORD_ATTR_VOLUME_NAME) { + dbg("found label, len %i", val_len); + if (val_len > VOLUME_ID_LABEL_SIZE) + val_len = VOLUME_ID_LABEL_SIZE; + + val = ((uint8_t *) attr) + val_off; + volume_id_set_label_raw(id, val, val_len); + volume_id_set_label_unicode16(id, val, LE, val_len); + } + } + + volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); + id->type = "ntfs"; + + return 0; +} === added file 'libvolume_id/nvidia_raid.c' --- grub-0.97.orig/libvolume_id/nvidia_raid.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/nvidia_raid.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,59 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2005 Kay Sievers + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +struct nvidia_meta { + uint8_t vendor[8]; + uint32_t size; + uint32_t chksum; + uint16_t version; +} PACKED; + +#define NVIDIA_SIGNATURE "NVIDIA" + +int volume_id_probe_nvidia_raid(struct volume_id *id, uint64_t off, uint64_t size) +{ + const uint8_t *buf; + uint64_t meta_off; + struct nvidia_meta *nv; + + info("probing at offset 0x%llx, size 0x%llx", + (unsigned long long) off, (unsigned long long) size); + + if (size < 0x10000) + return -1; + + meta_off = ((size / 0x200)-2) * 0x200; + buf = volume_id_get_buffer(id, off + meta_off, 0x200); + if (buf == NULL) + return -1; + + nv = (struct nvidia_meta *) buf; + if (memcmp((char *)nv->vendor, NVIDIA_SIGNATURE, sizeof(NVIDIA_SIGNATURE)-1) != 0) + return -1; + + volume_id_set_usage(id, VOLUME_ID_RAID); + sprintf(id->type_version, "%u", le16_to_cpu(nv->version)); + id->type = "nvidia_raid_member"; + + return 0; +} === added file 'libvolume_id/ocfs.c' --- grub-0.97.orig/libvolume_id/ocfs.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/ocfs.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,186 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Andre Masella + * Copyright (C) 2005 Kay Sievers + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +struct ocfs1_super_block_header { + uint32_t minor_version; + uint32_t major_version; + uint8_t signature[128]; + uint8_t mount_point[128]; + uint64_t serial_num; + uint64_t device_size; + uint64_t start_off; + uint64_t bitmap_off; + uint64_t publ_off; + uint64_t vote_off; + uint64_t root_bitmap_off; + uint64_t data_start_off; + uint64_t root_bitmap_size; + uint64_t root_off; + uint64_t root_size; + uint64_t cluster_size; + uint64_t num_nodes; + uint64_t num_clusters; + uint64_t dir_node_size; + uint64_t file_node_size; + uint64_t internal_off; + uint64_t node_cfg_off; + uint64_t node_cfg_size; + uint64_t new_cfg_off; + uint32_t prot_bits; + int32_t excl_mount; +} PACKED; + +struct ocfs1_super_block_label { + struct ocfs1_disk_lock { + uint32_t curr_master; + uint8_t file_lock; + uint8_t compat_pad[3]; + uint64_t last_write_time; + uint64_t last_read_time; + uint32_t writer_node_num; + uint32_t reader_node_num; + uint64_t oin_node_map; + uint64_t dlock_seq_num; + } PACKED disk_lock; + uint8_t label[64]; + uint16_t label_len; + uint8_t vol_id[16]; + uint16_t vol_id_len; + uint8_t cluster_name[64]; + uint16_t cluster_name_len; +} PACKED; + +struct ocfs2_super_block { + uint8_t i_signature[8]; + uint32_t i_generation; + int16_t i_suballoc_slot; + uint16_t i_suballoc_bit; + uint32_t i_reserved0; + uint32_t i_clusters; + uint32_t i_uid; + uint32_t i_gid; + uint64_t i_size; + uint16_t i_mode; + uint16_t i_links_count; + uint32_t i_flags; + uint64_t i_atime; + uint64_t i_ctime; + uint64_t i_mtime; + uint64_t i_dtime; + uint64_t i_blkno; + uint64_t i_last_eb_blk; + uint32_t i_fs_generation; + uint32_t i_atime_nsec; + uint32_t i_ctime_nsec; + uint32_t i_mtime_nsec; + uint64_t i_reserved1[9]; + uint64_t i_pad1; + uint16_t s_major_rev_level; + uint16_t s_minor_rev_level; + uint16_t s_mnt_count; + int16_t s_max_mnt_count; + uint16_t s_state; + uint16_t s_errors; + uint32_t s_checkinterval; + uint64_t s_lastcheck; + uint32_t s_creator_os; + uint32_t s_feature_compat; + uint32_t s_feature_incompat; + uint32_t s_feature_ro_compat; + uint64_t s_root_blkno; + uint64_t s_system_dir_blkno; + uint32_t s_blocksize_bits; + uint32_t s_clustersize_bits; + uint16_t s_max_slots; + uint16_t s_reserved1; + uint32_t s_reserved2; + uint64_t s_first_cluster_group; + uint8_t s_label[64]; + uint8_t s_uuid[16]; +} PACKED; + +int volume_id_probe_ocfs1(struct volume_id *id, uint64_t off, uint64_t size) +{ + const uint8_t *buf; + struct ocfs1_super_block_header *osh; + struct ocfs1_super_block_label *osl; + + info("probing at offset 0x%llx", (unsigned long long) off); + + buf = volume_id_get_buffer(id, off, 0x200); + if (buf == NULL) + return -1; + + osh = (struct ocfs1_super_block_header *) buf; + if (memcmp((char *)osh->signature, "OracleCFS", 9) != 0) + return -1; + sprintf(id->type_version, "%u.%u", osh->major_version, osh->minor_version); + + dbg("found OracleCFS signature, now reading label"); + buf = volume_id_get_buffer(id, off + 0x200, 0x200); + if (buf == NULL) + return -1; + + osl = (struct ocfs1_super_block_label *) buf; + volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); + if (osl->label_len <= 64) { + volume_id_set_label_raw(id, osl->label, 64); + volume_id_set_label_string(id, osl->label, 64); + } + if (osl->vol_id_len == 16) + volume_id_set_uuid(id, osl->vol_id, 0, UUID_DCE); + id->type = "ocfs"; + return 0; +} + +#define OCFS2_MAX_BLOCKSIZE 0x1000 +#define OCFS2_SUPER_BLOCK_BLKNO 2 + +int volume_id_probe_ocfs2(struct volume_id *id, uint64_t off, uint64_t size) +{ + const uint8_t *buf; + struct ocfs2_super_block *os; + size_t blksize; + + info("probing at offset 0x%llx", (unsigned long long) off); + + for (blksize = 0x200; blksize <= OCFS2_MAX_BLOCKSIZE; blksize <<= 1) { + buf = volume_id_get_buffer(id, off + OCFS2_SUPER_BLOCK_BLKNO * blksize, 0x200); + if (buf == NULL) + return -1; + + os = (struct ocfs2_super_block *) buf; + if (memcmp((char *)os->i_signature, "OCFSV2", 6) != 0) + continue; + + volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); + volume_id_set_label_raw(id, os->s_label, 64); + volume_id_set_label_string(id, os->s_label, 64); + volume_id_set_uuid(id, os->s_uuid, 0, UUID_DCE); + sprintf(id->type_version, "%u.%u", os->s_major_rev_level, os->s_minor_rev_level); + id->type = "ocfs2"; + return 0; + } + return -1; +} === added file 'libvolume_id/promise_raid.c' --- grub-0.97.orig/libvolume_id/promise_raid.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/promise_raid.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,65 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2005 Kay Sievers + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +struct promise_meta { + uint8_t sig[24]; +} PACKED; + +#define PDC_CONFIG_OFF 0x1200 +#define PDC_SIGNATURE "Promise Technology, Inc." + +int volume_id_probe_promise_fasttrack_raid(struct volume_id *id, uint64_t off, uint64_t size) +{ + const uint8_t *buf; + struct promise_meta *pdc; + unsigned int i; + static unsigned int sectors[] = { + 63, 255, 256, 16, 399, 0 + }; + + info("probing at offset 0x%llx, size 0x%llx", + (unsigned long long) off, (unsigned long long) size); + + if (size < 0x40000) + return -1; + + for (i = 0; sectors[i] != 0; i++) { + uint64_t meta_off; + + meta_off = ((size / 0x200) - sectors[i]) * 0x200; + buf = volume_id_get_buffer(id, off + meta_off, 0x200); + if (buf == NULL) + return -1; + + pdc = (struct promise_meta *) buf; + if (memcmp((char *)pdc->sig, PDC_SIGNATURE, sizeof(PDC_SIGNATURE)-1) == 0) + goto found; + } + return -1; + +found: + volume_id_set_usage(id, VOLUME_ID_RAID); + id->type = "promise_fasttrack_raid_member"; + + return 0; +} === added file 'libvolume_id/reiserfs.c' --- grub-0.97.orig/libvolume_id/reiserfs.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/reiserfs.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,113 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * Copyright (C) 2005 Tobias Klauser + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +struct reiserfs_super_block { + uint32_t blocks_count; + uint32_t free_blocks; + uint32_t root_block; + uint32_t journal_block; + uint32_t journal_dev; + uint32_t orig_journal_size; + uint32_t dummy2[5]; + uint16_t blocksize; + uint16_t dummy3[3]; + uint8_t magic[12]; + uint32_t dummy4[5]; + uint8_t uuid[16]; + uint8_t label[16]; +} PACKED; + +struct reiser4_super_block { + uint8_t magic[16]; + uint16_t dummy[2]; + uint8_t uuid[16]; + uint8_t label[16]; + uint64_t dummy2; +} PACKED; + +#define REISERFS1_SUPERBLOCK_OFFSET 0x2000 +#define REISERFS_SUPERBLOCK_OFFSET 0x10000 + +int volume_id_probe_reiserfs(struct volume_id *id, uint64_t off, uint64_t size) +{ + struct reiserfs_super_block *rs; + struct reiser4_super_block *rs4; + uint8_t *buf; + + info("probing at offset 0x%llx", (unsigned long long) off); + + buf = volume_id_get_buffer(id, off + REISERFS_SUPERBLOCK_OFFSET, 0x200); + if (buf == NULL) + return -1; + + rs = (struct reiserfs_super_block *) buf; + if (memcmp((char *)rs->magic, "ReIsErFs", 8) == 0) { + strcpy(id->type_version, "3.5"); + id->type = "reiserfs"; + goto found; + } + if (memcmp((char *)rs->magic, "ReIsEr2Fs", 9) == 0) { + strcpy(id->type_version, "3.6"); + id->type = "reiserfs"; + goto found_label; + } + if (memcmp((char *)rs->magic, "ReIsEr3Fs", 9) == 0) { + strcpy(id->type_version, "JR"); + id->type = "reiserfs"; + goto found_label; + } + + rs4 = (struct reiser4_super_block *) buf; + if (memcmp((char *)rs4->magic, "ReIsEr4", 7) == 0) { + strcpy(id->type_version, "4"); + volume_id_set_label_raw(id, rs4->label, 16); + volume_id_set_label_string(id, rs4->label, 16); + volume_id_set_uuid(id, rs4->uuid, 0, UUID_DCE); + id->type = "reiser4"; + goto found; + } + + buf = volume_id_get_buffer(id, off + REISERFS1_SUPERBLOCK_OFFSET, 0x200); + if (buf == NULL) + return -1; + + rs = (struct reiserfs_super_block *) buf; + if (memcmp((char *)rs->magic, "ReIsErFs", 8) == 0) { + strcpy(id->type_version, "3.5"); + id->type = "reiserfs"; + goto found; + } + + return -1; + +found_label: + volume_id_set_label_raw(id, rs->label, 16); + volume_id_set_label_string(id, rs->label, 16); + volume_id_set_uuid(id, rs->uuid, 0, UUID_DCE); + +found: + volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); + + return 0; +} === added file 'libvolume_id/romfs.c' --- grub-0.97.orig/libvolume_id/romfs.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/romfs.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,55 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +struct romfs_super { + uint8_t magic[8]; + uint32_t size; + uint32_t checksum; + uint8_t name[0]; +} PACKED; + +int volume_id_probe_romfs(struct volume_id *id, uint64_t off, uint64_t size) +{ + struct romfs_super *rfs; + + info("probing at offset 0x%llx", (unsigned long long) off); + + rfs = (struct romfs_super *) volume_id_get_buffer(id, off, 0x200); + if (rfs == NULL) + return -1; + + if (memcmp((char *)rfs->magic, "-rom1fs-", 4) == 0) { + size_t len = strlen((char *)rfs->name); + + if (len) { + volume_id_set_label_raw(id, rfs->name, len); + volume_id_set_label_string(id, rfs->name, len); + } + + volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); + id->type = "romfs"; + return 0; + } + + return -1; +} === added file 'libvolume_id/silicon_raid.c' --- grub-0.97.orig/libvolume_id/silicon_raid.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/silicon_raid.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,71 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2005 Kay Sievers + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +struct silicon_meta { + uint8_t unknown0[0x2E]; + uint8_t ascii_version[0x36 - 0x2E]; + uint8_t diskname[0x56 - 0x36]; + uint8_t unknown1[0x60 - 0x56]; + uint32_t magic; + uint32_t unknown1a[0x6C - 0x64]; + uint32_t array_sectors_low; + uint32_t array_sectors_high; + uint8_t unknown2[0x78 - 0x74]; + uint32_t thisdisk_sectors; + uint8_t unknown3[0x100 - 0x7C]; + uint8_t unknown4[0x104 - 0x100]; + uint16_t product_id; + uint16_t vendor_id; + uint16_t minor_ver; + uint16_t major_ver; +} PACKED; + +#define SILICON_MAGIC 0x2F000000 + +int volume_id_probe_silicon_medley_raid(struct volume_id *id, uint64_t off, uint64_t size) +{ + const uint8_t *buf; + uint64_t meta_off; + struct silicon_meta *sil; + + info("probing at offset 0x%llx, size 0x%llx", + (unsigned long long) off, (unsigned long long) size); + + if (size < 0x10000) + return -1; + + meta_off = ((size / 0x200)-1) * 0x200; + buf = volume_id_get_buffer(id, off + meta_off, 0x200); + if (buf == NULL) + return -1; + + sil = (struct silicon_meta *) buf; + if (le32_to_cpu(sil->magic) != SILICON_MAGIC) + return -1; + + volume_id_set_usage(id, VOLUME_ID_RAID); + sprintf(id->type_version, "%u.%u", le16_to_cpu(sil->major_ver), le16_to_cpu(sil->minor_ver)); + id->type = "silicon_medley_raid_member"; + + return 0; +} === added file 'libvolume_id/squashfs.c' --- grub-0.97.orig/libvolume_id/squashfs.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/squashfs.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,63 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2006 Kay Sievers + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +#define SQUASHFS_MAGIC 0x73717368 + +struct squashfs_super { + uint32_t s_magic; + uint32_t inodes; + uint32_t bytes_used_2; + uint32_t uid_start_2; + uint32_t guid_start_2; + uint32_t inode_table_start_2; + uint32_t directory_table_start_2; + uint16_t s_major; + uint16_t s_minor; +} PACKED; + +int volume_id_probe_squashfs(struct volume_id *id, uint64_t off, uint64_t size) +{ + struct squashfs_super *sqs; + + info("probing at offset 0x%llx", (unsigned long long) off); + + sqs = (struct squashfs_super *) volume_id_get_buffer(id, off, 0x200); + if (sqs == NULL) + return -1; + + if (sqs->s_magic == SQUASHFS_MAGIC) { + sprintf(id->type_version, "%u.%u", sqs->s_major, sqs->s_minor); + goto found; + } + if (sqs->s_magic == bswap_32(SQUASHFS_MAGIC)) { + sprintf(id->type_version, "%u.%u", bswap_16(sqs->s_major), bswap_16(sqs->s_minor)); + goto found; + } + + return -1; + +found: + volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); + id->type = "squashfs"; + return 0; +} === added file 'libvolume_id/strfuncs.h' --- grub-0.97.orig/libvolume_id/strfuncs.h 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/strfuncs.h 2008-07-15 12:31:43 +0000 @@ -0,0 +1,5 @@ + +#include + +size_t strnlen(const char *s, size_t limit); +char *strchr (const char *s, int c); === added file 'libvolume_id/sysv.c' --- grub-0.97.orig/libvolume_id/sysv.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/sysv.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,128 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2005 Kay Sievers + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +#define SYSV_NICINOD 100 +#define SYSV_NICFREE 50 + +struct sysv_super +{ + uint16_t s_isize; + uint16_t s_pad0; + uint32_t s_fsize; + uint16_t s_nfree; + uint16_t s_pad1; + uint32_t s_free[SYSV_NICFREE]; + uint16_t s_ninode; + uint16_t s_pad2; + uint16_t s_inode[SYSV_NICINOD]; + uint8_t s_flock; + uint8_t s_ilock; + uint8_t s_fmod; + uint8_t s_ronly; + uint32_t s_time; + uint16_t s_dinfo[4]; + uint32_t s_tfree; + uint16_t s_tinode; + uint16_t s_pad3; + uint8_t s_fname[6]; + uint8_t s_fpack[6]; + uint32_t s_fill[12]; + uint32_t s_state; + uint32_t s_magic; + uint32_t s_type; +} PACKED; + +#define XENIX_NICINOD 100 +#define XENIX_NICFREE 100 + +struct xenix_super { + uint16_t s_isize; + uint32_t s_fsize; + uint16_t s_nfree; + uint32_t s_free[XENIX_NICFREE]; + uint16_t s_ninode; + uint16_t s_inode[XENIX_NICINOD]; + uint8_t s_flock; + uint8_t s_ilock; + uint8_t s_fmod; + uint8_t s_ronly; + uint32_t s_time; + uint32_t s_tfree; + uint16_t s_tinode; + uint16_t s_dinfo[4]; + uint8_t s_fname[6]; + uint8_t s_fpack[6]; + uint8_t s_clean; + uint8_t s_fill[371]; + uint32_t s_magic; + uint32_t s_type; +} PACKED; + +#define SYSV_SUPERBLOCK_BLOCK 0x01 +#define SYSV_MAGIC 0xfd187e20 +#define XENIX_SUPERBLOCK_BLOCK 0x18 +#define XENIX_MAGIC 0x2b5544 +#define SYSV_MAX_BLOCKSIZE 0x800 + +int volume_id_probe_sysv(struct volume_id *id, uint64_t off, uint64_t size) +{ + struct sysv_super *vs; + struct xenix_super *xs; + unsigned int boff; + + info("probing at offset 0x%llx", (unsigned long long) off); + + for (boff = 0x200; boff <= SYSV_MAX_BLOCKSIZE; boff <<= 1) { + vs = (struct sysv_super *) + volume_id_get_buffer(id, off + (boff * SYSV_SUPERBLOCK_BLOCK), 0x200); + if (vs == NULL) + return -1; + + if (vs->s_magic == cpu_to_le32(SYSV_MAGIC) || vs->s_magic == cpu_to_be32(SYSV_MAGIC)) { + volume_id_set_label_raw(id, vs->s_fname, 6); + volume_id_set_label_string(id, vs->s_fname, 6); + id->type = "sysv"; + goto found; + } + } + + for (boff = 0x200; boff <= SYSV_MAX_BLOCKSIZE; boff <<= 1) { + xs = (struct xenix_super *) + volume_id_get_buffer(id, off + (boff + XENIX_SUPERBLOCK_BLOCK), 0x200); + if (xs == NULL) + return -1; + + if (xs->s_magic == cpu_to_le32(XENIX_MAGIC) || xs->s_magic == cpu_to_be32(XENIX_MAGIC)) { + volume_id_set_label_raw(id, xs->s_fname, 6); + volume_id_set_label_string(id, xs->s_fname, 6); + id->type = "xenix"; + goto found; + } + } + + return -1; + +found: + volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); + return 0; +} === added file 'libvolume_id/udf.c' --- grub-0.97.orig/libvolume_id/udf.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/udf.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,173 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +struct volume_descriptor { + struct descriptor_tag { + uint16_t id; + uint16_t version; + uint8_t checksum; + uint8_t reserved; + uint16_t serial; + uint16_t crc; + uint16_t crc_len; + uint32_t location; + } PACKED tag; + union { + struct anchor_descriptor { + uint32_t length; + uint32_t location; + } PACKED anchor; + struct primary_descriptor { + uint32_t seq_num; + uint32_t desc_num; + struct dstring { + uint8_t clen; + uint8_t c[31]; + } PACKED ident; + } PACKED primary; + } PACKED type; +} PACKED; + +struct volume_structure_descriptor { + uint8_t type; + uint8_t id[5]; + uint8_t version; +} PACKED; + +#define UDF_VSD_OFFSET 0x8000 + +int volume_id_probe_udf(struct volume_id *id, uint64_t off, uint64_t size) +{ + struct volume_descriptor *vd; + struct volume_structure_descriptor *vsd; + unsigned int bs; + unsigned int b; + unsigned int type; + unsigned int count; + unsigned int loc; + unsigned int clen; + + info("probing at offset 0x%llx", (unsigned long long) off); + + vsd = (struct volume_structure_descriptor *) volume_id_get_buffer(id, off + UDF_VSD_OFFSET, 0x200); + if (vsd == NULL) + return -1; + + if (memcmp((char *)vsd->id, "NSR02", 5) == 0) + goto blocksize; + if (memcmp((char *)vsd->id, "NSR03", 5) == 0) + goto blocksize; + if (memcmp((char *)vsd->id, "BEA01", 5) == 0) + goto blocksize; + if (memcmp((char *)vsd->id, "BOOT2", 5) == 0) + goto blocksize; + if (memcmp((char *)vsd->id, "CD001", 5) == 0) + goto blocksize; + if (memcmp((char *)vsd->id, "CDW02", 5) == 0) + goto blocksize; + if (memcmp((char *)vsd->id, "TEA03", 5) == 0) + goto blocksize; + return -1; + +blocksize: + /* search the next VSD to get the logical block size of the volume */ + for (bs = 0x800; bs < 0x8000; bs += 0x800) { + vsd = (struct volume_structure_descriptor *) volume_id_get_buffer(id, off + UDF_VSD_OFFSET + bs, 0x800); + if (vsd == NULL) + return -1; + dbg("test for blocksize: 0x%x", bs); + if (vsd->id[0] != '\0') + goto nsr; + } + return -1; + +nsr: + /* search the list of VSDs for a NSR descriptor */ + for (b = 0; b < 64; b++) { + vsd = (struct volume_structure_descriptor *) volume_id_get_buffer(id, off + UDF_VSD_OFFSET + (b * bs), 0x800); + if (vsd == NULL) + return -1; + + dbg("vsd: %c%c%c%c%c", + vsd->id[0], vsd->id[1], vsd->id[2], vsd->id[3], vsd->id[4]); + + if (vsd->id[0] == '\0') + return -1; + if (memcmp((char *)vsd->id, "NSR02", 5) == 0) + goto anchor; + if (memcmp((char *)vsd->id, "NSR03", 5) == 0) + goto anchor; + } + return -1; + +anchor: + /* read anchor volume descriptor */ + vd = (struct volume_descriptor *) volume_id_get_buffer(id, off + (256 * bs), 0x200); + if (vd == NULL) + return -1; + + type = le16_to_cpu(vd->tag.id); + if (type != 2) /* TAG_ID_AVDP */ + goto found; + + /* get desriptor list address and block count */ + count = le32_to_cpu(vd->type.anchor.length) / bs; + loc = le32_to_cpu(vd->type.anchor.location); + dbg("0x%x descriptors starting at logical secor 0x%x", count, loc); + + /* pick the primary descriptor from the list */ + for (b = 0; b < count; b++) { + vd = (struct volume_descriptor *) volume_id_get_buffer(id, off + ((loc + b) * bs), 0x200); + if (vd == NULL) + return -1; + + type = le16_to_cpu(vd->tag.id); + dbg("descriptor type %i", type); + + /* check validity */ + if (type == 0) + goto found; + if (le32_to_cpu(vd->tag.location) != loc + b) + goto found; + + if (type == 1) /* TAG_ID_PVD */ + goto pvd; + } + goto found; + +pvd: + volume_id_set_label_raw(id, &(vd->type.primary.ident.clen), 32); + + clen = vd->type.primary.ident.clen; + dbg("label string charsize=%i bit", clen); + if (clen == 8) + volume_id_set_label_string(id, vd->type.primary.ident.c, 31); + else if (clen == 16) + volume_id_set_label_unicode16(id, vd->type.primary.ident.c, BE,31); + +found: + volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); + id->type = "udf"; + + return 0; +} === added file 'libvolume_id/ufs.c' --- grub-0.97.orig/libvolume_id/ufs.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/ufs.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,217 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +struct ufs_super_block { + uint32_t fs_link; + uint32_t fs_rlink; + uint32_t fs_sblkno; + uint32_t fs_cblkno; + uint32_t fs_iblkno; + uint32_t fs_dblkno; + uint32_t fs_cgoffset; + uint32_t fs_cgmask; + uint32_t fs_time; + uint32_t fs_size; + uint32_t fs_dsize; + uint32_t fs_ncg; + uint32_t fs_bsize; + uint32_t fs_fsize; + uint32_t fs_frag; + uint32_t fs_minfree; + uint32_t fs_rotdelay; + uint32_t fs_rps; + uint32_t fs_bmask; + uint32_t fs_fmask; + uint32_t fs_bshift; + uint32_t fs_fshift; + uint32_t fs_maxcontig; + uint32_t fs_maxbpg; + uint32_t fs_fragshift; + uint32_t fs_fsbtodb; + uint32_t fs_sbsize; + uint32_t fs_csmask; + uint32_t fs_csshift; + uint32_t fs_nindir; + uint32_t fs_inopb; + uint32_t fs_nspf; + uint32_t fs_optim; + uint32_t fs_npsect_state; + uint32_t fs_interleave; + uint32_t fs_trackskew; + uint32_t fs_id[2]; + uint32_t fs_csaddr; + uint32_t fs_cssize; + uint32_t fs_cgsize; + uint32_t fs_ntrak; + uint32_t fs_nsect; + uint32_t fs_spc; + uint32_t fs_ncyl; + uint32_t fs_cpg; + uint32_t fs_ipg; + uint32_t fs_fpg; + struct ufs_csum { + uint32_t cs_ndir; + uint32_t cs_nbfree; + uint32_t cs_nifree; + uint32_t cs_nffree; + } PACKED fs_cstotal; + int8_t fs_fmod; + int8_t fs_clean; + int8_t fs_ronly; + int8_t fs_flags; + union { + struct { + int8_t fs_fsmnt[512]; + uint32_t fs_cgrotor; + uint32_t fs_csp[31]; + uint32_t fs_maxcluster; + uint32_t fs_cpc; + uint16_t fs_opostbl[16][8]; + } PACKED fs_u1; + struct { + int8_t fs_fsmnt[468]; + uint8_t fs_volname[32]; + uint64_t fs_swuid; + int32_t fs_pad; + uint32_t fs_cgrotor; + uint32_t fs_ocsp[28]; + uint32_t fs_contigdirs; + uint32_t fs_csp; + uint32_t fs_maxcluster; + uint32_t fs_active; + int32_t fs_old_cpc; + int32_t fs_maxbsize; + int64_t fs_sparecon64[17]; + int64_t fs_sblockloc; + struct ufs2_csum_total { + uint64_t cs_ndir; + uint64_t cs_nbfree; + uint64_t cs_nifree; + uint64_t cs_nffree; + uint64_t cs_numclusters; + uint64_t cs_spare[3]; + } PACKED fs_cstotal; + struct ufs_timeval { + int32_t tv_sec; + int32_t tv_usec; + } PACKED fs_time; + int64_t fs_size; + int64_t fs_dsize; + uint64_t fs_csaddr; + int64_t fs_pendingblocks; + int32_t fs_pendinginodes; + } PACKED fs_u2; + } fs_u11; + union { + struct { + int32_t fs_sparecon[53]; + int32_t fs_reclaim; + int32_t fs_sparecon2[1]; + int32_t fs_state; + uint32_t fs_qbmask[2]; + uint32_t fs_qfmask[2]; + } PACKED fs_sun; + struct { + int32_t fs_sparecon[53]; + int32_t fs_reclaim; + int32_t fs_sparecon2[1]; + uint32_t fs_npsect; + uint32_t fs_qbmask[2]; + uint32_t fs_qfmask[2]; + } PACKED fs_sunx86; + struct { + int32_t fs_sparecon[50]; + int32_t fs_contigsumsize; + int32_t fs_maxsymlinklen; + int32_t fs_inodefmt; + uint32_t fs_maxfilesize[2]; + uint32_t fs_qbmask[2]; + uint32_t fs_qfmask[2]; + int32_t fs_state; + } PACKED fs_44; + } fs_u2; + int32_t fs_postblformat; + int32_t fs_nrpos; + int32_t fs_postbloff; + int32_t fs_rotbloff; + uint32_t fs_magic; + uint8_t fs_space[1]; +} PACKED; + +#define UFS_MAGIC 0x00011954 +#define UFS2_MAGIC 0x19540119 +#define UFS_MAGIC_FEA 0x00195612 +#define UFS_MAGIC_LFN 0x00095014 + +int volume_id_probe_ufs(struct volume_id *id, uint64_t off, uint64_t size) +{ + uint32_t magic; + int i; + struct ufs_super_block *ufs; + int offsets[] = {0, 8, 64, 256, -1}; + + info("probing at offset 0x%llx", (unsigned long long) off); + + for (i = 0; offsets[i] >= 0; i++) { + ufs = (struct ufs_super_block *) volume_id_get_buffer(id, off + (offsets[i] * 0x400), 0x800); + if (ufs == NULL) + return -1; + + dbg("offset 0x%x", offsets[i] * 0x400); + magic = be32_to_cpu(ufs->fs_magic); + if ((magic == UFS_MAGIC) || + (magic == UFS2_MAGIC) || + (magic == UFS_MAGIC_FEA) || + (magic == UFS_MAGIC_LFN)) { + dbg("magic 0x%08x(be)", magic); + goto found; + } + magic = le32_to_cpu(ufs->fs_magic); + if ((magic == UFS_MAGIC) || + (magic == UFS2_MAGIC) || + (magic == UFS_MAGIC_FEA) || + (magic == UFS_MAGIC_LFN)) { + dbg("magic 0x%08x(le)", magic); + goto found; + } + } + return -1; + +found: + volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); + id->type = "ufs"; + switch (magic) { + case UFS_MAGIC: + strcpy(id->type_version, "1"); + break; + case UFS2_MAGIC: + strcpy(id->type_version, "2"); + volume_id_set_label_raw(id, ufs->fs_u11.fs_u2.fs_volname, 32); + volume_id_set_label_string(id, ufs->fs_u11.fs_u2.fs_volname, 32); + break; + default: + break; + } + + return 0; +} === added file 'libvolume_id/util.c' --- grub-0.97.orig/libvolume_id/util.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/util.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,472 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2005-2007 Kay Sievers + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "strfuncs.h" +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +static char hex[] = "0123456789abcdef"; + +#define hexhi(val) hex[val >> 4] +#define hexlo(val) hex[val & 0xf] + +/* count of characters used to encode one unicode char */ +static int utf8_encoded_expected_len(const char *str) +{ + unsigned char c = (unsigned char)str[0]; + + if (c < 0x80) + return 1; + if ((c & 0xe0) == 0xc0) + return 2; + if ((c & 0xf0) == 0xe0) + return 3; + if ((c & 0xf8) == 0xf0) + return 4; + if ((c & 0xfc) == 0xf8) + return 5; + if ((c & 0xfe) == 0xfc) + return 6; + return 0; +} + +/* decode one unicode char */ +static int utf8_encoded_to_unichar(const char *str) +{ + int unichar; + int len; + int i; + + len = utf8_encoded_expected_len(str); + switch (len) { + case 1: + return (int)str[0]; + case 2: + unichar = str[0] & 0x1f; + break; + case 3: + unichar = (int)str[0] & 0x0f; + break; + case 4: + unichar = (int)str[0] & 0x07; + break; + case 5: + unichar = (int)str[0] & 0x03; + break; + case 6: + unichar = (int)str[0] & 0x01; + break; + default: + return -1; + } + + for (i = 1; i < len; i++) { + if (((int)str[i] & 0xc0) != 0x80) + return -1; + unichar <<= 6; + unichar |= (int)str[i] & 0x3f; + } + + return unichar; +} + +/* expected size used to encode one unicode char */ +static int utf8_unichar_to_encoded_len(int unichar) +{ + if (unichar < 0x80) + return 1; + if (unichar < 0x800) + return 2; + if (unichar < 0x10000) + return 3; + if (unichar < 0x200000) + return 4; + if (unichar < 0x4000000) + return 5; + return 6; +} + +/* check if unicode char has a valid numeric range */ +static int utf8_unichar_valid_range(int unichar) +{ + if (unichar > 0x10ffff) + return 0; + if ((unichar & 0xfffff800) == 0xd800) + return 0; + if ((unichar > 0xfdcf) && (unichar < 0xfdf0)) + return 0; + if ((unichar & 0xffff) == 0xffff) + return 0; + return 1; +} + +/* validate one encoded unicode char and return its length */ +int volume_id_utf8_encoded_valid_unichar(const char *str) +{ + int len; + int unichar; + int i; + + len = utf8_encoded_expected_len(str); + if (len == 0) + return -1; + + /* ascii is valid */ + if (len == 1) + return 1; + + /* check if expected encoded chars are available */ + for (i = 0; i < len; i++) + if ((str[i] & 0x80) != 0x80) + return -1; + + unichar = utf8_encoded_to_unichar(str); + + /* check if encoded length matches encoded value */ + if (utf8_unichar_to_encoded_len(unichar) != len) + return -1; + + /* check if value has valid range */ + if (!utf8_unichar_valid_range(unichar)) + return -1; + + return len; +} + +size_t volume_id_set_unicode16(uint8_t *str, size_t len, const uint8_t *buf, enum endian endianess, size_t count) +{ + size_t i, j; + uint16_t c; + + j = 0; + for (i = 0; i + 2 <= count; i += 2) { + if (endianess == LE) + c = (buf[i+1] << 8) | buf[i]; + else + c = (buf[i] << 8) | buf[i+1]; + if (c == 0) { + str[j] = '\0'; + break; + } else if (c < 0x80) { + if (j+1 >= len) + break; + str[j++] = (uint8_t) c; + } else if (c < 0x800) { + if (j+2 >= len) + break; + str[j++] = (uint8_t) (0xc0 | (c >> 6)); + str[j++] = (uint8_t) (0x80 | (c & 0x3f)); + } else { + if (j+3 >= len) + break; + str[j++] = (uint8_t) (0xe0 | (c >> 12)); + str[j++] = (uint8_t) (0x80 | ((c >> 6) & 0x3f)); + str[j++] = (uint8_t) (0x80 | (c & 0x3f)); + } + } + str[j] = '\0'; + return j; +} + +static char *usage_to_string(enum volume_id_usage usage_id) +{ + switch (usage_id) { + case VOLUME_ID_FILESYSTEM: + return "filesystem"; + case VOLUME_ID_OTHER: + return "other"; + case VOLUME_ID_RAID: + return "raid"; + case VOLUME_ID_DISKLABEL: + return "disklabel"; + case VOLUME_ID_CRYPTO: + return "crypto"; + case VOLUME_ID_UNPROBED: + return "unprobed"; + case VOLUME_ID_UNUSED: + return "unused"; + } + return NULL; +} + +void volume_id_set_usage(struct volume_id *id, enum volume_id_usage usage_id) +{ + id->usage_id = usage_id; + id->usage = usage_to_string(usage_id); +} + +void volume_id_set_label_raw(struct volume_id *id, const uint8_t *buf, size_t count) +{ + if (count > sizeof(id->label)) + count = sizeof(id->label); + + memcpy(id->label_raw, buf, count); + id->label_raw_len = count; +} + +void volume_id_set_label_string(struct volume_id *id, const uint8_t *buf, size_t count) +{ + size_t i; + + if (count >= sizeof(id->label)) + count = sizeof(id->label)-1; + + memcpy(id->label, buf, count); + id->label[count] = '\0'; + + /* remove trailing whitespace */ + i = strnlen(id->label, count); + while (i--) { + if (!isspace(id->label[i])) + break; + } + id->label[i+1] = '\0'; +} + +void volume_id_set_label_unicode16(struct volume_id *id, const uint8_t *buf, enum endian endianess, size_t count) +{ + if (count >= sizeof(id->label)) + count = sizeof(id->label)-1; + + volume_id_set_unicode16((uint8_t *)id->label, sizeof(id->label), buf, endianess, count); +} + +void volume_id_set_uuid(struct volume_id *id, const uint8_t *buf, size_t len, enum uuid_format format) +{ + unsigned int i; + unsigned int count = 0; + char *uuid; + + if (len > sizeof(id->uuid_raw)) + len = sizeof(id->uuid_raw); + + switch(format) { + case UUID_STRING: + count = len; + break; + case UUID_HEX_STRING: + count = len; + break; + case UUID_DOS: + count = 4; + break; + case UUID_64BIT_LE: + case UUID_64BIT_BE: + count = 8; + break; + case UUID_DCE: + count = 16; + break; + case UUID_FOURINT: + count = 35; + break; + } + memcpy(id->uuid_raw, buf, count); + id->uuid_raw_len = count; + + /* if set, create string in the same format, the native platform uses */ + for (i = 0; i < count; i++) + if (buf[i] != 0) + goto set; + return; + +set: + uuid = id->uuid; + switch(format) { + case UUID_DOS: + *uuid++ = hexhi(buf[3]); + *uuid++ = hexlo(buf[3]); + *uuid++ = hexhi(buf[2]); + *uuid++ = hexlo(buf[2]); + *uuid++ = '-'; + *uuid++ = hexhi(buf[1]); + *uuid++ = hexlo(buf[1]); + *uuid++ = hexhi(buf[0]); + *uuid++ = hexlo(buf[0]); + *uuid = '\0'; + break; + case UUID_64BIT_LE: + *uuid++ = hexhi(buf[7]); + *uuid++ = hexlo(buf[7]); + *uuid++ = hexhi(buf[6]); + *uuid++ = hexlo(buf[6]); + *uuid++ = hexhi(buf[5]); + *uuid++ = hexlo(buf[5]); + *uuid++ = hexhi(buf[4]); + *uuid++ = hexlo(buf[4]); + *uuid++ = hexhi(buf[3]); + *uuid++ = hexlo(buf[3]); + *uuid++ = hexhi(buf[2]); + *uuid++ = hexlo(buf[2]); + *uuid++ = hexhi(buf[1]); + *uuid++ = hexlo(buf[1]); + *uuid++ = hexhi(buf[0]); + *uuid++ = hexlo(buf[0]); + *uuid = '\0'; + break; + case UUID_64BIT_BE: + *uuid++ = hexhi(buf[0]); + *uuid++ = hexlo(buf[0]); + *uuid++ = hexhi(buf[1]); + *uuid++ = hexlo(buf[1]); + *uuid++ = hexhi(buf[2]); + *uuid++ = hexlo(buf[2]); + *uuid++ = hexhi(buf[3]); + *uuid++ = hexlo(buf[3]); + *uuid++ = hexhi(buf[4]); + *uuid++ = hexlo(buf[4]); + *uuid++ = hexhi(buf[5]); + *uuid++ = hexlo(buf[5]); + *uuid++ = hexhi(buf[6]); + *uuid++ = hexlo(buf[6]); + *uuid++ = hexhi(buf[7]); + *uuid++ = hexlo(buf[7]); + *uuid = '\0'; + break; + case UUID_DCE: + *uuid++ = hexhi(buf[0]); + *uuid++ = hexlo(buf[0]); + *uuid++ = hexhi(buf[1]); + *uuid++ = hexlo(buf[1]); + *uuid++ = hexhi(buf[2]); + *uuid++ = hexlo(buf[2]); + *uuid++ = hexhi(buf[3]); + *uuid++ = hexlo(buf[3]); + *uuid++ = '-'; + *uuid++ = hexhi(buf[4]); + *uuid++ = hexlo(buf[4]); + *uuid++ = hexhi(buf[5]); + *uuid++ = hexlo(buf[5]); + *uuid++ = '-'; + *uuid++ = hexhi(buf[6]); + *uuid++ = hexlo(buf[6]); + *uuid++ = hexhi(buf[7]); + *uuid++ = hexlo(buf[7]); + *uuid++ = '-'; + *uuid++ = hexhi(buf[8]); + *uuid++ = hexlo(buf[8]); + *uuid++ = hexhi(buf[9]); + *uuid++ = hexlo(buf[9]); + *uuid++ = '-'; + *uuid++ = hexhi(buf[10]); + *uuid++ = hexlo(buf[10]); + *uuid++ = hexhi(buf[11]); + *uuid++ = hexlo(buf[11]); + *uuid++ = hexhi(buf[12]); + *uuid++ = hexlo(buf[12]); + *uuid++ = hexhi(buf[13]); + *uuid++ = hexlo(buf[13]); + *uuid++ = hexhi(buf[14]); + *uuid++ = hexlo(buf[14]); + *uuid++ = hexhi(buf[15]); + *uuid++ = hexlo(buf[15]); + *uuid = '\0'; + break; + case UUID_HEX_STRING: + /* translate A..F to a..f */ + memcpy(id->uuid, buf, count); + for (i = 0; i < count; i++) + if (id->uuid[i] >= 'A' && id->uuid[i] <= 'F') + id->uuid[i] = (id->uuid[i] - 'A') + 'a'; + id->uuid[count] = '\0'; + break; + case UUID_STRING: + memcpy(id->uuid, buf, count); + id->uuid[count] = '\0'; + break; + case UUID_FOURINT: + *uuid++ = hexhi(buf[0]); + *uuid++ = hexlo(buf[0]); + *uuid++ = hexhi(buf[1]); + *uuid++ = hexlo(buf[1]); + *uuid++ = hexhi(buf[2]); + *uuid++ = hexlo(buf[2]); + *uuid++ = hexhi(buf[3]); + *uuid++ = hexlo(buf[3]); + *uuid++ = ':'; + *uuid++ = hexhi(buf[4]); + *uuid++ = hexlo(buf[4]); + *uuid++ = hexhi(buf[5]); + *uuid++ = hexlo(buf[5]); + *uuid++ = hexhi(buf[6]); + *uuid++ = hexlo(buf[6]); + *uuid++ = hexhi(buf[7]); + *uuid++ = hexlo(buf[7]); + *uuid++ = ':'; + *uuid++ = hexhi(buf[8]); + *uuid++ = hexlo(buf[8]); + *uuid++ = hexhi(buf[9]); + *uuid++ = hexlo(buf[9]); + *uuid++ = hexhi(buf[10]); + *uuid++ = hexlo(buf[10]); + *uuid++ = hexhi(buf[11]); + *uuid++ = hexlo(buf[11]); + *uuid++ = ':'; + *uuid++ = hexhi(buf[12]); + *uuid++ = hexlo(buf[12]); + *uuid++ = hexhi(buf[13]); + *uuid++ = hexlo(buf[13]); + *uuid++ = hexhi(buf[14]); + *uuid++ = hexlo(buf[14]); + *uuid++ = hexhi(buf[15]); + *uuid++ = hexlo(buf[15]); + *uuid = '\0'; + break; + default: + *uuid = '\0'; + break; + } +} + +uint8_t *volume_id_get_buffer(struct volume_id *id, uint64_t off, size_t len) +{ + info("get buffer off 0x%llx(%llu), len 0x%zx", (unsigned long long) off, (unsigned long long) off, len); + /* check if requested area fits in superblock buffer */ + if (off + len <= SB_BUFFER_SIZE) { + /* check if we need to read */ + if ((off + len) > id->sbbuf_len) { + if (devread (0, 0, off + len, (char*)id->sbbuf) == 0) + { + return NULL; + } + id->sbbuf_len = off + len; + } + return &(id->sbbuf[off]); + } else { + if (len > SEEK_BUFFER_SIZE) { + dbg("seek buffer too small %d", SEEK_BUFFER_SIZE); + return NULL; + } + + /* check if we need to read */ + if ((off < id->seekbuf_off) || ((off + len) > (id->seekbuf_off + id->seekbuf_len))) { + info("read seekbuf off:0x%llx len:0x%zx", (unsigned long long) off, len); + if (devread(off >> 9, off & 0x1ff, len, (char*)id->seekbuf) == 0) + { + return NULL; + } + id->seekbuf_off = off; + id->seekbuf_len = len; + } + return &(id->seekbuf[off - id->seekbuf_off]); + } +} === added file 'libvolume_id/util.h' --- grub-0.97.orig/libvolume_id/util.h 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/util.h 2008-07-15 12:31:43 +0000 @@ -0,0 +1,98 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2005-2006 Kay Sievers + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _VOLUME_ID_UTIL_ +#define _VOLUME_ID_UTIL_ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#define ALLOWED_CHARS "#+-.:=@_" + +#ifndef PACKED +#define PACKED __attribute__((packed)) +#endif + +#define err(format, arg...) volume_id_log_fn(LOG_ERR, __FILE__, __LINE__, format, ##arg) +#ifdef INFO +#define info(format, arg...) volume_id_log_fn(LOG_INFO, __FILE__, __LINE__, format, ##arg) +#else +#define info(format, arg...) do { } while (0) +#endif + +#ifdef DEBUG +#define dbg(format, arg...) volume_id_log_fn(LOG_DEBUG, __FILE__, __LINE__, format, ##arg) +#else +#define dbg(format, arg...) do { } while (0) +#endif + +/* size of superblock buffer, reiserfs block is at 64k */ +#define SB_BUFFER_SIZE 0x11000 +/* size of seek buffer, FAT cluster is 32k max */ +#define SEEK_BUFFER_SIZE 0x10000 + +#ifdef __BYTE_ORDER +#if (__BYTE_ORDER == __LITTLE_ENDIAN) +#define le16_to_cpu(x) (x) +#define le32_to_cpu(x) (x) +#define le64_to_cpu(x) (x) +#define be16_to_cpu(x) bswap_16(x) +#define be32_to_cpu(x) bswap_32(x) +#define cpu_to_le16(x) (x) +#define cpu_to_le32(x) (x) +#define cpu_to_be32(x) bswap_32(x) +#elif (__BYTE_ORDER == __BIG_ENDIAN) +#define le16_to_cpu(x) bswap_16(x) +#define le32_to_cpu(x) bswap_32(x) +#define le64_to_cpu(x) bswap_64(x) +#define be16_to_cpu(x) (x) +#define be32_to_cpu(x) (x) +#define cpu_to_le16(x) bswap_16(x) +#define cpu_to_le32(x) bswap_32(x) +#define cpu_to_be32(x) (x) +#endif +#endif /* __BYTE_ORDER */ + +enum uuid_format { + UUID_STRING, + UUID_HEX_STRING, + UUID_DCE, + UUID_DOS, + UUID_64BIT_LE, + UUID_64BIT_BE, + UUID_FOURINT, +}; + +enum endian { + LE = 0, + BE = 1 +}; + +extern int volume_id_utf8_encoded_valid_unichar(const char *str); +extern size_t volume_id_set_unicode16(uint8_t *str, size_t len, const uint8_t *buf, enum endian endianess, size_t count); +extern void volume_id_set_usage(struct volume_id *id, enum volume_id_usage usage_id); +extern void volume_id_set_label_raw(struct volume_id *id, const uint8_t *buf, size_t count); +extern void volume_id_set_label_string(struct volume_id *id, const uint8_t *buf, size_t count); +extern void volume_id_set_label_unicode16(struct volume_id *id, const uint8_t *buf, enum endian endianess, size_t count); +extern void volume_id_set_uuid(struct volume_id *id, const uint8_t *buf, size_t len, enum uuid_format format); +extern uint8_t *volume_id_get_buffer(struct volume_id *id, uint64_t off, size_t len); +extern void volume_id_free_buffer(struct volume_id *id); + +#endif /* _VOLUME_ID_UTIL_ */ + === added file 'libvolume_id/via_raid.c' --- grub-0.97.orig/libvolume_id/via_raid.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/via_raid.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,88 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2005 Kay Sievers + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * Based on information taken from dmraid: + * Copyright (C) 2004-2006 Heinz Mauelshagen, Red Hat GmbH + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +struct via_meta { + uint16_t signature; + uint8_t version_number; + struct via_array { + uint16_t disk_bit_mask; + uint8_t disk_array_ex; + uint32_t capacity_low; + uint32_t capacity_high; + uint32_t serial_checksum; + } PACKED array; + uint32_t serial_checksum[8]; + uint8_t checksum; +} PACKED; + +#define VIA_SIGNATURE 0xAA55 + +/* 8 bit checksum on first 50 bytes of metadata. */ +static uint8_t meta_checksum(struct via_meta *via) +{ + uint8_t i = 50, sum = 0; + + while (i--) + sum += ((uint8_t*) via)[i]; + + return sum == via->checksum; +} + + +int volume_id_probe_via_raid(struct volume_id *id, uint64_t off, uint64_t size) +{ + const uint8_t *buf; + uint64_t meta_off; + struct via_meta *via; + + dbg("probing at offset 0x%llx, size 0x%llx", + (unsigned long long) off, (unsigned long long) size); + + if (size < 0x10000) + return -1; + + meta_off = ((size / 0x200)-1) * 0x200; + + buf = volume_id_get_buffer(id, off + meta_off, 0x200); + if (buf == NULL) + return -1; + + via = (struct via_meta *) buf; + if (le16_to_cpu(via->signature) != VIA_SIGNATURE) + return -1; + + if (via->version_number > 1) + return -1; + + if (!meta_checksum(via)) + return -1; + + volume_id_set_usage(id, VOLUME_ID_RAID); + sprintf(id->type_version, "%u", via->version_number); + id->type = "via_raid_member"; + + return 0; +} === added file 'libvolume_id/volume_id.c' --- grub-0.97.orig/libvolume_id/volume_id.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/volume_id.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,222 @@ +/* + * volume_id - reads volume label and uuid + * + * Copyright (C) 2005-2007 Kay Sievers + * Grub Port, Copyright (C) 2008 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "volume_id.h" +#include "util.h" +#include "strfuncs.h" +#include "shared.h" + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +struct prober { + volume_id_probe_fn_t prober; + const char *name[4]; +}; + +#define NOT_SUPPORTED(x) +#define SUPPORTED(x) x + +static const struct prober prober_raid[] = { + { volume_id_probe_ddf_raid, { "ddf_raid", } }, + + /* { volume_id_probe_linux_raid, { "linux_raid", } }, */ + /* { volume_id_probe_intel_software_raid, { "isw_raid", } }, */ + /* { volume_id_probe_lsi_mega_raid, { "lsi_mega_raid", } }, */ + /* { volume_id_probe_via_raid, { "via_raid", } }, */ + /* { volume_id_probe_silicon_medley_raid, { "silicon_medley_raid", } }, */ + /* { volume_id_probe_nvidia_raid, { "nvidia_raid", } }, */ + /* { volume_id_probe_promise_fasttrack_raid, { "promise_fasttrack_raid", } }, */ + /* { volume_id_probe_highpoint_45x_raid, { "highpoint_raid", } }, */ + /* { volume_id_probe_adaptec_raid, { "adaptec_raid", } }, */ + /* { volume_id_probe_jmicron_raid, { "jmicron_raid", } }, */ + /* { volume_id_probe_lvm1, { "lvm1", } }, */ + /* { volume_id_probe_lvm2, { "lvm2", } }, */ + /* { volume_id_probe_highpoint_37x_raid, { "highpoint_raid", } }, */ +}; + +static const struct prober prober_filesystem[] = { + { volume_id_probe_vfat, { "vfat", } }, + { volume_id_probe_luks, { "luks", } }, + { volume_id_probe_xfs, { "xfs", } }, + { volume_id_probe_ext, { "ext2", "ext3", "jbd", } }, + { volume_id_probe_reiserfs, { "reiserfs", "reiser4", } }, + { volume_id_probe_jfs, { "jfs", } }, + { volume_id_probe_hfs_hfsplus, { "hfs", "hfsplus", } }, + { volume_id_probe_ntfs, { "ntfs", } }, + { volume_id_probe_ocfs1, { "ocfs1", } }, + { volume_id_probe_ocfs2, { "ocfs2", } }, + + /* { volume_id_probe_linux_swap, { "swap", } }, */ + /* { volume_id_probe_udf, { "udf", } }, */ + /* { volume_id_probe_iso9660, { "iso9660", } }, */ + /* { volume_id_probe_ufs, { "ufs", } }, */ + /* { volume_id_probe_cramfs, { "cramfs", } }, */ + /* { volume_id_probe_romfs, { "romfs", } }, */ + /* { volume_id_probe_hpfs, { "hpfs", } }, */ + /* { volume_id_probe_sysv, { "sysv", "xenix", } }, */ + /* { volume_id_probe_minix, { "minix", } }, */ + /* { volume_id_probe_vxfs, { "vxfs", } }, */ + /* { volume_id_probe_squashfs, { "squashfs", } }, */ + /* { volume_id_probe_netware, { "netware", } }, */ +}; + +/* the user can overwrite this log function */ +static void default_log(int priority, const char *file, int line, const char *format, ...) +{ + return; +} + +volume_id_log_fn_t volume_id_log_fn = default_log; + +/** + * volume_id_get_type: + * @id: Probing context + * @type: Type string. Must not be freed by the caller. + * + * Get the type string after a successful probe. + * + * Returns: 1 if the value was set, 0 otherwise. + **/ +int volume_id_get_type(struct volume_id *id, const char **type) +{ + if (id == NULL) + return 0; + if (type == NULL) + return 0; + if (id->usage_id == VOLUME_ID_UNUSED) + return 0; + + *type = id->type; + return 1; +} + + +/** + * volume_id_get_uuid: + * @id: Probing context. + * @uuid: UUID string. Must not be freed by the caller. + * + * Get the raw UUID string after a successful probe. + * + * Returns: 1 if the value was set, 0 otherwise. + **/ +int volume_id_get_uuid(struct volume_id *id, const char **uuid) +{ + if (id == NULL) + return 0; + if (uuid == NULL) + return 0; + if (id->usage_id == VOLUME_ID_UNUSED) + return 0; + + *uuid = id->uuid; + return 1; +} + +/** + * volume_id_probe_raid: + * @id: Probing context. + * @off: Probing offset relative to the start of the device. + * @size: Total size of the device. + * + * Probe device for all known raid signatures. + * + * Returns: 0 on successful probe, otherwise negative value. + **/ +int volume_id_probe_raid(struct volume_id *id, uint64_t off, uint64_t size) +{ + unsigned int i; + + if (id == NULL) + return -1; + + info("probing at offset 0x%llx, size 0x%llx", + (unsigned long long) off, (unsigned long long) size); + + for (i = 0; i < ARRAY_SIZE(prober_raid); i++) + if (prober_raid[i].prober(id, off, size) == 0) + goto found; + return -1; + +found: + return 0; +} + +/** + * volume_id_probe_filesystem: + * @id: Probing context. + * @off: Probing offset relative to the start of the device. + * @size: Total size of the device. + * + * Probe device for all known filesystem signatures. + * + * Returns: 0 on successful probe, otherwise negative value. + **/ +int volume_id_probe_filesystem(struct volume_id *id, uint64_t off, uint64_t size) +{ + unsigned int i; + + if (id == NULL) + return -1; + + info("probing at offset 0x%llx, size 0x%llx", + (unsigned long long) off, (unsigned long long) size); + + for (i = 0; i < ARRAY_SIZE(prober_filesystem); i++) + if (prober_filesystem[i].prober(id, off, size) == 0) + goto found; + return -1; + +found: + return 0; +} + +/** + * volume_id_probe_raid: + * @all_probers_fn: prober function to called for all known probing routines. + * @id: Context passed to prober function. + * @off: Offset value passed to prober function. + * @size: Size value passed to prober function. + * @data: Arbitrary data passed to the prober function. + * + * Run a custom function for all known probing routines. + **/ +void volume_id_all_probers(all_probers_fn_t all_probers_fn, + struct volume_id *id, uint64_t off, uint64_t size, + void *data) +{ + unsigned int i; + + if (all_probers_fn == NULL) + return; + + for (i = 0; i < ARRAY_SIZE(prober_raid); i++) { + if (all_probers_fn(prober_raid[i].prober, id, off, size, data) != 0) + goto out; + } + for (i = 0; i < ARRAY_SIZE(prober_filesystem); i++) { + if (all_probers_fn(prober_filesystem[i].prober, id, off, size, data) != 0) + goto out; + } +out: + return; +} === added file 'libvolume_id/volume_id.h' --- grub-0.97.orig/libvolume_id/volume_id.h 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/volume_id.h 2008-07-15 12:31:43 +0000 @@ -0,0 +1,137 @@ +/* + * volume_id - reads volume label and uuid + * + * Copyright (C) 2005-2007 Kay Sievers + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _LIBVOLUME_ID_H_ +#define _LIBVOLUME_ID_H_ + +#include +#include + +typedef void (*volume_id_log_fn_t)(int priority, const char *file, int line, const char *format, ...) ; + +extern volume_id_log_fn_t volume_id_log_fn; + +struct volume_id; +typedef int (*volume_id_probe_fn_t)(struct volume_id *id, uint64_t off, uint64_t size); +typedef int (*all_probers_fn_t)(volume_id_probe_fn_t probe_fn, + struct volume_id *id, uint64_t off, uint64_t size, + void *data); + +extern struct volume_id *volume_id_open_fd(int fd); +extern void volume_id_close(struct volume_id *id); +extern int volume_id_probe_filesystem(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_raid(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_all(struct volume_id *id, uint64_t off, uint64_t size); +extern const volume_id_probe_fn_t *volume_id_get_prober_by_type(const char *type); +extern void volume_id_all_probers(all_probers_fn_t all_probers_fn, + struct volume_id *id, uint64_t off, uint64_t size, + void *data); +extern int volume_id_get_label(struct volume_id *id, const char **label); +extern int volume_id_get_label_raw(struct volume_id *id, const uint8_t **label, size_t *len); +extern int volume_id_get_uuid(struct volume_id *id, const char **uuid); +extern int volume_id_get_uuid_raw(struct volume_id *id, const uint8_t **uuid, size_t *len); +extern int volume_id_get_usage(struct volume_id *id, const char **usage); +extern int volume_id_get_type(struct volume_id *id, const char **type); +extern int volume_id_get_type_version(struct volume_id *id, const char **type_version); +extern int volume_id_encode_string(const char *str, char *str_enc, size_t len); + +/* + * Note: everything below will be made private or removed from + * a future version, and a new major release of libvolume_id + */ + +extern struct volume_id *volume_id_open_node(const char *path); + +#define VOLUME_ID_LABEL_SIZE 64 +#define VOLUME_ID_UUID_SIZE 36 +#define VOLUME_ID_FORMAT_SIZE 32 +#define VOLUME_ID_PATH_MAX 256 +#define VOLUME_ID_PARTITIONS_MAX 256 + +enum volume_id_usage { + VOLUME_ID_UNUSED, + VOLUME_ID_UNPROBED, + VOLUME_ID_OTHER, + VOLUME_ID_FILESYSTEM, + VOLUME_ID_RAID, + VOLUME_ID_DISKLABEL, + VOLUME_ID_CRYPTO, +}; + +#include + +struct volume_id { + uint8_t label_raw[VOLUME_ID_LABEL_SIZE]; + size_t label_raw_len; + char label[VOLUME_ID_LABEL_SIZE+1]; + uint8_t uuid_raw[VOLUME_ID_UUID_SIZE]; + size_t uuid_raw_len; + char uuid[VOLUME_ID_UUID_SIZE+1]; + enum volume_id_usage usage_id; + char *usage; + char *type; + char type_version[VOLUME_ID_FORMAT_SIZE]; + + int fd; + uint8_t sbbuf[SB_BUFFER_SIZE]; + size_t sbbuf_len; + uint8_t seekbuf[SEEK_BUFFER_SIZE]; + uint64_t seekbuf_off; + size_t seekbuf_len; + int fd_close:1; +}; + +/* filesystems */ +extern int volume_id_probe_cramfs(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_ext(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_vfat(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_hfs_hfsplus(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_hpfs(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_iso9660(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_jfs(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_minix(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_ntfs(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_ocfs1(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_ocfs2(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_reiserfs(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_romfs(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_sysv(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_udf(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_ufs(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_vxfs(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_xfs(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_squashfs(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_netware(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_gfs(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_gfs2(struct volume_id *id, uint64_t off, uint64_t size); + +/* special formats */ +extern int volume_id_probe_linux_swap(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_luks(struct volume_id *id, uint64_t off, uint64_t size); + +/* raid */ +extern int volume_id_probe_linux_raid(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_lvm1(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_lvm2(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_ddf_raid(struct volume_id *id, uint64_t off, uint64_t size); + +/* bios raid */ +extern int volume_id_probe_intel_software_raid(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_highpoint_37x_raid(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_highpoint_45x_raid(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_lsi_mega_raid(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_nvidia_raid(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_promise_fasttrack_raid(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_silicon_medley_raid(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_via_raid(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_adaptec_raid(struct volume_id *id, uint64_t off, uint64_t size); +extern int volume_id_probe_jmicron_raid(struct volume_id *id, uint64_t off, uint64_t size); + +#endif === added file 'libvolume_id/vxfs.c' --- grub-0.97.orig/libvolume_id/vxfs.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/vxfs.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,49 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +#define VXFS_SUPER_MAGIC 0xa501FCF5 + +struct vxfs_super { + uint32_t vs_magic; + int32_t vs_version; +} PACKED; + +int volume_id_probe_vxfs(struct volume_id *id, uint64_t off, uint64_t size) +{ + struct vxfs_super *vxs; + + info("probing at offset 0x%llx", (unsigned long long) off); + + vxs = (struct vxfs_super *) volume_id_get_buffer(id, off + 0x200, 0x200); + if (vxs == NULL) + return -1; + + if (vxs->vs_magic == cpu_to_le32(VXFS_SUPER_MAGIC)) { + sprintf(id->type_version, "%u", (unsigned int) vxs->vs_version); + volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); + id->type = "vxfs"; + return 0; + } + + return -1; +} === added file 'libvolume_id/xfs.c' --- grub-0.97.orig/libvolume_id/xfs.c 1970-01-01 00:00:00 +0000 +++ grub-0.97/libvolume_id/xfs.c 2008-07-15 12:31:43 +0000 @@ -0,0 +1,59 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "volume_id.h" +#include "util.h" +#include "shared.h" + +struct xfs_super_block { + uint8_t magic[4]; + uint32_t blocksize; + uint64_t dblocks; + uint64_t rblocks; + uint32_t dummy1[2]; + uint8_t uuid[16]; + uint32_t dummy2[15]; + uint8_t fname[12]; + uint32_t dummy3[2]; + uint64_t icount; + uint64_t ifree; + uint64_t fdblocks; +} PACKED; + +int volume_id_probe_xfs(struct volume_id *id, uint64_t off, uint64_t size) +{ + struct xfs_super_block *xs; + + info("probing at offset 0x%llx", (unsigned long long) off); + + xs = (struct xfs_super_block *) volume_id_get_buffer(id, off, 0x200); + if (xs == NULL) + return -1; + + if (memcmp((char *)xs->magic, "XFSB", 4) != 0) + return -1; + + volume_id_set_label_raw(id, xs->fname, 12); + volume_id_set_label_string(id, xs->fname, 12); + volume_id_set_uuid(id, xs->uuid, 0, UUID_DCE); + + volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); + id->type = "xfs"; + + return 0; +} === modified file 'stage2/Makefile.am' --- grub-0.97.orig/stage2/Makefile.am 2005-02-02 20:40:05 +0000 +++ grub-0.97/stage2/Makefile.am 2008-07-09 17:23:44 +0000 @@ -13,6 +13,10 @@ # For . INCLUDES = -I$(top_srcdir)/stage1 +if UUID_SUPPORT +INCLUDES += -I$(top_srcdir)/libvolume_id +endif + # The library for /sbin/grub. noinst_LIBRARIES = libgrub.a libgrub_a_SOURCES = boot.c builtins.c char_io.c cmdline.c common.c \ @@ -61,6 +65,12 @@ PXELOADER_LINK = -nostdlib -Wl,-N -Wl,-Ttext -Wl,7C00 START_ELTORITO_LINK = -nostdlib -Wl,-N -Wl,-Ttext -Wl,7C00 +if UUID_SUPPORT +UUID_FLAGS = -DSUPPORT_UUID=1 +else +UUID_FLAGS = +endif + if NETBOOT_SUPPORT NETBOOT_FLAGS = -I$(top_srcdir)/netboot -DSUPPORT_NETBOOT=1 else @@ -82,6 +92,8 @@ STAGE2_COMPILE = $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ $(NETBOOT_FLAGS) $(SERIAL_FLAGS) $(HERCULES_FLAGS) +STAGE2_COMPILE += $(UUID_FLAGS) + STAGE1_5_LINK = -nostdlib -Wl,-N -Wl,-Ttext -Wl,2000 STAGE1_5_COMPILE = $(STAGE2_COMPILE) -DNO_DECOMPRESSION=1 -DSTAGE1_5=1 @@ -97,7 +109,12 @@ if NETBOOT_SUPPORT pre_stage2_exec_LDADD = ../netboot/libdrivers.a -endif +else +if UUID_SUPPORT +pre_stage2_exec_LDADD = ../libvolume_id/libvolume_id.a +endif +endif + if DISKLESS_SUPPORT BUILT_SOURCES = stage2_size.h diskless_size.h === modified file 'stage2/builtins.c' --- grub-0.97.orig/stage2/builtins.c 2008-01-28 18:15:31 +0000 +++ grub-0.97/stage2/builtins.c 2008-07-09 17:23:44 +0000 @@ -49,6 +49,10 @@ # include #endif +#ifdef SUPPORT_UUID +#include +#endif + /* The type of kernel loaded. */ kernel_t kernel_type; /* The boot device. */ @@ -4790,6 +4794,168 @@ "Probe VBE information. If the mode number MODE is specified, show only" " the information about only the mode." }; + + + +#ifdef SUPPORT_UUID + +struct uuid_callback_data +{ + int found; /* 1 if uuid matches */ + char *uuid; /* uuid to look for */ +}; + +static void uuid_info_print(struct volume_id *id, const char *uuid) +{ + const char *type; + int i; + + volume_id_get_type(id, &type); + grub_printf("(hd%d", current_drive - 0x80); + if ((current_partition & 0xFF0000) != 0xFF0000) + { + grub_printf (",%d", (current_partition >> 16) & 0xFF); + } + if ((current_partition & 0x00FF00) != 0x00FF00) + { + grub_printf (",%c", 'a' + ((current_partition >> 8) & 0xFF)); + } + grub_printf(") %s",type); + for (i=0;i<6-strlen(type);i++) + { + grub_putchar(' '); + } + grub_printf(" %s\n",uuid); +} + +static int uuid_all_probers(volume_id_probe_fn_t probe_fn, + struct volume_id *id, + uint64_t off, + uint64_t size, + void *data) +{ + struct uuid_callback_data *uc_data = (struct uuid_callback_data*)data; + + if (probe_fn(id, off, size) == 0) + { + const char *volume_uuid; + if (volume_id_get_uuid(id, &volume_uuid)) + { + if (!*(uc_data->uuid)) + { + uuid_info_print(id, volume_uuid); + } + else + { + if (strcmp(volume_uuid, uc_data->uuid) == 0) + { + grub_printf("Boot from "); + uuid_info_print(id, volume_uuid); + uc_data->found = 1; + return 1; + } + } + } + } + return 0; +} + +/* uuid find */ +/* Search for the uuid arg in all of partitions. */ +static int +uuid_func(char *arg, int flag) +{ + unsigned long drive; + unsigned long tmp_drive = saved_drive; + unsigned long tmp_partition = saved_partition; + struct uuid_callback_data uc_data; + + uc_data.uuid = arg; + uc_data.found = 0; + + /* Just hard disks and USB drives supported by BIOS */ + for (drive = 0x80; drive < 0x88; drive++) + { + unsigned long part = 0xFFFFFF; + unsigned long start, len, offset, ext_offset, gpt_offset; + int type, entry, gpt_count, gpt_size; + char *buf = (char *) RAW_ADDR(0x100000); + struct volume_id *vol_id = (struct volume_id *) RAW_ADDR (0x100000 + SECTOR_SIZE); + + current_drive = drive; + while (next_partition (drive, 0xFFFFFF, &part, &type, + &start, &len, &offset, &entry, + &ext_offset, &gpt_offset, + &gpt_count, &gpt_size, buf)) + { + if (type != PC_SLICE_TYPE_NONE + && ! IS_PC_SLICE_TYPE_BSD (type) + && ! IS_PC_SLICE_TYPE_EXTENDED (type)) + { + current_partition = part; + errnum = ERR_NONE; + /* Attempt to open device, conventional way */ + if (! open_device ()) + { + errnum = ERR_NONE; + /* Failed, like NTFS or FAT filesystems, so try the rootnoverify way */ + if (open_partition ()) + { + set_bootdev (0); + if (errnum) + { + /* Give up */ + errnum = ERR_NONE; + continue; + } + } + } + + /* And probe for uuid across all fs types */ + saved_drive = current_drive; + saved_partition = current_partition; + + grub_memset(vol_id, 0, sizeof(struct volume_id) ); + volume_id_all_probers(uuid_all_probers, vol_id, 0, len, (void*)&uc_data); + if (uc_data.found) + { + /* Success! */ + errnum = ERR_NONE; + return 0; + } + } + /* We want to ignore any error here. */ + errnum = ERR_NONE; + } + + /* next_partition always sets ERRNUM in the last call, so clear it. */ + errnum = ERR_NONE; + } + + saved_drive = tmp_drive; + saved_partition = tmp_partition; + current_drive = GRUB_INVALID_DRIVE; + current_partition = 0xFFFFFF; + errnum = ERR_FILE_NOT_FOUND; + + if (!*arg) + { + errnum = ERR_NONE; + return 0; + } + return 1; +} + +static struct builtin builtin_uuid = +{ + "uuid", + uuid_func, + BUILTIN_CMDLINE | BUILTIN_HELP_LIST, + "uuid UUID", + "Set the current \"root device\" to the device with the uuid UUID," + " then attempt to mount it" +}; +#endif /* The table of builtin commands. Sorted in dictionary order. */ @@ -4879,6 +5045,9 @@ &builtin_title, &builtin_unhide, &builtin_uppermem, +#ifdef SUPPORT_UUID + &builtin_uuid, +#endif &builtin_vbeprobe, 0 };