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