diff options
author | H. Peter Anvin <hpa@zytor.com> | 2011-12-08 18:30:06 -0800 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2011-12-08 18:30:06 -0800 |
commit | 94f08b7a1d2c91922cbf8af580d118610a2cc193 (patch) | |
tree | 112252c59a39cd4d2bff18fe0def78c7ff7e089a | |
parent | 85c4ef2e1176d5eb0406177d634fd2504ba78859 (diff) | |
parent | 1704b46f53cf436c3c9c043d89cb8465650313be (diff) | |
download | syslinux-94f08b7a1d2c91922cbf8af580d118610a2cc193.tar.gz |
Merge remote-tracking branch 'origin/master' into lwipsyslinux-4.10-pre17
-rw-r--r-- | Makefile.private | 4 | ||||
-rw-r--r-- | NEWS | 4 | ||||
-rw-r--r-- | com32/modules/ifmemdsk.c | 392 | ||||
-rw-r--r-- | diag/geodsp/Makefile | 2 | ||||
-rw-r--r-- | extlinux/btrfs.h | 105 | ||||
-rwxr-xr-x | extlinux/main.c | 300 | ||||
-rw-r--r-- | mbr/isohdpfx.S | 31 | ||||
-rw-r--r-- | utils/Makefile | 2 | ||||
-rw-r--r-- | utils/isohybrid.c | 547 |
9 files changed, 1342 insertions, 45 deletions
diff --git a/Makefile.private b/Makefile.private index 972abc24..92127e98 100644 --- a/Makefile.private +++ b/Makefile.private @@ -100,7 +100,3 @@ LATEST_PREREL := syslinux-$(VERSION)-pre$(LATEST_PRERELNO) unprerel: echo $(LATEST_PRERELNO) > $(PRERELDIR)/.prerel @echo Next release will be $(LATEST_PREREL) - -preupload: - scp $(PRERELDIR)/$(LATEST_PREREL).* $(UPLOAD)/Testing - git push --tags @@ -23,6 +23,10 @@ Changes in 4.05: on virtually all systems since the beginning, and has been totally broken since 4.00 at least. Use MEMDISK instead. * chain.c32: Support chaining ReactOS' FreeLdr (Shao Miller) + * isohybrid: -m option to add support for Mac EFI booting. + * ifmemdsk.c32: Choose boot option based on presence of + MEMDISK. + * Remove bogus distributed mk-lba-img binary. Changes in 4.04: * PXELINUX: Fix handling of unqualified DNS names. diff --git a/com32/modules/ifmemdsk.c b/com32/modules/ifmemdsk.c new file mode 100644 index 00000000..cfed87f9 --- /dev/null +++ b/com32/modules/ifmemdsk.c @@ -0,0 +1,392 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2011 Shao Miller - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston MA 02110-1301, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/**** + * @file ifmemdsk.c + * + * This COM32 module detects if there are MEMDISKs established. + */ + +static const char usage_text[] = "\ +Usage:\n\ + ifmemdsk.c32 [<option> [...]] --info [<option> [...]]\n\ + ifmemdsk.c32 [<option> [...]] [<detected_cmd>] -- [<not_detected_cmd>]\n\ +\n\ +Options:\n\ + --info . . . . . Displays info about MEMDISK(s)\n\ + --safe-hooks . . Will scan INT 13h \"safe hook\" chain\n\ + --mbfts . . . . . Will scan memory for MEMDISK mBFTs\n\ + --no-sequential Suppresses probing all drive numbers\n\ +\n\ +If a MEMDISK is found, or if a particular MEMDISK is sought by the options\n\ +and is found, then the 'detected_cmd' action will be taken, else the\n\ +'not_detected_cmd' action will be taken.\n\ +\n"; + +#include <stdio.h> +#include <string.h> +#include <alloca.h> +#include <com32.h> +#include <console.h> +#include <syslinux/boot.h> + +/* Pull in MEMDISK common structures */ +#include "../../memdisk/mstructs.h" + +/*** Macros */ +#define M_GET_DRIVE_PARAMS (0x08) +#define M_SEGOFFTOPTR(seg, off) (((seg) << 4) + (off)) +#define M_INT13H M_SEGOFFTOPTR(0x0000, 0x0013 * 4) +#define M_FREEBASEMEM M_SEGOFFTOPTR(0x0040, 0x0013) +#define M_TOP M_SEGOFFTOPTR(0x9FFF, 0x0000) + +/*** Object types */ +typedef struct mdi s_mdi; +typedef real_addr_t u_segoff; +typedef struct safe_hook s_safe_hook; +typedef struct mBFT s_mbft; + +/*** Function types */ +typedef int f_find(void); + +/*** Function declarations */ +static const s_mdi * installation_check(int); +static f_find scan_drives; +static f_find walk_safe_hooks; +static const s_safe_hook * is_safe_hook(const void *); +static const s_mdi * is_memdisk_hook(const s_safe_hook *); +static f_find scan_mbfts; +static const s_mbft * is_mbft(const void *); +static f_find do_nothing; +static void memdisk_info(const s_mdi *); +static void boot_args(char **); +static const char * bootloadername(uint8_t); + +/*** Structure/union definitions */ + +/*** Objects */ +static int show_info = 0; + +/*** Function definitions */ + +int main(int argc, char ** argv) { + static f_find * do_scan_drives = scan_drives; + static f_find * do_walk_safe_hooks = do_nothing; + static f_find * do_scan_mbfts = do_nothing; + char ** detected_cmd; + char ** not_detected_cmd; + char ** cmd; + char ** cur_arg; + int show_usage; + int found; + + (void) argc; + + openconsole(&dev_null_r, &dev_stdcon_w); + + detected_cmd = NULL; + not_detected_cmd = NULL; + show_usage = 1; + for (cur_arg = argv + 1; *cur_arg; ++cur_arg) { + /* Check for command divider */ + if (!strcmp(*cur_arg, "--")) { + show_usage = 0; + *cur_arg = NULL; + not_detected_cmd = cur_arg + 1; + break; + } + + /* Check for '--info' */ + if (!strcmp(*cur_arg, "--info")) { + show_usage = 0; + show_info = 1; + continue; + } + + /* Other options */ + if (!strcmp(*cur_arg, "--no-sequential")) { + do_scan_drives = do_nothing; + continue; + } + + if (!strcmp(*cur_arg, "--safe-hooks")) { + do_walk_safe_hooks = walk_safe_hooks; + continue; + } + + if (!strcmp(*cur_arg, "--mbfts")) { + do_scan_mbfts = scan_mbfts; + continue; + } + + /* Check for invalid option */ + if (!memcmp(*cur_arg, "--", sizeof "--" - 1)) { + puts("Invalid option!"); + show_usage = 1; + break; + } + + /* Set 'detected_cmd' if it's null */ + if (!detected_cmd) + detected_cmd = cur_arg; + + continue; + } + + if (show_usage) { + fprintf(stderr, usage_text); + return 1; + } + + found = 0; + found += do_walk_safe_hooks(); + found += do_scan_mbfts(); + found += do_scan_drives(); + + cmd = found ? detected_cmd : not_detected_cmd; + if (cmd && *cmd) + boot_args(cmd); + + return 0; + } + +static const s_mdi * installation_check(int drive) { + com32sys_t params, results; + int found; + + /* Set parameters for INT 0x13 call */ + memset(¶ms, 0, sizeof params); + params.eax.w[0] = M_GET_DRIVE_PARAMS << 8; + params.edx.w[0] = drive; + /* 'ME' 'MD' 'IS' 'K?' */ + params.eax.w[1] = 0x454D; + params.ecx.w[1] = 0x444D; + params.edx.w[1] = 0x5349; + params.ebx.w[1] = 0x3F4B; + + /* Perform the call */ + __intcall(0x13, ¶ms, &results); + + /* Check result */ + found = ( + /* '!M' 'EM' 'DI' 'SK' */ + results.eax.w[1] == 0x4D21 && + results.ecx.w[1] == 0x4D45 && + results.edx.w[1] == 0x4944 && + results.ebx.w[1] == 0x4B53 + ); + + if (found) + return MK_PTR(results.es, results.edi.w[0]); + + return NULL; + } + +static int scan_drives(void) { + int found, drive; + const s_mdi * mdi; + + for (found = drive = 0; drive <= 0xFF; ++drive) { + mdi = installation_check(drive); + if (!mdi) + continue; + + memdisk_info(mdi); + ++found; + continue; + } + + return found; + } + +static int walk_safe_hooks(void) { + static const u_segoff * const int13 = (void *) M_INT13H; + const void * addr; + int found; + const s_safe_hook * hook; + const s_mdi * mdi; + + /* INT 0x13 vector */ + addr = MK_PTR(int13->seg_off.segment, int13->seg_off.offset); + found = 0; + while (addr) { + hook = is_safe_hook(addr); + if (!hook) + break; + + mdi = is_memdisk_hook(hook); + if (mdi) { + memdisk_info(mdi); + ++found; + } + + addr = MK_PTR( + hook->old_hook.seg_off.segment, + hook->old_hook.seg_off.offset + ); + continue; + } + return found; + } + +static const s_safe_hook * is_safe_hook(const void * addr) { + static const char magic[] = "$INT13SF"; + const s_safe_hook * const test = addr; + + if (memcmp(test->signature, magic, sizeof magic - 1)) + return NULL; + + return test; + } + +static const s_mdi * is_memdisk_hook(const s_safe_hook * hook) { + static const char magic[] = "MEMDISK"; + const s_mbft * mbft; + + if (memcmp(hook->vendor, magic, sizeof magic - 1)) + return NULL; + + /* An mBFT is always aligned */ + mbft = MK_PTR(hook->mbft >> 4, 0); + return &mbft->mdi; + } + +static int scan_mbfts(void) { + static const uint16_t * const free_base_mem = (void *) M_FREEBASEMEM; + static const void * const top = (void *) M_TOP; + const void * addr; + const s_mbft * mbft; + int found; + + found = 0; + for (addr = MK_PTR(*free_base_mem << 4, 0); addr < top; addr += 1 << 4) { + if (!(mbft = is_mbft(addr))) + continue; + + memdisk_info(&mbft->mdi); + ++found; + continue; + } + + return found; + } + +static const s_mbft * is_mbft(const void * addr) { + static const char magic[] = "mBFT"; + const s_mbft * const test = addr; + const uint8_t * ptr, * end; + uint8_t chksum; + + if (memcmp(test->acpi.signature, magic, sizeof magic - 1)) + return NULL; + + if (test->acpi.length != sizeof *test) + return NULL; + + end = (void *) (test + 1); + chksum = 0; + for (ptr = addr; ptr < end; ++ptr) + chksum += *ptr; + if (chksum) + return NULL; + + /* Looks like it's an mBFT! */ + return test; + } + +static int do_nothing(void) { + return 0; + } + +static void memdisk_info(const s_mdi * mdi) { + const char * cmdline; + + if (!show_info) + return; + + cmdline = MK_PTR( + mdi->cmdline.seg_off.segment, + mdi->cmdline.seg_off.offset + ); + printf( + "Found MEMDISK version %u.%02u:\n" + " diskbuf == 0x%08X, disksize == %u sectors\n" + " bootloaderid == 0x%02X (%s),\n" + " cmdline: %s\n", + mdi->version_major, + mdi->version_minor, + mdi->diskbuf, + mdi->disksize, + mdi->bootloaderid, + bootloadername(mdi->bootloaderid), + cmdline + ); + return; + } + +/* This function copyright H. Peter Anvin */ +static void boot_args(char **args) +{ + int len = 0, a = 0; + char **pp; + const char *p; + char c, *q, *str; + + for (pp = args; *pp; pp++) + len += strlen(*pp) + 1; + + q = str = alloca(len); + for (pp = args; *pp; pp++) { + p = *pp; + while ((c = *p++)) + *q++ = c; + *q++ = ' '; + a = 1; + } + q -= a; + *q = '\0'; + + if (!str[0]) + syslinux_run_default(); + else + syslinux_run_command(str); +} + +/* This function copyright H. Peter Anvin */ +static const char *bootloadername(uint8_t id) +{ + static const struct { + uint8_t id, mask; + const char *name; + } *lp, list[] = { + {0x00, 0xf0, "LILO"}, + {0x10, 0xf0, "LOADLIN"}, + {0x31, 0xff, "SYSLINUX"}, + {0x32, 0xff, "PXELINUX"}, + {0x33, 0xff, "ISOLINUX"}, + {0x34, 0xff, "EXTLINUX"}, + {0x30, 0xf0, "Syslinux family"}, + {0x40, 0xf0, "Etherboot"}, + {0x50, 0xf0, "ELILO"}, + {0x70, 0xf0, "GrUB"}, + {0x80, 0xf0, "U-Boot"}, + {0xA0, 0xf0, "Gujin"}, + {0xB0, 0xf0, "Qemu"}, + {0x00, 0x00, "unknown"} + }; + + for (lp = list;; lp++) { + if (((id ^ lp->id) & lp->mask) == 0) + return lp->name; + } +} + diff --git a/diag/geodsp/Makefile b/diag/geodsp/Makefile index bf26104e..119ccbc7 100644 --- a/diag/geodsp/Makefile +++ b/diag/geodsp/Makefile @@ -47,9 +47,9 @@ mk-lba-img: mk-lba-img.c tidy dist: rm -Rf *.lst *.img + rm -f mk-lba-img clean: tidy - rm -f mk-lba-img spotless: clean rm -f $(BTARGET) diff --git a/extlinux/btrfs.h b/extlinux/btrfs.h index 39a861a5..be0c24ef 100644 --- a/extlinux/btrfs.h +++ b/extlinux/btrfs.h @@ -1,6 +1,9 @@ #ifndef _BTRFS_H_ #define _BTRFS_H_ +#include <asm/types.h> +#include <linux/ioctl.h> + #define BTRFS_SUPER_MAGIC 0x9123683E #define BTRFS_SUPER_INFO_OFFSET (64 * 1024) #define BTRFS_SUPER_INFO_SIZE 4096 @@ -8,6 +11,40 @@ #define BTRFS_CSUM_SIZE 32 #define BTRFS_FSID_SIZE 16 +typedef __u64 u64; +typedef __u32 u32; +typedef __u16 u16; +typedef __u8 u8; +typedef u64 __le64; +typedef u16 __le16; + +#define BTRFS_ROOT_BACKREF_KEY 144 +#define BTRFS_ROOT_TREE_DIR_OBJECTID 6ULL +#define BTRFS_DIR_ITEM_KEY 84 + +/* + * * this is used for both forward and backward root refs + * */ +struct btrfs_root_ref { + __le64 dirid; + __le64 sequence; + __le16 name_len; +} __attribute__ ((__packed__)); + +struct btrfs_disk_key { + __le64 objectid; + u8 type; + __le64 offset; +} __attribute__ ((__packed__)); + +struct btrfs_dir_item { + struct btrfs_disk_key location; + __le64 transid; + __le16 data_len; + __le16 name_len; + u8 type; +} __attribute__ ((__packed__)); + struct btrfs_super_block { unsigned char csum[BTRFS_CSUM_SIZE]; /* the first 3 fields must match struct btrfs_header */ @@ -19,4 +56,72 @@ struct btrfs_super_block { u64 magic; } __attribute__ ((__packed__)); + +#define BTRFS_IOCTL_MAGIC 0x94 +#define BTRFS_VOL_NAME_MAX 255 +#define BTRFS_PATH_NAME_MAX 4087 + +struct btrfs_ioctl_vol_args { + __s64 fd; + char name[BTRFS_PATH_NAME_MAX + 1]; +}; + +struct btrfs_ioctl_search_key { + /* which root are we searching. 0 is the tree of tree roots */ + __u64 tree_id; + + /* keys returned will be >= min and <= max */ + __u64 min_objectid; + __u64 max_objectid; + + /* keys returned will be >= min and <= max */ + __u64 min_offset; + __u64 max_offset; + + /* max and min transids to search for */ + __u64 min_transid; + __u64 max_transid; + + /* keys returned will be >= min and <= max */ + __u32 min_type; + __u32 max_type; + + /* + * how many items did userland ask for, and how many are we + * returning + */ + __u32 nr_items; + + /* align to 64 bits */ + __u32 unused; + + /* some extra for later */ + __u64 unused1; + __u64 unused2; + __u64 unused3; + __u64 unused4; +}; + +struct btrfs_ioctl_search_header { + __u64 transid; + __u64 objectid; + __u64 offset; + __u32 type; + __u32 len; +} __attribute__((may_alias)); + +#define BTRFS_SEARCH_ARGS_BUFSIZE (4096 - sizeof(struct btrfs_ioctl_search_key)) +/* + * the buf is an array of search headers where + * each header is followed by the actual item + * the type field is expanded to 32 bits for alignment + */ +struct btrfs_ioctl_search_args { + struct btrfs_ioctl_search_key key; + char buf[BTRFS_SEARCH_ARGS_BUFSIZE]; +}; + +#define BTRFS_IOC_TREE_SEARCH _IOWR(BTRFS_IOCTL_MAGIC, 17, \ + struct btrfs_ioctl_search_args) + #endif diff --git a/extlinux/main.c b/extlinux/main.c index 26dba7ba..e574051b 100755 --- a/extlinux/main.c +++ b/extlinux/main.c @@ -20,12 +20,12 @@ #define _GNU_SOURCE /* Enable everything */ #include <inttypes.h> /* This is needed to deal with the kernel headers imported into glibc 3.3.3. */ -typedef uint64_t u64; #include <alloca.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <unistd.h> +#include <dirent.h> #ifndef __KLIBC__ #include <mntent.h> #endif @@ -65,7 +65,6 @@ typedef uint64_t u64; boot image, the boot sector is from 0~512, the boot image starts after */ #define BTRFS_BOOTSECT_AREA 65536 #define BTRFS_EXTLINUX_OFFSET SECTOR_SIZE -#define BTRFS_SUBVOL_OPT "subvol=" #define BTRFS_SUBVOL_MAX 256 /* By btrfs specification */ static char subvol[BTRFS_SUBVOL_MAX]; @@ -492,6 +491,267 @@ int btrfs_install_file(const char *path, int devfd, struct stat *rst) return 0; } +/* + * * test if path is a subvolume: + * * this function return + * * 0-> path exists but it is not a subvolume + * * 1-> path exists and it is a subvolume + * * -1 -> path is unaccessible + * */ +static int test_issubvolume(char *path) +{ + + struct stat st; + int res; + + res = stat(path, &st); + if(res < 0 ) + return -1; + + return (st.st_ino == 256) && S_ISDIR(st.st_mode); + +} + +/* + * Get file handle for a file or dir + */ +static int open_file_or_dir(const char *fname) +{ + int ret; + struct stat st; + DIR *dirstream; + int fd; + + ret = stat(fname, &st); + if (ret < 0) { + return -1; + } + if (S_ISDIR(st.st_mode)) { + dirstream = opendir(fname); + if (!dirstream) { + return -2; + } + fd = dirfd(dirstream); + } else { + fd = open(fname, O_RDWR); + } + if (fd < 0) { + return -3; + } + return fd; +} + +/* + * Get the default subvolume of a btrfs filesystem + * rootdir: btrfs root dir + * subvol: this function will save the default subvolume name here + */ +static char * get_default_subvol(char * rootdir, char * subvol) +{ + struct btrfs_ioctl_search_args args; + struct btrfs_ioctl_search_key *sk = &args.key; + struct btrfs_ioctl_search_header *sh; + int ret, i; + int fd; + struct btrfs_root_ref *ref; + struct btrfs_dir_item *dir_item; + unsigned long off = 0; + int name_len; + char *name; + char dirname[4096]; + u64 defaultsubvolid = 0; + + ret = test_issubvolume(rootdir); + if (ret == 1) { + fd = open_file_or_dir(rootdir); + if (fd < 0) { + fprintf(stderr, "ERROR: failed to open %s\n", rootdir); + } + ret = fd; + } + if (ret <= 0) { + subvol[0] = '\0'; + return NULL; + } + + memset(&args, 0, sizeof(args)); + + /* search in the tree of tree roots */ + sk->tree_id = 1; + + /* + * set the min and max to backref keys. The search will + * only send back this type of key now. + */ + sk->max_type = BTRFS_DIR_ITEM_KEY; + sk->min_type = BTRFS_DIR_ITEM_KEY; + + /* + * set all the other params to the max, we'll take any objectid + * and any trans + */ + sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID; + sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID; + + sk->max_offset = (u64)-1; + sk->min_offset = 0; + sk->max_transid = (u64)-1; + + /* just a big number, doesn't matter much */ + sk->nr_items = 4096; + + while(1) { + ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args); + if (ret < 0) { + fprintf(stderr, "ERROR: can't perform the search\n"); + subvol[0] = '\0'; + return NULL; + } + /* the ioctl returns the number of item it found in nr_items */ + if (sk->nr_items == 0) { + break; + } + + off = 0; + + /* + * for each item, pull the key out of the header and then + * read the root_ref item it contains + */ + for (i = 0; i < sk->nr_items; i++) { + sh = (struct btrfs_ioctl_search_header *)(args.buf + off); + off += sizeof(*sh); + if (sh->type == BTRFS_DIR_ITEM_KEY) { + dir_item = (struct btrfs_dir_item *)(args.buf + off); + name_len = dir_item->name_len; + name = (char *)(dir_item + 1); + + + /*add_root(&root_lookup, sh->objectid, sh->offset, + dir_id, name, name_len);*/ + strncpy(dirname, name, name_len); + dirname[name_len] = '\0'; + if (strcmp(dirname, "default") == 0) { + defaultsubvolid = dir_item->location.objectid; + break; + } + } + off += sh->len; + + /* + * record the mins in sk so we can make sure the + * next search doesn't repeat this root + */ + sk->min_objectid = sh->objectid; + sk->min_type = sh->type; + sk->max_type = sh->type; + sk->min_offset = sh->offset; + } + if (defaultsubvolid != 0) + break; + sk->nr_items = 4096; + /* this iteration is done, step forward one root for the next + * ioctl + */ + if (sk->min_objectid < (u64)-1) { + sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID; + sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID; + sk->max_type = BTRFS_ROOT_BACKREF_KEY; + sk->min_type = BTRFS_ROOT_BACKREF_KEY; + sk->min_offset = 0; + } else + break; + } + + if (defaultsubvolid == 0) { + subvol[0] = '\0'; + return NULL; + } + + memset(&args, 0, sizeof(args)); + + /* search in the tree of tree roots */ + sk->tree_id = 1; + + /* + * set the min and max to backref keys. The search will + * only send back this type of key now. + */ + sk->max_type = BTRFS_ROOT_BACKREF_KEY; + sk->min_type = BTRFS_ROOT_BACKREF_KEY; + + /* + * set all the other params to the max, we'll take any objectid + * and any trans + */ + sk->max_objectid = (u64)-1; + sk->max_offset = (u64)-1; + sk->max_transid = (u64)-1; + + /* just a big number, doesn't matter much */ + sk->nr_items = 4096; + + while(1) { + ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args); + if (ret < 0) { + fprintf(stderr, "ERROR: can't perform the search\n"); + subvol[0] = '\0'; + return NULL; + } + /* the ioctl returns the number of item it found in nr_items */ + if (sk->nr_items == 0) + break; + + off = 0; + + /* + * for each item, pull the key out of the header and then + * read the root_ref item it contains + */ + for (i = 0; i < sk->nr_items; i++) { + sh = (struct btrfs_ioctl_search_header *)(args.buf + off); + off += sizeof(*sh); + if (sh->type == BTRFS_ROOT_BACKREF_KEY) { + ref = (struct btrfs_root_ref *)(args.buf + off); + name_len = ref->name_len; + name = (char *)(ref + 1); + + if (sh->objectid == defaultsubvolid) { + strncpy(subvol, name, name_len); + subvol[name_len] = '\0'; + dprintf("The default subvolume: %s, ID: %llu\n", + subvol, sh->objectid); + break; + } + + } + + off += sh->len; + + /* + * record the mins in sk so we can make sure the + * next search doesn't repeat this root + */ + sk->min_objectid = sh->objectid; + sk->min_type = sh->type; + sk->min_offset = sh->offset; + } + if (subvol[0] != '\0') + break; + sk->nr_items = 4096; + /* this iteration is done, step forward one root for the next + * ioctl + */ + if (sk->min_objectid < (u64)-1) { + sk->min_objectid++; + sk->min_type = BTRFS_ROOT_BACKREF_KEY; + sk->min_offset = 0; + } else + break; + } + return subvol; +} + int install_file(const char *path, int devfd, struct stat *rst) { if (fs_type == EXT2 || fs_type == VFAT) @@ -546,19 +806,9 @@ static const char *find_device(const char *mtab_file, dev_t dev) if (!strcmp(mnt->mnt_type, "btrfs") && !stat(mnt->mnt_dir, &dst) && dst.st_dev == dev) { - char *opt = strstr(mnt->mnt_opts, BTRFS_SUBVOL_OPT); - - if (opt) { - if (!subvol[0]) { - char *tmp; - - strcpy(subvol, opt + sizeof(BTRFS_SUBVOL_OPT) - 1); - tmp = strchr(subvol, 32); - if (tmp) - *tmp = '\0'; - } - break; /* should break and let upper layer try again */ - } else + if (!subvol[0]) { + get_default_subvol(mnt->mnt_dir, subvol); + } done = true; } break; @@ -623,24 +873,10 @@ static const char *get_devname(const char *path) #else - /* check /etc/mtab first, since btrfs subvol info is only in here */ - devname = find_device("/etc/mtab", st.st_dev); - if (subvol[0] && !devname) { /* we just find it is a btrfs subvol */ - char parent[256]; - char *tmp; - - strcpy(parent, path); - tmp = strrchr(parent, '/'); - if (tmp) { - *tmp = '\0'; - fprintf(stderr, "%s is subvol, try its parent dir %s\n", path, parent); - devname = get_devname(parent); - } else - devname = NULL; - } + devname = find_device("/proc/mounts", st.st_dev); if (!devname) { - /* Didn't find it in /etc/mtab, try /proc/mounts */ - devname = find_device("/proc/mounts", st.st_dev); + /* Didn't find it in /proc/mounts, try /etc/mtab */ + devname = find_device("/etc/mtab", st.st_dev); } if (!devname) { fprintf(stderr, "%s: cannot find device for path %s\n", program, path); diff --git a/mbr/isohdpfx.S b/mbr/isohdpfx.S index 2784fb80..17e1efe1 100644 --- a/mbr/isohdpfx.S +++ b/mbr/isohdpfx.S @@ -66,6 +66,37 @@ bootsec: .globl _start _start: .byte 0x33, 0xed /* xorw %bp, %bp */ + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + .byte 0x33, 0xed /* xorw %bp, %bp */ cli movw %bp, %ss movw $stack, %sp diff --git a/utils/Makefile b/utils/Makefile index acda8c05..44cb54fb 100644 --- a/utils/Makefile +++ b/utils/Makefile @@ -51,7 +51,7 @@ isohdpfx.c: $(ISOHDPFX) isohdpfxarray.pl $(PERL) isohdpfxarray.pl $(ISOHDPFX) > $@ isohybrid: isohybrid.o isohdpfx.o - $(CC) $(LDFLAGS) -o $@ $^ + $(CC) $(LDFLAGS) -luuid -o $@ $^ gethostip: gethostip.o $(CC) $(LDFLAGS) -o $@ $^ diff --git a/utils/isohybrid.c b/utils/isohybrid.c index 8a605313..1dcbaa11 100644 --- a/utils/isohybrid.c +++ b/utils/isohybrid.c @@ -36,14 +36,19 @@ #include <unistd.h> #include <sys/stat.h> #include <inttypes.h> +#include <uuid/uuid.h> #include "isohybrid.h" char *prog = NULL; extern int opterr, optind; +struct stat isostat; +unsigned int padding = 0; + +uuid_t disk_uuid, part_uuid, iso_uuid; uint8_t mode = 0; -enum { VERBOSE = 1 }; +enum { VERBOSE = 1 , EFI = 2 , MAC = 4}; /* user options */ uint16_t head = 64; /* 1 <= head <= 256 */ @@ -61,10 +66,150 @@ uint16_t ve[16]; uint32_t catoffset = 0; uint32_t c = 0, cc = 0, cs = 0; +uint32_t psize = 0, isosize = 0; + /* boot catalogue parameters */ uint32_t de_lba = 0; uint16_t de_seg = 0, de_count = 0, de_mbz2 = 0; uint8_t de_boot = 0, de_media = 0, de_sys = 0, de_mbz1 = 0; +uint32_t efi_lba = 0, mac_lba = 0; +uint16_t efi_count = 0, mac_count = 0; +uint8_t efi_boot = 0, efi_media = 0, efi_sys = 0; + +int apm_parts = 3; + +uint8_t afp_header[] = { 0x45, 0x52, 0x08, 0x00, 0x00, 0x00, 0x90, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +uuid_t efi_system_partition = {0xC1, 0x2A, 0x73, 0x28, 0xF8, 0x1F, 0x11, 0xD2, 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B}; +uuid_t basic_partition = {0xEB,0xD0,0xA0,0xA2,0xB9,0xE5,0x44,0x33,0x87,0xC0,0x68,0xB6,0xB7,0x26,0x99,0xC7}; +uuid_t hfs_partition = {0x48, 0x46, 0x53, 0x00, 0x00, 0x00, 0x11, 0xAA, 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC}; + +uint32_t crc_tab[256] = +{ + 0, 0x77073096, 0xEE0E612C, 0x990951BA, + 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, + 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, + 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, + 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, + 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, + 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, + 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, + 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, + 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, + 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, + 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, + 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, + 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, + 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, + 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, + 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, + 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, + 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, + 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, + 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, + 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +}; + +struct iso_primary_descriptor { + uint8_t ignore [80]; + uint32_t size; + uint8_t ignore2 [44]; + uint16_t block_size; +}; + +struct gpt_header { + uint64_t signature; + uint32_t revision; + uint32_t headerSize; + uint32_t headerCRC; + uint32_t reserved; + uint64_t currentLBA; + uint64_t backupLBA; + uint64_t firstUsableLBA; + uint64_t lastUsableLBA; + uuid_t diskGUID; + uint64_t partitionEntriesLBA; + uint32_t numParts; + uint32_t sizeOfPartitionEntries; + uint32_t partitionEntriesCRC; + uint8_t reserved2[420]; +}; + +struct gpt_part_header { + uuid_t partTypeGUID; + uuid_t partGUID; + uint64_t firstLBA; + uint64_t lastLBA; + uint64_t attributes; + uint16_t name[36]; +}; + +#define APM_OFFSET 2048 + +struct apple_part_header { + uint16_t signature; /* expected to be MAC_PARTITION_MAGIC */ + uint16_t res1; + uint32_t map_count; /* # blocks in partition map */ + uint32_t start_block; /* absolute starting block # of partition */ + uint32_t block_count; /* number of blocks in partition */ + char name[32]; /* partition name */ + char type[32]; /* string type description */ + uint32_t data_start; /* rel block # of first data block */ + uint32_t data_count; /* number of data blocks */ + uint32_t status; /* partition status bits */ + uint32_t boot_start; + uint32_t boot_count; + uint32_t boot_load; + uint32_t boot_load2; + uint32_t boot_entry; + uint32_t boot_entry2; + uint32_t boot_cksum; + char processor[16]; /* Contains 680x0, x=0,2,3,4; or empty */ + uint32_t driver_sig; + char _padding[372]; +}; void @@ -89,6 +234,8 @@ printh(void) printf(FMT, " -o --offset", "Specify partition offset (default 0)"); printf(FMT, " -t --type", "Specify partition type (default 0x17)"); printf(FMT, " -i --id", "Specify MBR ID (default random)"); + printf(FMT, " -u --uefi", "Build EFI bootable image"); + printf(FMT, " -m --mac", "Add AFP table support"); printf("\n"); printf(FMT, " --forcehd0", "Assume we are loaded as disk ID 0"); @@ -122,6 +269,8 @@ check_option(int argc, char *argv[]) { "forcehd0", no_argument, NULL, 'f' }, { "ctrlhd0", no_argument, NULL, 'c' }, { "partok", no_argument, NULL, 'p'}, + { "uefi", no_argument, NULL, 'u'}, + { "mac", no_argument, NULL, 'm'}, { "help", no_argument, NULL, '?' }, { "verbose", no_argument, NULL, 'v' }, @@ -183,6 +332,14 @@ check_option(int argc, char *argv[]) partok = 1; break; + case 'u': + mode |= EFI; + break; + + case 'm': + mode |= MAC; + break; + case 'v': mode |= VERBOSE; break; @@ -207,6 +364,33 @@ check_option(int argc, char *argv[]) return optind; } +uint16_t +bendian_short(const uint16_t s) +{ + uint16_t r = 1; + + if (!*(uint8_t *)&r) + return s; + + r = (s & 0x00FF) << 8 | (s & 0xFF00) >> 8; + + return r; +} + + +uint32_t +bendian_int(const uint32_t s) +{ + uint32_t r = 1; + + if (!*(uint8_t *)&r) + return s; + + r = (s & 0x000000FF) << 24 | (s & 0xFF000000) >> 24 + | (s & 0x0000FF00) << 8 | (s & 0x00FF0000) >> 8; + + return r; +} uint16_t lendian_short(const uint16_t s) @@ -236,6 +420,22 @@ lendian_int(const uint32_t s) return r; } +uint64_t +lendian_64(const uint64_t s) +{ + uint64_t r = 1; + + if (*(uint8_t *)&r) + return s; + + r = (s & 0x00000000000000FF) << 56 | (s & 0xFF00000000000000) >> 56 + | (s & 0x000000000000FF00) << 40 | (s & 0x00FF000000000000) >> 40 + | (s & 0x0000000000FF0000) << 24 | (s & 0x0000FF0000000000) >> 24 + | (s & 0x00000000FF000000) << 8 | (s & 0x000000FF00000000) >> 8; + + return r; +} + int check_banner(const uint8_t *buf) @@ -314,6 +514,43 @@ read_catalogue(const uint8_t *buf) } +int +read_efi_section(const uint8_t *buf) +{ + unsigned char header_indicator; + unsigned char platform_id; + short count; + + memcpy(&header_indicator, buf++, 1); + memcpy(&platform_id, buf++, 1); + + memcpy(&count, buf, 2); + count = lendian_short(count); + buf += 2; + + if (platform_id == 0xef) + return 0; + + return 1; +} + +int +read_efi_catalogue(const uint8_t *buf, uint16_t *count, uint32_t *lba) +{ + buf += 6; + + memcpy(count, buf, 2); + *count = lendian_short(*count); + buf += 2; + + memcpy(lba, buf, 4); + *lba = lendian_int(*lba); + buf += 6; + + return 0; +} + + void display_catalogue(void) { @@ -327,12 +564,11 @@ display_catalogue(void) printf("de_mbz2: %hu\n", de_mbz2); } - int initialise_mbr(uint8_t *mbr) { int i = 0; - uint32_t psize = 0, tmp = 0; + uint32_t tmp = 0; uint8_t ptype = 0, *rbm = mbr; uint8_t bhead = 0, bsect = 0, bcyle = 0; uint8_t ehead = 0, esect = 0, ecyle = 0; @@ -340,6 +576,11 @@ initialise_mbr(uint8_t *mbr) extern unsigned char isohdpfx[][MBRSIZE]; memcpy(mbr, &isohdpfx[hd0 + 3 * partok], MBRSIZE); + + if (mode & MAC) { + memcpy(mbr, afp_header, sizeof(afp_header)); + } + mbr += MBRSIZE; /* offset 432 */ tmp = lendian_int(de_lba * 4); @@ -401,7 +642,6 @@ initialise_mbr(uint8_t *mbr) return mbr - rbm; } - void display_mbr(const uint8_t *mbr, size_t len) { @@ -431,14 +671,179 @@ display_mbr(const uint8_t *mbr, size_t len) } +uint32_t chksum_crc32 (unsigned char *block, unsigned int length) +{ + register unsigned long crc; + unsigned long i; + + crc = 0xFFFFFFFF; + for (i = 0; i < length; i++) + { + crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_tab[(crc ^ *block++) & 0xFF]; + } + return (crc ^ 0xFFFFFFFF); +} + +void +reverse_uuid(uuid_t uuid) +{ + uint8_t t, *p = (uint8_t *)uuid; + + t = p[0]; p[0] = p[3]; p[3] = t; + t = p[1]; p[1] = p[2]; p[2] = t; + t = p[4]; p[4] = p[5]; p[5] = t; + t = p[6]; p[6] = p[7]; p[7] = t; +} + +void +initialise_gpt(uint8_t *gpt, uint32_t current, uint32_t alternate, int primary) +{ + struct gpt_header *header = (struct gpt_header *)gpt; + struct gpt_part_header *part; + int hole = 0; + int gptsize = 128 / 4 + 2; + + if (mac_lba) { + /* 2048 bytes per partition, plus round to 2048 boundary */ + hole = (apm_parts * 4) + 2; + } + + if (primary) { + uuid_generate(disk_uuid); + reverse_uuid(disk_uuid); + } + + header->signature = lendian_64(0x5452415020494645); + header->revision = lendian_int(0x010000); + header->headerSize = lendian_int(0x5c); + header->currentLBA = lendian_64(current); + header->backupLBA = lendian_64(alternate); + header->firstUsableLBA = lendian_64(gptsize + hole); + header->lastUsableLBA = lendian_64((isostat.st_size + padding)/512 - + gptsize); + if (primary) + header->partitionEntriesLBA = lendian_64(0x02 + hole); + else + header->partitionEntriesLBA = lendian_64(current - (128 / 4)); + header->numParts = lendian_int(0x80); + header->sizeOfPartitionEntries = lendian_int(0x80); + memcpy(header->diskGUID, disk_uuid, sizeof(uuid_t)); + + if (primary) + gpt += sizeof(struct gpt_header) + hole * 512; + else + gpt -= header->sizeOfPartitionEntries * header->numParts; + + part = (struct gpt_part_header *)gpt; + if (primary) { + uuid_generate(part_uuid); + uuid_generate(iso_uuid); + reverse_uuid(part_uuid); + reverse_uuid(iso_uuid); + } + + memcpy(part->partGUID, iso_uuid, sizeof(uuid_t)); + memcpy(part->partTypeGUID, basic_partition, sizeof(uuid_t)); + part->firstLBA = lendian_64(0); + part->lastLBA = lendian_64(psize); + memcpy(part->name, "ISOHybrid ISO", 28); + + gpt += sizeof(struct gpt_part_header); + part++; + + memcpy(part->partGUID, part_uuid, sizeof(uuid_t)); + memcpy(part->partTypeGUID, basic_partition, sizeof(uuid_t)); + part->firstLBA = lendian_64(efi_lba * 4); + part->lastLBA = lendian_64(part->firstLBA + efi_count - 1); + memcpy(part->name, "ISOHybrid", 20); + + gpt += sizeof(struct gpt_part_header); + + if (mac_lba) { + gpt += sizeof(struct gpt_part_header); + + part++; + + memcpy(part->partGUID, part_uuid, sizeof(uuid_t)); + memcpy(part->partTypeGUID, hfs_partition, sizeof(uuid_t)); + part->firstLBA = lendian_64(mac_lba * 4); + part->lastLBA = lendian_64(part->firstLBA + mac_count - 1); + memcpy(part->name, "ISOHybrid", 20); + + part--; + } + + part--; + + header->partitionEntriesCRC = lendian_int (chksum_crc32((uint8_t *)part, + header->numParts * header->sizeOfPartitionEntries)); + + header->headerCRC = lendian_int(chksum_crc32((uint8_t *)header, + header->headerSize)); +} + +void +initialise_apm(uint8_t *gpt, uint32_t start) +{ + struct apple_part_header *part = (struct apple_part_header *)gpt; + + part->signature = bendian_short(0x504d); + part->map_count = bendian_int(apm_parts); + part->start_block = bendian_int(1); + part->block_count = bendian_int(0x10); + strcpy(part->name, "Apple"); + strcpy(part->type, "Apple_partition_map"); + part->data_start = bendian_int(0); + part->data_count = bendian_int(10); + part->status = bendian_int(0x03); + + part = (struct apple_part_header *)(gpt + 2048); + + part->signature = bendian_short(0x504d); + part->map_count = bendian_int(3); + part->start_block = bendian_int(efi_lba); + part->block_count = bendian_int(efi_count); + strcpy(part->name, "EFI"); + strcpy(part->type, "Apple_HFS"); + part->data_start = bendian_int(0); + part->data_count = bendian_int(efi_count); + part->status = bendian_int(0x33); + + part = (struct apple_part_header *)(gpt + 4096); + + if (mac_lba) + { + part->signature = bendian_short(0x504d); + part->map_count = bendian_int(3); + part->start_block = bendian_int(mac_lba); + part->block_count = bendian_int(mac_count); + strcpy(part->name, "EFI"); + strcpy(part->type, "Apple_HFS"); + part->data_start = bendian_int(0); + part->data_count = bendian_int(mac_count); + part->status = bendian_int(0x33); + } else { + part->signature = bendian_short(0x504d); + part->map_count = bendian_int(3); + part->start_block = bendian_int((start/2048) + 10); + part->block_count = bendian_int(efi_lba - start/2048 - 10); + strcpy(part->name, "ISO"); + strcpy(part->type, "Apple_Free"); + part->data_start = bendian_int(0); + part->data_count = bendian_int(efi_lba - start/2048 - 10); + part->status = bendian_int(0x01); + } +} + int main(int argc, char *argv[]) { int i = 0; FILE *fp = NULL; - struct stat isostat; uint8_t *buf = NULL, *bufz = NULL; - int cylsize = 0, frac = 0, padding = 0; + int cylsize = 0, frac = 0; + size_t orig_gpt_size, free_space, gpt_size; + struct iso_primary_descriptor descriptor; prog = strcpy(alloca(strlen(argv[0]) + 1), argv[0]); i = check_option(argc, argv); @@ -450,10 +855,21 @@ main(int argc, char *argv[]) usage(); return 1; } + + if ((mode & EFI) && offset) + errx(1, "%s: --offset is invalid with UEFI images\n", argv[0]); + srand(time(NULL) << (getppid() << getpid())); if (!(fp = fopen(argv[0], "r+"))) err(1, "could not open file `%s'", argv[0]); + + if (fseek(fp, (16 << 11), SEEK_SET)) + err(1, "%s: seek error - 0", argv[0]); + + if (fread(&descriptor, sizeof(char), sizeof(descriptor), fp) != sizeof(descriptor)) + err(1, "%s: read error - 0", argv[0]); + if (fseek(fp, 17 * 2048, SEEK_SET)) err(1, "%s: seek error - 1", argv[0]); @@ -485,6 +901,40 @@ main(int argc, char *argv[]) if (mode & VERBOSE) display_catalogue(); + buf += 32; + + if (mode & EFI) + { + if (!read_efi_section(buf)) { + buf += 32; + if (!read_efi_catalogue(buf, &efi_count, &efi_lba) && efi_lba) { + offset = 1; + type = 0xee; + } else { + errx(1, "%s: invalid efi catalogue", argv[0]); + } + } else { + errx(1, "%s: unable to find efi image", argv[0]); + } + } + + buf += 32; + + if (mode & MAC) + { + if (!read_efi_section(buf)) { + buf += 32; + if (!read_efi_catalogue(buf, &mac_count, &mac_lba) && mac_lba) { + offset = 1; + type = 0xee; + } else { + errx(1, "%s: invalid efi catalogue", argv[0]); + } + } else { + errx(1, "%s: unable to find mac efi image", argv[0]); + } + } + if (fseek(fp, (de_lba * 2048 + 0x40), SEEK_SET)) err(1, "%s: seek error - 3", argv[0]); @@ -501,6 +951,9 @@ main(int argc, char *argv[]) if (stat(argv[0], &isostat)) err(1, "%s", argv[0]); + isosize = lendian_int(descriptor.size) * lendian_short(descriptor.block_size); + free_space = isostat.st_size - isosize; + cylsize = head * sector * 512; frac = isostat.st_size % cylsize; padding = (frac > 0) ? cylsize - frac : 0; @@ -508,7 +961,7 @@ main(int argc, char *argv[]) if (mode & VERBOSE) printf("imgsize: %zu, padding: %d\n", (size_t)isostat.st_size, padding); - cc = c = (isostat.st_size + padding) / cylsize; + cc = c = ( isostat.st_size + padding) / cylsize; if (c > 1024) { warnx("Warning: more than 1024 cylinders: %d", c); @@ -548,6 +1001,62 @@ main(int argc, char *argv[]) if (fwrite(buf, sizeof(char), i, fp) != (size_t)i) err(1, "%s: write error - 1", argv[0]); + if (efi_lba) { + reverse_uuid(basic_partition); + reverse_uuid(hfs_partition); + + /* 512 byte header, 128 entries of 128 bytes */ + orig_gpt_size = gpt_size = 512 + (128 * 128); + + /* Leave space for the APM if necessary */ + if (mac_lba) + gpt_size += (4 * 2048); + + buf = calloc(gpt_size, sizeof(char)); + memset(buf, 0, gpt_size); + + /* + * We need to ensure that we have enough space for the secondary GPT. + * Unlike the primary, this doesn't need a hole for the APM. We still + * want to be 1MB aligned so just bump the padding by a megabyte. + */ + if (free_space < orig_gpt_size && padding < orig_gpt_size) { + padding += 1024 * 1024; + } + + /* + * Determine the size of the ISO filesystem. This will define the size + * of the partition that covers it. + */ + psize = isosize / 512; + + /* + * Primary GPT starts at sector 1, secondary GPT starts at 1 sector + * before the end of the image + */ + initialise_gpt(buf, 1, (isostat.st_size + padding - 1024) / 512, 1); + + if (fseek(fp, 512, SEEK_SET)) + err(1, "%s: seek error - 6", argv[0]); + + if (fwrite(buf, sizeof(char), gpt_size, fp) != (size_t)gpt_size) + err(1, "%s: write error - 2", argv[0]); + } + + if (mac_lba) + { + /* Apple partition entries filling 2048 bytes each */ + int apm_size = apm_parts * 2048; + + buf = realloc(buf, apm_size); + memset(buf, 0, apm_size); + + initialise_apm(buf, APM_OFFSET); + + fseek(fp, APM_OFFSET, SEEK_SET); + fwrite(buf, sizeof(char), apm_size, fp); + } + if (padding) { if (fsync(fileno(fp))) @@ -557,6 +1066,30 @@ main(int argc, char *argv[]) err(1, "%s: could not add padding bytes", argv[0]); } + if (efi_lba) { + buf = realloc(buf, orig_gpt_size); + memset(buf, 0, orig_gpt_size); + + buf += orig_gpt_size - sizeof(struct gpt_header); + + initialise_gpt(buf, (isostat.st_size + padding - 1024) / 512, 1, 0); + + /* Shift back far enough to write the 128 GPT entries */ + buf -= 128 * sizeof(struct gpt_part_header); + + /* + * Seek far enough back that the gpt header is 512 bytes before the + * end of the image + */ + + if (fseek(fp, (isostat.st_size + padding) - orig_gpt_size - 512, + SEEK_SET)) + err(1, "%s: seek error - 8", argv[0]); + + if (fwrite(buf, sizeof(char), orig_gpt_size, fp) != orig_gpt_size) + err(1, "%s: write error - 4", argv[0]); + } + free(buf); fclose(fp); |