SOURCES: lomount.c (NEW) - saved from http://xenbits.xensource.com...
glen
glen at pld-linux.org
Thu Jun 14 09:55:57 CEST 2007
Author: glen Date: Thu Jun 14 07:55:57 2007 GMT
Module: SOURCES Tag: HEAD
---- Log message:
- saved from http://xenbits.xensource.com/xen-unstable.hg?raw-file/729a6231de35/tools/misc/lomount/lomount.c
---- Files affected:
SOURCES:
lomount.c (NONE -> 1.1) (NEW)
---- Diffs:
================================================================
Index: SOURCES/lomount.c
diff -u /dev/null SOURCES/lomount.c:1.1
--- /dev/null Thu Jun 14 09:55:57 2007
+++ SOURCES/lomount.c Thu Jun 14 09:55:52 2007
@@ -0,0 +1,435 @@
+/*
+ * lomount - utility to mount partitions in a hard disk image
+ *
+ * Copyright (c) 2004 Jim Brown
+ * Copyright (c) 2004 Brad Watson
+ * Copyright (c) 2004 Mulyadi Santosa
+ * Major rewrite by Tristan Gingold:
+ * - Handle GPT partitions
+ * - Handle large files
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/*
+ * Return code:
+ *
+ * bit 7 set: lomount wrapper failed
+ * bit 7 clear: lomount wrapper ok; mount's return code in low 7 bits
+ * 0 success
+ */
+
+enum
+{
+ ERR_USAGE = 0x80, // Incorrect usage
+ ERR_PART_PARSE, // Failed to parse partition table
+ ERR_NO_PART, // No such partition
+ ERR_NO_EPART, // No such extended partition
+ ERR_MOUNT // Other failure of mount command
+};
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/wait.h>
+#include <errno.h>
+
+#define BUF 4096
+
+#define SECSIZE 512
+
+struct pentry
+{
+ unsigned char bootable;
+ unsigned char start_head;
+ unsigned int start_cylinder;
+ unsigned char start_sector;
+ unsigned char system;
+ unsigned char end_head;
+ unsigned int end_cylinder;
+ unsigned char end_sector;
+ unsigned long long start_sector_abs;
+ unsigned long long no_of_sectors_abs;
+};
+
+static void
+disp_entry (struct pentry *p)
+{
+ printf ("%10llu - %10llu: %02x %x\n",
+ SECSIZE * p->start_sector_abs,
+ SECSIZE * (p->start_sector_abs + p->no_of_sectors_abs - 1),
+ p->system,
+ p->bootable);
+}
+
+static unsigned long
+read_le4 (unsigned char *p)
+{
+ return (unsigned long) p[0]
+ | ((unsigned long) p[1] << 8)
+ | ((unsigned long) p[2] << 16)
+ | ((unsigned long) p[3] << 24);
+}
+
+static unsigned long long
+read_le8 (unsigned char *p)
+{
+ return (unsigned long long) p[0]
+ | ((unsigned long long) p[1] << 8)
+ | ((unsigned long long) p[2] << 16)
+ | ((unsigned long long) p[3] << 24)
+ | ((unsigned long long) p[4] << 32)
+ | ((unsigned long long) p[5] << 40)
+ | ((unsigned long long) p[6] << 48)
+ | ((unsigned long long) p[7] << 56);
+}
+
+/* Return true if the partition table is a GPT protective MBR. */
+static int
+check_gpt (struct pentry *part, int nbr_part)
+{
+ if (nbr_part != 4)
+ return 0;
+ if (part[0].system == 0xee
+ && part[1].no_of_sectors_abs == 0
+ && part[2].no_of_sectors_abs == 0
+ && part[3].no_of_sectors_abs == 0)
+ return 1;
+ return 0;
+}
+
+static int
+load_gpt (const char *diskimage, struct pentry *parttbl[])
+{
+ FILE *fd;
+ size_t size;
+ int fail = -1;
+ unsigned char data[SECSIZE];
+ unsigned long long entries_lba;
+ unsigned long entry_size;
+ struct pentry *part;
+ int nbr_part;
+ unsigned long long off;
+ int i;
+
+ fd = fopen(diskimage, "r");
+ if (fd == NULL)
+ {
+ perror(diskimage);
+ goto done;
+ }
+ fseeko (fd, SECSIZE, SEEK_SET);
+ size = fread (&data, 1, sizeof(data), fd);
+ if (size < (size_t)sizeof(data))
+ {
+ fprintf(stderr, "Could not read the GPT header of %s.\n",
+ diskimage);
+ goto done;
+ }
+
+ if (memcmp (data, "EFI PART", 8) != 0)
+ {
+ fprintf (stderr, "Bad GPT signature\n");
+ goto done;
+ }
+
+ entries_lba = read_le8 (&data[72]);
+ nbr_part = read_le4 (&data[80]);
+ entry_size = read_le4 (&data[84]);
+
+#ifdef DEBUG
+ fprintf(stderr, "lba entries: %llu, nbr_part: %u, entry_size: %lu\n",
+ entries_lba, nbr_part, entry_size);
+#endif
+ part = malloc (nbr_part * sizeof (struct pentry));
+ if (part == NULL)
+ {
+ fprintf(stderr,"Cannot allocate memory\n");
+ goto done;
+ }
+ memset (part, 0, nbr_part * sizeof (struct pentry));
+ *parttbl = part;
+
+ off = entries_lba * SECSIZE;
+ for (i = 0; i < nbr_part; i++)
+ {
+ static const char unused_guid[16] = {0};
+ fseeko (fd, off, SEEK_SET);
+ size = fread (&data, 1, 128, fd);
+ if (size < 128)
+ {
+ fprintf(stderr, "Could not read a GPT entry of %s.\n",
+ diskimage);
+ goto done;
+ }
+ if (memcmp (&data[0], unused_guid, 16) == 0)
+ {
+ part[i].start_sector_abs = 0;
+ part[i].no_of_sectors_abs = 0;
+ }
+ else
+ {
+ part[i].start_sector_abs = read_le8 (&data[32]);
+ part[i].no_of_sectors_abs = read_le8 (&data[40]);
+#ifdef DEBUG
+ fprintf (stderr, "%d: %llu - %llu\n", i,
+ part[i].start_sector_abs,
+ part[i].no_of_sectors_abs);
+#endif
+ /* Convert end to a number. */
+ part[i].no_of_sectors_abs -=
+ part[i].start_sector_abs - 1;
+ }
+ off += entry_size;
+ }
+
+ fail = nbr_part;
+
+done:
+ if (fd)
+ fclose(fd);
+ return fail;
+}
+
+/* Read an MBR entry. */
+static void
+read_mbr_record (unsigned char pi[16], struct pentry *res)
+{
+ res->bootable = *pi;
+ res->start_head = *(pi + 1);
+ res->start_cylinder = *(pi + 3) | ((*(pi + 2) << 2) & 0x300);
+ res->start_sector = *(pi + 2) & 0x3f;
+ res->system = *(pi + 4);
+ res->end_head = *(pi + 5);
+ res->end_cylinder = *(pi + 7) | ((*(pi + 6) << 2) & 0x300);
+ res->end_sector = *(pi + 6) & 0x3f;
+ res->start_sector_abs = read_le4 (&pi[8]);
+ res->no_of_sectors_abs = read_le4 (&pi[12]);
+}
+
+/* Returns the number of partitions, -1 in case of failure. */
+int load_mbr(const char *diskimage, struct pentry *parttbl[])
+{
+ FILE *fd;
+ size_t size;
+ int fail = -1;
+ int nbr_part;
+ int i;
+ unsigned char *pi;
+ unsigned char data [SECSIZE];
+ unsigned long long extent;
+ struct pentry *part;
+
+ nbr_part = 0;
+
+ fd = fopen(diskimage, "r");
+ if (fd == NULL)
+ {
+ perror(diskimage);
+ goto done;
+ }
+ size = fread (&data, 1, sizeof(data), fd);
+ if (size < (size_t)sizeof(data))
+ {
+ fprintf(stderr, "Could not read the entire first sector of %s.\n", diskimage);
+ goto done;
+ }
+
+ if (data [510] != 0x55 || data [511] != 0xaa)
+ {
+ fprintf(stderr,"MBR signature mismatch (invalid partition table?)\n");
+ goto done;
+ }
+
+ /* There is at most 4*4 + 4 = 20 entries, also there should be only
+ one extended partition. */
+ part = malloc (20 * sizeof (struct pentry));
+ if (part == NULL)
+ {
+ fprintf(stderr,"Cannot allocate memory\n");
+ goto done;
+ }
+ *parttbl = part;
+
+ /* Read MBR. */
+ nbr_part = 4;
+ for (i = 0; i < 4; i++)
+ {
+ pi = &data [446 + 16 * i];
+ read_mbr_record (pi, &part[i]);
+ }
+
+ /* Read extended partitions. */
+ for (i = 0; i < 4; i++)
+ {
+ if (part[i].system == 0xF || part[i].system == 0x5)
+ {
+ int j;
+
+ extent = part[i].start_sector_abs * SECSIZE;
+
+ fseeko (fd, extent, SEEK_SET);
+ size = fread (&data, 1, sizeof(data), fd);
+ if (size < (size_t)sizeof(data))
+ {
+ fprintf(stderr, "Could not read extended partition of %s.", diskimage);
+ goto done;
+ }
+
+ for (j = 0; j < 4; j++)
+ {
+ int n;
+ pi = &data [446 + 16 * j];
+ n = nbr_part + j;
+ read_mbr_record (pi, &part[n]);
+ }
+
+ nbr_part += 4;
+ }
+ }
+
+ fail = nbr_part;
+
+done:
+ if (fd)
+ fclose(fd);
+ return fail;
+}
+
+void usage(void)
+{
+ fprintf(stderr, "Usage: lomount [-verbose] [OPTIONS] -diskimage FILE -partition NUM [OPTIONS]\n");
+ fprintf(stderr, "All OPTIONS are passed through to 'mount'.\n");
+ fprintf(stderr, "ex. lomount -t fs-type -diskimage hda.img -partition 1 /mnt\n");
+ exit(ERR_USAGE);
+}
+
+int main(int argc, char ** argv)
+{
+ int status;
+ int nbr_part;
+ struct pentry *parttbl;
+ char buf[BUF], argv2[BUF];
+ const char * diskimage = NULL;
+ int partition = 0;
+ unsigned long long sec, num, pnum;
+ int i;
+ size_t argv2_len = sizeof(argv2);
+ int verbose = 0;
+
+ argv2[0] = '\0';
+
+ for (i = 1; i < argc; i ++)
+ {
+ if (strcmp(argv[i], "-diskimage")==0)
+ {
+ if (i == argc-1)
+ usage();
+ i++;
+ diskimage = argv[i];
+ }
+ else if (strcmp(argv[i], "-partition")==0)
+ {
+ if (i == argc-1)
+ usage();
+ i++;
+ partition = atoi(argv[i]);
+ }
+ else if (strcmp(argv[i], "-verbose")==0)
+ {
+ verbose++;
+ }
+ else
+ {
+ size_t len = strlen(argv[i]);
+ if (len >= argv2_len-1)
+ usage();
+ strcat(argv2, argv[i]);
+ strcat(argv2, " ");
+ len -= (len+1);
+ }
+ }
+ if (! diskimage || partition < 0)
+ usage();
+
+ nbr_part = load_mbr(diskimage, &parttbl);
+ if (check_gpt (parttbl, nbr_part)) {
+ free (parttbl);
+ nbr_part = load_gpt (diskimage, &parttbl);
+ }
+ if (nbr_part < 0)
+ return ERR_PART_PARSE;
+ if (partition == 0)
+ {
+ printf("Please specify a partition number. Table is:\n");
+ printf("Num Start - End OS Bootable\n");
+ for (i = 0; i < nbr_part; i++)
+ {
+ if (parttbl[i].no_of_sectors_abs != 0)
+ {
+ printf ("%2d: ", i + 1);
+ disp_entry (&parttbl[i]);
+ }
+ }
+ if (partition == 0)
+ return 0;
+ }
+ /* NOTE: need to make sure this always rounds down */
+ //sec = total_known_sectors / sizeof_diskimage;
+ /* The above doesn't work unless the disk image is completely
+ filled by partitions ... unused space will thrown off the
+ sector size. The calculation assumes the disk image is
+ completely filled, and that the few sectors used to store
+ the partition table/MBR are few enough that the calculated
+ value is off by (larger than) a value less than one. */
+ sec = 512; /* TODO: calculate real sector size */
+#ifdef DEBUG
+ printf("sec: %llu\n", sec);
+#endif
+ if (partition > nbr_part)
+ {
+ fprintf(stderr, "Bad partition number\n");
+ return ERR_NO_EPART;
+ }
+ num = parttbl[partition-1].start_sector_abs;
+ if (num == 0)
+ {
+ fprintf(stderr, "Partition %d was not found in %s.\n",
+ partition, diskimage);
+ return ERR_NO_PART;
+ }
+
+ pnum = sec * num;
+#ifdef DEBUG
+ printf("offset = %llu\n", pnum);
+#endif
+ snprintf(buf, sizeof(buf), "mount -oloop,offset=%lld %s %s",
+ pnum, diskimage, argv2);
+ if (verbose)
+ printf("%s\n", buf);
+
+ status = system(buf);
+ if (WIFEXITED(status))
+ status = WEXITSTATUS(status);
+ else
+ status = ERR_MOUNT;
+ return status;
+}
================================================================
More information about the pld-cvs-commit
mailing list