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