diff --git a/Makefile b/Makefile index 60edff9b4..0f21ccff3 100644 --- a/Makefile +++ b/Makefile @@ -452,6 +452,7 @@ libs-y := \ shell/ \ sysklogd/ \ util-linux/ \ + util-linux/volume_id/ \ endif # KBUILD_EXTMOD diff --git a/e2fsprogs/old_e2fsprogs/tune2fs.c b/e2fsprogs/old_e2fsprogs/tune2fs.c index c5c84d68e..b7a1b21eb 100644 --- a/e2fsprogs/old_e2fsprogs/tune2fs.c +++ b/e2fsprogs/old_e2fsprogs/tune2fs.c @@ -557,20 +557,6 @@ static void parse_tune2fs_options(int argc, char **argv) device_name = x_blkid_get_devname(argv[optind]); } -#ifdef CONFIG_FINDFS -static ATTRIBUTE_NORETURN void do_findfs(int argc, char **argv) -{ - if ((argc != 2) || - (strncmp(argv[1], "LABEL=", 6) && strncmp(argv[1], "UUID=", 5))) - bb_show_usage(); - device_name = x_blkid_get_devname(argv[1]); - puts(device_name); - exit(0); -} -#else -#define do_findfs(x, y) -#endif - static void tune2fs_clean_up(void) { if (ENABLE_FEATURE_CLEAN_UP && device_name) free(device_name); @@ -588,9 +574,7 @@ int tune2fs_main(int argc, char **argv) if (ENABLE_FEATURE_CLEAN_UP) atexit(tune2fs_clean_up); - if (ENABLE_FINDFS && (applet_name[0] == 'f')) /* findfs */ - do_findfs(argc, argv); /* no return */ - else if (ENABLE_E2LABEL && (applet_name[0] == 'e')) /* e2label */ + if (ENABLE_E2LABEL && (applet_name[0] == 'e')) /* e2label */ parse_e2label_options(argc, argv); else parse_tune2fs_options(argc, argv); /* tune2fs */ diff --git a/include/usage.h b/include/usage.h index 04ef1822e..d1878827b 100644 --- a/include/usage.h +++ b/include/usage.h @@ -1029,6 +1029,13 @@ USE_FEATURE_BRCTL_FANCY("\n" \ " -t Get only headers\n" \ " -z Delete messages on server" +#define findfs_trivial_usage \ + "LABEL=label or UUID=uuid" +#define findfs_full_usage \ + "Finds a filesystem device based on a label or UUID." +#define findfs_example_usage \ + "$ findfs LABEL=MyDevice" + #define find_trivial_usage \ "[PATH...] [EXPRESSION]" #define find_full_usage \ diff --git a/include/volume_id.h b/include/volume_id.h new file mode 100644 index 000000000..99cb11ff6 --- /dev/null +++ b/include/volume_id.h @@ -0,0 +1,22 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2005 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +char *get_devname_from_label(const char *spec); +char *get_devname_from_uuid(const char *spec); diff --git a/util-linux/Config.in b/util-linux/Config.in index 3b0f778cb..552ca0f31 100644 --- a/util-linux/Config.in +++ b/util-linux/Config.in @@ -150,6 +150,17 @@ config FEATURE_FDISK_ADVANCED partition, and similarly evil things. Unless you have a very good reason you would be wise to leave this disabled. +config FINDFS + bool "findfs" + default n + select VOLUMEID + help + This is similar to the findfs program that is part of the e2fsprogs + package. However, the e2fsprogs version only support ext2/3. This + version supports those in addition to FAT, swap, and ReiserFS. + WARNING: + With all submodules selected, it will add ~11k to busybox. + config FREERAMDISK bool "freeramdisk" default n @@ -375,6 +386,215 @@ config FEATURE_USE_TERMIOS will be unable to determine the current screen size, and will be unable to move the cursor. +config VOLUMEID + bool "Routines for detecting label and uuid on common filesystems" + default n + help + TODO + +config FEATURE_VOLUMEID_EXT + bool "Ext filesystem" + default n + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_REISERFS + bool "Reiser filesystem" + default n + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_FAT + bool "fat filesystem" + default n + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_HFS + bool "hfs filesystem" + default n + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_JFS + bool "jfs filesystem" + default n + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_UFS + bool "ufs filesystem" + default n + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_XFS + bool "xfs filesystem" + default n + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_NTFS + bool "ntfs filesystem" + default n + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_ISO9660 + bool "iso9660 filesystem" + default n + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_UDF + bool "udf filesystem" + default n + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_LUKS + bool "luks filesystem" + default n + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_LINUXSWAP + bool "linux swap filesystem" + default n + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_LVM + bool "lvm" + default n + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_CRAMFS + bool "cramfs filesystem" + default n + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_HPFS + bool "hpfs filesystem" + default n + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_ROMFS + bool "romfs filesystem" + default n + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_SYSV + bool "sysv filesystem" + default n + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_MINIX + bool "minix filesystem" + default n + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_MAC + bool "mac filesystem" + default n + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_MSDOS + bool "msdos filesystem" + default n + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_OCFS2 + bool "ocfs2 filesystem" + default n + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_HIGHPOINTRAID + bool "highpoint raid" + default n + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_ISWRAID + bool "intel raid" + default n + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_LSIRAID + bool "lsi raid" + default n + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_VIARAID + bool "via raid" + default n + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_SILICONRAID + bool "silicon raid" + default n + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_NVIDIARAID + bool "nvidia raid" + default n + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_PROMISERAID + bool "promise raid" + default n + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_LINUXRAID + bool "linuxraid" + default n + depends on VOLUMEID + help + TODO + config MOUNT bool "mount" default n @@ -414,6 +634,15 @@ config FEATURE_MOUNT_HELPERS "sometype [-o opts] fs /mnt" if simple mount syscall fails. The idea is to use such virtual filesystems in /etc/fstab. +config FEATURE_MOUNT_LABEL + bool " Support specifiying devices by label or UUID" + default n + depends on MOUNT + select FINDFS + help + This allows for specifying a device by label or uuid, rather than by + name. This feature utilizes the same functionality as findfs. + config FEATURE_MOUNT_NFS bool "Support mounting NFS file systems" default n diff --git a/util-linux/Kbuild b/util-linux/Kbuild index 4a18ff21f..c71186e86 100644 --- a/util-linux/Kbuild +++ b/util-linux/Kbuild @@ -10,6 +10,7 @@ lib-$(CONFIG_FBSET) +=fbset.o lib-$(CONFIG_FDFLUSH) +=freeramdisk.o lib-$(CONFIG_FDFORMAT) +=fdformat.o lib-$(CONFIG_FDISK) +=fdisk.o +lib-$(CONFIG_FINDFS) +=findfs.o lib-$(CONFIG_FREERAMDISK) +=freeramdisk.o lib-$(CONFIG_FSCK_MINIX) +=fsck_minix.o lib-$(CONFIG_GETOPT) +=getopt.o diff --git a/util-linux/fdisk_sgi.c b/util-linux/fdisk_sgi.c index 7826bb7cc..1fce0c1c7 100644 --- a/util-linux/fdisk_sgi.c +++ b/util-linux/fdisk_sgi.c @@ -781,7 +781,7 @@ create_sgilabel(void) printf(msg_building_new_label, "SGI disklabel"); - sgi_other_endian = (BYTE_ORDER == LITTLE_ENDIAN); + sgi_other_endian = BB_LITTLE_ENDIAN; res = ioctl(fd, BLKGETSIZE, &longsectors); if (!ioctl(fd, HDIO_GETGEO, &geometry)) { g_heads = geometry.heads; diff --git a/util-linux/findfs.c b/util-linux/findfs.c new file mode 100644 index 000000000..4f036425c --- /dev/null +++ b/util-linux/findfs.c @@ -0,0 +1,38 @@ +/* vi: set sw=4 ts=4: */ +/* + * Support functions for mounting devices by label/uuid + * + * Copyright (C) 2006 by Jason Schoon + * Some portions cribbed from e2fsprogs, util-linux, dosfstools + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +#include "libbb.h" +#include "volume_id.h" + +int findfs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int findfs_main(int argc, char **argv) +{ + char *tmp = NULL; + + if (argc != 2) + bb_show_usage(); + + if (!strncmp(argv[1], "LABEL=", 6)) + tmp = get_devname_from_label(argv[1] + 6); + else if (!strncmp(argv[1], "UUID=", 5)) + tmp = get_devname_from_uuid(argv[1] + 5); + else if (!strncmp(argv[1], "/dev/", 5)) { + /* Just pass a device name right through. This might aid in some scripts + being able to call this unconditionally */ + tmp = argv[1]; + } else + bb_show_usage(); + + if (tmp) { + puts(tmp); + return 0; + } + return 1; +} diff --git a/util-linux/mount.c b/util-linux/mount.c index 8b3230935..b19c3a3ef 100644 --- a/util-linux/mount.c +++ b/util-linux/mount.c @@ -19,10 +19,13 @@ */ #include -#include "libbb.h" #include +#include "libbb.h" -/* Needed for nfs support only... */ +/* For FEATURE_MOUNT_LABEL only */ +#include "volume_id.h" + +/* Needed for nfs support only */ #include #undef TRUE #undef FALSE @@ -245,6 +248,22 @@ static int verbose_mount(const char *source, const char *target, #define verbose_mount(...) mount(__VA_ARGS__) #endif +static int resolve_mount_spec(char **fsname) +{ + char *tmp = NULL; + + if (!strncmp(*fsname, "UUID=", 5)) + tmp = get_devname_from_uuid(*fsname + 5); + else if (!strncmp(*fsname, "LABEL=", 6)) + tmp = get_devname_from_label(*fsname + 6); + + if (tmp) { + *fsname = tmp; + return 1; + } + return 0; +} + /* Append mount options to string */ static void append_mount_options(char **oldopts, const char *newopts) { @@ -1781,6 +1800,9 @@ int mount_main(int argc, char **argv) mtpair->mnt_dir = argv[1]; mtpair->mnt_type = fstype; mtpair->mnt_opts = cmdopts; + if (ENABLE_FEATURE_MOUNT_LABEL) { + resolve_mount_spec(&mtpair->mnt_fsname); + } rc = singlemount(mtpair, 0); goto clean_up; } @@ -1842,6 +1864,9 @@ int mount_main(int argc, char **argv) mtcur->mnt_opts = xstrdup(mtcur->mnt_opts); append_mount_options(&(mtcur->mnt_opts), cmdopts); + if (ENABLE_FEATURE_MOUNT_LABEL) { + resolve_mount_spec(&mtpair->mnt_fsname); + } rc = singlemount(mtcur, 0); free(mtcur->mnt_opts); } @@ -1884,6 +1909,9 @@ int mount_main(int argc, char **argv) bb_error_msg_and_die(must_be_root); // Mount this thing. + if (ENABLE_FEATURE_MOUNT_LABEL) { + resolve_mount_spec(&mtpair->mnt_fsname); + } // NFS mounts want this to be xrealloc-able mtcur->mnt_opts = xstrdup(mtcur->mnt_opts); diff --git a/util-linux/volume_id/Kbuild b/util-linux/volume_id/Kbuild new file mode 100644 index 000000000..c2eb01564 --- /dev/null +++ b/util-linux/volume_id/Kbuild @@ -0,0 +1,41 @@ +# Makefile for busybox +# +# Copyright (C) 1999-2005 by Erik Andersen +# +# Licensed under the GPL v2, see the file LICENSE in this tarball. + +lib-y:= + +lib-$(CONFIG_FINDFS) += get_devname.o +lib-$(CONFIG_FEATURE_MOUNT_LABEL) += get_devname.o + +lib-$(CONFIG_VOLUMEID) += volume_id.o util.o +lib-$(CONFIG_FEATURE_VOLUMEID_EXT) += ext.o +lib-$(CONFIG_FEATURE_VOLUMEID_FAT) += fat.o +lib-$(CONFIG_FEATURE_VOLUMEID_HFS) += hfs.o +lib-$(CONFIG_FEATURE_VOLUMEID_HIGHPOINTRAID) += highpoint.o +lib-$(CONFIG_FEATURE_VOLUMEID_ISWRAID) += isw_raid.o +lib-$(CONFIG_FEATURE_VOLUMEID_LSIRAID) += lsi_raid.o +lib-$(CONFIG_FEATURE_VOLUMEID_VIARAID) += via_raid.o +lib-$(CONFIG_FEATURE_VOLUMEID_SILICONRAID) += silicon_raid.o +lib-$(CONFIG_FEATURE_VOLUMEID_NVIDIARAID) += nvidia_raid.o +lib-$(CONFIG_FEATURE_VOLUMEID_PROMISERAID) += promise_raid.o +lib-$(CONFIG_FEATURE_VOLUMEID_ISO9660) += iso9660.o +lib-$(CONFIG_FEATURE_VOLUMEID_JFS) += jfs.o +lib-$(CONFIG_FEATURE_VOLUMEID_LINUXRAID) += linux_raid.o +lib-$(CONFIG_FEATURE_VOLUMEID_LINUXSWAP) += linux_swap.o +lib-$(CONFIG_FEATURE_VOLUMEID_LVM) += lvm.o +lib-$(CONFIG_FEATURE_VOLUMEID_MAC) += mac.o +lib-$(CONFIG_FEATURE_VOLUMEID_MSDOS) += msdos.o +lib-$(CONFIG_FEATURE_VOLUMEID_NTFS) += ntfs.o +lib-$(CONFIG_FEATURE_VOLUMEID_REISERFS) += reiserfs.o +lib-$(CONFIG_FEATURE_VOLUMEID_UDF) += udf.o +lib-$(CONFIG_FEATURE_VOLUMEID_UFS) += ufs.o +lib-$(CONFIG_FEATURE_VOLUMEID_XFS) += xfs.o +lib-$(CONFIG_FEATURE_VOLUMEID_CRAMFS) += cramfs.o +lib-$(CONFIG_FEATURE_VOLUMEID_HPFS) += hpfs.o +lib-$(CONFIG_FEATURE_VOLUMEID_ROMFS) += romfs.o +lib-$(CONFIG_FEATURE_VOLUMEID_SYSV) += sysv.o +lib-$(CONFIG_FEATURE_VOLUMEID_MINIX) += minix.o +lib-$(CONFIG_FEATURE_VOLUMEID_LUKS) += luks.o +lib-$(CONFIG_FEATURE_VOLUMEID_OCFS2) += ocfs2.o diff --git a/util-linux/volume_id/cramfs.c b/util-linux/volume_id/cramfs.c new file mode 100644 index 000000000..fd6e87522 --- /dev/null +++ b/util-linux/volume_id/cramfs.c @@ -0,0 +1,58 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "volume_id_internal.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; + } __attribute__((__packed__)) info; + uint8_t name[16]; +} __attribute__((__packed__)); + +int volume_id_probe_cramfs(struct volume_id *id, uint64_t off) +{ + struct cramfs_super *cs; + + dbg("probing at offset 0x%llx", (unsigned long long) off); + + cs = volume_id_get_buffer(id, off, 0x200); + if (cs == NULL) + return -1; + + if (memcmp(cs->magic, "\x45\x3d\xcd\x28", 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; +} diff --git a/util-linux/volume_id/ext.c b/util-linux/volume_id/ext.c new file mode 100644 index 000000000..3c07f5301 --- /dev/null +++ b/util-linux/volume_id/ext.c @@ -0,0 +1,71 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "volume_id_internal.h" + +struct ext2_super_block { + uint32_t inodes_count; + uint32_t blocks_count; + uint32_t r_blocks_count; + uint32_t free_blocks_count; + uint32_t free_inodes_count; + uint32_t first_data_block; + uint32_t log_block_size; + uint32_t dummy3[7]; + uint8_t magic[2]; + uint16_t state; + uint32_t dummy5[8]; + uint32_t feature_compat; + uint32_t feature_incompat; + uint32_t feature_ro_compat; + uint8_t uuid[16]; + uint8_t volume_name[16]; +} __attribute__((__packed__)); + +#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x00000004 +#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x00000008 +#define EXT_SUPERBLOCK_OFFSET 0x400 + +int volume_id_probe_ext(struct volume_id *id, uint64_t off) +{ + struct ext2_super_block *es; + + dbg("probing at offset 0x%llx", (unsigned long long) off); + + es = volume_id_get_buffer(id, off + EXT_SUPERBLOCK_OFFSET, 0x200); + if (es == NULL) + return -1; + + if (es->magic[0] != 0123 || + es->magic[1] != 0357) + return -1; + + volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); + volume_id_set_label_raw(id, es->volume_name, 16); + volume_id_set_label_string(id, es->volume_name, 16); + volume_id_set_uuid(id, es->uuid, UUID_DCE); + + if ((le32_to_cpu(es->feature_compat) & EXT3_FEATURE_COMPAT_HAS_JOURNAL) != 0) + id->type = "ext3"; + else + id->type = "ext2"; + + return 0; +} diff --git a/util-linux/volume_id/fat.c b/util-linux/volume_id/fat.c new file mode 100644 index 000000000..4c2a91749 --- /dev/null +++ b/util-linux/volume_id/fat.c @@ -0,0 +1,333 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "volume_id_internal.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 + +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]; + } __attribute__((__packed__)) fat; + struct fat32_super_block { + uint32_t fat32_length; + uint16_t flags; + uint8_t version[2]; + uint32_t root_cluster; + uint16_t insfo_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]; + } __attribute__((__packed__)) fat32; + } __attribute__((__packed__)) type; +} __attribute__((__packed__)); + +struct vfat_dir_entry { + uint8_t name[11]; + uint8_t attr; + uint16_t time_creat; + uint16_t date_creat; + uint16_t time_acc; + uint16_t date_acc; + uint16_t cluster_high; + uint16_t time_write; + uint16_t date_write; + uint16_t cluster_low; + uint32_t size; +} __attribute__((__packed__)); + +static uint8_t *get_attr_volume_id(struct vfat_dir_entry *dir, unsigned count) +{ + unsigned i; + + for (i = 0; i < count; i++) { + /* end marker */ + if (dir[i].name[0] == 0x00) { + dbg("end of dir"); + break; + } + + /* empty entry */ + if (dir[i].name[0] == FAT_ENTRY_FREE) + continue; + + /* long name */ + if ((dir[i].attr & FAT_ATTR_MASK) == FAT_ATTR_LONG_NAME) + continue; + + if ((dir[i].attr & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) == FAT_ATTR_VOLUME_ID) { + /* labels do not have file data */ + if (dir[i].cluster_high != 0 || dir[i].cluster_low != 0) + continue; + + dbg("found ATTR_VOLUME_ID id in root dir"); + return dir[i].name; + } + + dbg("skip dir entry"); + } + + return NULL; +} + +int volume_id_probe_vfat(struct volume_id *id, uint64_t off) +{ + struct vfat_super_block *vs; + struct vfat_dir_entry *dir; + 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; + uint32_t fat_length; + uint64_t root_start; + uint32_t start_data_sect; + uint16_t root_dir_entries; + uint8_t *buf; + uint32_t buf_size; + uint8_t *label = NULL; + uint32_t next; + int maxloop; + + dbg("probing at offset 0x%llx", (unsigned long long) off); + + vs = volume_id_get_buffer(id, off, 0x200); + if (vs == NULL) + return -1; + + /* believe only that's fat, don't trust the version + * the cluster_count will tell us + */ + if (memcmp(vs->sysid, "NTFS", 4) == 0) + return -1; + + if (memcmp(vs->type.fat32.magic, "MSWIN", 5) == 0) + goto valid; + + if (memcmp(vs->type.fat32.magic, "FAT32 ", 8) == 0) + goto valid; + + if (memcmp(vs->type.fat.magic, "FAT16 ", 8) == 0) + goto valid; + + if (memcmp(vs->type.fat.magic, "MSDOS", 5) == 0) + goto valid; + + if (memcmp(vs->type.fat.magic, "FAT12 ", 8) == 0) + goto valid; + + /* + * There are old floppies out there without a magic, so we check + * for well known values and guess if it's a fat volume + */ + + /* boot jump address check */ + if ((vs->boot_jump[0] != 0xeb || vs->boot_jump[2] != 0x90) && + vs->boot_jump[0] != 0xe9) + return -1; + + /* heads check */ + if (vs->heads == 0) + return -1; + + /* cluster size check*/ + if (vs->sectors_per_cluster == 0 || + (vs->sectors_per_cluster & (vs->sectors_per_cluster-1))) + return -1; + + /* media check */ + if (vs->media < 0xf8 && vs->media != 0xf0) + return -1; + + /* fat count*/ + if (vs->fats != 2) + return -1; + + valid: + /* sector size check */ + sector_size = le16_to_cpu(vs->sector_size); + if (sector_size != 0x200 && sector_size != 0x400 && + sector_size != 0x800 && sector_size != 0x1000) + 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); + if (fat_length == 0) + fat_length = le32_to_cpu(vs->type.fat32.fat32_length); + dbg("fat_length 0x%x", fat_length); + + fat_size = fat_length * vs->fats; + 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); + + if (cluster_count < FAT12_MAX) { + strcpy(id->type_version, "FAT12"); + } else if (cluster_count < FAT16_MAX) { + strcpy(id->type_version, "FAT16"); + } else { + strcpy(id->type_version, "FAT32"); + 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; + + dir = (struct vfat_dir_entry*) buf; + + label = get_attr_volume_id(dir, root_dir_entries); + + vs = volume_id_get_buffer(id, off, 0x200); + if (vs == NULL) + return -1; + + if (label != NULL && memcmp(label, "NO NAME ", 11) != 0) { + volume_id_set_label_raw(id, label, 11); + volume_id_set_label_string(id, label, 11); + } else if (memcmp(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, UUID_DOS); + goto found; + + 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; + + dir = (struct vfat_dir_entry*) buf; + count = buf_size / sizeof(struct vfat_dir_entry); + dbg("expected entries 0x%x", count); + + label = get_attr_volume_id(dir, count); + if (label) + 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 == 0) + break; + } + if (maxloop == 0) + dbg("reached maximum follow count of root cluster chain, give up"); + + vs = volume_id_get_buffer(id, off, 0x200); + if (vs == NULL) + return -1; + + if (label != NULL && memcmp(label, "NO NAME ", 11) != 0) { + volume_id_set_label_raw(id, label, 11); + volume_id_set_label_string(id, label, 11); + } else if (memcmp(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, UUID_DOS); + + found: + volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); + id->type = "vfat"; + + return 0; +} diff --git a/util-linux/volume_id/get_devname.c b/util-linux/volume_id/get_devname.c new file mode 100644 index 000000000..75060b0d8 --- /dev/null +++ b/util-linux/volume_id/get_devname.c @@ -0,0 +1,399 @@ +/* vi: set sw=4 ts=4: */ +/* + * Support functions for mounting devices by label/uuid + * + * Copyright (C) 2006 by Jason Schoon + * Some portions cribbed from e2fsprogs, util-linux, dosfstools + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +#include "volume_id_internal.h" + +#define BLKGETSIZE64 _IOR(0x12,114,size_t) + +#define PROC_PARTITIONS "/proc/partitions" +#define PROC_CDROMS "/proc/sys/dev/cdrom/info" +#define DEVLABELDIR "/dev" +#define SYS_BLOCK "/sys/block" + +static struct uuidCache_s { + struct uuidCache_s *next; + char uuid[16]; + char *device; + char *label; + int major, minor; +} *uuidCache; + +/* for now, only ext2, ext3 and xfs are supported */ +static int +get_label_uuid(const char *device, char **label, char **uuid, int iso_only) +{ + int rv = 1; + uint64_t size; + struct volume_id *vid; + + vid = volume_id_open_node(device); + + if (ioctl(vid->fd, BLKGETSIZE64, &size) != 0) { + size = 0; + } + +#if ENABLE_FEATURE_VOLUMEID_ISO9660 + if (iso_only ? + volume_id_probe_iso9660(vid, 0) != 0 : + volume_id_probe_all(vid, 0, size) != 0) { + goto ret; + } +#else + if (volume_id_probe_all(vid, 0, size) != 0) { + goto ret; + } +#endif + + if (vid->label[0] != '\0') { + *label = xstrndup(vid->label, sizeof(vid->label)); + *uuid = xstrndup(vid->uuid, sizeof(vid->uuid)); + printf("Found label %s on %s (uuid:%s)\n", *label, device, *uuid); + rv = 0; + } + ret: + free_volume_id(vid); + return rv; +} + +static void +uuidcache_addentry(char * device, int major, int minor, char *label, char *uuid) +{ + struct uuidCache_s *last; + + if (!uuidCache) { + last = uuidCache = xzalloc(sizeof(*uuidCache)); + } else { + for (last = uuidCache; last->next; last = last->next) + continue; + last->next = xzalloc(sizeof(*uuidCache)); + last = last->next; + } + /*last->next = NULL; - xzalloc did it*/ + last->label = label; + last->device = device; + last->major = major; + last->minor = minor; + memcpy(last->uuid, uuid, sizeof(last->uuid)); +} + +static void +uuidcache_check_device(const char *device_name, int ma, int mi, int iso_only) +{ + char device[110]; + char *uuid = NULL, *label = NULL; + char *ptr; + char *deviceDir = NULL; + int mustRemove = 0; + int mustRemoveDir = 0; + int i; + + sprintf(device, "%s/%s", DEVLABELDIR, device_name); + if (access(device, F_OK)) { + ptr = device; + i = 0; + while (*ptr) + if (*ptr++ == '/') + i++; + if (i > 2) { + deviceDir = alloca(strlen(device) + 1); + strcpy(deviceDir, device); + ptr = deviceDir + (strlen(device) - 1); + while (*ptr != '/') + *ptr-- = '\0'; + if (mkdir(deviceDir, 0644)) { + printf("mkdir: cannot create directory %s: %d\n", deviceDir, errno); + } else { + mustRemoveDir = 1; + } + } + + mknod(device, S_IFBLK | 0600, makedev(ma, mi)); + mustRemove = 1; + } + if (!get_label_uuid(device, &label, &uuid, iso_only)) + uuidcache_addentry(strdup(device), ma, mi, + label, uuid); + + if (mustRemove) unlink(device); + if (mustRemoveDir) rmdir(deviceDir); +} + +static void +uuidcache_init_partitions(void) +{ + char line[100]; + int ma, mi; + unsigned long long sz; + FILE *procpt; + int firstPass; + int handleOnFirst; + char *chptr; + + procpt = xfopen(PROC_PARTITIONS, "r"); +/* +# cat /proc/partitions +major minor #blocks name + + 8 0 293036184 sda + 8 1 6835626 sda1 + 8 2 1 sda2 + 8 5 979933 sda5 + 8 6 15623181 sda6 + 8 7 97659103 sda7 + 8 8 171935631 sda8 +*/ + for (firstPass = 1; firstPass >= 0; firstPass--) { + fseek(procpt, 0, SEEK_SET); + + while (fgets(line, sizeof(line), procpt)) { + /* The original version of this code used sscanf, but + diet's sscanf is quite limited */ + chptr = line; + if (*chptr != ' ') continue; + chptr++; + + ma = bb_strtou(chptr, &chptr, 0); + if (ma < 0) continue; + chptr = skip_whitespace(chptr); + + mi = bb_strtou(chptr, &chptr, 0); + if (mi < 0) continue; + chptr = skip_whitespace(chptr); + + sz = bb_strtoull(chptr, &chptr, 0); + if ((long long)sz == -1LL) continue; + chptr = skip_whitespace(chptr); + + /* skip extended partitions (heuristic: size 1) */ + if (sz == 1) + continue; + + *strchrnul(chptr, '\n') = '\0'; + /* now chptr => device name */ + if (!chptr[0]) + continue; + + /* look only at md devices on first pass */ + handleOnFirst = (chptr[0] == 'm' && chptr[1] == 'd'); + if (firstPass != handleOnFirst) + continue; + + /* heuristic: partition name ends in a digit */ + if (isdigit(chptr[strlen(chptr) - 1])) { + uuidcache_check_device(chptr, ma, mi, 0); + } + } + } + + fclose(procpt); +} + +static int +dev_get_major_minor(char *device_name, int *major, int *minor) +{ + char * dev_path; + int fd; + char dev[7]; + char *major_ptr, *minor_ptr; + + dev_path = alloca(strlen(SYS_BLOCK) + strlen(device_name) + 6); + sprintf(dev_path, "%s/%s/dev", SYS_BLOCK, device_name); + + fd = open(dev_path, O_RDONLY); + if (fd < 0) return 1; + full_read(fd, dev, sizeof(dev)); + close(fd); + + major_ptr = dev; + minor_ptr = strchr(dev, ':'); + if (!minor_ptr) return 1; + *minor_ptr++ = '\0'; + + *major = strtol(major_ptr, NULL, 10); + *minor = strtol(minor_ptr, NULL, 10); + + return 0; +} + +static void +uuidcache_init_cdroms(void) +{ + char line[100]; + int ma, mi; + FILE *proccd; + + proccd = fopen(PROC_CDROMS, "r"); + if (!proccd) { + static smallint warn = 0; + if (!warn) { + warn = 1; + bb_error_msg("mount: could not open %s, so UUID and LABEL " + "conversion cannot be done for CD-Roms.", + PROC_CDROMS); + } + return; + } + + while (fgets(line, sizeof(line), proccd)) { + const char *drive_name_string = "drive name:\t\t"; + if (!strncmp(line, drive_name_string, strlen(drive_name_string))) { + char *device_name; + device_name = strtok(line + strlen(drive_name_string), "\t\n"); + while (device_name) { + dev_get_major_minor(device_name, &ma, &mi); + uuidcache_check_device(device_name, ma, mi, 1); + device_name = strtok(NULL, "\t\n"); + } + break; + } + } + + fclose(proccd); +} + +static void +uuidcache_init(void) +{ + if (uuidCache) + return; + + uuidcache_init_partitions(); + uuidcache_init_cdroms(); +} + +#define UUID 1 +#define VOL 2 + +#ifdef UNUSED +static char * +get_spec_by_x(int n, const char *t, int * majorPtr, int * minorPtr) +{ + struct uuidCache_s *uc; + + uuidcache_init(); + uc = uuidCache; + + while(uc) { + switch (n) { + case UUID: + if (!memcmp(t, uc->uuid, sizeof(uc->uuid))) { + *majorPtr = uc->major; + *minorPtr = uc->minor; + return uc->device; + } + break; + case VOL: + if (!strcmp(t, uc->label)) { + *majorPtr = uc->major; + *minorPtr = uc->minor; + return uc->device; + } + break; + } + uc = uc->next; + } + return NULL; +} + +static unsigned char +fromhex(char c) +{ + if (isdigit(c)) + return (c - '0'); + if (islower(c)) + return (c - 'a' + 10); + return (c - 'A' + 10); +} + +static char * +get_spec_by_uuid(const char *s, int * major, int * minor) +{ + unsigned char uuid[16]; + int i; + + if (strlen(s) != 36 || + s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-') + goto bad_uuid; + for (i=0; i<16; i++) { + if (*s == '-') s++; + if (!isxdigit(s[0]) || !isxdigit(s[1])) + goto bad_uuid; + uuid[i] = ((fromhex(s[0])<<4) | fromhex(s[1])); + s += 2; + } + return get_spec_by_x(UUID, (char *)uuid, major, minor); + + bad_uuid: + fprintf(stderr, _("mount: bad UUID")); + return 0; +} + +static char * +get_spec_by_volume_label(const char *s, int *major, int *minor) +{ + return get_spec_by_x(VOL, s, major, minor); +} + +static int display_uuid_cache(void) +{ + struct uuidCache_s *u; + size_t i; + + uuidcache_init(); + + u = uuidCache; + while (u) { + printf("%s %s ", u->device, u->label); + for (i = 0; i < sizeof(u->uuid); i++) { + if (i == 4 || i == 6 || i == 8 || i == 10) + printf("-"); + printf("%x", u->uuid[i] & 0xff); + } + printf("\n"); + u = u->next; + } + + return 0; +} +#endif // UNUSED + + +/* Used by mount and findfs */ + +char *get_devname_from_label(const char *spec) +{ + struct uuidCache_s *uc; + int spec_len = strlen(spec); + + uuidcache_init(); + uc = uuidCache; + while (uc) { + if (uc->label && !strncmp(spec, uc->label, spec_len)) { + return xstrdup(uc->device); + } + uc = uc->next; + } + return NULL; +} + +char *get_devname_from_uuid(const char *spec) +{ + struct uuidCache_s *uc; + + uuidcache_init(); + uc = uuidCache; + while (uc) { + if (!memcmp(spec, uc->uuid, sizeof(uc->uuid))) { + return xstrdup(uc->device); + } + uc = uc->next; + } + return NULL; +} diff --git a/util-linux/volume_id/hfs.c b/util-linux/volume_id/hfs.c new file mode 100644 index 000000000..71a3df0b8 --- /dev/null +++ b/util-linux/volume_id/hfs.c @@ -0,0 +1,292 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "volume_id_internal.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]; +} __attribute__((__packed__)); + +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; +} __attribute__((__packed__)); + +struct hfsplus_bnode_descriptor { + uint32_t next; + uint32_t prev; + uint8_t type; + uint8_t height; + uint16_t num_recs; + uint16_t reserved; +} __attribute__((__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; +} __attribute__((__packed__)); + +struct hfsplus_catalog_key { + uint16_t key_len; + uint32_t parent_id; + uint16_t unicode_len; + uint8_t unicode[255 * 2]; +} __attribute__((__packed__)); + +struct hfsplus_extent { + uint32_t start_block; + uint32_t block_count; +} __attribute__((__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]; +} __attribute__((__packed__)); + +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; +} __attribute__((__packed__)); + +#define HFS_SUPERBLOCK_OFFSET 0x400 +#define HFS_NODE_LEAF 0xff +#define HFSPLUS_POR_CNID 1 + +int volume_id_probe_hfs_hfsplus(struct volume_id *id, uint64_t off) +{ + unsigned blocksize; + unsigned cat_block; + unsigned ext_block_start; + unsigned ext_block_count; + int ext; + unsigned leaf_node_head; + unsigned leaf_node_count; + unsigned leaf_node_size; + unsigned leaf_block; + uint64_t leaf_off; + unsigned alloc_block_size; + unsigned alloc_first_block; + unsigned embed_first_block; + unsigned record_count; + struct hfsplus_vol_header *hfsplus; + struct hfsplus_bnode_descriptor *descr; + struct hfsplus_bheader_record *bnode; + struct hfsplus_catalog_key *key; + unsigned label_len; + struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT]; + struct hfs_mdb *hfs; + const uint8_t *buf; + + dbg("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 (hfs->signature[0] != 'B' || hfs->signature[1] != 'D') + goto checkplus; + + /* it may be just a hfs wrapper for hfs+ */ + if (memcmp(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) ; + } + + volume_id_set_uuid(id, hfs->finder_info.id, UUID_HFS); + + volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); + id->type = "hfs"; + + return 0; + + checkplus: + hfsplus = (struct hfsplus_vol_header *) buf; + if (hfs->signature[0] == 'H') + if (hfs->signature[1] == '+' || hfs->signature[1] == 'X') + goto hfsplus; + return -1; + + hfsplus: + volume_id_set_uuid(id, hfsplus->finder_info.id, UUID_HFS); + + 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 (key->parent_id != cpu_to_be32(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; +} diff --git a/util-linux/volume_id/highpoint.c b/util-linux/volume_id/highpoint.c new file mode 100644 index 000000000..de31a2a26 --- /dev/null +++ b/util-linux/volume_id/highpoint.c @@ -0,0 +1,86 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "volume_id_internal.h" + +struct hpt37x_meta { + uint8_t filler1[32]; + uint32_t magic; +} __attribute__((packed)); + +struct hpt45x_meta { + uint32_t magic; +} __attribute__((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) +{ + struct hpt37x_meta *hpt; + uint32_t magic; + + dbg("probing at offset 0x%llx", (unsigned long long) off); + + hpt = volume_id_get_buffer(id, off + HPT37X_CONFIG_OFF, 0x200); + if (hpt == NULL) + return -1; + + magic = hpt->magic; + if (magic != cpu_to_le32(HPT37X_MAGIC_OK) && magic != cpu_to_le32(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) +{ + 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; + hpt = volume_id_get_buffer(id, off + meta_off, 0x200); + if (hpt == NULL) + return -1; + + magic = hpt->magic; + if (magic != cpu_to_le32(HPT45X_MAGIC_OK) && magic != cpu_to_le32(HPT45X_MAGIC_BAD)) + return -1; + + volume_id_set_usage(id, VOLUME_ID_RAID); + id->type = "highpoint_raid_member"; + + return 0; +} diff --git a/util-linux/volume_id/hpfs.c b/util-linux/volume_id/hpfs.c new file mode 100644 index 000000000..b43fb79b5 --- /dev/null +++ b/util-linux/volume_id/hpfs.c @@ -0,0 +1,50 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2005 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "volume_id_internal.h" + +struct hpfs_super +{ + uint8_t magic[4]; + uint8_t version; +} __attribute__((__packed__)); + +#define HPFS_SUPERBLOCK_OFFSET 0x2000 + +int volume_id_probe_hpfs(struct volume_id *id, uint64_t off) +{ + struct hpfs_super *hs; + + dbg("probing at offset 0x%llx", (unsigned long long) off); + + hs = volume_id_get_buffer(id, off + HPFS_SUPERBLOCK_OFFSET, 0x200); + if (hs == NULL) + return -1; + + if (memcmp(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; +} diff --git a/util-linux/volume_id/iso9660.c b/util-linux/volume_id/iso9660.c new file mode 100644 index 000000000..fa9227746 --- /dev/null +++ b/util-linux/volume_id/iso9660.c @@ -0,0 +1,118 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "volume_id_internal.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 vd_type; + uint8_t vd_id[5]; + uint8_t vd_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]; +} __attribute__((__packed__)); + +struct high_sierra_volume_descriptor { + uint8_t foo[8]; + uint8_t type; + uint8_t id[4]; + uint8_t version; +} __attribute__((__packed__)); + +int volume_id_probe_iso9660(struct volume_id *id, uint64_t off) +{ + uint8_t *buf; + struct iso_volume_descriptor *is; + struct high_sierra_volume_descriptor *hs; + + dbg("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(is->vd_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 = volume_id_get_buffer(id, off + vd_offset, 0x200); + if (is == NULL || is->vd_type == ISO_VD_END) + break; + if (is->vd_type != ISO_VD_SUPPLEMENTARY) + continue; + + dbg("found SVD at offset 0x%llx", (unsigned long long) (off + vd_offset)); + if (memcmp(is->escape_sequences, "%/@", 3) == 0|| + memcmp(is->escape_sequences, "%/C", 3) == 0|| + memcmp(is->escape_sequences, "%/E", 3) == 0) { + dbg("Joliet extension found"); + volume_id_set_unicode16((char *)svd_label, sizeof(svd_label), is->volume_id, BE, 32); + if (memcmp(id->label, 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(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; +} diff --git a/util-linux/volume_id/isw_raid.c b/util-linux/volume_id/isw_raid.c new file mode 100644 index 000000000..8f55f49d9 --- /dev/null +++ b/util-linux/volume_id/isw_raid.c @@ -0,0 +1,58 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2005 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "volume_id_internal.h" + +struct isw_meta { + uint8_t sig[32]; + uint32_t check_sum; + uint32_t mpb_size; + uint32_t family_num; + uint32_t generation_num; +} __attribute__((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) +{ + uint64_t meta_off; + struct isw_meta *isw; + + 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)-2) * 0x200; + isw = volume_id_get_buffer(id, off + meta_off, 0x200); + if (isw == NULL) + return -1; + + if (memcmp(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; +} diff --git a/util-linux/volume_id/jfs.c b/util-linux/volume_id/jfs.c new file mode 100644 index 000000000..28b4eb694 --- /dev/null +++ b/util-linux/volume_id/jfs.c @@ -0,0 +1,59 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "volume_id_internal.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]; +} __attribute__((__packed__)); + +#define JFS_SUPERBLOCK_OFFSET 0x8000 + +int volume_id_probe_jfs(struct volume_id *id, uint64_t off) +{ + struct jfs_super_block *js; + + dbg("probing at offset 0x%llx", (unsigned long long) off); + + js = volume_id_get_buffer(id, off + JFS_SUPERBLOCK_OFFSET, 0x200); + if (js == NULL) + return -1; + + if (memcmp(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, UUID_DCE); + + volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); + id->type = "jfs"; + + return 0; +} diff --git a/util-linux/volume_id/linux_raid.c b/util-linux/volume_id/linux_raid.c new file mode 100644 index 000000000..bb9b3c5cf --- /dev/null +++ b/util-linux/volume_id/linux_raid.c @@ -0,0 +1,79 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "volume_id_internal.h" + +struct mdp_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; +} __attribute__((packed)); + +#define MD_RESERVED_BYTES 0x10000 +#define MD_MAGIC 0xa92b4efc + +int volume_id_probe_linux_raid(struct volume_id *id, uint64_t off, uint64_t size) +{ + uint64_t sboff; + uint8_t uuid[16]; + struct mdp_super_block *mdp; + + dbg("probing at offset 0x%llx, size 0x%llx", + (unsigned long long) off, (unsigned long long) size); + + if (size < 0x10000) + return -1; + + sboff = (size & ~(MD_RESERVED_BYTES - 1)) - MD_RESERVED_BYTES; + mdp = volume_id_get_buffer(id, off + sboff, 0x800); + if (mdp == NULL) + return -1; + + if (mdp->md_magic != cpu_to_le32(MD_MAGIC)) + return -1; + + memcpy(uuid, &mdp->set_uuid0, 4); + memcpy(&uuid[4], &mdp->set_uuid1, 12); + volume_id_set_uuid(id, uuid, UUID_DCE); + + snprintf(id->type_version, sizeof(id->type_version)-1, "%u.%u.%u", + le32_to_cpu(mdp->major_version), + le32_to_cpu(mdp->minor_version), + le32_to_cpu(mdp->patch_version)); + + dbg("found raid signature"); + volume_id_set_usage(id, VOLUME_ID_RAID); + id->type = "linux_raid_member"; + + return 0; +} diff --git a/util-linux/volume_id/linux_swap.c b/util-linux/volume_id/linux_swap.c new file mode 100644 index 000000000..56b5d5085 --- /dev/null +++ b/util-linux/volume_id/linux_swap.c @@ -0,0 +1,73 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "volume_id_internal.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]; +} __attribute__((__packed__)); + +#define LARGEST_PAGESIZE 0x4000 + +int volume_id_probe_linux_swap(struct volume_id *id, uint64_t off) +{ + struct swap_header_v1_2 *sw; + const uint8_t *buf; + unsigned page; + + dbg("probing at offset 0x%llx", (unsigned long long) off); + + /* 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(buf, "SWAP-SPACE", 10) == 0) { + id->type_version[0] = '1'; + id->type_version[1] = '\0'; + goto found; + } + + if (memcmp(buf, "SWAPSPACE2", 10) == 0) { + sw = volume_id_get_buffer(id, off, sizeof(struct swap_header_v1_2)); + if (sw == NULL) + return -1; + id->type_version[0] = '2'; + id->type_version[1] = '\0'; + 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, UUID_DCE); + goto found; + } + } + return -1; + +found: + volume_id_set_usage(id, VOLUME_ID_OTHER); + id->type = "swap"; + + return 0; +} diff --git a/util-linux/volume_id/lsi_raid.c b/util-linux/volume_id/lsi_raid.c new file mode 100644 index 000000000..0eab1c709 --- /dev/null +++ b/util-linux/volume_id/lsi_raid.c @@ -0,0 +1,52 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2005 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "volume_id_internal.h" + +struct lsi_meta { + uint8_t sig[6]; +} __attribute__((packed)); + +#define LSI_SIGNATURE "$XIDE$" + +int volume_id_probe_lsi_mega_raid(struct volume_id *id, uint64_t off, uint64_t size) +{ + uint64_t meta_off; + struct lsi_meta *lsi; + + 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; + lsi = volume_id_get_buffer(id, off + meta_off, 0x200); + if (lsi == NULL) + return -1; + + if (memcmp(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; +} diff --git a/util-linux/volume_id/luks.c b/util-linux/volume_id/luks.c new file mode 100644 index 000000000..e73ce3a03 --- /dev/null +++ b/util-linux/volume_id/luks.c @@ -0,0 +1,76 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2005 W. Michael Petullo + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "volume_id_internal.h" + +#define SECTOR_SHIFT 9 +#define SECTOR_SIZE (1 << 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 + +static const uint8_t LUKS_MAGIC[] = { 'L','U','K','S', 0xba, 0xbe }; +#define LUKS_MAGIC_L 6 +#define LUKS_PHDR_SIZE (sizeof(struct luks_phdr)/SECTOR_SIZE+1) +#define UUID_STRING_L 40 + +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) +{ + struct luks_phdr *header; + + header = volume_id_get_buffer(id, off, LUKS_PHDR_SIZE); + if (header == NULL) + return -1; + + if (memcmp(header->magic, LUKS_MAGIC, LUKS_MAGIC_L)) + return -1; + + volume_id_set_usage(id, VOLUME_ID_CRYPTO); + volume_id_set_uuid(id, header->uuid, UUID_DCE_STRING); + + id->type = "crypto_LUKS"; + + return 0; +} diff --git a/util-linux/volume_id/lvm.c b/util-linux/volume_id/lvm.c new file mode 100644 index 000000000..baa8456db --- /dev/null +++ b/util-linux/volume_id/lvm.c @@ -0,0 +1,91 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "volume_id_internal.h" + +struct lvm1_super_block { + uint8_t id[2]; +} __attribute__((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]; +} __attribute__((packed)); + +#define LVM1_SB_OFF 0x400 +#define LVM1_MAGIC "HM" + +int volume_id_probe_lvm1(struct volume_id *id, uint64_t off) +{ + const uint8_t *buf; + struct lvm1_super_block *lvm; + + dbg("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(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) +{ + const uint8_t *buf; + unsigned 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(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; +} diff --git a/util-linux/volume_id/mac.c b/util-linux/volume_id/mac.c new file mode 100644 index 000000000..94a99bee0 --- /dev/null +++ b/util-linux/volume_id/mac.c @@ -0,0 +1,125 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "volume_id_internal.h" + +struct mac_driver_desc { + uint8_t signature[2]; + uint16_t block_size; + uint32_t block_count; +} __attribute__((__packed__)); + +struct mac_partition { + uint8_t signature[2]; + uint16_t res1; + uint32_t map_count; + uint32_t start_block; + uint32_t block_count; + uint8_t name[32]; + uint8_t type[32]; +} __attribute__((__packed__)); + +int volume_id_probe_mac_partition_map(struct volume_id *id, uint64_t off) +{ + const uint8_t *buf; + struct mac_driver_desc *driver; + struct mac_partition *part; + + dbg("probing at offset 0x%llx", (unsigned long long) off); + + buf = volume_id_get_buffer(id, off, 0x200); + if (buf == NULL) + return -1; + + part = (struct mac_partition *) buf; + if ((memcmp(part->signature, "PM", 2) == 0) && + (memcmp(part->type, "Apple_partition_map", 19) == 0)) { + /* linux creates an own subdevice for the map + * just return the type if the drive header is missing */ + volume_id_set_usage(id, VOLUME_ID_PARTITIONTABLE); + id->type = "mac_partition_map"; + return 0; + } + + driver = (struct mac_driver_desc *) buf; + if (memcmp(driver->signature, "ER", 2) == 0) { + /* we are on a main device, like a CD + * just try to probe the first partition from the map */ + unsigned bsize = be16_to_cpu(driver->block_size); + int part_count; + int i; + + /* get first entry of partition table */ + buf = volume_id_get_buffer(id, off + bsize, 0x200); + if (buf == NULL) + return -1; + + part = (struct mac_partition *) buf; + if (memcmp(part->signature, "PM", 2) != 0) + return -1; + + part_count = be32_to_cpu(part->map_count); + dbg("expecting %d partition entries", part_count); + + if (id->partitions != NULL) + free(id->partitions); + id->partitions = + malloc(part_count * sizeof(struct volume_id_partition)); + if (id->partitions == NULL) + return -1; + memset(id->partitions, 0x00, sizeof(struct volume_id_partition)); + + id->partition_count = part_count; + + for (i = 0; i < part_count; i++) { + uint64_t poff; + uint64_t plen; + + buf = volume_id_get_buffer(id, off + ((i+1) * bsize), 0x200); + if (buf == NULL) + return -1; + + part = (struct mac_partition *) buf; + if (memcmp(part->signature, "PM", 2) != 0) + return -1; + + poff = be32_to_cpu(part->start_block) * bsize; + plen = be32_to_cpu(part->block_count) * bsize; + dbg("found '%s' partition entry at 0x%llx, len 0x%llx", + part->type, (unsigned long long) poff, (unsigned long long) plen); + + id->partitions[i].off = poff; + id->partitions[i].len = plen; + + if (memcmp(part->type, "Apple_Free", 10) == 0) { + volume_id_set_usage_part(&id->partitions[i], VOLUME_ID_UNUSED); + } else if (memcmp(part->type, "Apple_partition_map", 19) == 0) { + volume_id_set_usage_part(&id->partitions[i], VOLUME_ID_PARTITIONTABLE); + } else { + volume_id_set_usage_part(&id->partitions[i], VOLUME_ID_UNPROBED); + } + } + volume_id_set_usage(id, VOLUME_ID_PARTITIONTABLE); + id->type = "mac_partition_map"; + return 0; + } + + return -1; +} diff --git a/util-linux/volume_id/minix.c b/util-linux/volume_id/minix.c new file mode 100644 index 000000000..ede23cb24 --- /dev/null +++ b/util-linux/volume_id/minix.c @@ -0,0 +1,76 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2005 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "volume_id_internal.h" + +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; +} __attribute__((__packed__)); + +#define MINIX_SUPERBLOCK_OFFSET 0x400 + +int volume_id_probe_minix(struct volume_id *id, uint64_t off) +{ + struct minix_super_block *ms; + + dbg("probing at offset 0x%llx", (unsigned long long) off); + + ms = volume_id_get_buffer(id, off + MINIX_SUPERBLOCK_OFFSET, 0x200); + if (ms == NULL) + return -1; + + if (le16_to_cpu(ms->s_magic) == 0x137f) { + id->type_version[0] = '1'; + goto found; + } + + if (le16_to_cpu(ms->s_magic) == 0x1387) { + id->type_version[0] = '1'; + goto found; + } + + if (le16_to_cpu(ms->s_magic) == 0x2468) { + id->type_version[0] = '2'; + goto found; + } + + if (le16_to_cpu(ms->s_magic) == 0x2478) { + id->type_version[0] = '2'; + goto found; + } + + return -1; + + found: + id->type_version[1] = '\0'; + volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); + id->type = "minix"; + return 0; +} diff --git a/util-linux/volume_id/msdos.c b/util-linux/volume_id/msdos.c new file mode 100644 index 000000000..b4b6711dc --- /dev/null +++ b/util-linux/volume_id/msdos.c @@ -0,0 +1,196 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "volume_id_internal.h" + +struct msdos_partition_entry { + uint8_t boot_ind; + uint8_t head; + uint8_t sector; + uint8_t cyl; + uint8_t sys_ind; + uint8_t end_head; + uint8_t end_sector; + uint8_t end_cyl; + uint32_t start_sect; + uint32_t nr_sects; +} __attribute__((packed)); + +#define MSDOS_MAGIC "\x55\xaa" +#define MSDOS_PARTTABLE_OFFSET 0x1be +#define MSDOS_SIG_OFF 0x1fe +#define BSIZE 0x200 +#define DOS_EXTENDED_PARTITION 0x05 +#define LINUX_EXTENDED_PARTITION 0x85 +#define WIN98_EXTENDED_PARTITION 0x0f +#define LINUX_RAID_PARTITION 0xfd +#define is_extended(type) \ + (type == DOS_EXTENDED_PARTITION || \ + type == WIN98_EXTENDED_PARTITION || \ + type == LINUX_EXTENDED_PARTITION) +#define is_raid(type) \ + (type == LINUX_RAID_PARTITION) + +int volume_id_probe_msdos_part_table(struct volume_id *id, uint64_t off) +{ + const uint8_t *buf; + int i; + uint64_t poff; + uint64_t plen; + uint64_t extended = 0; + uint64_t current; + uint64_t next; + int limit; + int empty = 1; + struct msdos_partition_entry *part; + struct volume_id_partition *p; + + dbg("probing at offset 0x%llx", (unsigned long long) off); + + buf = volume_id_get_buffer(id, off, 0x200); + if (buf == NULL) + return -1; + + if (memcmp(&buf[MSDOS_SIG_OFF], MSDOS_MAGIC, 2) != 0) + return -1; + + /* check flags on all entries for a valid partition table */ + part = (struct msdos_partition_entry*) &buf[MSDOS_PARTTABLE_OFFSET]; + for (i = 0; i < 4; i++) { + if (part[i].boot_ind != 0 && + part[i].boot_ind != 0x80) + return -1; + + if (part[i].nr_sects != 0) + empty = 0; + } + if (empty == 1) + return -1; + + if (id->partitions != NULL) + free(id->partitions); + id->partitions = malloc(VOLUME_ID_PARTITIONS_MAX * + sizeof(struct volume_id_partition)); + if (id->partitions == NULL) + return -1; + memset(id->partitions, 0x00, + VOLUME_ID_PARTITIONS_MAX * sizeof(struct volume_id_partition)); + + for (i = 0; i < 4; i++) { + poff = (uint64_t) le32_to_cpu(part[i].start_sect) * BSIZE; + plen = (uint64_t) le32_to_cpu(part[i].nr_sects) * BSIZE; + + if (plen == 0) + continue; + + p = &id->partitions[i]; + + p->partition_type_raw = part[i].sys_ind; + + if (is_extended(part[i].sys_ind)) { + dbg("found extended partition at 0x%llx", (unsigned long long) poff); + volume_id_set_usage_part(p, VOLUME_ID_PARTITIONTABLE); + p->type = "msdos_extended_partition"; + if (extended == 0) + extended = off + poff; + } else { + dbg("found 0x%x data partition at 0x%llx, len 0x%llx", + part[i].sys_ind, (unsigned long long) poff, (unsigned long long) plen); + + if (is_raid(part[i].sys_ind)) + volume_id_set_usage_part(p, VOLUME_ID_RAID); + else + volume_id_set_usage_part(p, VOLUME_ID_UNPROBED); + } + + p->off = off + poff; + p->len = plen; + id->partition_count = i+1; + } + + next = extended; + current = extended; + limit = 50; + + /* follow extended partition chain and add data partitions */ + while (next != 0) { + if (limit-- == 0) { + dbg("extended chain limit reached"); + break; + } + + buf = volume_id_get_buffer(id, current, 0x200); + if (buf == NULL) + break; + + part = (struct msdos_partition_entry*) &buf[MSDOS_PARTTABLE_OFFSET]; + + if (memcmp(&buf[MSDOS_SIG_OFF], MSDOS_MAGIC, 2) != 0) + break; + + next = 0; + + for (i = 0; i < 4; i++) { + poff = (uint64_t) le32_to_cpu(part[i].start_sect) * BSIZE; + plen = (uint64_t) le32_to_cpu(part[i].nr_sects) * BSIZE; + + if (plen == 0) + continue; + + if (is_extended(part[i].sys_ind)) { + dbg("found extended partition at 0x%llx", (unsigned long long) poff); + if (next == 0) + next = extended + poff; + } else { + dbg("found 0x%x data partition at 0x%llx, len 0x%llx", + part[i].sys_ind, (unsigned long long) poff, (unsigned long long) plen); + + /* we always start at the 5th entry */ + while (id->partition_count < 4) + volume_id_set_usage_part(&id->partitions[id->partition_count++], VOLUME_ID_UNUSED); + + p = &id->partitions[id->partition_count]; + + if (is_raid(part[i].sys_ind)) + volume_id_set_usage_part(p, VOLUME_ID_RAID); + else + volume_id_set_usage_part(p, VOLUME_ID_UNPROBED); + + p->off = current + poff; + p->len = plen; + id->partition_count++; + + p->partition_type_raw = part[i].sys_ind; + + if (id->partition_count >= VOLUME_ID_PARTITIONS_MAX) { + dbg("too many partitions"); + next = 0; + } + } + } + + current = next; + } + + volume_id_set_usage(id, VOLUME_ID_PARTITIONTABLE); + id->type = "msdos_partition_table"; + + return 0; +} diff --git a/util-linux/volume_id/ntfs.c b/util-linux/volume_id/ntfs.c new file mode 100644 index 000000000..cbd5d5bba --- /dev/null +++ b/util-linux/volume_id/ntfs.c @@ -0,0 +1,193 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "volume_id_internal.h" + +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; +} __attribute__((__packed__)); + +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; +} __attribute__((__packed__)); + +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; +} __attribute__((__packed__)); + +struct volume_info { + uint64_t reserved; + uint8_t major_ver; + uint8_t minor_ver; +} __attribute__((__packed__)); + +#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 + +int volume_id_probe_ntfs(struct volume_id *id, uint64_t off) +{ + unsigned sector_size; + unsigned cluster_size; + uint64_t mft_cluster; + uint64_t mft_off; + unsigned mft_record_size; + unsigned attr_type; + unsigned attr_off; + unsigned attr_len; + unsigned val_off; + unsigned val_len; + struct master_file_table_record *mftr; + struct ntfs_super_block *ns; + const uint8_t *buf; + const uint8_t *val; + + dbg("probing at offset 0x%llx", (unsigned long long) off); + + ns = volume_id_get_buffer(id, off, 0x200); + if (ns == NULL) + return -1; + + if (memcmp(ns->oem_id, "NTFS", 4) != 0) + return -1; + + volume_id_set_uuid(id, ns->volume_serial, UUID_NTFS); + + sector_size = le16_to_cpu(ns->bytes_per_sector); + 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) + goto found; + + 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(mftr->magic, "FILE", 4) != 0) + goto found; + + attr_off = le16_to_cpu(mftr->attrs_offset); + dbg("file $Volume's attributes are at offset %i", attr_off); + + while (1) { + struct file_attribute *attr; + + 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) { + struct volume_info *info; + dbg("found info, len %i", val_len); + info = (struct volume_info*) (((uint8_t *) attr) + val_off); + snprintf(id->type_version, sizeof(id->type_version)-1, + "%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); + } + } + + found: + volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); + id->type = "ntfs"; + + return 0; +} diff --git a/util-linux/volume_id/nvidia_raid.c b/util-linux/volume_id/nvidia_raid.c new file mode 100644 index 000000000..8619565c9 --- /dev/null +++ b/util-linux/volume_id/nvidia_raid.c @@ -0,0 +1,56 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2005 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "volume_id_internal.h" + +struct nvidia_meta { + uint8_t vendor[8]; + uint32_t size; + uint32_t chksum; + uint16_t version; +} __attribute__((packed)); + +#define NVIDIA_SIGNATURE "NVIDIA" + +int volume_id_probe_nvidia_raid(struct volume_id *id, uint64_t off, uint64_t size) +{ + uint64_t meta_off; + struct nvidia_meta *nv; + + 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)-2) * 0x200; + nv = volume_id_get_buffer(id, off + meta_off, 0x200); + if (nv == NULL) + return -1; + + if (memcmp(nv->vendor, NVIDIA_SIGNATURE, sizeof(NVIDIA_SIGNATURE)-1) != 0) + return -1; + + volume_id_set_usage(id, VOLUME_ID_RAID); + snprintf(id->type_version, sizeof(id->type_version)-1, "%u", le16_to_cpu(nv->version)); + id->type = "nvidia_raid_member"; + + return 0; +} diff --git a/util-linux/volume_id/ocfs2.c b/util-linux/volume_id/ocfs2.c new file mode 100644 index 000000000..bc490df57 --- /dev/null +++ b/util-linux/volume_id/ocfs2.c @@ -0,0 +1,105 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) Andre Masella + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "volume_id_internal.h" + +/* All these values are taken from ocfs2-tools's ocfs2_fs.h */ +#define OCFS2_VOL_UUID_LEN 16 +#define OCFS2_MAX_VOL_LABEL_LEN 64 +#define OCFS2_SUPERBLOCK_OFFSET 0x2000 + + +/* This is the superblock. The OCFS2 header files have structs in structs. +This is one has been simplified since we only care about the superblock. +*/ + +struct ocfs2_super_block { + uint8_t i_signature[8]; /* Signature for validation */ + uint32_t i_generation; /* Generation number */ + int16_t i_suballoc_slot; /* Slot suballocator this inode belongs to */ + uint16_t i_suballoc_bit; /* Bit offset in suballocator block group */ + uint32_t i_reserved0; + uint32_t i_clusters; /* Cluster count */ + uint32_t i_uid; /* Owner UID */ + uint32_t i_gid; /* Owning GID */ + uint64_t i_size; /* Size in bytes */ + uint16_t i_mode; /* File mode */ + uint16_t i_links_count; /* Links count */ + uint32_t i_flags; /* File flags */ + uint64_t i_atime; /* Access time */ + uint64_t i_ctime; /* Creation time */ + uint64_t i_mtime; /* Modification time */ + uint64_t i_dtime; /* Deletion time */ + uint64_t i_blkno; /* Offset on disk, in blocks */ + uint64_t i_last_eb_blk; /* Pointer to last extent block */ + uint32_t i_fs_generation; /* Generation per fs-instance */ + uint32_t i_atime_nsec; + uint32_t i_ctime_nsec; + uint32_t i_mtime_nsec; + uint64_t i_reserved1[9]; + uint64_t i_pad1; /* Generic way to refer to this 64bit union */ + /* Normally there is a union of the different block types, but we only care about the superblock. */ + 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; /* File system state */ + uint16_t s_errors; /* Behaviour when detecting errors */ + uint32_t s_checkinterval; /* Max time between checks */ + uint64_t s_lastcheck; /* Time of last check */ + uint32_t s_creator_os; /* OS */ + uint32_t s_feature_compat; /* Compatible feature set */ + uint32_t s_feature_incompat; /* Incompatible feature set */ + uint32_t s_feature_ro_compat; /* Readonly-compatible feature set */ + uint64_t s_root_blkno; /* Offset, in blocks, of root directory dinode */ + uint64_t s_system_dir_blkno; /* Offset, in blocks, of system directory dinode */ + uint32_t s_blocksize_bits; /* Blocksize for this fs */ + uint32_t s_clustersize_bits; /* Clustersize for this fs */ + uint16_t s_max_slots; /* Max number of simultaneous mounts before tunefs required */ + uint16_t s_reserved1; + uint32_t s_reserved2; + uint64_t s_first_cluster_group; /* Block offset of 1st cluster group header */ + uint8_t s_label[OCFS2_MAX_VOL_LABEL_LEN]; /* Label for mounting, etc. */ + uint8_t s_uuid[OCFS2_VOL_UUID_LEN]; /* 128-bit uuid */ +} __attribute__((__packed__)); + +int volume_id_probe_ocfs2(struct volume_id *id, uint64_t off) +{ + struct ocfs2_super_block *os; + + dbg("probing at offset 0x%llx", (unsigned long long) off); + + os = volume_id_get_buffer(id, off + OCFS2_SUPERBLOCK_OFFSET, 0x200); + if (os == NULL) + return -1; + + if (memcmp(os->i_signature, "OCFSV2", 6) != 0) { + return -1; + } + + volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); + volume_id_set_label_raw(id, os->s_label, OCFS2_MAX_VOL_LABEL_LEN < VOLUME_ID_LABEL_SIZE ? + OCFS2_MAX_VOL_LABEL_LEN : VOLUME_ID_LABEL_SIZE); + volume_id_set_label_string(id, os->s_label, OCFS2_MAX_VOL_LABEL_LEN < VOLUME_ID_LABEL_SIZE ? + OCFS2_MAX_VOL_LABEL_LEN : VOLUME_ID_LABEL_SIZE); + volume_id_set_uuid(id, os->s_uuid, UUID_DCE); + id->type = "ocfs2"; + return 0; +} diff --git a/util-linux/volume_id/promise_raid.c b/util-linux/volume_id/promise_raid.c new file mode 100644 index 000000000..9195c637b --- /dev/null +++ b/util-linux/volume_id/promise_raid.c @@ -0,0 +1,63 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2005 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "volume_id_internal.h" + +struct promise_meta { + uint8_t sig[24]; +} __attribute__((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) +{ + static const unsigned short sectors[] = { + 63, 255, 256, 16, 399 + }; + + struct promise_meta *pdc; + unsigned i; + + dbg("probing at offset 0x%llx, size 0x%llx", + (unsigned long long) off, (unsigned long long) size); + + if (size < 0x40000) + return -1; + + for (i = 0; i < ARRAY_SIZE(sectors); i++) { + uint64_t meta_off; + + meta_off = ((size / 0x200) - sectors[i]) * 0x200; + pdc = volume_id_get_buffer(id, off + meta_off, 0x200); + if (pdc == NULL) + return -1; + + if (memcmp(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; +} diff --git a/util-linux/volume_id/reiserfs.c b/util-linux/volume_id/reiserfs.c new file mode 100644 index 000000000..98ecec23a --- /dev/null +++ b/util-linux/volume_id/reiserfs.c @@ -0,0 +1,105 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * Copyright (C) 2005 Tobias Klauser + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "volume_id_internal.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]; +} __attribute__((__packed__)); + +struct reiser4_super_block { + uint8_t magic[16]; + uint16_t dummy[2]; + uint8_t uuid[16]; + uint8_t label[16]; + uint64_t dummy2; +} __attribute__((__packed__)); + +#define REISERFS1_SUPERBLOCK_OFFSET 0x2000 +#define REISERFS_SUPERBLOCK_OFFSET 0x10000 + +int volume_id_probe_reiserfs(struct volume_id *id, uint64_t off) +{ + struct reiserfs_super_block *rs; + struct reiser4_super_block *rs4; + + dbg("probing at offset 0x%llx", (unsigned long long) off); + + rs = volume_id_get_buffer(id, off + REISERFS_SUPERBLOCK_OFFSET, 0x200); + if (rs == NULL) + return -1; + + if (memcmp(rs->magic, "ReIsErFs", 8) == 0) { + strcpy(id->type_version, "3.5"); + goto found; + } + if (memcmp(rs->magic, "ReIsEr2Fs", 9) == 0) { + strcpy(id->type_version, "3.6"); + goto found_label; + } + if (memcmp(rs->magic, "ReIsEr3Fs", 9) == 0) { + strcpy(id->type_version, "JR"); + goto found_label; + } + + rs4 = (struct reiser4_super_block *) rs; + if (memcmp(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, UUID_DCE); + goto found; + } + + rs = volume_id_get_buffer(id, off + REISERFS1_SUPERBLOCK_OFFSET, 0x200); + if (rs == NULL) + return -1; + + if (memcmp(rs->magic, "ReIsErFs", 8) == 0) { + strcpy(id->type_version, "3.5"); + 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, UUID_DCE); + + found: + volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); + id->type = "reiserfs"; + + return 0; +} diff --git a/util-linux/volume_id/romfs.c b/util-linux/volume_id/romfs.c new file mode 100644 index 000000000..7c4fc0f70 --- /dev/null +++ b/util-linux/volume_id/romfs.c @@ -0,0 +1,54 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "volume_id_internal.h" + +struct romfs_super { + uint8_t magic[8]; + uint32_t size; + uint32_t checksum; + uint8_t name[0]; +} __attribute__((__packed__)); + +int volume_id_probe_romfs(struct volume_id *id, uint64_t off) +{ + struct romfs_super *rfs; + + dbg("probing at offset 0x%llx", (unsigned long long) off); + + rfs = volume_id_get_buffer(id, off, 0x200); + if (rfs == NULL) + return -1; + + if (memcmp(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; +} diff --git a/util-linux/volume_id/silicon_raid.c b/util-linux/volume_id/silicon_raid.c new file mode 100644 index 000000000..ea001745f --- /dev/null +++ b/util-linux/volume_id/silicon_raid.c @@ -0,0 +1,69 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2005 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "volume_id_internal.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; +} __attribute__((packed)); + +#define SILICON_MAGIC 0x2F000000 + +int volume_id_probe_silicon_medley_raid(struct volume_id *id, uint64_t off, uint64_t size) +{ + uint64_t meta_off; + struct silicon_meta *sil; + + 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; + sil = volume_id_get_buffer(id, off + meta_off, 0x200); + if (sil == NULL) + return -1; + + if (sil->magic != cpu_to_le32(SILICON_MAGIC)) + return -1; + + volume_id_set_usage(id, VOLUME_ID_RAID); + snprintf(id->type_version, sizeof(id->type_version)-1, "%u.%u", + le16_to_cpu(sil->major_ver), le16_to_cpu(sil->minor_ver)); + id->type = "silicon_medley_raid_member"; + + return 0; +} diff --git a/util-linux/volume_id/sysv.c b/util-linux/volume_id/sysv.c new file mode 100644 index 000000000..71c0fd496 --- /dev/null +++ b/util-linux/volume_id/sysv.c @@ -0,0 +1,125 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2005 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "volume_id_internal.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; +} __attribute__((__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; +} __attribute__((__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) +{ + struct sysv_super *vs; + struct xenix_super *xs; + unsigned boff; + + dbg("probing at offset 0x%llx", (unsigned long long) off); + + for (boff = 0x200; boff <= SYSV_MAX_BLOCKSIZE; boff <<= 1) { + vs = 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 = 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; +} diff --git a/util-linux/volume_id/udf.c b/util-linux/volume_id/udf.c new file mode 100644 index 000000000..5cdb49c31 --- /dev/null +++ b/util-linux/volume_id/udf.c @@ -0,0 +1,172 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "volume_id_internal.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; + } __attribute__((__packed__)) tag; + union { + struct anchor_descriptor { + uint32_t length; + uint32_t location; + } __attribute__((__packed__)) anchor; + struct primary_descriptor { + uint32_t seq_num; + uint32_t desc_num; + struct dstring { + uint8_t clen; + uint8_t c[31]; + } __attribute__((__packed__)) ident; + } __attribute__((__packed__)) primary; + } __attribute__((__packed__)) type; +} __attribute__((__packed__)); + +struct volume_structure_descriptor { + uint8_t type; + uint8_t id[5]; + uint8_t version; +} __attribute__((__packed__)); + +#define UDF_VSD_OFFSET 0x8000 + +int volume_id_probe_udf(struct volume_id *id, uint64_t off) +{ + struct volume_descriptor *vd; + struct volume_structure_descriptor *vsd; + unsigned bs; + unsigned b; + unsigned type; + unsigned count; + unsigned loc; + unsigned clen; + + dbg("probing at offset 0x%llx", (unsigned long long) off); + + vsd = volume_id_get_buffer(id, off + UDF_VSD_OFFSET, 0x200); + if (vsd == NULL) + return -1; + + if (memcmp(vsd->id, "NSR02", 5) == 0) + goto blocksize; + if (memcmp(vsd->id, "NSR03", 5) == 0) + goto blocksize; + if (memcmp(vsd->id, "BEA01", 5) == 0) + goto blocksize; + if (memcmp(vsd->id, "BOOT2", 5) == 0) + goto blocksize; + if (memcmp(vsd->id, "CD001", 5) == 0) + goto blocksize; + if (memcmp(vsd->id, "CDW02", 5) == 0) + goto blocksize; + if (memcmp(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 = 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 = 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(vsd->id, "NSR02", 5) == 0) + goto anchor; + if (memcmp(vsd->id, "NSR03", 5) == 0) + goto anchor; + } + return -1; + +anchor: + /* read anchor volume descriptor */ + vd = 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 = 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; +} diff --git a/util-linux/volume_id/ufs.c b/util-linux/volume_id/ufs.c new file mode 100644 index 000000000..768670e9d --- /dev/null +++ b/util-linux/volume_id/ufs.c @@ -0,0 +1,206 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "volume_id_internal.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; + } __attribute__((__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]; + } __attribute__((__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]; + } __attribute__((__packed__)) fs_cstotal; + struct ufs_timeval { + int32_t tv_sec; + int32_t tv_usec; + } __attribute__((__packed__)) fs_time; + int64_t fs_size; + int64_t fs_dsize; + uint64_t fs_csaddr; + int64_t fs_pendingblocks; + int32_t fs_pendinginodes; + } __attribute__((__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]; + } __attribute__((__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]; + } __attribute__((__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; + } __attribute__((__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]; +} __attribute__((__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) +{ + static const short offsets[] = { 0, 8, 64, 256 }; + + uint32_t magic; + int i; + struct ufs_super_block *ufs; + + dbg("probing at offset 0x%llx", (unsigned long long) off); + + for (i = 0; i < ARRAY_SIZE(offsets); i++) { + ufs = volume_id_get_buffer(id, off + (offsets[i] * 0x400), 0x800); + if (ufs == NULL) + return -1; + + dbg("offset 0x%x", offsets[i] * 0x400); + magic = ufs->fs_magic; + if ((magic == cpu_to_be32(UFS_MAGIC)) + || (magic == cpu_to_be32(UFS2_MAGIC)) + || (magic == cpu_to_be32(UFS_MAGIC_FEA)) + || (magic == cpu_to_be32(UFS_MAGIC_LFN)) + ) { + dbg("magic 0x%08x(be)", magic); + goto found; + } + if ((magic == cpu_to_le32(UFS_MAGIC)) + || (magic == cpu_to_le32(UFS2_MAGIC)) + || (magic == cpu_to_le32(UFS_MAGIC_FEA)) + || (magic == cpu_to_le32(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"; + + return 0; +} diff --git a/util-linux/volume_id/util.c b/util-linux/volume_id/util.c new file mode 100644 index 000000000..d2265c249 --- /dev/null +++ b/util-linux/volume_id/util.c @@ -0,0 +1,260 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2005 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "volume_id_internal.h" + +void volume_id_set_unicode16(char *str, size_t len, const uint8_t *buf, enum endian endianess, size_t count) +{ + unsigned 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'; +} + +static const char *usage_to_string(enum volume_id_usage usage_id) +{ + switch (usage_id) { + case VOLUME_ID_FILESYSTEM: + return "filesystem"; + case VOLUME_ID_PARTITIONTABLE: + return "partitiontable"; + 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_part(struct volume_id_partition *part, enum volume_id_usage usage_id) +{ + part->usage_id = usage_id; + part->usage = usage_to_string(usage_id); +} + +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) +{ + memcpy(id->label_raw, buf, count); + id->label_raw_len = count; +} + +#ifdef NOT_NEEDED +static size_t strnlen(const char *s, size_t maxlen) +{ + size_t i; + if (!maxlen) return 0; + if (!s) return 0; + for (i = 0; *s && i < maxlen; ++s) ++i; + return i; +} +#endif + +void volume_id_set_label_string(struct volume_id *id, const uint8_t *buf, size_t count) +{ + unsigned i; + + memcpy(id->label, buf, count); + + /* 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) +{ + volume_id_set_unicode16(id->label, sizeof(id->label), buf, endianess, count); +} + +void volume_id_set_uuid(struct volume_id *id, const uint8_t *buf, enum uuid_format format) +{ + unsigned i; + unsigned count = 0; + + switch(format) { + case UUID_DOS: + count = 4; + break; + case UUID_NTFS: + case UUID_HFS: + count = 8; + break; + case UUID_DCE: + count = 16; + break; + case UUID_DCE_STRING: + count = 36; + 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: + switch(format) { + case UUID_DOS: + sprintf(id->uuid, "%02X%02X-%02X%02X", + buf[3], buf[2], buf[1], buf[0]); + break; + case UUID_NTFS: + sprintf(id->uuid,"%02X%02X%02X%02X%02X%02X%02X%02X", + buf[7], buf[6], buf[5], buf[4], + buf[3], buf[2], buf[1], buf[0]); + break; + case UUID_HFS: + sprintf(id->uuid,"%02X%02X%02X%02X%02X%02X%02X%02X", + buf[0], buf[1], buf[2], buf[3], + buf[4], buf[5], buf[6], buf[7]); + break; + case UUID_DCE: + sprintf(id->uuid, + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + buf[0], buf[1], buf[2], buf[3], + buf[4], buf[5], + buf[6], buf[7], + buf[8], buf[9], + buf[10], buf[11], buf[12], buf[13], buf[14],buf[15]); + break; + case UUID_DCE_STRING: + memcpy(id->uuid, buf, count); + id->uuid[count] = '\0'; + break; + } +} + +void *volume_id_get_buffer(struct volume_id *id, uint64_t off, size_t len) +{ + ssize_t buf_len; + + dbg("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) { + if (id->sbbuf == NULL) { + id->sbbuf = xmalloc(SB_BUFFER_SIZE); + } + + /* check if we need to read */ + if ((off + len) > id->sbbuf_len) { + dbg("read sbbuf len:0x%llx", (unsigned long long) (off + len)); + xlseek(id->fd, 0, SEEK_SET); + buf_len = full_read(id->fd, id->sbbuf, off + len); + if (buf_len < 0) { + dbg("read failed (%s)", strerror(errno)); + return NULL; + } + dbg("got 0x%zx (%zi) bytes", buf_len, buf_len); + id->sbbuf_len = buf_len; + if (buf_len < off + len) { + dbg("requested 0x%zx bytes, got only 0x%zx bytes", len, buf_len); + return NULL; + } + } + + return &(id->sbbuf[off]); + } + + if (len > SEEK_BUFFER_SIZE) { + dbg("seek buffer too small %d", SEEK_BUFFER_SIZE); + return NULL; + } + + /* get seek buffer */ + if (id->seekbuf == NULL) { + id->seekbuf = xmalloc(SEEK_BUFFER_SIZE); + } + + /* check if we need to read */ + if ((off < id->seekbuf_off) || ((off + len) > (id->seekbuf_off + id->seekbuf_len))) { + dbg("read seekbuf off:0x%llx len:0x%zx", (unsigned long long) off, len); + xlseek(id->fd, off, SEEK_SET); + buf_len = full_read(id->fd, id->seekbuf, len); + if (buf_len < 0) { + dbg("read failed (%s)", strerror(errno)); + return NULL; + } + dbg("got 0x%zx (%zi) bytes", buf_len, buf_len); + id->seekbuf_off = off; + id->seekbuf_len = buf_len; + if (buf_len < len) { + dbg("requested 0x%zx bytes, got only 0x%zx bytes", len, buf_len); + return NULL; + } + } + + return &(id->seekbuf[off - id->seekbuf_off]); +} + +void volume_id_free_buffer(struct volume_id *id) +{ + free(id->sbbuf); + id->sbbuf = NULL; + id->sbbuf_len = 0; + free(id->seekbuf); + id->seekbuf = NULL; + id->seekbuf_len = 0; +} diff --git a/util-linux/volume_id/via_raid.c b/util-linux/volume_id/via_raid.c new file mode 100644 index 000000000..a9bd5b7b9 --- /dev/null +++ b/util-linux/volume_id/via_raid.c @@ -0,0 +1,68 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2005 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "volume_id_internal.h" + +struct via_meta { + uint16_t signature; + uint8_t version_number; + struct via_array { + uint16_t disk_bits; + uint8_t disk_array_ex; + uint32_t capacity_low; + uint32_t capacity_high; + uint32_t serial_checksum; + } __attribute((packed)) array; + uint32_t serial_checksum[8]; + uint8_t checksum; +} __attribute__((packed)); + +#define VIA_SIGNATURE 0xAA55 + +int volume_id_probe_via_raid(struct volume_id *id, uint64_t off, uint64_t size) +{ + 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; + + via = volume_id_get_buffer(id, off + meta_off, 0x200); + if (via == NULL) + return -1; + + if (via->signature != cpu_to_le16(VIA_SIGNATURE)) + return -1; + + if (via->version_number > 1) + return -1; + + volume_id_set_usage(id, VOLUME_ID_RAID); + id->type_version[0] = '0' + via->version_number; + id->type_version[1] = '\0'; + id->type = "via_raid_member"; + + return 0; +} diff --git a/util-linux/volume_id/volume_id.c b/util-linux/volume_id/volume_id.c new file mode 100644 index 000000000..809884a41 --- /dev/null +++ b/util-linux/volume_id/volume_id.c @@ -0,0 +1,214 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2005 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "volume_id_internal.h" + +typedef int (*raid_probe_fptr)(struct volume_id *id, uint64_t off, uint64_t size); +typedef int (*probe_fptr)(struct volume_id *id, uint64_t off); + +static const raid_probe_fptr raid1[] = { +#if ENABLE_FEATURE_VOLUMEID_LINUXRAID + volume_id_probe_linux_raid, +#endif +#if ENABLE_FEATURE_VOLUMEID_ISWRAID + volume_id_probe_intel_software_raid, +#endif +#if ENABLE_FEATURE_VOLUMEID_LSIRAID + volume_id_probe_lsi_mega_raid, +#endif +#if ENABLE_FEATURE_VOLUMEID_VIARAID + volume_id_probe_via_raid, +#endif +#if ENABLE_FEATURE_VOLUMEID_SILICONRAID + volume_id_probe_silicon_medley_raid, +#endif +#if ENABLE_FEATURE_VOLUMEID_NVIDIARAID + volume_id_probe_nvidia_raid, +#endif +#if ENABLE_FEATURE_VOLUMEID_PROMISERAID + volume_id_probe_promise_fasttrack_raid, +#endif +#if ENABLE_FEATURE_VOLUMEID_HIGHPOINTRAID + volume_id_probe_highpoint_45x_raid, +#endif +}; + +static const probe_fptr raid2[] = { +#if ENABLE_FEATURE_VOLUMEID_LVM + volume_id_probe_lvm1, + volume_id_probe_lvm2, +#endif +#if ENABLE_FEATURE_VOLUMEID_HIGHPOINTRAID + volume_id_probe_highpoint_37x_raid, +#endif +#if ENABLE_FEATURE_VOLUMEID_LUKS + volume_id_probe_luks, +#endif +}; + +/* signature in the first block, only small buffer needed */ +static const probe_fptr fs1[] = { +#if ENABLE_FEATURE_VOLUMEID_FAT + volume_id_probe_vfat, +#endif +#if ENABLE_FEATURE_VOLUMEID_MAC + volume_id_probe_mac_partition_map, +#endif +#if ENABLE_FEATURE_VOLUMEID_XFS + volume_id_probe_xfs, +#endif +}; + +/* fill buffer with maximum */ +static const probe_fptr fs2[] = { +#if ENABLE_FEATURE_VOLUMEID_LINUXSWAP + volume_id_probe_linux_swap, +#endif +#if ENABLE_FEATURE_VOLUMEID_EXT + volume_id_probe_ext, +#endif +#if ENABLE_FEATURE_VOLUMEID_REISERFS + volume_id_probe_reiserfs, +#endif +#if ENABLE_FEATURE_VOLUMEID_JFS + volume_id_probe_jfs, +#endif +#if ENABLE_FEATURE_VOLUMEID_UDF + volume_id_probe_udf, +#endif +#if ENABLE_FEATURE_VOLUMEID_ISO9660 + volume_id_probe_iso9660, +#endif +#if ENABLE_FEATURE_VOLUMEID_HFS + volume_id_probe_hfs_hfsplus, +#endif +#if ENABLE_FEATURE_VOLUMEID_UFS + volume_id_probe_ufs, +#endif +#if ENABLE_FEATURE_VOLUMEID_NTFS + volume_id_probe_ntfs, +#endif +#if ENABLE_FEATURE_VOLUMEID_CRAMFS + volume_id_probe_cramfs, +#endif +#if ENABLE_FEATURE_VOLUMEID_ROMFS + volume_id_probe_romfs, +#endif +#if ENABLE_FEATURE_VOLUMEID_HPFS + volume_id_probe_hpfs, +#endif +#if ENABLE_FEATURE_VOLUMEID_SYSV + volume_id_probe_sysv, +#endif +#if ENABLE_FEATURE_VOLUMEID_MINIX + volume_id_probe_minix, +#endif +#if ENABLE_FEATURE_VOLUMEID_OCFS2 + volume_id_probe_ocfs2, +#endif +}; + +int volume_id_probe_all(struct volume_id *id, uint64_t off, uint64_t size) +{ + int i; + + if (id == NULL) + return -EINVAL; + + /* probe for raid first, cause fs probes may be successful on raid members */ + if (size) { + for (i = 0; i < ARRAY_SIZE(raid1); i++) + if (raid1[i](id, off, size) == 0) + goto ret; + } + + for (i = 0; i < ARRAY_SIZE(raid2); i++) + if (raid2[i](id, off) == 0) + goto ret; + + /* signature in the first block, only small buffer needed */ + for (i = 0; i < ARRAY_SIZE(fs1); i++) + if (fs1[i](id, off) == 0) + goto ret; + + /* fill buffer with maximum */ + volume_id_get_buffer(id, 0, SB_BUFFER_SIZE); + + for (i = 0; i < ARRAY_SIZE(fs2); i++) + if (fs2[i](id, off) == 0) + goto ret; + return -1; + + ret: + /* If the filestystem in recognized, we free the allocated buffers, + otherwise they will stay in place for the possible next probe call */ + volume_id_free_buffer(id); + + return 0; +} + +/* open volume by device node */ +struct volume_id *volume_id_open_node(const char *path) +{ + struct volume_id *id; + int fd; + + fd = xopen(path, O_RDONLY); + id = xzalloc(sizeof(struct volume_id)); + id->fd = fd; + ///* close fd on device close */ + //id->fd_close = 1; + + return id; +} + +#ifdef UNUSED +/* open volume by major/minor */ +struct volume_id *volume_id_open_dev_t(dev_t devt) +{ + struct volume_id *id; + char *tmp_node[VOLUME_ID_PATH_MAX]; + + tmp_node = xasprintf("/dev/.volume_id-%u-%u-%u", + (unsigned)getpid(), (unsigned)major(devt), (unsigned)minor(devt)); + + /* create temporary node to open block device */ + unlink(tmp_node); + if (mknod(tmp_node, (S_IFBLK | 0600), devt) != 0) + bb_perror_msg_and_die("cannot mknod(%s)", tmp_node); + + id = volume_id_open_node(tmp_node); + unlink(tmp_node); + free(tmp_node); + return id; +} +#endif + +void free_volume_id(struct volume_id *id) +{ + if (id == NULL) + return; + + //if (id->fd_close != 0) - always true + close(id->fd); + volume_id_free_buffer(id); + free(id->partitions); + free(id); +} diff --git a/util-linux/volume_id/volume_id_internal.h b/util-linux/volume_id/volume_id_internal.h new file mode 100644 index 000000000..5a38562f4 --- /dev/null +++ b/util-linux/volume_id/volume_id_internal.h @@ -0,0 +1,220 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2005 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "libbb.h" +#include "volume_id.h" + + +#define dbg(...) ((void)0) + + +/* volume_id.h */ + +#define VOLUME_ID_VERSION 48 + +#define VOLUME_ID_LABEL_SIZE 64 +#define VOLUME_ID_UUID_SIZE 36 +#define VOLUME_ID_FORMAT_SIZE 32 +#define VOLUME_ID_PARTITIONS_MAX 256 + +enum volume_id_usage { + VOLUME_ID_UNUSED, + VOLUME_ID_UNPROBED, + VOLUME_ID_OTHER, + VOLUME_ID_FILESYSTEM, + VOLUME_ID_PARTITIONTABLE, + VOLUME_ID_RAID, + VOLUME_ID_DISKLABEL, + VOLUME_ID_CRYPTO, +}; + +struct volume_id_partition { + enum volume_id_usage usage_id; + const char *usage; + const char *type; + uint64_t off; + uint64_t len; + uint8_t partition_type_raw; +}; + +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; + const char *usage; + const char *type; + char type_version[VOLUME_ID_FORMAT_SIZE]; + + struct volume_id_partition *partitions; + size_t partition_count; + + int fd; + uint8_t *sbbuf; + uint8_t *seekbuf; + size_t sbbuf_len; + uint64_t seekbuf_off; + size_t seekbuf_len; +// int fd_close:1; +}; + +struct volume_id *volume_id_open_node(const char *path); +int volume_id_probe_all(struct volume_id *id, uint64_t off, uint64_t size); +void free_volume_id(struct volume_id *id); + +/* util.h */ + +/* 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 + +#define bswap16(x) (uint16_t) ( \ + (((uint16_t)(x) & 0x00ffu) << 8) | \ + (((uint16_t)(x) & 0xff00u) >> 8)) + +#define bswap32(x) (uint32_t) ( \ + (((uint32_t)(x) & 0xff000000u) >> 24) | \ + (((uint32_t)(x) & 0x00ff0000u) >> 8) | \ + (((uint32_t)(x) & 0x0000ff00u) << 8) | \ + (((uint32_t)(x) & 0x000000ffu) << 24)) + +#define bswap64(x) (uint64_t) ( \ + (((uint64_t)(x) & 0xff00000000000000ull) >> 56) | \ + (((uint64_t)(x) & 0x00ff000000000000ull) >> 40) | \ + (((uint64_t)(x) & 0x0000ff0000000000ull) >> 24) | \ + (((uint64_t)(x) & 0x000000ff00000000ull) >> 8) | \ + (((uint64_t)(x) & 0x00000000ff000000ull) << 8) | \ + (((uint64_t)(x) & 0x0000000000ff0000ull) << 24) | \ + (((uint64_t)(x) & 0x000000000000ff00ull) << 40) | \ + (((uint64_t)(x) & 0x00000000000000ffull) << 56)) + +#if BB_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) bswap16(x) +#define be32_to_cpu(x) bswap32(x) +#define cpu_to_le16(x) (x) +#define cpu_to_le32(x) (x) +#define cpu_to_be32(x) bswap32(x) +#else +#define le16_to_cpu(x) bswap16(x) +#define le32_to_cpu(x) bswap32(x) +#define le64_to_cpu(x) bswap64(x) +#define be16_to_cpu(x) (x) +#define be32_to_cpu(x) (x) +#define cpu_to_le16(x) bswap16(x) +#define cpu_to_le32(x) bswap32(x) +#define cpu_to_be32(x) (x) +#endif + +enum uuid_format { + UUID_DCE_STRING, + UUID_DCE, + UUID_DOS, + UUID_NTFS, + UUID_HFS, +}; + +enum endian { + LE = 0, + BE = 1 +}; + +void volume_id_set_unicode16(char *str, size_t len, const uint8_t *buf, enum endian endianess, size_t count); +void volume_id_set_usage(struct volume_id *id, enum volume_id_usage usage_id); +void volume_id_set_usage_part(struct volume_id_partition *part, enum volume_id_usage usage_id); +void volume_id_set_label_raw(struct volume_id *id, const uint8_t *buf, size_t count); +void volume_id_set_label_string(struct volume_id *id, const uint8_t *buf, size_t count); +void volume_id_set_label_unicode16(struct volume_id *id, const uint8_t *buf, enum endian endianess, size_t count); +void volume_id_set_uuid(struct volume_id *id, const uint8_t *buf, enum uuid_format format); +void *volume_id_get_buffer(struct volume_id *id, uint64_t off, size_t len); +void volume_id_free_buffer(struct volume_id *id); + + +/* Probe routines */ + +/* RAID */ + +int volume_id_probe_highpoint_37x_raid(struct volume_id *id, uint64_t off); +int volume_id_probe_highpoint_45x_raid(struct volume_id *id, uint64_t off, uint64_t size); + +int volume_id_probe_intel_software_raid(struct volume_id *id, uint64_t off, uint64_t size); + +int volume_id_probe_linux_raid(struct volume_id *id, uint64_t off, uint64_t size); + +int volume_id_probe_lsi_mega_raid(struct volume_id *id, uint64_t off, uint64_t size); + +int volume_id_probe_nvidia_raid(struct volume_id *id, uint64_t off, uint64_t size); + +int volume_id_probe_promise_fasttrack_raid(struct volume_id *id, uint64_t off, uint64_t size); + +int volume_id_probe_silicon_medley_raid(struct volume_id *id, uint64_t off, uint64_t size); + +int volume_id_probe_via_raid(struct volume_id *id, uint64_t off, uint64_t size); + +int volume_id_probe_lvm1(struct volume_id *id, uint64_t off); +int volume_id_probe_lvm2(struct volume_id *id, uint64_t off); + +/* FS */ + +int volume_id_probe_cramfs(struct volume_id *id, uint64_t off); + +int volume_id_probe_ext(struct volume_id *id, uint64_t off); + +int volume_id_probe_vfat(struct volume_id *id, uint64_t off); + +int volume_id_probe_hfs_hfsplus(struct volume_id *id, uint64_t off); + +int volume_id_probe_hpfs(struct volume_id *id, uint64_t off); + +int volume_id_probe_iso9660(struct volume_id *id, uint64_t off); + +int volume_id_probe_jfs(struct volume_id *id, uint64_t off); + +int volume_id_probe_linux_swap(struct volume_id *id, uint64_t off); + +int volume_id_probe_luks(struct volume_id *id, uint64_t off); + +int volume_id_probe_mac_partition_map(struct volume_id *id, uint64_t off); + +int volume_id_probe_minix(struct volume_id *id, uint64_t off); + +int volume_id_probe_msdos_part_table(struct volume_id *id, uint64_t off); + +int volume_id_probe_ntfs(struct volume_id *id, uint64_t off); + +int volume_id_probe_ocfs2(struct volume_id *id, uint64_t off); + +int volume_id_probe_reiserfs(struct volume_id *id, uint64_t off); + +int volume_id_probe_romfs(struct volume_id *id, uint64_t off); + +int volume_id_probe_sysv(struct volume_id *id, uint64_t off); + +int volume_id_probe_udf(struct volume_id *id, uint64_t off); + +int volume_id_probe_ufs(struct volume_id *id, uint64_t off); + +int volume_id_probe_xfs(struct volume_id *id, uint64_t off); diff --git a/util-linux/volume_id/xfs.c b/util-linux/volume_id/xfs.c new file mode 100644 index 000000000..343ac7015 --- /dev/null +++ b/util-linux/volume_id/xfs.c @@ -0,0 +1,59 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2004 Kay Sievers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "volume_id_internal.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; +} __attribute__((__packed__)); + +int volume_id_probe_xfs(struct volume_id *id, uint64_t off) +{ + struct xfs_super_block *xs; + + dbg("probing at offset 0x%llx", (unsigned long long) off); + + xs = volume_id_get_buffer(id, off, 0x200); + if (xs == NULL) + return -1; + + if (memcmp(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, UUID_DCE); + + volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); + id->type = "xfs"; + + return 0; +}