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