]> git.wh0rd.org - dump.git/blob - compat/lib/bylabel.c
Made dump understand the LABEL= and UUID= notations.
[dump.git] / compat / lib / bylabel.c
1 /*
2 * mount_by_label.c - aeb
3 *
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
12 */
13
14 #include <stdio.h>
15 #include <sys/param.h>
16 #include <string.h>
17 #include <ctype.h>
18 #include <fcntl.h>
19 #include <unistd.h>
20 #include <linux/ext2_fs.h>
21 #include <ext2fs/ext2fs.h>
22 #include "bylabel.h"
23
24 #define PROC_PARTITIONS "/proc/partitions"
25 #define DEVLABELDIR "/dev"
26
27 void msg __P((const char *fmt, ...));
28
29 static struct uuidCache_s {
30 struct uuidCache_s *next;
31 char uuid[16];
32 char *label;
33 char *device;
34 } *uuidCache = NULL;
35
36 /* for now, only ext2 is supported */
37 static int
38 get_label_uuid(const char *device, char **label, char *uuid) {
39
40 /* start with a test for ext2, taken from mount_guess_fstype */
41 /* should merge these later */
42 int fd;
43 struct ext2_super_block e2sb;
44
45 fd = open(device, O_RDONLY);
46 if (fd < 0)
47 return 1;
48
49 if (lseek(fd, 1024, SEEK_SET) != 1024
50 || read(fd, (char *) &e2sb, sizeof(e2sb)) != sizeof(e2sb)
51 || (e2sb.s_magic != EXT2_SUPER_MAGIC)) {
52 close(fd);
53 return 1;
54 }
55
56 close(fd);
57
58 /* superblock is ext2 - now what is its label? */
59 memcpy(uuid, e2sb.s_uuid, sizeof(e2sb.s_uuid));
60 *label = strdup(e2sb.s_volume_name);
61
62 return 0;
63 }
64
65 static void
66 uuidcache_addentry(char *device, char *label, char *uuid) {
67 struct uuidCache_s *last;
68
69 if (!uuidCache) {
70 last = uuidCache = malloc(sizeof(*uuidCache));
71 } else {
72 for (last = uuidCache; last->next; last = last->next) ;
73 last->next = malloc(sizeof(*uuidCache));
74 last = last->next;
75 }
76 last->next = NULL;
77 last->device = device;
78 last->label = label;
79 memcpy(last->uuid, uuid, sizeof(last->uuid));
80 }
81
82 static void
83 uuidcache_init(void) {
84 char line[100];
85 char *s;
86 int ma, mi, sz;
87 static char ptname[100];
88 FILE *procpt;
89 char uuid[16], *label;
90 char device[110];
91 int firstPass;
92 int handleOnFirst;
93
94 if (uuidCache)
95 return;
96
97 procpt = fopen(PROC_PARTITIONS, "r");
98 if (!procpt)
99 return;
100
101 for (firstPass = 1; firstPass >= 0; firstPass--) {
102 fseek(procpt, 0, SEEK_SET);
103
104 while (fgets(line, sizeof(line), procpt)) {
105 if (sscanf (line, " %d %d %d %[^\n ]",
106 &ma, &mi, &sz, ptname) != 4)
107 continue;
108
109 /* skip extended partitions (heuristic: size 1) */
110 if (sz == 1)
111 continue;
112
113 /* look only at md devices on first pass */
114 handleOnFirst = !strncmp(ptname, "md", 2);
115 if (firstPass != handleOnFirst)
116 continue;
117
118 /* skip entire disk (minor 0, 64, ... on ide;
119 0, 16, ... on sd) */
120 /* heuristic: partition name ends in a digit */
121
122 for(s = ptname; *s; s++);
123 if (isdigit(s[-1])) {
124 /*
125 * Note: this is a heuristic only - there is no reason
126 * why these devices should live in /dev.
127 * Perhaps this directory should be specifiable by option.
128 * One might for example have /devlabel with links to /dev
129 * for the devices that may be accessed in this way.
130 * (This is useful, if the cdrom on /dev/hdc must not
131 * be accessed.)
132 */
133 sprintf(device, "%s/%s", DEVLABELDIR, ptname);
134 if (!get_label_uuid(device, &label, uuid))
135 uuidcache_addentry(strdup(device), label, uuid);
136 }
137 }
138 }
139
140 fclose(procpt);
141 }
142
143 #define UUID 1
144 #define VOL 2
145
146 static char *
147 get_spec_by_x(int n, const char *t) {
148 struct uuidCache_s *uc;
149
150 uuidcache_init();
151 uc = uuidCache;
152
153 while(uc) {
154 switch (n) {
155 case UUID:
156 if (!memcmp(t, uc->uuid, sizeof(uc->uuid)))
157 return strdup(uc->device);
158 break;
159 case VOL:
160 if (!strcmp(t, uc->label))
161 return strdup(uc->device);
162 break;
163 }
164 uc = uc->next;
165 }
166 return NULL;
167 }
168
169 static u_char
170 fromhex(char c) {
171 if (isdigit(c))
172 return (c - '0');
173 else if (islower(c))
174 return (c - 'a' + 10);
175 else
176 return (c - 'A' + 10);
177 }
178
179 static char *
180 get_spec_by_uuid(const char *s) {
181 u_char uuid[16];
182 int i;
183
184 if (strlen(s) != 36 ||
185 s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-')
186 goto bad_uuid;
187 for (i=0; i<16; i++) {
188 if (*s == '-') s++;
189 if (!isxdigit(s[0]) || !isxdigit(s[1]))
190 goto bad_uuid;
191 uuid[i] = ((fromhex(s[0])<<4) | fromhex(s[1]));
192 s += 2;
193 }
194 return get_spec_by_x(UUID, uuid);
195
196 bad_uuid:
197 msg("mount: bad UUID\n");
198 return NULL; /* just for gcc */
199 }
200
201 static char *
202 get_spec_by_volume_label(const char *s) {
203 return get_spec_by_x(VOL, s);
204 }
205
206 const char *
207 get_device_name(const char * item) {
208 const char * rc;
209
210 if (!strncmp(item, "UUID=", 5)) {
211 rc = get_spec_by_uuid(item+5);
212 }
213 else
214 if (!strncmp(item, "LABEL=", 6)) {
215 rc = get_spec_by_volume_label(item+6);
216 }
217 else {
218 rc = item;
219 }
220
221 return rc;
222 }