summaryrefslogtreecommitdiffstats
path: root/mount/get_label_uuid.c
diff options
context:
space:
mode:
Diffstat (limited to 'mount/get_label_uuid.c')
-rw-r--r--mount/get_label_uuid.c118
1 files changed, 118 insertions, 0 deletions
diff --git a/mount/get_label_uuid.c b/mount/get_label_uuid.c
new file mode 100644
index 000000000..310de6dc8
--- /dev/null
+++ b/mount/get_label_uuid.c
@@ -0,0 +1,118 @@
+/*
+ * Get label. Used by both mount and umount.
+ */
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "linux_fs.h"
+#include "get_label_uuid.h"
+
+/*
+ * See whether this device has (the magic of) a RAID superblock at the end.
+ * If so, it probably is, or has been, part of a RAID array.
+ *
+ * For the moment this test is switched off - it causes problems.
+ * "Checking for a disk label should only be done on the full raid,
+ * not on the disks that form the raid array. This test causes a lot of
+ * problems when run on my striped promise fasttrak 100 array."
+ */
+static inline int
+is_raid_partition(int fd) {
+#if 0
+ struct mdp_super_block mdsb;
+ int n;
+
+ /* hardcode 4096 here in various places, because that's
+ what it's defined to be. Note that even if we used
+ the actual kernel headers, sizeof(mdp_super_t) is
+ slightly larger in the 2.2 kernel on 64-bit archs,
+ so using that wouldn't work. */
+ lseek(fd, -4096, SEEK_END); /* Ignore possible error
+ about return value overflow */
+ n = 4096;
+ if (sizeof(mdsb) < n)
+ n = sizeof(mdsb);
+ if (read(fd, &mdsb, n) != n)
+ return 1; /* error */
+ return (mdsbmagic(mdsb) == MD_SB_MAGIC);
+#else
+ return 0;
+#endif
+}
+
+/* for now, only ext2, ext3, xfs, ocfs are supported */
+int
+get_label_uuid(const char *device, char **label, char *uuid) {
+ int fd;
+ int rv = 1;
+ size_t namesize;
+ struct ext2_super_block e2sb;
+ struct xfs_super_block xfsb;
+ struct jfs_super_block jfssb;
+ struct ocfs_volume_header ovh; /* Oracle */
+ struct ocfs_volume_label olbl;
+
+ fd = open(device, O_RDONLY);
+ if (fd < 0)
+ return rv;
+
+ /* If there is a RAID partition, or an error, ignore this partition */
+ if (is_raid_partition(fd)) {
+ close(fd);
+ return rv;
+ }
+
+ if (lseek(fd, 1024, SEEK_SET) == 1024
+ && read(fd, (char *) &e2sb, sizeof(e2sb)) == sizeof(e2sb)
+ && (ext2magic(e2sb) == EXT2_SUPER_MAGIC)) {
+ memcpy(uuid, e2sb.s_uuid, sizeof(e2sb.s_uuid));
+ namesize = sizeof(e2sb.s_volume_name);
+ if ((*label = calloc(namesize + 1, 1)) != NULL)
+ memcpy(*label, e2sb.s_volume_name, namesize);
+ rv = 0;
+ }
+ else if (lseek(fd, 0, SEEK_SET) == 0
+ && read(fd, (char *) &xfsb, sizeof(xfsb)) == sizeof(xfsb)
+ && (strncmp(xfsb.s_magic, XFS_SUPER_MAGIC, 4) == 0)) {
+ memcpy(uuid, xfsb.s_uuid, sizeof(xfsb.s_uuid));
+ namesize = sizeof(xfsb.s_fname);
+ if ((*label = calloc(namesize + 1, 1)) != NULL)
+ memcpy(*label, xfsb.s_fname, namesize);
+ rv = 0;
+ }
+ else if (lseek(fd, 0, SEEK_SET) == 0
+ && read(fd, (char *) &ovh, sizeof(ovh)) == sizeof(ovh)
+ && (strncmp(ovh.signature, OCFS_MAGIC, sizeof(OCFS_MAGIC)) == 0)
+ && (lseek(fd, 512, SEEK_SET) == 512)
+ && read(fd, (char *) &olbl, sizeof(olbl)) == sizeof(olbl)) {
+ uuid[0] = '\0';
+ namesize = ocfslabellen(olbl);
+ if ((*label = calloc(namesize + 1, 1)) != NULL)
+ memcpy(*label, olbl.label, namesize);
+ rv = 0;
+ }
+ else if (lseek(fd, JFS_SUPER1_OFF, SEEK_SET) == JFS_SUPER1_OFF
+ && read(fd, (char *) &jfssb, sizeof(jfssb)) == sizeof(jfssb)
+ && (strncmp(jfssb.s_magic, JFS_MAGIC, 4) == 0)) {
+ if (assemble4le(jfssb.s_version) == 1) {
+ /* old (OS/2 compatible) jfs filesystems don't
+ have UUIDs and only have a very small label. */
+ memset(uuid, 0, 16);
+ namesize = sizeof(jfssb.s_fpack);
+ if ((*label = calloc(namesize + 1, 1)) != NULL)
+ memcpy(*label, jfssb.s_fpack, namesize);
+ } else {
+ memcpy(uuid, jfssb.s_uuid, sizeof(jfssb.s_uuid));
+ namesize = sizeof(jfssb.s_label);
+ if ((*label = calloc(namesize + 1, 1)) != NULL)
+ memcpy(*label, jfssb.s_label, namesize);
+ }
+ rv = 0;
+ }
+
+ close(fd);
+ return rv;
+}