--- e2fsprogs-1.19/misc/get_device_by_label.c.mountlabel Mon Feb 7 19:47:54 2000 +++ e2fsprogs-1.19/misc/get_device_by_label.c Wed Aug 9 13:01:21 2000 @@ -7,6 +7,7 @@ * License. * * Taken from aeb's mount, 990619 + * Updated from aeb's mount, 20000725 */ #include @@ -14,7 +15,6 @@ #include #include #include -#include "nls-enable.h" #include "get_device_by_label.h" #define PROC_PARTITIONS "/proc/partitions" @@ -30,104 +30,147 @@ }; #define ext2magic(s) ((unsigned int) s.s_magic[0] + (((unsigned int) s.s_magic[1]) << 8)) - -static FILE *procpt; - -static void -procptclose(void) { - if (procpt) - fclose (procpt); - procpt = 0; -} - -static int -procptopen(void) { - return ((procpt = fopen(PROC_PARTITIONS, "r")) != NULL); -} - -static char * -procptnext(void) { - char line[100]; - char *s; - int ma, mi, sz; - static char ptname[100]; - - while (fgets(line, sizeof(line), procpt)) { - if (sscanf (line, " %d %d %d %[^\n]\n", &ma, &mi, &sz, ptname) != 4) - continue; - - /* skip extended partitions (heuristic: size 1) */ - if (sz == 1) - 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])) - return ptname; - } - return 0; -} - -#define UUID 1 -#define VOL 2 +static struct uuidCache_s { + struct uuidCache_s *next; + char uuid[16]; + char *label; + char *device; +} *uuidCache = NULL; /* for now, only ext2 is supported */ static int -has_right_label(const char *device, int n, const void *label) { +get_label_uuid(const char *device, char **label, char *uuid) { /* start with a test for ext2, taken from mount_guess_fstype */ + /* should merge these later */ int fd; struct ext2_super_block e2sb; fd = open(device, O_RDONLY); if (fd < 0) - return 0; + return 1; if (lseek(fd, 1024, SEEK_SET) != 1024 || read(fd, (char *) &e2sb, sizeof(e2sb)) != sizeof(e2sb) || (ext2magic(e2sb) != EXT2_SUPER_MAGIC)) { close(fd); - return 0; + return 1; } close(fd); /* superblock is ext2 - now what is its label? */ - if (n == UUID) - return (memcmp(e2sb.s_uuid, label, 16) == 0); - else - return (strncmp(e2sb.s_volume_name, - (const char *) label, 16) == 0); + memcpy(uuid, e2sb.s_uuid, sizeof(e2sb.s_uuid)); + *label = strdup(e2sb.s_volume_name); + + return 0; } -static char * -get_spec_by_x(int n, const void *t) { - char *pt; +static void +uuidcache_addentry(char *device, char *label, char *uuid) { + struct uuidCache_s *last; + + if (!uuidCache) { + last = uuidCache = malloc(sizeof(*uuidCache)); + } else { + for (last = uuidCache; last->next; last = last->next) ; + last->next = malloc(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; - if(!procptopen()) - return NULL; - while((pt = procptnext()) != NULL) { - /* 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.) - */ - sprintf(device, "%s/%s", DEVLABELDIR, pt); - if (has_right_label(device, n, t)) { - procptclose(); - return strdup(device); + 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.) + */ + sprintf(device, "%s/%s", DEVLABELDIR, ptname); + if (!get_label_uuid(device, &label, uuid)) + uuidcache_addentry(strdup(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 strdup(uc->device); + break; + case VOL: + if (!strcmp(t, uc->label)) + return strdup(uc->device); + break; + } + uc = uc->next; } - procptclose(); return NULL; } -static unsigned char +static u_char fromhex(char c) { if (isdigit(c)) return (c - '0'); @@ -138,10 +181,9 @@ } char * -get_spec_by_uuid(const char *s0) { - unsigned char uuid[16]; +get_spec_by_uuid(const char *s) { + u_char uuid[16]; int i; - const char *s = s0; if (strlen(s) != 36 || s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-') @@ -156,11 +198,26 @@ return get_spec_by_x(UUID, uuid); bad_uuid: - fprintf(stderr, _("WARNING: %s: bad UUID"), s0); - return NULL; + fprintf(stderr, ("WARNING: bad UUID")); + return NULL; /* just for gcc */ } char * get_spec_by_volume_label(const char *s) { return get_spec_by_x(VOL, s); +} + +const char * +get_volume_label_by_spec(const char *spec) { + struct uuidCache_s *uc; + + uuidcache_init(); + uc = uuidCache; + + while(uc) { + if (!strcmp(spec, uc->device)) + return uc->label; + uc = uc->next; + } + return NULL; }