ia64/xen-unstable

view tools/misc/lomount/lomount.c @ 10910:9632ececc8f4

[TOOLS] lomount: Fix printf formats inside #ifdef DEBUG.

Signed-off-by: Tristan Gingold <tristan.gingold@bull.net>
author kfraser@localhost.localdomain
date Wed Aug 02 10:13:30 2006 +0100 (2006-08-02)
parents fa143f374f3d
children 729a6231de35
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 #define _LARGEFILE_SOURCE
48 #define _FILE_OFFSET_BITS 64
49 #include <unistd.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <strings.h>
54 #include <sys/wait.h>
55 #include <errno.h>
57 #define BUF 4096
59 #define SECSIZE 512
61 struct pentry
62 {
63 unsigned char bootable;
64 unsigned char start_head;
65 unsigned int start_cylinder;
66 unsigned char start_sector;
67 unsigned char system;
68 unsigned char end_head;
69 unsigned int end_cylinder;
70 unsigned char end_sector;
71 unsigned long long start_sector_abs;
72 unsigned long long no_of_sectors_abs;
73 };
75 static void
76 disp_entry (struct pentry *p)
77 {
78 printf ("%10llu - %10llu: %02x %x\n",
79 SECSIZE * p->start_sector_abs,
80 SECSIZE * (p->start_sector_abs + p->no_of_sectors_abs - 1),
81 p->system,
82 p->bootable);
83 }
85 static unsigned long
86 read_le4 (unsigned char *p)
87 {
88 return (unsigned long) p[0]
89 | ((unsigned long) p[1] << 8)
90 | ((unsigned long) p[2] << 16)
91 | ((unsigned long) p[3] << 24);
92 }
94 static unsigned long long
95 read_le8 (unsigned char *p)
96 {
97 return (unsigned long long) p[0]
98 | ((unsigned long long) p[1] << 8)
99 | ((unsigned long long) p[2] << 16)
100 | ((unsigned long long) p[3] << 24)
101 | ((unsigned long long) p[4] << 32)
102 | ((unsigned long long) p[5] << 40)
103 | ((unsigned long long) p[6] << 48)
104 | ((unsigned long long) p[7] << 56);
105 }
107 /* Return true if the partition table is a GPT protective MBR. */
108 static int
109 check_gpt (struct pentry *part, int nbr_part)
110 {
111 if (nbr_part != 4)
112 return 0;
113 if (part[0].system == 0xee
114 && part[1].no_of_sectors_abs == 0
115 && part[2].no_of_sectors_abs == 0
116 && part[3].no_of_sectors_abs == 0)
117 return 1;
118 return 0;
119 }
121 static int
122 load_gpt (const char *diskimage, struct pentry *parttbl[])
123 {
124 FILE *fd;
125 size_t size;
126 int fail = -1;
127 unsigned char data[SECSIZE];
128 unsigned long long entries_lba;
129 unsigned long entry_size;
130 struct pentry *part;
131 int nbr_part;
132 unsigned long long off;
133 int i;
135 fd = fopen(diskimage, "r");
136 if (fd == NULL)
137 {
138 perror(diskimage);
139 goto done;
140 }
141 fseeko (fd, SECSIZE, SEEK_SET);
142 size = fread (&data, 1, sizeof(data), fd);
143 if (size < (size_t)sizeof(data))
144 {
145 fprintf(stderr, "Could not read the GPT header of %s.\n",
146 diskimage);
147 goto done;
148 }
150 if (memcmp (data, "EFI PART", 8) != 0)
151 {
152 fprintf (stderr, "Bad GPT signature\n");
153 goto done;
154 }
156 entries_lba = read_le8 (&data[72]);
157 nbr_part = read_le4 (&data[80]);
158 entry_size = read_le4 (&data[84]);
160 #ifdef DEBUG
161 fprintf(stderr, "lba entries: %llu, nbr_part: %u, entry_size: %lu\n",
162 entries_lba, nbr_part, entry_size);
163 #endif
164 part = malloc (nbr_part * sizeof (struct pentry));
165 if (part == NULL)
166 {
167 fprintf(stderr,"Cannot allocate memory\n");
168 goto done;
169 }
170 memset (part, 0, nbr_part * sizeof (struct pentry));
171 *parttbl = part;
173 off = entries_lba * SECSIZE;
174 for (i = 0; i < nbr_part; i++)
175 {
176 static const char unused_guid[16] = {0};
177 fseeko (fd, off, SEEK_SET);
178 size = fread (&data, 1, 128, fd);
179 if (size < 128)
180 {
181 fprintf(stderr, "Could not read a GPT entry of %s.\n",
182 diskimage);
183 goto done;
184 }
185 if (memcmp (&data[0], unused_guid, 16) == 0)
186 {
187 part[i].start_sector_abs = 0;
188 part[i].no_of_sectors_abs = 0;
189 }
190 else
191 {
192 part[i].start_sector_abs = read_le8 (&data[32]);
193 part[i].no_of_sectors_abs = read_le8 (&data[40]);
194 #ifdef DEBUG
195 fprintf (stderr, "%d: %llu - %llu\n", i,
196 part[i].start_sector_abs,
197 part[i].no_of_sectors_abs);
198 #endif
199 /* Convert end to a number. */
200 part[i].no_of_sectors_abs -=
201 part[i].start_sector_abs - 1;
202 }
203 off += entry_size;
204 }
206 fail = nbr_part;
208 done:
209 if (fd)
210 fclose(fd);
211 return fail;
212 }
214 /* Read an MBR entry. */
215 static void
216 read_mbr_record (unsigned char pi[16], struct pentry *res)
217 {
218 res->bootable = *pi;
219 res->start_head = *(pi + 1);
220 res->start_cylinder = *(pi + 3) | ((*(pi + 2) << 2) & 0x300);
221 res->start_sector = *(pi + 2) & 0x3f;
222 res->system = *(pi + 4);
223 res->end_head = *(pi + 5);
224 res->end_cylinder = *(pi + 7) | ((*(pi + 6) << 2) & 0x300);
225 res->end_sector = *(pi + 6) & 0x3f;
226 res->start_sector_abs = read_le4 (&pi[8]);
227 res->no_of_sectors_abs = read_le4 (&pi[12]);
228 }
230 /* Returns the number of partitions, -1 in case of failure. */
231 int load_mbr(const char *diskimage, struct pentry *parttbl[])
232 {
233 FILE *fd;
234 size_t size;
235 int fail = -1;
236 int nbr_part;
237 int i;
238 unsigned char *pi;
239 unsigned char data [SECSIZE];
240 unsigned long long extent;
241 struct pentry *part;
243 nbr_part = 0;
245 fd = fopen(diskimage, "r");
246 if (fd == NULL)
247 {
248 perror(diskimage);
249 goto done;
250 }
251 size = fread (&data, 1, sizeof(data), fd);
252 if (size < (size_t)sizeof(data))
253 {
254 fprintf(stderr, "Could not read the entire first sector of %s.\n", diskimage);
255 goto done;
256 }
258 if (data [510] != 0x55 || data [511] != 0xaa)
259 {
260 fprintf(stderr,"MBR signature mismatch (invalid partition table?)\n");
261 goto done;
262 }
264 /* There is at most 4*4 + 4 = 20 entries, also there should be only
265 one extended partition. */
266 part = malloc (20 * sizeof (struct pentry));
267 if (part == NULL)
268 {
269 fprintf(stderr,"Cannot allocate memory\n");
270 goto done;
271 }
272 *parttbl = part;
274 /* Read MBR. */
275 nbr_part = 4;
276 for (i = 0; i < 4; i++)
277 {
278 pi = &data [446 + 16 * i];
279 read_mbr_record (pi, &part[i]);
280 }
282 /* Read extended partitions. */
283 for (i = 0; i < 4; i++)
284 {
285 if (part[i].system == 0xF || part[i].system == 0x5)
286 {
287 int j;
289 extent = part[i].start_sector_abs * SECSIZE;
291 fseeko (fd, extent, SEEK_SET);
292 size = fread (&data, 1, sizeof(data), fd);
293 if (size < (size_t)sizeof(data))
294 {
295 fprintf(stderr, "Could not read extended partition of %s.", diskimage);
296 goto done;
297 }
299 for (j = 0; j < 4; j++)
300 {
301 int n;
302 pi = &data [446 + 16 * j];
303 n = nbr_part + j;
304 read_mbr_record (pi, &part[n]);
305 }
307 nbr_part += 4;
308 }
309 }
311 fail = nbr_part;
313 done:
314 if (fd)
315 fclose(fd);
316 return fail;
317 }
319 void usage(void)
320 {
321 fprintf(stderr, "Usage: lomount [-verbose] [OPTIONS] -diskimage FILE -partition NUM [OPTIONS]\n");
322 fprintf(stderr, "All OPTIONS are passed through to 'mount'.\n");
323 fprintf(stderr, "ex. lomount -t fs-type -diskimage hda.img -partition 1 /mnt\n");
324 exit(ERR_USAGE);
325 }
327 int main(int argc, char ** argv)
328 {
329 int status;
330 int nbr_part;
331 struct pentry *parttbl;
332 char buf[BUF], argv2[BUF];
333 const char * diskimage = NULL;
334 int partition = 0;
335 unsigned long long sec, num, pnum;
336 int i;
337 size_t argv2_len = sizeof(argv2);
338 int verbose = 0;
340 argv2[0] = '\0';
342 for (i = 1; i < argc; i ++)
343 {
344 if (strcmp(argv[i], "-diskimage")==0)
345 {
346 if (i == argc-1)
347 usage();
348 i++;
349 diskimage = argv[i];
350 }
351 else if (strcmp(argv[i], "-partition")==0)
352 {
353 if (i == argc-1)
354 usage();
355 i++;
356 partition = atoi(argv[i]);
357 }
358 else if (strcmp(argv[i], "-verbose")==0)
359 {
360 verbose++;
361 }
362 else
363 {
364 size_t len = strlen(argv[i]);
365 if (len >= argv2_len-1)
366 usage();
367 strcat(argv2, argv[i]);
368 strcat(argv2, " ");
369 len -= (len+1);
370 }
371 }
372 if (! diskimage || partition < 0)
373 usage();
375 nbr_part = load_mbr(diskimage, &parttbl);
376 if (check_gpt (parttbl, nbr_part)) {
377 free (parttbl);
378 nbr_part = load_gpt (diskimage, &parttbl);
379 }
380 if (nbr_part < 0)
381 return ERR_PART_PARSE;
382 if (partition == 0)
383 {
384 printf("Please specify a partition number. Table is:\n");
385 printf("Num Start - End OS Bootable\n");
386 for (i = 0; i < nbr_part; i++)
387 {
388 if (parttbl[i].no_of_sectors_abs != 0)
389 {
390 printf ("%2d: ", i + 1);
391 disp_entry (&parttbl[i]);
392 }
393 }
394 if (partition == 0)
395 return 0;
396 }
397 /* NOTE: need to make sure this always rounds down */
398 //sec = total_known_sectors / sizeof_diskimage;
399 /* The above doesn't work unless the disk image is completely
400 filled by partitions ... unused space will thrown off the
401 sector size. The calculation assumes the disk image is
402 completely filled, and that the few sectors used to store
403 the partition table/MBR are few enough that the calculated
404 value is off by (larger than) a value less than one. */
405 sec = 512; /* TODO: calculate real sector size */
406 #ifdef DEBUG
407 printf("sec: %llu\n", sec);
408 #endif
409 if (partition > nbr_part)
410 {
411 fprintf(stderr, "Bad partition number\n");
412 return ERR_NO_EPART;
413 }
414 num = parttbl[partition-1].start_sector_abs;
415 if (num == 0)
416 {
417 fprintf(stderr, "Partition %d was not found in %s.\n",
418 partition, diskimage);
419 return ERR_NO_PART;
420 }
422 pnum = sec * num;
423 #ifdef DEBUG
424 printf("offset = %llu\n", pnum);
425 #endif
426 snprintf(buf, sizeof(buf), "mount -oloop,offset=%lld %s %s",
427 pnum, diskimage, argv2);
428 if (verbose)
429 printf("%s\n", buf);
431 status = system(buf);
432 if (WIFEXITED(status))
433 status = WEXITSTATUS(status);
434 else
435 status = ERR_MOUNT;
436 return status;
437 }