busybox/util-linux/volume_id/get_devname.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * Support functions for mounting devices by label/uuid
   4 *
   5 * Copyright (C) 2006 by Jason Schoon <floydpink@gmail.com>
   6 * Some portions cribbed from e2fsprogs, util-linux, dosfstools
   7 *
   8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
   9 */
  10
  11#include "volume_id_internal.h"
  12
  13//#define BLKGETSIZE64 _IOR(0x12,114,size_t)
  14
  15static struct uuidCache_s {
  16        struct uuidCache_s *next;
  17//      int major, minor;
  18        char *device;
  19        char *label;
  20        char *uc_uuid; /* prefix makes it easier to grep for */
  21} *uuidCache;
  22
  23/* Returns !0 on error.
  24 * Otherwise, returns malloc'ed strings for label and uuid
  25 * (and they can't be NULL, although they can be "").
  26 * NB: closes fd. */
  27static int
  28get_label_uuid(int fd, char **label, char **uuid)
  29{
  30        int rv = 1;
  31        uint64_t size;
  32        struct volume_id *vid;
  33
  34        /* fd is owned by vid now */
  35        vid = volume_id_open_node(fd);
  36
  37        if (ioctl(/*vid->*/fd, BLKGETSIZE64, &size) != 0)
  38                size = 0;
  39
  40        if (volume_id_probe_all(vid, /*0,*/ size) != 0)
  41                goto ret;
  42
  43        if (vid->label[0] != '\0' || vid->uuid[0] != '\0') {
  44                *label = xstrndup(vid->label, sizeof(vid->label));
  45                *uuid  = xstrndup(vid->uuid, sizeof(vid->uuid));
  46                dbg("found label '%s', uuid '%s' on %s", *label, *uuid, device);
  47                rv = 0;
  48        }
  49 ret:
  50        free_volume_id(vid); /* also closes fd */
  51        return rv;
  52}
  53
  54/* NB: we take ownership of (malloc'ed) label and uuid */
  55static void
  56uuidcache_addentry(char *device, /*int major, int minor,*/ char *label, char *uuid)
  57{
  58        struct uuidCache_s *last;
  59
  60        if (!uuidCache) {
  61                last = uuidCache = xzalloc(sizeof(*uuidCache));
  62        } else {
  63                for (last = uuidCache; last->next; last = last->next)
  64                        continue;
  65                last->next = xzalloc(sizeof(*uuidCache));
  66                last = last->next;
  67        }
  68        /*last->next = NULL; - xzalloc did it*/
  69//      last->major = major;
  70//      last->minor = minor;
  71        last->device = device;
  72        last->label = label;
  73        last->uc_uuid = uuid;
  74}
  75
  76/* If get_label_uuid() on device_name returns success,
  77 * add a cache entry for this device.
  78 * If device node does not exist, it will be temporarily created. */
  79static int FAST_FUNC
  80uuidcache_check_device(const char *device,
  81                struct stat *statbuf,
  82                void *userData UNUSED_PARAM,
  83                int depth UNUSED_PARAM)
  84{
  85        char *uuid = uuid; /* for compiler */
  86        char *label = label;
  87        int fd;
  88
  89        if (!S_ISBLK(statbuf->st_mode))
  90                return TRUE;
  91
  92        fd = open(device, O_RDONLY);
  93        if (fd < 0)
  94                return TRUE;
  95
  96        /* get_label_uuid() closes fd in all cases (success & failure) */
  97        if (get_label_uuid(fd, &label, &uuid) == 0) {
  98                /* uuidcache_addentry() takes ownership of all three params */
  99                uuidcache_addentry(xstrdup(device), /*ma, mi,*/ label, uuid);
 100        }
 101        return TRUE;
 102}
 103
 104static void
 105uuidcache_init(void)
 106{
 107        if (uuidCache)
 108                return;
 109
 110        /* We were scanning /proc/partitions
 111         * and /proc/sys/dev/cdrom/info here.
 112         * Missed volume managers. I see that "standard" blkid uses these:
 113         * /dev/mapper/control
 114         * /proc/devices
 115         * /proc/evms/volumes
 116         * /proc/lvm/VGs
 117         * This is unacceptably complex. Let's just scan /dev.
 118         * (Maybe add scanning of /sys/block/XXX/dev for devices
 119         * somehow not having their /dev/XXX entries created?) */
 120
 121        recursive_action("/dev", ACTION_RECURSE,
 122                uuidcache_check_device, /* file_action */
 123                NULL, /* dir_action */
 124                NULL, /* userData */
 125                0 /* depth */);
 126}
 127
 128#define UUID   1
 129#define VOL    2
 130
 131#ifdef UNUSED
 132static char *
 133get_spec_by_x(int n, const char *t, int *majorPtr, int *minorPtr)
 134{
 135        struct uuidCache_s *uc;
 136
 137        uuidcache_init();
 138        uc = uuidCache;
 139
 140        while (uc) {
 141                switch (n) {
 142                case UUID:
 143                        if (strcmp(t, uc->uc_uuid) == 0) {
 144                                *majorPtr = uc->major;
 145                                *minorPtr = uc->minor;
 146                                return uc->device;
 147                        }
 148                        break;
 149                case VOL:
 150                        if (strcmp(t, uc->label) == 0) {
 151                                *majorPtr = uc->major;
 152                                *minorPtr = uc->minor;
 153                                return uc->device;
 154                        }
 155                        break;
 156                }
 157                uc = uc->next;
 158        }
 159        return NULL;
 160}
 161
 162static unsigned char
 163fromhex(char c)
 164{
 165        if (isdigit(c))
 166                return (c - '0');
 167        return ((c|0x20) - 'a' + 10);
 168}
 169
 170static char *
 171get_spec_by_uuid(const char *s, int *major, int *minor)
 172{
 173        unsigned char uuid[16];
 174        int i;
 175
 176        if (strlen(s) != 36 || s[8] != '-' || s[13] != '-'
 177         || s[18] != '-' || s[23] != '-'
 178        ) {
 179                goto bad_uuid;
 180        }
 181        for (i = 0; i < 16; i++) {
 182                if (*s == '-')
 183                        s++;
 184                if (!isxdigit(s[0]) || !isxdigit(s[1]))
 185                        goto bad_uuid;
 186                uuid[i] = ((fromhex(s[0]) << 4) | fromhex(s[1]));
 187                s += 2;
 188        }
 189        return get_spec_by_x(UUID, (char *)uuid, major, minor);
 190
 191 bad_uuid:
 192        fprintf(stderr, _("mount: bad UUID"));
 193        return 0;
 194}
 195
 196static char *
 197get_spec_by_volume_label(const char *s, int *major, int *minor)
 198{
 199        return get_spec_by_x(VOL, s, major, minor);
 200}
 201#endif // UNUSED
 202
 203/* Used by blkid */
 204void display_uuid_cache(void)
 205{
 206        struct uuidCache_s *u;
 207
 208        uuidcache_init();
 209        u = uuidCache;
 210        while (u) {
 211                printf("%s:", u->device);
 212                if (u->label[0])
 213                        printf(" LABEL=\"%s\"", u->label);
 214                if (u->uc_uuid[0])
 215                        printf(" UUID=\"%s\"", u->uc_uuid);
 216                bb_putchar('\n');
 217                u = u->next;
 218        }
 219}
 220
 221/* Used by mount and findfs */
 222
 223char *get_devname_from_label(const char *spec)
 224{
 225        struct uuidCache_s *uc;
 226
 227        uuidcache_init();
 228        uc = uuidCache;
 229        while (uc) {
 230                if (uc->label[0] && strcmp(spec, uc->label) == 0) {
 231                        return xstrdup(uc->device);
 232                }
 233                uc = uc->next;
 234        }
 235        return NULL;
 236}
 237
 238char *get_devname_from_uuid(const char *spec)
 239{
 240        struct uuidCache_s *uc;
 241
 242        uuidcache_init();
 243        uc = uuidCache;
 244        while (uc) {
 245                /* case of hex numbers doesn't matter */
 246                if (strcasecmp(spec, uc->uc_uuid) == 0) {
 247                        return xstrdup(uc->device);
 248                }
 249                uc = uc->next;
 250        }
 251        return NULL;
 252}
 253