Annotation of /tags/mkinitrd-6_2_2/nash/mount_by_label.c
Parent Directory | Revision Log
Revision 1005 -
(hide annotations)
(download)
Sun May 30 12:33:03 2010 UTC (14 years, 4 months ago) by niro
File MIME type: text/plain
File size: 6885 byte(s)
Sun May 30 12:33:03 2010 UTC (14 years, 4 months ago) by niro
File MIME type: text/plain
File size: 6885 byte(s)
tagged 'mkinitrd-6_2_2'
1 | niro | 532 | /* |
2 | * taken from util-linux 2.11g and hacked into nash | ||
3 | * | ||
4 | * mount_by_label.c - aeb | ||
5 | * | ||
6 | * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL> | ||
7 | * - added Native Language Support | ||
8 | * 2000-01-20 James Antill <james@and.org> | ||
9 | * - Added error message if /proc/partitions cannot be opened | ||
10 | * 2000-05-09 Erik Troan <ewt@redhat.com> | ||
11 | * - Added cache for UUID and disk labels | ||
12 | * 2000-11-07 Nathan Scott <nathans@sgi.com> | ||
13 | * - Added XFS support | ||
14 | */ | ||
15 | |||
16 | #include <errno.h> | ||
17 | #include <stdio.h> | ||
18 | #include <string.h> | ||
19 | #include <ctype.h> | ||
20 | #include <fcntl.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <unistd.h> | ||
23 | #include <sys/stat.h> | ||
24 | #include "linux_fs.h" | ||
25 | #include "mount_by_label.h" | ||
26 | |||
27 | #define PROC_PARTITIONS "/proc/partitions" | ||
28 | #define DEVLABELDIR "/dev" | ||
29 | |||
30 | #define _(str) (str) | ||
31 | |||
32 | static struct uuidCache_s { | ||
33 | struct uuidCache_s *next; | ||
34 | char uuid[16]; | ||
35 | char *device; | ||
36 | char *label; | ||
37 | int major, minor; | ||
38 | } *uuidCache = NULL; | ||
39 | |||
40 | /* for now, only ext2, ext3 and xfs are supported */ | ||
41 | static int | ||
42 | get_label_uuid(const char *device, char **label, char *uuid) { | ||
43 | |||
44 | /* start with ext2/3 and xfs tests, taken from mount_guess_fstype */ | ||
45 | /* should merge these later */ | ||
46 | int fd; | ||
47 | int rv = 1; | ||
48 | size_t namesize; | ||
49 | struct ext2_super_block e2sb; | ||
50 | struct xfs_super_block xfsb; | ||
51 | |||
52 | fd = open(device, O_RDONLY); | ||
53 | if (fd < 0) | ||
54 | return rv; | ||
55 | |||
56 | if (lseek(fd, 1024, SEEK_SET) == 1024 | ||
57 | && read(fd, (char *) &e2sb, sizeof(e2sb)) == sizeof(e2sb) | ||
58 | && (ext2magic(e2sb) == EXT2_SUPER_MAGIC)) { | ||
59 | memcpy(uuid, e2sb.s_uuid, sizeof(e2sb.s_uuid)); | ||
60 | namesize = sizeof(e2sb.s_volume_name); | ||
61 | if ((*label = calloc(namesize + 1, 1)) != NULL) | ||
62 | memcpy(*label, e2sb.s_volume_name, namesize); | ||
63 | rv = 0; | ||
64 | } | ||
65 | else if (lseek(fd, 0, SEEK_SET) == 0 | ||
66 | && read(fd, (char *) &xfsb, sizeof(xfsb)) == sizeof(xfsb) | ||
67 | && (strncmp((char *)xfsb.s_magic, XFS_SUPER_MAGIC, 4) == 0)) { | ||
68 | memcpy(uuid, xfsb.s_uuid, sizeof(xfsb.s_uuid)); | ||
69 | namesize = sizeof(xfsb.s_fname); | ||
70 | if ((*label = calloc(namesize + 1, 1)) != NULL) | ||
71 | memcpy(*label, xfsb.s_fname, namesize); | ||
72 | rv = 0; | ||
73 | } | ||
74 | |||
75 | close(fd); | ||
76 | return rv; | ||
77 | } | ||
78 | |||
79 | static void | ||
80 | uuidcache_addentry(char * device, int major, int minor, char *label, char *uuid) { | ||
81 | struct uuidCache_s *last; | ||
82 | |||
83 | if (!uuidCache) { | ||
84 | last = uuidCache = calloc(1, sizeof (*uuidCache)); | ||
85 | } else { | ||
86 | for (last = uuidCache; last->next; last = last->next) ; | ||
87 | last->next = calloc(1, sizeof (*uuidCache)); | ||
88 | last = last->next; | ||
89 | } | ||
90 | last->next = NULL; | ||
91 | last->label = label; | ||
92 | last->device = device; | ||
93 | last->major = major; | ||
94 | last->minor = minor; | ||
95 | memcpy(last->uuid, uuid, sizeof(last->uuid)); | ||
96 | } | ||
97 | |||
98 | static void | ||
99 | uuidcache_init(void) { | ||
100 | char line[100]; | ||
101 | char *s; | ||
102 | int ma, mi, sz; | ||
103 | static char ptname[100]; | ||
104 | FILE *procpt; | ||
105 | char uuid[16], *label; | ||
106 | char device[110]; | ||
107 | int firstPass; | ||
108 | int handleOnFirst; | ||
109 | char * chptr, * endptr; | ||
110 | |||
111 | if (uuidCache) | ||
112 | return; | ||
113 | |||
114 | procpt = fopen(PROC_PARTITIONS, "r"); | ||
115 | if (!procpt) { | ||
116 | static int warn = 0; | ||
117 | if (!warn++) | ||
118 | fprintf (stderr, _("mount: could not open %s, so UUID and LABEL " | ||
119 | "conversion cannot be done.\n"), | ||
120 | PROC_PARTITIONS); | ||
121 | return; | ||
122 | } | ||
123 | |||
124 | for (firstPass = 1; firstPass >= 0; firstPass--) { | ||
125 | fseek(procpt, 0, SEEK_SET); | ||
126 | |||
127 | while (fgets(line, sizeof(line), procpt)) { | ||
128 | /* The original version of this code used sscanf, but | ||
129 | diet's sscanf is quite limited */ | ||
130 | chptr = line; | ||
131 | if (*chptr++ != ' ') continue; | ||
132 | |||
133 | ma = strtol(chptr, &endptr, 0); | ||
134 | if (endptr == chptr) continue; | ||
135 | while (isspace(*endptr)) endptr++; | ||
136 | chptr = endptr; | ||
137 | |||
138 | mi = strtol(chptr, &endptr, 0); | ||
139 | if (endptr == chptr) continue; | ||
140 | while (isspace(*endptr)) endptr++; | ||
141 | chptr = endptr; | ||
142 | |||
143 | sz = strtol(chptr, &endptr, 0); | ||
144 | if (endptr == chptr) continue; | ||
145 | while (isspace(*endptr)) endptr++; | ||
146 | chptr = endptr; | ||
147 | |||
148 | while (!isspace(*endptr) && *endptr != '\n') endptr++; | ||
149 | if (chptr == endptr) continue; | ||
150 | strncpy(ptname, chptr, endptr - chptr); | ||
151 | ptname[endptr - chptr] = '\0'; | ||
152 | |||
153 | /* skip extended partitions (heuristic: size 1) */ | ||
154 | if (sz == 1) | ||
155 | continue; | ||
156 | |||
157 | /* look only at md devices on first pass */ | ||
158 | handleOnFirst = !strncmp(ptname, "md", 2); | ||
159 | if (firstPass != handleOnFirst) | ||
160 | continue; | ||
161 | |||
162 | /* skip entire disk (minor 0, 64, ... on ide; | ||
163 | 0, 16, ... on sd) */ | ||
164 | /* heuristic: partition name ends in a digit */ | ||
165 | |||
166 | for(s = ptname; *s; s++); | ||
167 | |||
168 | if (isdigit(s[-1])) { | ||
169 | char * ptr; | ||
170 | char * deviceDir = NULL; | ||
171 | int mustRemove = 0; | ||
172 | int mustRemoveDir = 0; | ||
173 | int i; | ||
174 | |||
175 | sprintf(device, "%s/%s", DEVLABELDIR, ptname); | ||
176 | if (access(device, F_OK)) { | ||
177 | ptr = device; | ||
178 | i = 0; | ||
179 | while (*ptr) | ||
180 | if (*ptr++ == '/') | ||
181 | i++; | ||
182 | if (i > 2) { | ||
183 | deviceDir = alloca(strlen(device) + 1); | ||
184 | strcpy(deviceDir, device); | ||
185 | ptr = deviceDir + (strlen(device) - 1); | ||
186 | while (*ptr != '/') | ||
187 | *ptr-- = '\0'; | ||
188 | if (mkdir(deviceDir, 0644)) { | ||
189 | printf("mkdir: cannot create directory %s: %d\n", deviceDir, errno); | ||
190 | } else { | ||
191 | mustRemoveDir = 1; | ||
192 | } | ||
193 | } | ||
194 | |||
195 | mknod(device, S_IFBLK | 0600, makedev(ma, mi)); | ||
196 | mustRemove = 1; | ||
197 | } | ||
198 | if (!get_label_uuid(device, &label, uuid)) | ||
199 | uuidcache_addentry(strdup(device), ma, mi, | ||
200 | label, uuid); | ||
201 | |||
202 | if (mustRemove) unlink(device); | ||
203 | if (mustRemoveDir) rmdir(deviceDir); | ||
204 | } | ||
205 | } | ||
206 | } | ||
207 | |||
208 | fclose(procpt); | ||
209 | } | ||
210 | |||
211 | #define UUID 1 | ||
212 | #define VOL 2 | ||
213 | |||
214 | static char * | ||
215 | get_spec_by_x(int n, const char *t, int * majorPtr, int * minorPtr) { | ||
216 | struct uuidCache_s *uc; | ||
217 | |||
218 | uuidcache_init(); | ||
219 | uc = uuidCache; | ||
220 | |||
221 | while(uc) { | ||
222 | switch (n) { | ||
223 | case UUID: | ||
224 | if (!memcmp(t, uc->uuid, sizeof(uc->uuid))) { | ||
225 | *majorPtr = uc->major; | ||
226 | *minorPtr = uc->minor; | ||
227 | return uc->device; | ||
228 | } | ||
229 | break; | ||
230 | case VOL: | ||
231 | if (!strcmp(t, uc->label)) { | ||
232 | *majorPtr = uc->major; | ||
233 | *minorPtr = uc->minor; | ||
234 | return uc->device; | ||
235 | } | ||
236 | break; | ||
237 | } | ||
238 | uc = uc->next; | ||
239 | } | ||
240 | return NULL; | ||
241 | } | ||
242 | |||
243 | static unsigned char | ||
244 | fromhex(char c) { | ||
245 | if (isdigit(c)) | ||
246 | return (c - '0'); | ||
247 | else if (islower(c)) | ||
248 | return (c - 'a' + 10); | ||
249 | else | ||
250 | return (c - 'A' + 10); | ||
251 | } | ||
252 | |||
253 | char * | ||
254 | get_spec_by_uuid(const char *s, int * major, int * minor) { | ||
255 | unsigned char uuid[16]; | ||
256 | int i; | ||
257 | |||
258 | if (strlen(s) != 36 || | ||
259 | s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-') | ||
260 | goto bad_uuid; | ||
261 | for (i=0; i<16; i++) { | ||
262 | if (*s == '-') s++; | ||
263 | if (!isxdigit(s[0]) || !isxdigit(s[1])) | ||
264 | goto bad_uuid; | ||
265 | uuid[i] = ((fromhex(s[0])<<4) | fromhex(s[1])); | ||
266 | s += 2; | ||
267 | } | ||
268 | return get_spec_by_x(UUID, (char *)uuid, major, minor); | ||
269 | |||
270 | bad_uuid: | ||
271 | fprintf(stderr, _("mount: bad UUID")); | ||
272 | return NULL; | ||
273 | } | ||
274 | |||
275 | char * | ||
276 | get_spec_by_volume_label(const char *s, int * major, int * minor) { | ||
277 | return get_spec_by_x(VOL, s, major, minor); | ||
278 | } | ||
279 | |||
280 | int | ||
281 | display_uuid_cache(char *cmd, char *end) | ||
282 | { | ||
283 | struct uuidCache_s * u; | ||
284 | size_t i; | ||
285 | |||
286 | uuidcache_init(); | ||
287 | |||
288 | u = uuidCache; | ||
289 | while (u) { | ||
290 | printf("%s %s ", u->device, u->label); | ||
291 | for (i = 0; i < sizeof(u->uuid); i++) { | ||
292 | if (i == 4 || i == 6 || i == 8 || i == 10) | ||
293 | printf("-"); | ||
294 | printf("%x", u->uuid[i] & 0xff); | ||
295 | } | ||
296 | printf("\n"); | ||
297 | u = u->next; | ||
298 | } | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 |