summaryrefslogtreecommitdiff
path: root/util-linux/volume_id/get_devname.c
diff options
context:
space:
mode:
authorDenis Vlasenko2008-02-18 21:08:49 +0000
committerDenis Vlasenko2008-02-18 21:08:49 +0000
commitde7684a309ad20c1b889d048d741cb1dd52245f7 (patch)
treeefae3387e1978cdd128ff2a922b734d0e9d0180f /util-linux/volume_id/get_devname.c
parent27dd495b98a6135554b1d839fefe436ba3c6ca71 (diff)
downloadbusybox-de7684a309ad20c1b889d048d741cb1dd52245f7.zip
busybox-de7684a309ad20c1b889d048d741cb1dd52245f7.tar.gz
support for mount by label (not yet tested)
Also adds findfs applet. Closes bug 1143.
Diffstat (limited to 'util-linux/volume_id/get_devname.c')
-rw-r--r--util-linux/volume_id/get_devname.c399
1 files changed, 399 insertions, 0 deletions
diff --git a/util-linux/volume_id/get_devname.c b/util-linux/volume_id/get_devname.c
new file mode 100644
index 0000000..75060b0
--- /dev/null
+++ b/util-linux/volume_id/get_devname.c
@@ -0,0 +1,399 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Support functions for mounting devices by label/uuid
+ *
+ * Copyright (C) 2006 by Jason Schoon <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;
+}