176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* ----------------------------------------------------------------------- *
276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   Copyright 2010 Shao Miller
676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   Copyright 2010-2012 Michal Soltys
776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   Permission is hereby granted, free of charge, to any person
976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   obtaining a copy of this software and associated documentation
1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   files (the "Software"), to deal in the Software without
1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   restriction, including without limitation the rights to use,
1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   copy, modify, merge, publish, distribute, sublicense, and/or
1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   sell copies of the Software, and to permit persons to whom
1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   the Software is furnished to do so, subject to the following
1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   conditions:
1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   The above copyright notice and this permission notice shall
1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   be included in all copies or substantial portions of the Software.
1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   OTHER DEALINGS IN THE SOFTWARE.
2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ----------------------------------------------------------------------- */
3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <com32.h>
3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdlib.h>
3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdio.h>
3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <string.h>
3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdint.h>
3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <dprintf.h>
3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <syslinux/config.h>
3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "chain.h"
3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "options.h"
4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "utility.h"
4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "partiter.h"
4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "mangle.h"
4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic const char cmldr_signature[8] = "cmdcons";
4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Create boot info table: needed when you want to chainload
4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * another version of ISOLINUX (or another bootlaoder that needs
4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the -boot-info-table switch of mkisofs)
4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * (will only work when run from ISOLINUX)
5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint manglef_isolinux(struct data_area *data)
5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    const union syslinux_derivative_info *sdi;
5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    unsigned char *isolinux_bin;
5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    uint32_t *checksum, *chkhead, *chktail;
5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    uint32_t file_lba = 0;
5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!(opt.file && opt.isolinux))
5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    sdi = syslinux_derivative_info();
6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (sdi->c.filesystem != SYSLINUX_FS_ISOLINUX) {
6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	error("The isolinux= option is only valid when run from ISOLINUX.");
6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	goto bail;
6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Boot info table info (integers in little endian format)
6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman       Offset Name         Size      Meaning
7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman       8      bi_pvd       4 bytes   LBA of primary volume descriptor
7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman       12     bi_file      4 bytes   LBA of boot file
7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman       16     bi_length    4 bytes   Boot file length in bytes
7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman       20     bi_csum      4 bytes   32-bit checksum
7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman       24     bi_reserved  40 bytes  Reserved
7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman       The 32-bit checksum is the sum of all the 32-bit words in the
7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman       boot file starting at byte offset 64. All linear block
7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman       addresses (LBAs) are given in CD sectors (normally 2048 bytes).
8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman       LBA of primary volume descriptor should already be set to 16.
8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman       */
8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    isolinux_bin = (unsigned char *)data->data;
8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Get LBA address of bootfile */
8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    file_lba = get_file_lba(opt.file);
8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (file_lba == 0) {
9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	error("Failed to find LBA offset of the boot file.");
9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	goto bail;
9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Set it */
9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    *((uint32_t *) & isolinux_bin[12]) = file_lba;
9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Set boot file length */
9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    *((uint32_t *) & isolinux_bin[16]) = data->size;
9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Calculate checksum */
10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    checksum = (uint32_t *) & isolinux_bin[20];
10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    chkhead = (uint32_t *) & isolinux_bin[64];
10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    chktail = (uint32_t *) & isolinux_bin[data->size & ~3u];
10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    *checksum = 0;
10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    while (chkhead < chktail)
10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	*checksum += *chkhead++;
10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /*
10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * Deal with possible fractional dword at the end;
10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * this *should* never happen...
11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     */
11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (data->size & 3) {
11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint32_t xword = 0;
11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	memcpy(&xword, chkhead, data->size & 3);
11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	*checksum += xword;
11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return 0;
11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanbail:
11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return -1;
11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Legacy grub's stage2 chainloading
12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint manglef_grub(const struct part_iter *iter, struct data_area *data)
12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Layout of stage2 file (from byte 0x0 to 0x270) */
12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct grub_stage2_patch_area {
12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* 0x0 to 0x205 */
12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	char unknown[0x206];
13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* 0x206: compatibility version number major */
13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint8_t compat_version_major;
13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* 0x207: compatibility version number minor */
13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint8_t compat_version_minor;
13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* 0x208: install_partition variable */
13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct {
13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    /* 0x208: sub-partition in sub-partition part2 */
13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    uint8_t part3;
13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    /* 0x209: sub-partition in top-level partition */
14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    uint8_t part2;
14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    /* 0x20a: top-level partiton number */
14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    uint8_t part1;
14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    /* 0x20b: BIOS drive number (must be 0) */
14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    uint8_t drive;
14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	} __attribute__ ((packed)) install_partition;
14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* 0x20c: deprecated (historical reason only) */
14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint32_t saved_entryno;
14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* 0x210: stage2_ID: will always be STAGE2_ID_STAGE2 = 0 in stage2 */
15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint8_t stage2_id;
15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* 0x211: force LBA */
15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint8_t force_lba;
15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* 0x212: version string (will probably be 0.97) */
15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	char version_string[5];
15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* 0x217: config filename */
15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	char config_file[89];
15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* 0x270: start of code (after jump from 0x200) */
15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	char codestart[1];
15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } __attribute__ ((packed)) *stage2;
16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!(opt.file && opt.grub))
16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (data->size < sizeof *stage2) {
16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	error("The file specified by grub=<loader> is too small to be stage2 of GRUB Legacy.");
16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	goto bail;
16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    stage2 = data->data;
16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /*
17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * Check the compatibility version number to see if we loaded a real
17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * stage2 file or a stage2 file that we support.
17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     */
17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (stage2->compat_version_major != 3
17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    || stage2->compat_version_minor != 2) {
17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	error("The file specified by grub=<loader> is not a supported stage2 GRUB Legacy binary.");
17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	goto bail;
17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /*
18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * GRUB Legacy wants the partition number in the install_partition
18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * variable, located at offset 0x208 of stage2.
18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * When GRUB Legacy is loaded, it is located at memory address 0x8208.
18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     *
18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * It looks very similar to the "boot information format" of the
18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * Multiboot specification:
18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     *   http://www.gnu.org/software/grub/manual/multiboot/multiboot.html#Boot-information-format
18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     *
18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     *   0x208 = part3: sub-partition in sub-partition part2
19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     *   0x209 = part2: sub-partition in top-level partition
19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     *   0x20a = part1: top-level partition number
19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     *   0x20b = drive: BIOS drive number (must be 0)
19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     *
19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * GRUB Legacy doesn't store the BIOS drive number at 0x20b, but at
19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * another location.
19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     *
19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * Partition numbers always start from zero.
19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * Unused partition bytes must be set to 0xFF.
19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     *
20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * We only care about top-level partition, so we only need to change
20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * "part1" to the appropriate value:
20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     *   -1:   whole drive (default) (-1 = 0xFF)
20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     *   0-3:  primary partitions
20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     *   4-*:  logical partitions
20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     */
20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    stage2->install_partition.part1 = iter->index - 1;
20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /*
20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * Grub Legacy reserves 89 bytes (from 0x8217 to 0x826f) for the
21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * config filename. The filename passed via grubcfg= will overwrite
21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * the default config filename "/boot/grub/menu.lst".
21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     */
21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (opt.grubcfg) {
21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (strlen(opt.grubcfg) >= sizeof stage2->config_file) {
21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    error("The config filename length can't exceed 88 characters.");
21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    goto bail;
21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	strcpy((char *)stage2->config_file, opt.grubcfg);
22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return 0;
22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanbail:
22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return -1;
22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if 0
22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Dell's DRMK chainloading.
22976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
23076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint manglef_drmk(struct data_area *data)
23176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
23276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /*
23376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * DRMK entry is different than MS-DOS/PC-DOS
23476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * A new size, aligned to 16 bytes to ease use of ds:[bp+28].
23576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * We only really need 4 new, usable bytes at the end.
23676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     */
23776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
23876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!(opt.file && opt.drmk))
23976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
24076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
24176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    uint32_t tsize = (data->size + 19) & 0xfffffff0;
24276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    const union syslinux_derivative_info *sdi;
24376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    uint64_t fs_lba;
24476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
24576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    sdi = syslinux_derivative_info();
24676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* We should lookup the Syslinux partition offset and use it */
24776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    fs_lba = *sdi->disk.partoffset;
24876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
24976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /*
25076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * fs_lba should be verified against the disk as some DRMK
25176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * variants will check and fail if it does not match
25276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     */
25376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    dprintf("  fs_lba offset is %d\n", fs_lba);
25476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* DRMK only uses a DWORD */
25576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (fs_lba > 0xffffffff) {
25676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	error("LBA very large; Only using lower 32 bits; DRMK will probably fail.");
25776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
25876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    opt.regs.ss = opt.regs.fs = opt.regs.gs = 0;	/* Used before initialized */
25976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!realloc(data->data, tsize)) {
26076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	error("Failed to realloc for DRMK.");
26176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	goto bail;
26276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
26376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    data->size = tsize;
26476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* ds:bp is assumed by DRMK to be the boot sector */
26576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* offset 28 is the FAT HiddenSectors value */
26676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    opt.regs.ds = (tsize >> 4) + (opt.fseg - 2);
26776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* "Patch" into tail of the new space */
26876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    *(uint32_t *)((char*)data->data + tsize - 4) = fs_lba;
26976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
27076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return 0;
27176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanbail:
27276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return -1;
27376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
27476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif
27576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Adjust BPB common function */
27676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int mangle_bpb(const struct part_iter *iter, struct data_area *data, const char *tag)
27776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
27876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int type = bpb_detect(data->data, tag);
27976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int off = drvoff_detect(type);
28076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
28176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* BPB: hidden sectors 64bit - exFAT only for now */
28276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (type == bpbEXF)
28376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    *(uint64_t *) ((char *)data->data + 0x40) = iter->abs_lba;
28476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* BPB: hidden sectors 32bit*/
28576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    else if (bpbV34 <= type && type <= bpbV70) {
28676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (iter->abs_lba < ~0u)
28776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    *(uint32_t *) ((char *)data->data + 0x1c) = iter->abs_lba;
28876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	else
28976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    /* won't really help much, but ... */
29076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    *(uint32_t *) ((char *)data->data + 0x1c) = ~0u;
29176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* BPB: hidden sectors 16bit*/
29276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else if (bpbV30 <= type && type <= bpbV32) {
29376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (iter->abs_lba < 0xFFFF)
29476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    *(uint16_t *) ((char *)data->data + 0x1c) = iter->abs_lba;
29576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	else
29676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    /* won't really help much, but ... */
29776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    *(uint16_t *) ((char *)data->data + 0x1c) = (uint16_t)~0u;
29876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
29976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
30076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* BPB: legacy geometry */
30176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (bpbV30 <= type && type <= bpbV70) {
30276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (iter->di.cbios)
30376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    *(uint32_t *)((char *)data->data + 0x18) = (iter->di.head << 16) | iter->di.spt;
30476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	else {
30576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (iter->di.disk & 0x80)
30676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		*(uint32_t *)((char *)data->data + 0x18) = 0x00FF003F;
30776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    else
30876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		*(uint32_t *)((char *)data->data + 0x18) = 0x00020012;
30976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
31076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
31176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* BPB: drive */
31276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (off >= 0) {
31376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	*(uint8_t *)((char *)data->data + off) = (opt.swap ? iter->di.disk & 0x80 : iter->di.disk);
31476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
31576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
31676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return 0;
31776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
31876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
31976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
32076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Adjust BPB of a BPB-compatible file
32176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
32276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint manglef_bpb(const struct part_iter *iter, struct data_area *data)
32376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
32476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!(opt.file && opt.filebpb))
32576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
32676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
32776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return mangle_bpb(iter, data, "file");
32876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
32976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
33076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
33176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Adjust BPB of a sector
33276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
33376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint mangles_bpb(const struct part_iter *iter, struct data_area *data)
33476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
33576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!(opt.sect && opt.setbpb))
33676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
33776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
33876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return mangle_bpb(iter, data, "sect");
33976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
34076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
34176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
34276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This function performs full BPB patching, analogously to syslinux's
34376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * native BSS.
34476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
34576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint manglesf_bss(struct data_area *sec, struct data_area *fil)
34676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
34776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int type1, type2;
34876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    size_t cnt = 0;
34976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
35076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!(opt.sect && opt.file && opt.bss))
35176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
35276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
35376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    type1 = bpb_detect(fil->data, "bss/file");
35476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    type2 = bpb_detect(sec->data, "bss/sect");
35576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
35676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!type1 || !type2) {
35776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	error("Couldn't determine the BPB type for option 'bss'.");
35876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	goto bail;
35976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
36076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (type1 != type2) {
36176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	error("Option 'bss' can't be used,\n"
36276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		"when a sector and a file have incompatible BPBs.");
36376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	goto bail;
36476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
36576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
36676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Copy common 2.0 data */
36776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    memcpy((char *)fil->data + 0x0B, (char *)sec->data + 0x0B, 0x0D);
36876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
36976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Copy 3.0+ data */
37076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (type1 <= bpbV30) {
37176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	cnt = 0x06;
37276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else if (type1 <= bpbV32) {
37376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	cnt = 0x08;
37476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else if (type1 <= bpbV34) {
37576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	cnt = 0x0C;
37676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else if (type1 <= bpbV40) {
37776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	cnt = 0x2E;
37876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else if (type1 <= bpbVNT) {
37976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	cnt = 0x3C;
38076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else if (type1 <= bpbV70) {
38176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	cnt = 0x42;
38276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else if (type1 <= bpbEXF) {
38376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	cnt = 0x60;
38476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
38576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    memcpy((char *)fil->data + 0x18, (char *)sec->data + 0x18, cnt);
38676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
38776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return 0;
38876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanbail:
38976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return -1;
39076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
39176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
39276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
39376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Save sector.
39476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
39576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint mangles_save(const struct part_iter *iter, const struct data_area *data, void *org)
39676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
39776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!(opt.sect && opt.save))
39876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
39976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
40076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (memcmp(org, data->data, data->size)) {
40176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (disk_write_sectors(&iter->di, iter->abs_lba, data->data, 1)) {
40276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    error("Cannot write the updated sector.");
40376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    goto bail;
40476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
40576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* function can be called again */
40676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	memcpy(org, data->data, data->size);
40776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
40876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
40976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return 0;
41076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanbail:
41176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return -1;
41276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
41376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
41476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
41576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * To boot the Recovery Console of Windows NT/2K/XP we need to write
41676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the string "cmdcons\0" to memory location 0000:7C03.
41776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Memory location 0000:7C00 contains the bootsector of the partition.
41876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
41976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint mangles_cmldr(struct data_area *data)
42076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
42176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!(opt.sect && opt.cmldr))
42276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
42376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
42476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    memcpy((char *)data->data + 3, cmldr_signature, sizeof cmldr_signature);
42576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return 0;
42676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
42776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
42876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Set common registers */
42976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint mangler_init(const struct part_iter *iter)
43076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
43176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Set initial registry values */
43276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (opt.file) {
43376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	opt.regs.cs = opt.regs.ds = opt.regs.ss = opt.fseg;
43476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	opt.regs.ip = opt.fip;
43576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else {
43676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	opt.regs.cs = opt.regs.ds = opt.regs.ss = opt.sseg;
43776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	opt.regs.ip = opt.sip;
43876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
43976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
44076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (opt.regs.ip == 0x7C00 && !opt.regs.cs)
44176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	opt.regs.esp.l = 0x7C00;
44276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
44376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* DOS kernels want the drive number in BL instead of DL. Indulge them. */
44476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    opt.regs.ebx.b[0] = opt.regs.edx.b[0] = iter->di.disk;
44576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
44676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return 0;
44776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
44876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
44976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* ds:si & ds:bp */
45076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint mangler_handover(const struct part_iter *iter, const struct data_area *data)
45176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
45276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (opt.file && opt.maps && !opt.hptr) {
45376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	opt.regs.esi.l = opt.regs.ebp.l = opt.soff;
45476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	opt.regs.ds = opt.sseg;
45576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	opt.regs.eax.l = 0;
45676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else if (opt.hand) {
45776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* base is really 0x7be */
45876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	opt.regs.esi.l = opt.regs.ebp.l = data->base;
45976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	opt.regs.ds = 0;
46076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (iter->index && iter->type == typegpt)   /* must be iterated and GPT */
46176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    opt.regs.eax.l = 0x54504721;	/* '!GPT' */
46276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	else
46376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    opt.regs.eax.l = 0;
46476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
46576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
46676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return 0;
46776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
46876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
46976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
47076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * GRLDR of GRUB4DOS wants the partition number in DH:
47176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * -1:   whole drive (default)
47276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 0-3:  primary partitions
47376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 4-*:  logical partitions
47476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
47576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint mangler_grldr(const struct part_iter *iter)
47676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
47776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (opt.grldr)
47876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	opt.regs.edx.b[1] = iter->index - 1;
47976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
48076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return 0;
48176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
48276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
48376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
48476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * try to copy values from temporary iterator, if positions match
48576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
48676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void mbrcpy(struct part_iter *diter, struct part_iter *siter)
48776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
48876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (diter->dos.cebr_lba == siter->dos.cebr_lba &&
48976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    diter->di.disk == siter->di.disk) {
49076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	memcpy(diter->data, siter->data, sizeof(struct disk_dos_mbr));
49176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
49276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
49376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
49476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int fliphide(struct part_iter *iter, struct part_iter *miter)
49576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
49676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct disk_dos_part_entry *dp;
49776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    static const uint16_t mask =
49876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	(1 << 0x01) | (1 << 0x04) | (1 << 0x06) |
49976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	(1 << 0x07) | (1 << 0x0b) | (1 << 0x0c) | (1 << 0x0e);
50076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    uint8_t t;
50176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
50276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    dp = (struct disk_dos_part_entry *)iter->record;
50376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    t = dp->ostype;
50476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
50576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if ((t <= 0x1f) && ((mask >> (t & ~0x10u)) & 1)) {
50676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* It's a hideable partition type */
50776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (miter->index == iter->index || opt.hide & HIDE_REV)
50876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    t &= ~0x10u;	/* unhide */
50976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	else
51076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    t |= 0x10u;	/* hide */
51176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
51276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (dp->ostype != t) {
51376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	dp->ostype = t;
51476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return -1;
51576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
51676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return 0;
51776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
51876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
51976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
52076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * miter - iterator we match against
52176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * hide bits meaning:
52276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ..| - enable (1) / disable (0)
52376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * .|. - all (1) / pri (0)
52476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * |.. - unhide (1) / hide (0)
52576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
52676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint manglepe_hide(struct part_iter *miter)
52776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
52876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int wb = 0, werr = 0;
52976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct part_iter *iter = NULL;
53076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int ridx;
53176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
53276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!(opt.hide & HIDE_ON))
53376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
53476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
53576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (miter->type != typedos) {
53676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	error("Option '[un]hide[all]' works only for legacy (DOS) partition scheme.");
53776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return -1;
53876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
53976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
54076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (miter->index > 4 && !(opt.hide & HIDE_EXT))
54176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	warn("Specified partition is logical, so it can't be unhidden without 'unhideall'.");
54276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
54376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!(iter = pi_begin(&miter->di, PIF_STEPALL | opt.piflags)))
54476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return -1;
54576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
54676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    while (!pi_next(iter) && !werr) {
54776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	ridx = iter->index0;
54876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (!(opt.hide & HIDE_EXT) && ridx > 3)
54976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;  /* skip when we're constrained to pri only */
55076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
55176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (iter->index != -1)
55276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    wb |= fliphide(iter, miter);
55376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
55476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/*
55576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 * we have to update mbr and each extended partition, but only if
55676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 * changes (wb) were detected and there was no prior write error (werr)
55776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 */
55876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (ridx >= 3 && wb && !werr) {
55976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    mbrcpy(miter, iter);
56076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    werr |= disk_write_sectors(&iter->di, iter->dos.cebr_lba, iter->data, 1);
56176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    wb = 0;
56276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
56376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
56476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
56576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (iter->status < 0)
56676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	goto bail;
56776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
56876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* last update */
56976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (wb && !werr) {
57076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mbrcpy(miter, iter);
57176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	werr |= disk_write_sectors(&iter->di, iter->dos.cebr_lba, iter->data, 1);
57276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
57376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (werr)
57476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	warn("Failed to write E/MBR during '[un]hide[all]'.");
57576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
57676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanbail:
57776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pi_del(&iter);
57876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return 0;
57976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
58076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
58176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int updchs(struct part_iter *iter, int ext)
58276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
58376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct disk_dos_part_entry *dp;
58476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    uint32_t ochs1, ochs2, lba;
58576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
58676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    dp = (struct disk_dos_part_entry *)iter->record;
58776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!ext) {
58876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* primary or logical */
58976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	lba = (uint32_t)iter->abs_lba;
59076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else {
59176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* extended */
59276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	dp += 1;
59376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	lba = iter->dos.nebr_lba;
59476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
59576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ochs1 = *(uint32_t *)dp->start;
59676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ochs2 = *(uint32_t *)dp->end;
59776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
59876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /*
59976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * We have to be a bit more careful here in case of 0 start and/or length;
60076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * start = 0 would be converted to the beginning of the disk (C/H/S =
60176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * 0/0/1) or the [B]EBR, length = 0 would actually set the end CHS to be
60276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * lower than the start CHS.
60376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     *
60476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * Both are harmless in case of a hole (and in non-hole case will make
60576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * partiter complain about corrupt layout if PIF_STRICT is set), but it
60676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * makes everything look silly and not really correct.
60776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     *
60876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * Thus the approach as seen below.
60976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     */
61076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
61176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (dp->start_lba || iter->index != -1) {
61276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	lba2chs(&dp->start, &iter->di, lba, L2C_CADD);
61376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else {
61476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	memset(&dp->start, 0, sizeof dp->start);
61576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
61676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
61776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if ((dp->start_lba || iter->index != -1) && dp->length) {
61876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	lba2chs(&dp->end, &iter->di, lba + dp->length - 1, L2C_CADD);
61976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else {
62076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	memset(&dp->end, 0, sizeof dp->end);
62176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
62276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
62376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return
62476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	*(uint32_t *)dp->start != ochs1 ||
62576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	*(uint32_t *)dp->end != ochs2;
62676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
62776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
62876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
62976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * miter - iterator we match against
63076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
63176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint manglepe_fixchs(struct part_iter *miter)
63276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
63376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int wb = 0, werr = 0;
63476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct part_iter *iter = NULL;
63576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int ridx;
63676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
63776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!opt.fixchs)
63876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
63976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
64076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (miter->type != typedos) {
64176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	error("Option 'fixchs' works only for legacy (DOS) partition scheme.");
64276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return -1;
64376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
64476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
64576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!(iter = pi_begin(&miter->di, PIF_STEPALL | opt.piflags)))
64676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return -1;
64776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
64876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    while (!pi_next(iter) && !werr) {
64976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	ridx = iter->index0;
65076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
65176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	wb |= updchs(iter, 0);
65276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (ridx > 3)
65376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    wb |= updchs(iter, 1);
65476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
65576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/*
65676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 * we have to update mbr and each extended partition, but only if
65776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 * changes (wb) were detected and there was no prior write error (werr)
65876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 */
65976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (ridx >= 3 && wb && !werr) {
66076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    mbrcpy(miter, iter);
66176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    werr |= disk_write_sectors(&iter->di, iter->dos.cebr_lba, iter->data, 1);
66276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    wb = 0;
66376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
66476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
66576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
66676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (iter->status < 0)
66776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	goto bail;
66876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
66976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* last update */
67076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (wb && !werr) {
67176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mbrcpy(miter, iter);
67276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	werr |= disk_write_sectors(&iter->di, iter->dos.cebr_lba, iter->data, 1);
67376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
67476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (werr)
67576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	warn("Failed to write E/MBR during 'fixchs'.");
67676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
67776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanbail:
67876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pi_del(&iter);
67976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return 0;
68076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
68176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
68276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* vim: set ts=8 sts=4 sw=4 noet: */
683