123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- /* 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 source tree.
- */
- #include <sys/mount.h> /* BLKGETSIZE64 */
- #if !defined(BLKGETSIZE64)
- # define BLKGETSIZE64 _IOR(0x12,114,size_t)
- #endif
- #include "volume_id_internal.h"
- static struct uuidCache_s {
- struct uuidCache_s *next;
- // int major, minor;
- char *device;
- char *label;
- char *uc_uuid; /* prefix makes it easier to grep for */
- } *uuidCache;
- /* Returns !0 on error.
- * Otherwise, returns malloc'ed strings for label and uuid
- * (and they can't be NULL, although they can be "").
- * NB: closes fd. */
- static int
- get_label_uuid(int fd, char **label, char **uuid)
- {
- int rv = 1;
- uint64_t size;
- struct volume_id *vid;
- /* fd is owned by vid now */
- vid = volume_id_open_node(fd);
- if (ioctl(/*vid->*/fd, BLKGETSIZE64, &size) != 0)
- size = 0;
- if (volume_id_probe_all(vid, /*0,*/ size) != 0)
- goto ret;
- if (vid->label[0] != '\0' || vid->uuid[0] != '\0') {
- *label = xstrndup(vid->label, sizeof(vid->label));
- *uuid = xstrndup(vid->uuid, sizeof(vid->uuid));
- dbg("found label '%s', uuid '%s'", *label, *uuid);
- rv = 0;
- }
- ret:
- free_volume_id(vid); /* also closes fd */
- return rv;
- }
- /* NB: we take ownership of (malloc'ed) label and uuid */
- 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->major = major;
- // last->minor = minor;
- last->device = device;
- last->label = label;
- last->uc_uuid = uuid;
- }
- /* If get_label_uuid() on device_name returns success,
- * add a cache entry for this device.
- * If device node does not exist, it will be temporarily created. */
- static int FAST_FUNC
- uuidcache_check_device(const char *device,
- struct stat *statbuf,
- void *userData UNUSED_PARAM,
- int depth UNUSED_PARAM)
- {
- char *uuid = uuid; /* for compiler */
- char *label = label;
- int fd;
- /* note: this check rejects links to devices, among other nodes */
- if (!S_ISBLK(statbuf->st_mode))
- return TRUE;
- /* Users report that mucking with floppies (especially non-present
- * ones) is significant PITA. This is a horribly dirty hack,
- * but it is very useful in real world.
- * If this will ever need to be enabled, consider using O_NONBLOCK.
- */
- if (major(statbuf->st_rdev) == 2)
- return TRUE;
- fd = open(device, O_RDONLY);
- if (fd < 0)
- return TRUE;
- /* get_label_uuid() closes fd in all cases (success & failure) */
- if (get_label_uuid(fd, &label, &uuid) == 0) {
- /* uuidcache_addentry() takes ownership of all three params */
- uuidcache_addentry(xstrdup(device), /*ma, mi,*/ label, uuid);
- }
- return TRUE;
- }
- static void
- uuidcache_init(void)
- {
- if (uuidCache)
- return;
- /* We were scanning /proc/partitions
- * and /proc/sys/dev/cdrom/info here.
- * Missed volume managers. I see that "standard" blkid uses these:
- * /dev/mapper/control
- * /proc/devices
- * /proc/evms/volumes
- * /proc/lvm/VGs
- * This is unacceptably complex. Let's just scan /dev.
- * (Maybe add scanning of /sys/block/XXX/dev for devices
- * somehow not having their /dev/XXX entries created?) */
- recursive_action("/dev", ACTION_RECURSE,
- uuidcache_check_device, /* file_action */
- NULL, /* dir_action */
- NULL, /* userData */
- 0 /* depth */);
- }
- #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 (strcmp(t, uc->uc_uuid) == 0) {
- *majorPtr = uc->major;
- *minorPtr = uc->minor;
- return uc->device;
- }
- break;
- case VOL:
- if (strcmp(t, uc->label) == 0) {
- *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');
- return ((c|0x20) - '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);
- }
- #endif // UNUSED
- /* Used by blkid */
- void display_uuid_cache(void)
- {
- struct uuidCache_s *u;
- uuidcache_init();
- u = uuidCache;
- while (u) {
- printf("%s:", u->device);
- if (u->label[0])
- printf(" LABEL=\"%s\"", u->label);
- if (u->uc_uuid[0])
- printf(" UUID=\"%s\"", u->uc_uuid);
- bb_putchar('\n');
- u = u->next;
- }
- }
- /* Used by mount and findfs */
- char *get_devname_from_label(const char *spec)
- {
- struct uuidCache_s *uc;
- uuidcache_init();
- uc = uuidCache;
- while (uc) {
- if (uc->label[0] && strcmp(spec, uc->label) == 0) {
- 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) {
- /* case of hex numbers doesn't matter */
- if (strcasecmp(spec, uc->uc_uuid) == 0) {
- return xstrdup(uc->device);
- }
- uc = uc->next;
- }
- return NULL;
- }
- int resolve_mount_spec(char **fsname)
- {
- char *tmp = *fsname;
- if (strncmp(*fsname, "UUID=", 5) == 0)
- tmp = get_devname_from_uuid(*fsname + 5);
- else if (strncmp(*fsname, "LABEL=", 6) == 0)
- tmp = get_devname_from_label(*fsname + 6);
- if (tmp == *fsname)
- return 0; /* no UUID= or LABEL= prefix found */
- if (tmp)
- *fsname = tmp;
- return 1;
- }
|