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