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