support for mount by label (not yet tested)
authorDenis Vlasenko <vda.linux@googlemail.com>
Mon, 18 Feb 2008 21:08:49 +0000 (21:08 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Mon, 18 Feb 2008 21:08:49 +0000 (21:08 -0000)
Also adds findfs applet. Closes bug 1143.

43 files changed:
Makefile
e2fsprogs/old_e2fsprogs/tune2fs.c
include/usage.h
include/volume_id.h [new file with mode: 0644]
util-linux/Config.in
util-linux/Kbuild
util-linux/fdisk_sgi.c
util-linux/findfs.c [new file with mode: 0644]
util-linux/mount.c
util-linux/volume_id/Kbuild [new file with mode: 0644]
util-linux/volume_id/cramfs.c [new file with mode: 0644]
util-linux/volume_id/ext.c [new file with mode: 0644]
util-linux/volume_id/fat.c [new file with mode: 0644]
util-linux/volume_id/get_devname.c [new file with mode: 0644]
util-linux/volume_id/hfs.c [new file with mode: 0644]
util-linux/volume_id/highpoint.c [new file with mode: 0644]
util-linux/volume_id/hpfs.c [new file with mode: 0644]
util-linux/volume_id/iso9660.c [new file with mode: 0644]
util-linux/volume_id/isw_raid.c [new file with mode: 0644]
util-linux/volume_id/jfs.c [new file with mode: 0644]
util-linux/volume_id/linux_raid.c [new file with mode: 0644]
util-linux/volume_id/linux_swap.c [new file with mode: 0644]
util-linux/volume_id/lsi_raid.c [new file with mode: 0644]
util-linux/volume_id/luks.c [new file with mode: 0644]
util-linux/volume_id/lvm.c [new file with mode: 0644]
util-linux/volume_id/mac.c [new file with mode: 0644]
util-linux/volume_id/minix.c [new file with mode: 0644]
util-linux/volume_id/msdos.c [new file with mode: 0644]
util-linux/volume_id/ntfs.c [new file with mode: 0644]
util-linux/volume_id/nvidia_raid.c [new file with mode: 0644]
util-linux/volume_id/ocfs2.c [new file with mode: 0644]
util-linux/volume_id/promise_raid.c [new file with mode: 0644]
util-linux/volume_id/reiserfs.c [new file with mode: 0644]
util-linux/volume_id/romfs.c [new file with mode: 0644]
util-linux/volume_id/silicon_raid.c [new file with mode: 0644]
util-linux/volume_id/sysv.c [new file with mode: 0644]
util-linux/volume_id/udf.c [new file with mode: 0644]
util-linux/volume_id/ufs.c [new file with mode: 0644]
util-linux/volume_id/util.c [new file with mode: 0644]
util-linux/volume_id/via_raid.c [new file with mode: 0644]
util-linux/volume_id/volume_id.c [new file with mode: 0644]
util-linux/volume_id/volume_id_internal.h [new file with mode: 0644]
util-linux/volume_id/xfs.c [new file with mode: 0644]

index 60edff9b45123476d4387d62185ad63b934d1964..0f21ccff329c51b0c283c01a4f8e3d2da7146b8d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -452,6 +452,7 @@ libs-y              := \
                shell/ \
                sysklogd/ \
                util-linux/ \
+               util-linux/volume_id/ \
 
 endif # KBUILD_EXTMOD
 
index c5c84d68ec968e991659c62131f3e41dde23f01f..b7a1b21eb0fc49fd94f69b14d03876b34c99b1c2 100644 (file)
@@ -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 */
index 04ef1822ef956de40a030390d1918cc01b54b989..d1878827ba3f55244949412b69e05be5bbcea62b 100644 (file)
@@ -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 (file)
index 0000000..99cb11f
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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);
index 3b0f778cbdba21e9bca25c989d74ed4152d48017..552ca0f314aea3ad9f195f63370ca4b9bf35bc43 100644 (file)
@@ -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
index 4a18ff21f400a87b46f3c12f7d9e3e75f56cc850..c71186e86be7f933580665b2c0617aa063285f87 100644 (file)
@@ -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
index 7826bb7cce0dd525c09a9d54963458aa6f1b6d40..1fce0c1c7b4ebef7f3c009dc11be1965efb75c2e 100644 (file)
@@ -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 (file)
index 0000000..4f03642
--- /dev/null
@@ -0,0 +1,38 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Support functions for mounting devices by label/uuid
+ *
+ * Copyright (C) 2006 by Jason Schoon <floydpink@gmail.com>
+ * 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;
+}    
index 8b32309357a95bea5bc99a8aa5ff8487200f92b0..b19c3a3efeec9df5d34e092c8e5eeb893b8e21ba 100644 (file)
 */
 
 #include <mntent.h>
-#include "libbb.h"
 #include <syslog.h>
+#include "libbb.h"
 
-/* Needed for nfs support only... */
+/* For FEATURE_MOUNT_LABEL only */
+#include "volume_id.h"
+
+/* Needed for nfs support only */
 #include <sys/utsname.h>
 #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 (file)
index 0000000..c2eb015
--- /dev/null
@@ -0,0 +1,41 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+#
+# 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 (file)
index 0000000..fd6e875
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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 (file)
index 0000000..3c07f53
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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 (file)
index 0000000..4c2a917
--- /dev/null
@@ -0,0 +1,333 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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 (file)
index 0000000..75060b0
--- /dev/null
@@ -0,0 +1,399 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Support functions for mounting devices by label/uuid
+ *
+ * Copyright (C) 2006 by Jason Schoon <floydpink@gmail.com>
+ * 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 (file)
index 0000000..71a3df0
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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 (file)
index 0000000..de31a2a
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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 (file)
index 0000000..b43fb79
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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 (file)
index 0000000..fa92277
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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 (file)
index 0000000..8f55f49
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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 (file)
index 0000000..28b4eb6
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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 (file)
index 0000000..bb9b3c5
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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 (file)
index 0000000..56b5d50
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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 (file)
index 0000000..0eab1c7
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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 (file)
index 0000000..e73ce3a
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 W. Michael Petullo <mike@flyn.org>
+ *
+ *     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 (file)
index 0000000..baa8456
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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 (file)
index 0000000..94a99be
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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 (file)
index 0000000..ede23cb
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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 (file)
index 0000000..b4b6711
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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 (file)
index 0000000..cbd5d5b
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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 (file)
index 0000000..8619565
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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 (file)
index 0000000..bc490df
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) Andre Masella <andre@masella.no-ip.org>
+ *
+ *     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 (file)
index 0000000..9195c63
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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 (file)
index 0000000..98ecec2
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2005 Tobias Klauser <tklauser@access.unizh.ch>
+ *
+ *     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 (file)
index 0000000..7c4fc0f
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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 (file)
index 0000000..ea00174
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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 (file)
index 0000000..71c0fd4
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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 (file)
index 0000000..5cdb49c
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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 (file)
index 0000000..768670e
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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 (file)
index 0000000..d2265c2
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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 (file)
index 0000000..a9bd5b7
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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 (file)
index 0000000..809884a
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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 (file)
index 0000000..5a38562
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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 (file)
index 0000000..343ac70
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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;
+}