summaryrefslogtreecommitdiff
path: root/bylabel.c
diff options
context:
space:
mode:
Diffstat (limited to 'bylabel.c')
-rw-r--r--bylabel.c275
1 files changed, 275 insertions, 0 deletions
diff --git a/bylabel.c b/bylabel.c
new file mode 100644
index 0000000..68a109c
--- /dev/null
+++ b/bylabel.c
@@ -0,0 +1,275 @@
+/*
+ * Derived from the util-linux/mount/mount_by_label.c source,
+ * currently maintained by Andries Brouwer <aeb@cwi.nl>.
+ *
+ * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
+ * - added Native Language Support
+ * 2000-01-20 James Antill <james@and.org>
+ * - Added error message if /proc/partitions cannot be opened
+ * 2000-05-09 Erik Troan <ewt@redhat.com>
+ * - Added cache for UUID and disk labels
+ * 2000-11-07 Nathan Scott <nathans@sgi.com>
+ * - Added XFS support
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <sys/param.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "bylabel.h"
+#include "common.h"
+#include "pot.h"
+
+#define PROC_PARTITIONS "/proc/partitions"
+#define DEVLABELDIR "/dev"
+
+static struct uuidCache_s {
+ struct uuidCache_s *next;
+ char uuid[16];
+ char *label;
+ char *device;
+} *uuidCache = NULL;
+
+#define EXT2_SUPER_MAGIC 0xEF53
+struct ext2_super_block {
+ u_char s_dummy1[56];
+ u_char s_magic[2];
+ u_char s_dummy2[46];
+ u_char s_uuid[16];
+ u_char s_volume_name[16];
+};
+
+#define ext2magic(s) ((uint) s.s_magic[0] + (((uint) s.s_magic[1]) << 8))
+
+#define XFS_SUPER_MAGIC "XFSB"
+#define XFS_SUPER_MAGIC2 "BSFX"
+struct xfs_super_block {
+ u_char s_magic[4];
+ u_char s_dummy[28];
+ u_char s_uuid[16];
+ u_char s_dummy2[60];
+ u_char s_fsname[12];
+};
+
+#define REISER_SUPER_MAGIC "ReIsEr2Fs"
+struct reiserfs_super_block {
+ u_char s_dummy1[52];
+ u_char s_magic[10];
+ u_char s_dummy2[22];
+ u_char s_uuid[16];
+ u_char s_volume_name[16];
+};
+
+static inline unsigned short swapped(unsigned short a)
+{
+ return (a >> 8) | (a << 8);
+}
+
+/* for now, only ext2 and xfs are supported */
+static int get_label_uuid(const char *device, char **label, char *uuid)
+{
+
+ /* start with ext2 and xfs tests, taken from mount_guess_fstype */
+ /* should merge these later */
+ int fd, rv = 1;
+ size_t namesize;
+ struct ext2_super_block e2sb;
+ struct xfs_super_block xfsb;
+ struct reiserfs_super_block reisersb;
+
+ fd = open(device, O_RDONLY);
+ if (fd < 0)
+ 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);
+ *label = smalloc(namesize + 1);
+ sstrncpy(*label, (char *)e2sb.s_volume_name, namesize);
+ rv = 0;
+ }
+ else if (lseek(fd, 0, SEEK_SET) == 0
+ && read(fd, (char *)&xfsb, sizeof(xfsb)) == sizeof(xfsb)
+ && (strncmp((char *)&xfsb.s_magic, XFS_SUPER_MAGIC, 4) == 0 ||
+ strncmp((char *)&xfsb.s_magic, XFS_SUPER_MAGIC2, 4) == 0)) {
+ memcpy(uuid, xfsb.s_uuid, sizeof(xfsb.s_uuid));
+ namesize = sizeof(xfsb.s_fsname);
+ *label = smalloc(namesize + 1);
+ sstrncpy(*label, (char *)xfsb.s_fsname, namesize);
+ rv = 0;
+ }
+ else if (lseek(fd, 65536, SEEK_SET) == 65536
+ && read(fd, (char *)&reisersb, sizeof(reisersb)) == sizeof(reisersb)
+ && !strncmp((char *)&reisersb.s_magic, REISER_SUPER_MAGIC, 9)) {
+ memcpy(uuid, reisersb.s_uuid, sizeof(reisersb.s_uuid));
+ namesize = sizeof(reisersb.s_volume_name);
+ *label = smalloc(namesize + 1);
+ sstrncpy(*label, (char *)reisersb.s_volume_name, namesize);
+ rv = 0;
+ }
+ close(fd);
+ return rv;
+}
+
+static void uuidcache_addentry(char *device, char *label, char *uuid)
+{
+ struct uuidCache_s *last;
+
+ if (!uuidCache) {
+ last = uuidCache = smalloc(sizeof(*uuidCache));
+ }
+ else {
+ for (last = uuidCache; last->next; last = last->next);
+ last->next = smalloc(sizeof(*uuidCache));
+ last = last->next;
+ }
+ last->next = NULL;
+ last->device = device;
+ last->label = label;
+ memcpy(last->uuid, uuid, sizeof(last->uuid));
+}
+
+static void uuidcache_init(void)
+{
+ char line[100];
+ char *s;
+ int ma, mi, sz;
+ static char ptname[100];
+ FILE *procpt;
+ char uuid[16], *label;
+ char device[110];
+ int firstPass;
+ int handleOnFirst;
+
+ if (uuidCache)
+ return;
+
+ procpt = fopen(PROC_PARTITIONS, "r");
+ if (!procpt)
+ return;
+
+ for (firstPass = 1; firstPass >= 0; firstPass--) {
+ fseek(procpt, 0, SEEK_SET);
+
+ while (fgets(line, sizeof(line), procpt)) {
+ if (sscanf(line, " %d %d %d %[^\n ]", &ma, &mi, &sz, ptname) != 4)
+ continue;
+
+ /* skip extended partitions (heuristic: size 1) */
+ if (sz == 1)
+ continue;
+
+ /* look only at md devices on first pass */
+ handleOnFirst = !strncmp(ptname, "md", 2);
+ if (firstPass != handleOnFirst)
+ continue;
+
+ /* skip entire disk (minor 0, 64, ... on ide;
+ 0, 16, ... on sd) */
+ /* heuristic: partition name ends in a digit */
+
+ for (s = ptname; *s; s++);
+ if (isdigit(s[-1])) {
+ /*
+ * Note: this is a heuristic only - there is no reason
+ * why these devices should live in /dev.
+ * Perhaps this directory should be specifiable by option.
+ * One might for example have /devlabel with links to /dev
+ * for the devices that may be accessed in this way.
+ * (This is useful, if the cdrom on /dev/hdc must not
+ * be accessed.)
+ */
+ snprintf(device, sizeof(device), "%s/%s", DEVLABELDIR, ptname);
+ if (!get_label_uuid(device, &label, uuid))
+ uuidcache_addentry(sstrdup(device), label, uuid);
+ }
+ }
+ }
+
+ fclose(procpt);
+}
+
+#define UUID 1
+#define VOL 2
+
+static char *get_spec_by_x(int n, const char *t)
+{
+ struct uuidCache_s *uc;
+
+ uuidcache_init();
+ uc = uuidCache;
+
+ while (uc) {
+ switch (n) {
+ case UUID:
+ if (!memcmp(t, uc->uuid, sizeof(uc->uuid)))
+ return sstrdup(uc->device);
+ break;
+ case VOL:
+ if (!strcmp(t, uc->label))
+ return sstrdup(uc->device);
+ break;
+ }
+ uc = uc->next;
+ }
+ return NULL;
+}
+
+static u_char fromhex(char c)
+{
+ if (isdigit(c))
+ return (c - '0');
+ else if (islower(c))
+ return (c - 'a' + 10);
+ else
+ return (c - 'A' + 10);
+}
+
+static char *get_spec_by_uuid(const char *s)
+{
+ u_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);
+
+ bad_uuid:
+ errstr(_("Found an invalid UUID: %s\n"), s);
+ return NULL;
+}
+
+static char *get_spec_by_volume_label(const char *s)
+{
+ return get_spec_by_x(VOL, s);
+}
+
+const char *get_device_name(const char *item)
+{
+ const char *rc;
+
+ if (!strncmp(item, "UUID=", 5))
+ rc = get_spec_by_uuid(item + 5);
+ else if (!strncmp(item, "LABEL=", 6))
+ rc = get_spec_by_volume_label(item + 6);
+ else
+ rc = sstrdup(item);
+ if (!rc)
+ errstr(_("Error checking device name: %s\n"), item);
+ return rc;
+}