2 * mount_by_label.c - aeb
4 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
5 * - added Native Language Support
6 * 2000-01-20 James Antill <james@and.org>
7 * - Added error message if /proc/partitions cannot be opened
8 * 2000-05-09 Erik Troan <ewt@redhat.com>
9 * - Added cache for UUID and disk labels
10 * Wed Aug 16 2000 Erik Troan <ewt@redhat.com>
11 * - Ported to dump/restore
15 #include <compatlfs.h>
17 #include <sys/param.h>
25 #define PROC_PARTITIONS "/proc/partitions"
26 #define DEVLABELDIR "/dev"
28 #define EXT2_SUPER_OFFSET 1024
29 #define EXT2_SUPER_SIZE sizeof(struct ext2_super_block)
30 #define EXT2_SUPER_MAGIC 0xEF53
32 struct ext2_super_block {
33 unsigned char s_dummy1[56];
34 unsigned char s_magic[2];
35 unsigned char s_dummy2[46];
36 unsigned char s_uuid[16];
37 unsigned char s_volume_name[16];
39 #define ext2magic(s) ((unsigned int) s.s_magic[0] + (((unsigned int) s.s_magic[1]) << 8))
41 void msg __P((const char *fmt, ...));
43 static struct uuidCache_s {
44 struct uuidCache_s *next;
50 /* for now, only ext2 is supported */
52 get_label_uuid(const char *device, char **label, char *uuid) {
54 /* start with a test for ext2, taken from mount_guess_fstype */
55 /* should merge these later */
57 struct ext2_super_block e2sb;
59 fd = OPEN(device, O_RDONLY);
63 if (LSEEK(fd, EXT2_SUPER_OFFSET, SEEK_SET) != EXT2_SUPER_OFFSET ||
64 read(fd, (char *) &e2sb, EXT2_SUPER_SIZE) != EXT2_SUPER_SIZE ||
65 ext2magic(e2sb) != EXT2_SUPER_MAGIC) {
72 /* superblock is ext2 - now what is its label? */
73 memcpy(uuid, e2sb.s_uuid, sizeof(e2sb.s_uuid));
74 *label = strdup(e2sb.s_volume_name);
80 uuidcache_addentry(char *device, char *label, char *uuid) {
81 struct uuidCache_s *last;
84 last = uuidCache = (struct uuidCache_s *)malloc(sizeof(*uuidCache));
86 for (last = uuidCache; last->next; last = last->next) ;
87 last->next = (struct uuidCache_s *)malloc(sizeof(*uuidCache));
91 last->device = device;
93 memcpy(last->uuid, uuid, sizeof(last->uuid));
97 uuidcache_init(void) {
101 static char ptname[100];
103 char uuid[16], *label;
111 procpt = fopen(PROC_PARTITIONS, "r");
115 for (firstPass = 1; firstPass >= 0; firstPass--) {
116 fseek(procpt, 0, SEEK_SET);
118 while (fgets(line, sizeof(line), procpt)) {
119 if (sscanf (line, " %d %d %d %[^\n ]",
120 &ma, &mi, &sz, ptname) != 4)
123 /* skip extended partitions (heuristic: size 1) */
127 /* look only at md devices on first pass */
128 handleOnFirst = !strncmp(ptname, "md", 2);
129 if (firstPass != handleOnFirst)
132 /* skip entire disk (minor 0, 64, ... on ide;
134 /* heuristic: partition name ends in a digit */
136 for(s = ptname; *s; s++);
137 if (isdigit(s[-1])) {
139 * Note: this is a heuristic only - there is no reason
140 * why these devices should live in /dev.
141 * Perhaps this directory should be specifiable by option.
142 * One might for example have /devlabel with links to /dev
143 * for the devices that may be accessed in this way.
144 * (This is useful, if the cdrom on /dev/hdc must not
147 sprintf(device, "%s/%s", DEVLABELDIR, ptname);
148 if (!get_label_uuid(device, &label, uuid))
149 uuidcache_addentry(strdup(device), label, uuid);
161 get_spec_by_x(int n, const char *t) {
162 struct uuidCache_s *uc;
170 if (!memcmp(t, uc->uuid, sizeof(uc->uuid)))
171 return strdup(uc->device);
174 if (!strcmp(t, uc->label))
175 return strdup(uc->device);
188 return (c - 'a' + 10);
190 return (c - 'A' + 10);
194 get_spec_by_uuid(const char *s) {
198 if (strlen(s) != 36 ||
199 s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-')
201 for (i=0; i<16; i++) {
203 if (!isxdigit(s[0]) || !isxdigit(s[1]))
205 uuid[i] = ((fromhex(s[0])<<4) | fromhex(s[1]));
208 return get_spec_by_x(UUID, uuid);
211 msg("mount: bad UUID\n");
212 return NULL; /* just for gcc */
216 get_spec_by_volume_label(const char *s) {
217 return get_spec_by_x(VOL, s);
221 get_device_name(const char * item) {
224 if (!strncmp(item, "UUID=", 5)) {
225 rc = get_spec_by_uuid(item+5);
228 if (!strncmp(item, "LABEL=", 6)) {
229 rc = get_spec_by_volume_label(item+6);
239 get_device_label(const char * spec) {
240 struct uuidCache_s *uc;
246 if (!strcmp(spec, uc->device))
247 return uc->label[0] == '\0' ? NULL : strdup(uc->label);