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