debuggers.hg

view tools/misc/lomount/lomount.c @ 22848:6341fe0f4e5a

Added tag 4.1.0-rc2 for changeset 9dca60d88c63
author Keir Fraser <keir@xen.org>
date Tue Jan 25 14:06:55 2011 +0000 (2011-01-25)
parents 729a6231de35
children
line source
1 /*
2 * lomount - utility to mount partitions in a hard disk image
3 *
4 * Copyright (c) 2004 Jim Brown
5 * Copyright (c) 2004 Brad Watson
6 * Copyright (c) 2004 Mulyadi Santosa
7 * Major rewrite by Tristan Gingold:
8 * - Handle GPT partitions
9 * - Handle large files
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a copy
12 * of this software and associated documentation files (the "Software"), to deal
13 * in the Software without restriction, including without limitation the rights
14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 * copies of the Software, and to permit persons to whom the Software is
16 * furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 * THE SOFTWARE.
28 */
30 /*
31 * Return code:
32 *
33 * bit 7 set: lomount wrapper failed
34 * bit 7 clear: lomount wrapper ok; mount's return code in low 7 bits
35 * 0 success
36 */
38 enum
39 {
40 ERR_USAGE = 0x80, // Incorrect usage
41 ERR_PART_PARSE, // Failed to parse partition table
42 ERR_NO_PART, // No such partition
43 ERR_NO_EPART, // No such extended partition
44 ERR_MOUNT // Other failure of mount command
45 };
47 #include <unistd.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <strings.h>
52 #include <sys/wait.h>
53 #include <errno.h>
55 #define BUF 4096
57 #define SECSIZE 512
59 struct pentry
60 {
61 unsigned char bootable;
62 unsigned char start_head;
63 unsigned int start_cylinder;
64 unsigned char start_sector;
65 unsigned char system;
66 unsigned char end_head;
67 unsigned int end_cylinder;
68 unsigned char end_sector;
69 unsigned long long start_sector_abs;
70 unsigned long long no_of_sectors_abs;
71 };
73 static void
74 disp_entry (struct pentry *p)
75 {
76 printf ("%10llu - %10llu: %02x %x\n",
77 SECSIZE * p->start_sector_abs,
78 SECSIZE * (p->start_sector_abs + p->no_of_sectors_abs - 1),
79 p->system,
80 p->bootable);
81 }
83 static unsigned long
84 read_le4 (unsigned char *p)
85 {
86 return (unsigned long) p[0]
87 | ((unsigned long) p[1] << 8)
88 | ((unsigned long) p[2] << 16)
89 | ((unsigned long) p[3] << 24);
90 }
92 static unsigned long long
93 read_le8 (unsigned char *p)
94 {
95 return (unsigned long long) p[0]
96 | ((unsigned long long) p[1] << 8)
97 | ((unsigned long long) p[2] << 16)
98 | ((unsigned long long) p[3] << 24)
99 | ((unsigned long long) p[4] << 32)
100 | ((unsigned long long) p[5] << 40)
101 | ((unsigned long long) p[6] << 48)
102 | ((unsigned long long) p[7] << 56);
103 }
105 /* Return true if the partition table is a GPT protective MBR. */
106 static int
107 check_gpt (struct pentry *part, int nbr_part)
108 {
109 if (nbr_part != 4)
110 return 0;
111 if (part[0].system == 0xee
112 && part[1].no_of_sectors_abs == 0
113 && part[2].no_of_sectors_abs == 0
114 && part[3].no_of_sectors_abs == 0)
115 return 1;
116 return 0;
117 }
119 static int
120 load_gpt (const char *diskimage, struct pentry *parttbl[])
121 {
122 FILE *fd;
123 size_t size;
124 int fail = -1;
125 unsigned char data[SECSIZE];
126 unsigned long long entries_lba;
127 unsigned long entry_size;
128 struct pentry *part;
129 int nbr_part;
130 unsigned long long off;
131 int i;
133 fd = fopen(diskimage, "r");
134 if (fd == NULL)
135 {
136 perror(diskimage);
137 goto done;
138 }
139 fseeko (fd, SECSIZE, SEEK_SET);
140 size = fread (&data, 1, sizeof(data), fd);
141 if (size < (size_t)sizeof(data))
142 {
143 fprintf(stderr, "Could not read the GPT header of %s.\n",
144 diskimage);
145 goto done;
146 }
148 if (memcmp (data, "EFI PART", 8) != 0)
149 {
150 fprintf (stderr, "Bad GPT signature\n");
151 goto done;
152 }
154 entries_lba = read_le8 (&data[72]);
155 nbr_part = read_le4 (&data[80]);
156 entry_size = read_le4 (&data[84]);
158 #ifdef DEBUG
159 fprintf(stderr, "lba entries: %llu, nbr_part: %u, entry_size: %lu\n",
160 entries_lba, nbr_part, entry_size);
161 #endif
162 part = malloc (nbr_part * sizeof (struct pentry));
163 if (part == NULL)
164 {
165 fprintf(stderr,"Cannot allocate memory\n");
166 goto done;
167 }
168 memset (part, 0, nbr_part * sizeof (struct pentry));
169 *parttbl = part;
171 off = entries_lba * SECSIZE;
172 for (i = 0; i < nbr_part; i++)
173 {
174 static const char unused_guid[16] = {0};
175 fseeko (fd, off, SEEK_SET);
176 size = fread (&data, 1, 128, fd);
177 if (size < 128)
178 {
179 fprintf(stderr, "Could not read a GPT entry of %s.\n",
180 diskimage);
181 goto done;
182 }
183 if (memcmp (&data[0], unused_guid, 16) == 0)
184 {
185 part[i].start_sector_abs = 0;
186 part[i].no_of_sectors_abs = 0;
187 }
188 else
189 {
190 part[i].start_sector_abs = read_le8 (&data[32]);
191 part[i].no_of_sectors_abs = read_le8 (&data[40]);
192 #ifdef DEBUG
193 fprintf (stderr, "%d: %llu - %llu\n", i,
194 part[i].start_sector_abs,
195 part[i].no_of_sectors_abs);
196 #endif
197 /* Convert end to a number. */
198 part[i].no_of_sectors_abs -=
199 part[i].start_sector_abs - 1;
200 }
201 off += entry_size;
202 }
204 fail = nbr_part;
206 done:
207 if (fd)
208 fclose(fd);
209 return fail;
210 }
212 /* Read an MBR entry. */
213 static void
214 read_mbr_record (unsigned char pi[16], struct pentry *res)
215 {
216 res->bootable = *pi;
217 res->start_head = *(pi + 1);
218 res->start_cylinder = *(pi + 3) | ((*(pi + 2) << 2) & 0x300);
219 res->start_sector = *(pi + 2) & 0x3f;
220 res->system = *(pi + 4);
221 res->end_head = *(pi + 5);
222 res->end_cylinder = *(pi + 7) | ((*(pi + 6) << 2) & 0x300);
223 res->end_sector = *(pi + 6) & 0x3f;
224 res->start_sector_abs = read_le4 (&pi[8]);
225 res->no_of_sectors_abs = read_le4 (&pi[12]);
226 }
228 /* Returns the number of partitions, -1 in case of failure. */
229 int load_mbr(const char *diskimage, struct pentry *parttbl[])
230 {
231 FILE *fd;
232 size_t size;
233 int fail = -1;
234 int nbr_part;
235 int i;
236 unsigned char *pi;
237 unsigned char data [SECSIZE];
238 unsigned long long extent;
239 struct pentry *part;
241 nbr_part = 0;
243 fd = fopen(diskimage, "r");
244 if (fd == NULL)
245 {
246 perror(diskimage);
247 goto done;
248 }
249 size = fread (&data, 1, sizeof(data), fd);
250 if (size < (size_t)sizeof(data))
251 {
252 fprintf(stderr, "Could not read the entire first sector of %s.\n", diskimage);
253 goto done;
254 }
256 if (data [510] != 0x55 || data [511] != 0xaa)
257 {
258 fprintf(stderr,"MBR signature mismatch (invalid partition table?)\n");
259 goto done;
260 }
262 /* There is at most 4*4 + 4 = 20 entries, also there should be only
263 one extended partition. */
264 part = malloc (20 * sizeof (struct pentry));
265 if (part == NULL)
266 {
267 fprintf(stderr,"Cannot allocate memory\n");
268 goto done;
269 }
270 *parttbl = part;
272 /* Read MBR. */
273 nbr_part = 4;
274 for (i = 0; i < 4; i++)
275 {
276 pi = &data [446 + 16 * i];
277 read_mbr_record (pi, &part[i]);
278 }
280 /* Read extended partitions. */
281 for (i = 0; i < 4; i++)
282 {
283 if (part[i].system == 0xF || part[i].system == 0x5)
284 {
285 int j;
287 extent = part[i].start_sector_abs * SECSIZE;
289 fseeko (fd, extent, SEEK_SET);
290 size = fread (&data, 1, sizeof(data), fd);
291 if (size < (size_t)sizeof(data))
292 {
293 fprintf(stderr, "Could not read extended partition of %s.", diskimage);
294 goto done;
295 }
297 for (j = 0; j < 4; j++)
298 {
299 int n;
300 pi = &data [446 + 16 * j];
301 n = nbr_part + j;
302 read_mbr_record (pi, &part[n]);
303 }
305 nbr_part += 4;
306 }
307 }
309 fail = nbr_part;
311 done:
312 if (fd)
313 fclose(fd);
314 return fail;
315 }
317 void usage(void)
318 {
319 fprintf(stderr, "Usage: lomount [-verbose] [OPTIONS] -diskimage FILE -partition NUM [OPTIONS]\n");
320 fprintf(stderr, "All OPTIONS are passed through to 'mount'.\n");
321 fprintf(stderr, "ex. lomount -t fs-type -diskimage hda.img -partition 1 /mnt\n");
322 exit(ERR_USAGE);
323 }
325 int main(int argc, char ** argv)
326 {
327 int status;
328 int nbr_part;
329 struct pentry *parttbl;
330 char buf[BUF], argv2[BUF];
331 const char * diskimage = NULL;
332 int partition = 0;
333 unsigned long long sec, num, pnum;
334 int i;
335 size_t argv2_len = sizeof(argv2);
336 int verbose = 0;
338 argv2[0] = '\0';
340 for (i = 1; i < argc; i ++)
341 {
342 if (strcmp(argv[i], "-diskimage")==0)
343 {
344 if (i == argc-1)
345 usage();
346 i++;
347 diskimage = argv[i];
348 }
349 else if (strcmp(argv[i], "-partition")==0)
350 {
351 if (i == argc-1)
352 usage();
353 i++;
354 partition = atoi(argv[i]);
355 }
356 else if (strcmp(argv[i], "-verbose")==0)
357 {
358 verbose++;
359 }
360 else
361 {
362 size_t len = strlen(argv[i]);
363 if (len >= argv2_len-1)
364 usage();
365 strcat(argv2, argv[i]);
366 strcat(argv2, " ");
367 len -= (len+1);
368 }
369 }
370 if (! diskimage || partition < 0)
371 usage();
373 nbr_part = load_mbr(diskimage, &parttbl);
374 if (check_gpt (parttbl, nbr_part)) {
375 free (parttbl);
376 nbr_part = load_gpt (diskimage, &parttbl);
377 }
378 if (nbr_part < 0)
379 return ERR_PART_PARSE;
380 if (partition == 0)
381 {
382 printf("Please specify a partition number. Table is:\n");
383 printf("Num Start - End OS Bootable\n");
384 for (i = 0; i < nbr_part; i++)
385 {
386 if (parttbl[i].no_of_sectors_abs != 0)
387 {
388 printf ("%2d: ", i + 1);
389 disp_entry (&parttbl[i]);
390 }
391 }
392 if (partition == 0)
393 return 0;
394 }
395 /* NOTE: need to make sure this always rounds down */
396 //sec = total_known_sectors / sizeof_diskimage;
397 /* The above doesn't work unless the disk image is completely
398 filled by partitions ... unused space will thrown off the
399 sector size. The calculation assumes the disk image is
400 completely filled, and that the few sectors used to store
401 the partition table/MBR are few enough that the calculated
402 value is off by (larger than) a value less than one. */
403 sec = 512; /* TODO: calculate real sector size */
404 #ifdef DEBUG
405 printf("sec: %llu\n", sec);
406 #endif
407 if (partition > nbr_part)
408 {
409 fprintf(stderr, "Bad partition number\n");
410 return ERR_NO_EPART;
411 }
412 num = parttbl[partition-1].start_sector_abs;
413 if (num == 0)
414 {
415 fprintf(stderr, "Partition %d was not found in %s.\n",
416 partition, diskimage);
417 return ERR_NO_PART;
418 }
420 pnum = sec * num;
421 #ifdef DEBUG
422 printf("offset = %llu\n", pnum);
423 #endif
424 snprintf(buf, sizeof(buf), "mount -oloop,offset=%lld %s %s",
425 pnum, diskimage, argv2);
426 if (verbose)
427 printf("%s\n", buf);
429 status = system(buf);
430 if (WIFEXITED(status))
431 status = WEXITSTATUS(status);
432 else
433 status = ERR_MOUNT;
434 return status;
435 }