[BACK]Return to cd9660_eltorito.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / usr.sbin / makefs / cd9660

Annotation of src/usr.sbin/makefs/cd9660/cd9660_eltorito.c, Revision 1.17.2.3

1.17.2.3! yamt        1: /*     $NetBSD: cd9660_eltorito.c,v 1.17.2.2 2012/05/23 10:08:29 yamt Exp $    */
1.1       fvdl        2:
                      3: /*
                      4:  * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
                      5:  * Perez-Rathke and Ram Vedam.  All rights reserved.
                      6:  *
                      7:  * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
                      8:  * Alan Perez-Rathke and Ram Vedam.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or
                     11:  * without modification, are permitted provided that the following
                     12:  * conditions are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above
                     16:  *    copyright notice, this list of conditions and the following
                     17:  *    disclaimer in the documentation and/or other materials provided
                     18:  *    with the distribution.
                     19:  *
                     20:  * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
                     21:  * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
                     22:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1.5       dyoung     23:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1.1       fvdl       24:  * DISCLAIMED.  IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
                     25:  * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
                     26:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     27:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
                     28:  * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
                     29:  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
                     30:  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     31:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
                     32:  * OF SUCH DAMAGE.
                     33:  */
1.15      christos   34:
                     35:
1.1       fvdl       36: #include "cd9660.h"
                     37: #include "cd9660_eltorito.h"
1.17.2.1  yamt       38: #include <sys/bootblock.h>
1.17.2.3! yamt       39: #include <util.h>
1.1       fvdl       40:
                     41: #include <sys/cdefs.h>
                     42: #if defined(__RCSID) && !defined(__lint)
1.17.2.3! yamt       43: __RCSID("$NetBSD: cd9660_eltorito.c,v 1.17.2.2 2012/05/23 10:08:29 yamt Exp $");
1.1       fvdl       44: #endif  /* !__lint */
                     45:
1.7       dyoung     46: #ifdef DEBUG
                     47: #define        ELTORITO_DPRINTF(__x)   printf __x
                     48: #else
                     49: #define        ELTORITO_DPRINTF(__x)
                     50: #endif
                     51:
1.17.2.3! yamt       52: #include <util.h>
        !            53:
1.1       fvdl       54: static struct boot_catalog_entry *cd9660_init_boot_catalog_entry(void);
                     55: static struct boot_catalog_entry *cd9660_boot_setup_validation_entry(char);
                     56: static struct boot_catalog_entry *cd9660_boot_setup_default_entry(
                     57:     struct cd9660_boot_image *);
                     58: static struct boot_catalog_entry *cd9660_boot_setup_section_head(char);
                     59: static struct boot_catalog_entry *cd9660_boot_setup_validation_entry(char);
                     60: #if 0
                     61: static u_char cd9660_boot_get_system_type(struct cd9660_boot_image *);
                     62: #endif
                     63:
                     64: int
1.17.2.3! yamt       65: cd9660_add_boot_disk(iso9660_disk *diskStructure, const char *boot_info)
1.1       fvdl       66: {
                     67:        struct stat stbuf;
1.9       dyoung     68:        const char *mode_msg;
1.1       fvdl       69:        char *temp;
                     70:        char *sysname;
                     71:        char *filename;
1.8       dyoung     72:        struct cd9660_boot_image *new_image, *tmp_image;
1.5       dyoung     73:
1.1       fvdl       74:        assert(boot_info != NULL);
                     75:
1.2       dyoung     76:        if (*boot_info == '\0') {
                     77:                warnx("Error: Boot disk information must be in the "
                     78:                      "format 'system;filename'");
1.5       dyoung     79:                return 0;
1.2       dyoung     80:        }
                     81:
1.1       fvdl       82:        /* First decode the boot information */
1.17.2.3! yamt       83:        temp = estrdup(boot_info);
1.1       fvdl       84:
                     85:        sysname = temp;
                     86:        filename = strchr(sysname, ';');
                     87:        if (filename == NULL) {
1.2       dyoung     88:                warnx("supply boot disk information in the format "
                     89:                    "'system;filename'");
1.11      christos   90:                free(temp);
1.5       dyoung     91:                return 0;
1.1       fvdl       92:        }
                     93:
1.2       dyoung     94:        *filename++ = '\0';
                     95:
1.17.2.3! yamt       96:        if (diskStructure->verbose_level > 0) {
1.9       dyoung     97:                printf("Found bootdisk with system %s, and filename %s\n",
                     98:                    sysname, filename);
                     99:        }
1.17.2.3! yamt      100:        new_image = ecalloc(1, sizeof(*new_image));
1.1       fvdl      101:        new_image->loadSegment = 0;     /* default for now */
                    102:
                    103:        /* Decode System */
1.2       dyoung    104:        if (strcmp(sysname, "i386") == 0)
1.1       fvdl      105:                new_image->system = ET_SYS_X86;
1.2       dyoung    106:        else if (strcmp(sysname, "powerpc") == 0)
1.1       fvdl      107:                new_image->system = ET_SYS_PPC;
1.4       dyoung    108:        else if (strcmp(sysname, "macppc") == 0 ||
                    109:                 strcmp(sysname, "mac68k") == 0)
1.1       fvdl      110:                new_image->system = ET_SYS_MAC;
                    111:        else {
1.2       dyoung    112:                warnx("boot disk system must be "
                    113:                      "i386, powerpc, macppc, or mac68k");
1.11      christos  114:                free(temp);
                    115:                free(new_image);
1.1       fvdl      116:                return 0;
                    117:        }
1.5       dyoung    118:
                    119:
1.17.2.3! yamt      120:        new_image->filename = estrdup(filename);
1.1       fvdl      121:
                    122:        free(temp);
1.5       dyoung    123:
1.1       fvdl      124:        /* Get information about the file */
                    125:        if (lstat(new_image->filename, &stbuf) == -1)
1.2       dyoung    126:                err(EXIT_FAILURE, "%s: lstat(\"%s\")", __func__,
                    127:                    new_image->filename);
1.1       fvdl      128:
                    129:        switch (stbuf.st_size) {
                    130:        case 1440 * 1024:
                    131:                new_image->targetMode = ET_MEDIA_144FDD;
1.9       dyoung    132:                mode_msg = "Assigned boot image to 1.44 emulation mode";
1.1       fvdl      133:                break;
                    134:        case 1200 * 1024:
                    135:                new_image->targetMode = ET_MEDIA_12FDD;
1.9       dyoung    136:                mode_msg = "Assigned boot image to 1.2 emulation mode";
1.1       fvdl      137:                break;
                    138:        case 2880 * 1024:
                    139:                new_image->targetMode = ET_MEDIA_288FDD;
1.9       dyoung    140:                mode_msg = "Assigned boot image to 2.88 emulation mode";
1.1       fvdl      141:                break;
                    142:        default:
                    143:                new_image->targetMode = ET_MEDIA_NOEM;
1.9       dyoung    144:                mode_msg = "Assigned boot image to no emulation mode";
1.1       fvdl      145:                break;
                    146:        }
1.5       dyoung    147:
1.17.2.3! yamt      148:        if (diskStructure->verbose_level > 0)
1.9       dyoung    149:                printf("%s\n", mode_msg);
                    150:
1.1       fvdl      151:        new_image->size = stbuf.st_size;
                    152:        new_image->num_sectors =
1.17.2.3! yamt      153:            howmany(new_image->size, diskStructure->sectorSize) *
        !           154:            howmany(diskStructure->sectorSize, 512);
        !           155:        if (diskStructure->verbose_level > 0) {
1.9       dyoung    156:                printf("New image has size %d, uses %d 512-byte sectors\n",
                    157:                    new_image->size, new_image->num_sectors);
                    158:        }
1.1       fvdl      159:        new_image->sector = -1;
                    160:        /* Bootable by default */
                    161:        new_image->bootable = ET_BOOTABLE;
                    162:        /* Add boot disk */
                    163:
1.8       dyoung    164:        /* Group images for the same platform together. */
1.17.2.3! yamt      165:        TAILQ_FOREACH(tmp_image, &diskStructure->boot_images, image_list) {
1.8       dyoung    166:                if (tmp_image->system != new_image->system)
                    167:                        break;
                    168:        }
                    169:
                    170:        if (tmp_image == NULL) {
1.17.2.3! yamt      171:                TAILQ_INSERT_HEAD(&diskStructure->boot_images, new_image,
1.1       fvdl      172:                    image_list);
1.8       dyoung    173:        } else
                    174:                TAILQ_INSERT_BEFORE(tmp_image, new_image, image_list);
                    175:
1.17.2.3! yamt      176:        new_image->serialno = diskStructure->image_serialno++;
1.5       dyoung    177:
1.1       fvdl      178:        /* TODO : Need to do anything about the boot image in the tree? */
1.17.2.3! yamt      179:        diskStructure->is_bootable = 1;
1.5       dyoung    180:
1.1       fvdl      181:        return 1;
                    182: }
                    183:
                    184: int
1.17.2.3! yamt      185: cd9660_eltorito_add_boot_option(iso9660_disk *diskStructure,
        !           186:     const char *option_string, const char *value)
1.1       fvdl      187: {
1.7       dyoung    188:        char *eptr;
1.1       fvdl      189:        struct cd9660_boot_image *image;
1.5       dyoung    190:
1.1       fvdl      191:        assert(option_string != NULL);
1.5       dyoung    192:
1.1       fvdl      193:        /* Find the last image added */
1.17.2.3! yamt      194:        TAILQ_FOREACH(image, &diskStructure->boot_images, image_list) {
        !           195:                if (image->serialno + 1 == diskStructure->image_serialno)
1.8       dyoung    196:                        break;
                    197:        }
1.1       fvdl      198:        if (image == NULL)
1.2       dyoung    199:                errx(EXIT_FAILURE, "Attempted to add boot option, "
                    200:                    "but no boot images have been specified");
1.1       fvdl      201:
                    202:        if (strcmp(option_string, "no-emul-boot") == 0) {
1.5       dyoung    203:                image->targetMode = ET_MEDIA_NOEM;
1.1       fvdl      204:        } else if (strcmp(option_string, "no-boot") == 0) {
                    205:                image->bootable = ET_NOT_BOOTABLE;
                    206:        } else if (strcmp(option_string, "hard-disk-boot") == 0) {
                    207:                image->targetMode = ET_MEDIA_HDD;
                    208:        } else if (strcmp(option_string, "boot-load-segment") == 0) {
1.7       dyoung    209:                image->loadSegment = strtoul(value, &eptr, 16);
                    210:                if (eptr == value || *eptr != '\0' || errno != ERANGE) {
                    211:                        warn("%s: strtoul", __func__);
                    212:                        return 0;
                    213:                }
1.1       fvdl      214:        } else {
1.5       dyoung    215:                return 0;
1.1       fvdl      216:        }
                    217:        return 1;
                    218: }
                    219:
                    220: static struct boot_catalog_entry *
                    221: cd9660_init_boot_catalog_entry(void)
                    222: {
1.17.2.3! yamt      223:        return ecalloc(1, sizeof(struct boot_catalog_entry));
1.1       fvdl      224: }
                    225:
                    226: static struct boot_catalog_entry *
                    227: cd9660_boot_setup_validation_entry(char sys)
                    228: {
1.6       dyoung    229:        struct boot_catalog_entry *entry;
                    230:        boot_catalog_validation_entry *ve;
1.1       fvdl      231:        int16_t checksum;
                    232:        unsigned char *csptr;
1.17.2.2  yamt      233:        size_t i;
1.6       dyoung    234:        entry = cd9660_init_boot_catalog_entry();
1.5       dyoung    235:
1.6       dyoung    236:        ve = &entry->entry_data.VE;
                    237:
                    238:        ve->header_id[0] = 1;
                    239:        ve->platform_id[0] = sys;
                    240:        ve->key[0] = 0x55;
                    241:        ve->key[1] = 0xAA;
1.1       fvdl      242:
                    243:        /* Calculate checksum */
                    244:        checksum = 0;
1.6       dyoung    245:        cd9660_721(0, ve->checksum);
1.7       dyoung    246:        csptr = (unsigned char*)ve;
1.6       dyoung    247:        for (i = 0; i < sizeof(*ve); i += 2) {
                    248:                checksum += (int16_t)csptr[i];
                    249:                checksum += 256 * (int16_t)csptr[i + 1];
1.1       fvdl      250:        }
                    251:        checksum = -checksum;
1.6       dyoung    252:        cd9660_721(checksum, ve->checksum);
1.5       dyoung    253:
1.7       dyoung    254:         ELTORITO_DPRINTF(("%s: header_id %d, platform_id %d, key[0] %d, key[1] %d, "
                    255:            "checksum %04x\n", __func__, ve->header_id[0], ve->platform_id[0],
                    256:            ve->key[0], ve->key[1], checksum));
1.6       dyoung    257:        return entry;
1.1       fvdl      258: }
                    259:
                    260: static struct boot_catalog_entry *
                    261: cd9660_boot_setup_default_entry(struct cd9660_boot_image *disk)
                    262: {
                    263:        struct boot_catalog_entry *default_entry;
1.6       dyoung    264:        boot_catalog_initial_entry *ie;
1.1       fvdl      265:
                    266:        default_entry = cd9660_init_boot_catalog_entry();
                    267:        if (default_entry == NULL)
                    268:                return NULL;
1.5       dyoung    269:
1.6       dyoung    270:        ie = &default_entry->entry_data.IE;
1.5       dyoung    271:
1.6       dyoung    272:        ie->boot_indicator[0] = disk->bootable;
                    273:        ie->media_type[0] = disk->targetMode;
                    274:        cd9660_721(disk->loadSegment, ie->load_segment);
                    275:        ie->system_type[0] = disk->system;
1.7       dyoung    276:        cd9660_721(disk->num_sectors, ie->sector_count);
1.6       dyoung    277:        cd9660_731(disk->sector, ie->load_rba);
1.5       dyoung    278:
1.7       dyoung    279:        ELTORITO_DPRINTF(("%s: boot indicator %d, media type %d, "
                    280:            "load segment %04x, system type %d, sector count %d, "
                    281:            "load rba %d\n", __func__, ie->boot_indicator[0],
                    282:            ie->media_type[0], disk->loadSegment, ie->system_type[0],
                    283:            disk->num_sectors, disk->sector));
1.1       fvdl      284:        return default_entry;
                    285: }
                    286:
                    287: static struct boot_catalog_entry *
                    288: cd9660_boot_setup_section_head(char platform)
                    289: {
1.6       dyoung    290:        struct boot_catalog_entry *entry;
                    291:        boot_catalog_section_header *sh;
1.1       fvdl      292:
1.6       dyoung    293:        entry = cd9660_init_boot_catalog_entry();
                    294:        if (entry == NULL)
1.1       fvdl      295:                return NULL;
1.6       dyoung    296:
                    297:        sh = &entry->entry_data.SH;
1.1       fvdl      298:        /* More by default. The last one will manually be set to 0x91 */
1.6       dyoung    299:        sh->header_indicator[0] = ET_SECTION_HEADER_MORE;
                    300:        sh->platform_id[0] = platform;
                    301:        sh->num_section_entries[0] = 0;
                    302:        return entry;
1.1       fvdl      303: }
                    304:
                    305: static struct boot_catalog_entry *
                    306: cd9660_boot_setup_section_entry(struct cd9660_boot_image *disk)
                    307: {
                    308:        struct boot_catalog_entry *entry;
1.6       dyoung    309:        boot_catalog_section_entry *se;
1.1       fvdl      310:        if ((entry = cd9660_init_boot_catalog_entry()) == NULL)
                    311:                return NULL;
1.5       dyoung    312:
1.6       dyoung    313:        se = &entry->entry_data.SE;
                    314:
                    315:        se->boot_indicator[0] = ET_BOOTABLE;
                    316:        se->media_type[0] = disk->targetMode;
                    317:        cd9660_721(disk->loadSegment, se->load_segment);
1.7       dyoung    318:        cd9660_721(disk->num_sectors, se->sector_count);
                    319:        cd9660_731(disk->sector, se->load_rba);
1.1       fvdl      320:        return entry;
                    321: }
                    322:
                    323: #if 0
                    324: static u_char
                    325: cd9660_boot_get_system_type(struct cd9660_boot_image *disk)
                    326: {
                    327:        /*
                    328:                For hard drive booting, we need to examine the MBR to figure
                    329:                out what the partition type is
                    330:        */
                    331:        return 0;
                    332: }
                    333: #endif
                    334:
                    335: /*
                    336:  * Set up the BVD, Boot catalog, and the boot entries, but do no writing
                    337:  */
                    338: int
1.17.2.3! yamt      339: cd9660_setup_boot(iso9660_disk *diskStructure, int first_sector)
1.1       fvdl      340: {
                    341:        int sector;
                    342:        int used_sectors;
                    343:        int num_entries = 0;
                    344:        int catalog_sectors;
                    345:        struct boot_catalog_entry *x86_head, *mac_head, *ppc_head,
1.8       dyoung    346:                *valid_entry, *default_entry, *temp, *head, **headp, *next;
1.1       fvdl      347:        struct cd9660_boot_image *tmp_disk;
                    348:
1.8       dyoung    349:        headp = NULL;
                    350:        x86_head = mac_head = ppc_head = NULL;
1.5       dyoung    351:
1.1       fvdl      352:        /* If there are no boot disks, don't bother building boot information */
1.17.2.3! yamt      353:        if (TAILQ_EMPTY(&diskStructure->boot_images))
1.1       fvdl      354:                return 0;
                    355:
                    356:        /* Point to catalog: For now assume it consumes one sector */
1.9       dyoung    357:        ELTORITO_DPRINTF(("Boot catalog will go in sector %d\n", first_sector));
1.17.2.3! yamt      358:        diskStructure->boot_catalog_sector = first_sector;
1.1       fvdl      359:        cd9660_bothendian_dword(first_sector,
1.17.2.3! yamt      360:                diskStructure->boot_descriptor->boot_catalog_pointer);
1.5       dyoung    361:
1.1       fvdl      362:        /* Step 1: Generate boot catalog */
                    363:        /* Step 1a: Validation entry */
                    364:        valid_entry = cd9660_boot_setup_validation_entry(ET_SYS_X86);
                    365:        if (valid_entry == NULL)
                    366:                return -1;
1.5       dyoung    367:
1.1       fvdl      368:        /*
                    369:         * Count how many boot images there are,
                    370:         * and how many sectors they consume.
                    371:         */
                    372:        num_entries = 1;
                    373:        used_sectors = 0;
1.5       dyoung    374:
1.17.2.3! yamt      375:        TAILQ_FOREACH(tmp_disk, &diskStructure->boot_images, image_list) {
1.1       fvdl      376:                used_sectors += tmp_disk->num_sectors;
1.5       dyoung    377:
1.1       fvdl      378:                /* One default entry per image */
                    379:                num_entries++;
                    380:        }
1.17.2.3! yamt      381:        catalog_sectors = howmany(num_entries * 0x20, diskStructure->sectorSize);
1.1       fvdl      382:        used_sectors += catalog_sectors;
1.5       dyoung    383:
1.17.2.3! yamt      384:        if (diskStructure->verbose_level > 0) {
1.9       dyoung    385:                printf("%s: there will be %i entries consuming %i sectors. "
                    386:                       "Catalog is %i sectors\n", __func__, num_entries,
                    387:                       used_sectors, catalog_sectors);
                    388:        }
1.5       dyoung    389:
1.1       fvdl      390:        /* Populate sector numbers */
                    391:        sector = first_sector + catalog_sectors;
1.17.2.3! yamt      392:        TAILQ_FOREACH(tmp_disk, &diskStructure->boot_images, image_list) {
1.1       fvdl      393:                tmp_disk->sector = sector;
                    394:                sector += tmp_disk->num_sectors;
                    395:        }
1.5       dyoung    396:
1.17.2.3! yamt      397:        LIST_INSERT_HEAD(&diskStructure->boot_entries, valid_entry, ll_struct);
1.5       dyoung    398:
1.1       fvdl      399:        /* Step 1b: Initial/default entry */
                    400:        /* TODO : PARAM */
1.17.2.3! yamt      401:        tmp_disk = TAILQ_FIRST(&diskStructure->boot_images);
1.1       fvdl      402:        default_entry = cd9660_boot_setup_default_entry(tmp_disk);
                    403:        if (default_entry == NULL) {
                    404:                warnx("Error: memory allocation failed in cd9660_setup_boot");
                    405:                return -1;
                    406:        }
1.5       dyoung    407:
1.1       fvdl      408:        LIST_INSERT_AFTER(valid_entry, default_entry, ll_struct);
1.5       dyoung    409:
1.1       fvdl      410:        /* Todo: multiple default entries? */
1.5       dyoung    411:
1.7       dyoung    412:        tmp_disk = TAILQ_NEXT(tmp_disk, image_list);
1.5       dyoung    413:
1.1       fvdl      414:        temp = default_entry;
1.5       dyoung    415:
1.1       fvdl      416:        /* If multiple boot images are given : */
                    417:        while (tmp_disk != NULL) {
                    418:                /* Step 2: Section header */
                    419:                switch (tmp_disk->system) {
                    420:                case ET_SYS_X86:
1.8       dyoung    421:                        headp = &x86_head;
1.1       fvdl      422:                        break;
                    423:                case ET_SYS_PPC:
1.8       dyoung    424:                        headp = &ppc_head;
1.1       fvdl      425:                        break;
                    426:                case ET_SYS_MAC:
1.8       dyoung    427:                        headp = &mac_head;
1.1       fvdl      428:                        break;
1.8       dyoung    429:                default:
                    430:                        warnx("%s: internal error: unknown system type",
                    431:                            __func__);
                    432:                        return -1;
1.1       fvdl      433:                }
                    434:
1.8       dyoung    435:                if (*headp == NULL) {
                    436:                        head =
1.5       dyoung    437:                            cd9660_boot_setup_section_head(tmp_disk->system);
1.8       dyoung    438:                        if (head == NULL) {
1.1       fvdl      439:                                warnx("Error: memory allocation failed in "
                    440:                                      "cd9660_setup_boot");
                    441:                                return -1;
                    442:                        }
1.8       dyoung    443:                        LIST_INSERT_AFTER(default_entry, head, ll_struct);
                    444:                        *headp = head;
                    445:                } else
                    446:                        head = *headp;
                    447:
                    448:                head->entry_data.SH.num_section_entries[0]++;
1.5       dyoung    449:
1.1       fvdl      450:                /* Step 2a: Section entry and extensions */
                    451:                temp = cd9660_boot_setup_section_entry(tmp_disk);
                    452:                if (temp == NULL) {
1.8       dyoung    453:                        warn("%s: cd9660_boot_setup_section_entry", __func__);
1.1       fvdl      454:                        return -1;
                    455:                }
                    456:
1.8       dyoung    457:                while ((next = LIST_NEXT(head, ll_struct)) != NULL &&
1.3       dyoung    458:                       next->entry_type == ET_ENTRY_SE)
1.8       dyoung    459:                        head = next;
1.5       dyoung    460:
1.8       dyoung    461:                LIST_INSERT_AFTER(head, temp, ll_struct);
1.7       dyoung    462:                tmp_disk = TAILQ_NEXT(tmp_disk, image_list);
1.1       fvdl      463:        }
1.5       dyoung    464:
1.1       fvdl      465:        /* TODO: Remaining boot disks when implemented */
1.5       dyoung    466:
1.1       fvdl      467:        return first_sector + used_sectors;
                    468: }
                    469:
                    470: int
1.17.2.3! yamt      471: cd9660_setup_boot_volume_descriptor(iso9660_disk *diskStructure,
        !           472:     volume_descriptor *bvd)
1.1       fvdl      473: {
                    474:        boot_volume_descriptor *bvdData =
                    475:            (boot_volume_descriptor*)bvd->volumeDescriptorData;
                    476:
                    477:        bvdData->boot_record_indicator[0] = ISO_VOLUME_DESCRIPTOR_BOOT;
                    478:        memcpy(bvdData->identifier, ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5);
                    479:        bvdData->version[0] = 1;
                    480:        memcpy(bvdData->boot_system_identifier, ET_ID, 23);
                    481:        memcpy(bvdData->identifier, ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5);
1.17.2.3! yamt      482:        diskStructure->boot_descriptor =
1.1       fvdl      483:            (boot_volume_descriptor*) bvd->volumeDescriptorData;
                    484:        return 1;
                    485: }
                    486:
1.15      christos  487: static int
                    488: cd9660_write_mbr_partition_entry(FILE *fd, int idx, off_t sector_start,
                    489:     off_t nsectors, int type)
                    490: {
                    491:        uint8_t val;
                    492:        uint32_t lba;
                    493:
                    494:        if (fseeko(fd, (off_t)(idx) * 16 + 0x1be, SEEK_SET) == -1)
                    495:                err(1, "fseeko");
                    496:
                    497:        val = 0x80; /* Bootable */
                    498:        fwrite(&val, sizeof(val), 1, fd);
                    499:
                    500:        val = 0xff; /* CHS begin */
                    501:        fwrite(&val, sizeof(val), 1, fd);
                    502:        fwrite(&val, sizeof(val), 1, fd);
                    503:        fwrite(&val, sizeof(val), 1, fd);
                    504:
                    505:        val = type; /* Part type */
                    506:        fwrite(&val, sizeof(val), 1, fd);
                    507:
                    508:        val = 0xff; /* CHS end */
                    509:        fwrite(&val, sizeof(val), 1, fd);
                    510:        fwrite(&val, sizeof(val), 1, fd);
                    511:        fwrite(&val, sizeof(val), 1, fd);
                    512:
                    513:        /* LBA extent */
                    514:        lba = htole32(sector_start);
                    515:        fwrite(&lba, sizeof(lba), 1, fd);
                    516:        lba = htole32(nsectors);
                    517:        fwrite(&lba, sizeof(lba), 1, fd);
                    518:
                    519:        return 0;
                    520: }
                    521:
                    522: static int
                    523: cd9660_write_apm_partition_entry(FILE *fd, int idx, int total_partitions,
                    524:     off_t sector_start, off_t nsectors, off_t sector_size,
                    525:     const char *part_name, const char *part_type)
                    526: {
1.17.2.1  yamt      527:        uint32_t apm32, part_status;
1.15      christos  528:        uint16_t apm16;
                    529:
1.17.2.1  yamt      530:        /* See Apple Tech Note 1189 for the details about the pmPartStatus
                    531:         * flags.
                    532:         * Below the flags which are default:
                    533:         * - IsValid     0x01
                    534:         * - IsAllocated 0x02
                    535:         * - IsReadable  0x10
                    536:         * - IsWritable  0x20
                    537:         */
                    538:        part_status = APPLE_PS_VALID | APPLE_PS_ALLOCATED | APPLE_PS_READABLE |
                    539:            APPLE_PS_WRITABLE;
                    540:
1.15      christos  541:        if (fseeko(fd, (off_t)(idx + 1) * sector_size, SEEK_SET) == -1)
                    542:                err(1, "fseeko");
                    543:
                    544:        /* Signature */
                    545:        apm16 = htobe16(0x504d);
                    546:        fwrite(&apm16, sizeof(apm16), 1, fd);
                    547:        apm16 = 0;
                    548:        fwrite(&apm16, sizeof(apm16), 1, fd);
                    549:
                    550:        /* Total number of partitions */
                    551:        apm32 = htobe32(total_partitions);
                    552:        fwrite(&apm32, sizeof(apm32), 1, fd);
                    553:        /* Bounds */
                    554:        apm32 = htobe32(sector_start);
                    555:        fwrite(&apm32, sizeof(apm32), 1, fd);
                    556:        apm32 = htobe32(nsectors);
                    557:        fwrite(&apm32, sizeof(apm32), 1, fd);
                    558:
                    559:        fwrite(part_name, strlen(part_name) + 1, 1, fd);
                    560:        fseek(fd, 32 - strlen(part_name) - 1, SEEK_CUR);
                    561:        fwrite(part_type, strlen(part_type) + 1, 1, fd);
1.17.2.1  yamt      562:        fseek(fd, 32 - strlen(part_type) - 1, SEEK_CUR);
                    563:
                    564:        apm32 = 0;
                    565:        /* pmLgDataStart */
                    566:        fwrite(&apm32, sizeof(apm32), 1, fd);
                    567:        /* pmDataCnt */
                    568:        apm32 = htobe32(nsectors);
                    569:        fwrite(&apm32, sizeof(apm32), 1, fd);
                    570:        /* pmPartStatus */
                    571:        apm32 = htobe32(part_status);
                    572:        fwrite(&apm32, sizeof(apm32), 1, fd);
1.15      christos  573:
                    574:        return 0;
                    575: }
                    576:
1.5       dyoung    577: int
1.17.2.3! yamt      578: cd9660_write_boot(iso9660_disk *diskStructure, FILE *fd)
1.1       fvdl      579: {
                    580:        struct boot_catalog_entry *e;
                    581:        struct cd9660_boot_image *t;
1.15      christos  582:        int apm_partitions = 0;
                    583:        int mbr_partitions = 0;
1.1       fvdl      584:
                    585:        /* write boot catalog */
1.17.2.3! yamt      586:        if (fseeko(fd, (off_t)diskStructure->boot_catalog_sector *
        !           587:            diskStructure->sectorSize, SEEK_SET) == -1)
1.13      christos  588:                err(1, "fseeko");
1.5       dyoung    589:
1.17.2.3! yamt      590:        if (diskStructure->verbose_level > 0) {
1.14      christos  591:                printf("Writing boot catalog to sector %" PRId64 "\n",
1.17.2.3! yamt      592:                    diskStructure->boot_catalog_sector);
1.9       dyoung    593:        }
1.17.2.3! yamt      594:        LIST_FOREACH(e, &diskStructure->boot_entries, ll_struct) {
        !           595:                if (diskStructure->verbose_level > 0) {
1.9       dyoung    596:                        printf("Writing catalog entry of type %d\n",
                    597:                            e->entry_type);
                    598:                }
1.1       fvdl      599:                /*
                    600:                 * It doesnt matter which one gets written
                    601:                 * since they are the same size
                    602:                 */
                    603:                fwrite(&(e->entry_data.VE), 1, 32, fd);
                    604:        }
1.17.2.3! yamt      605:        if (diskStructure->verbose_level > 0)
1.10      dyoung    606:                printf("Finished writing boot catalog\n");
1.5       dyoung    607:
1.1       fvdl      608:        /* copy boot images */
1.17.2.3! yamt      609:        TAILQ_FOREACH(t, &diskStructure->boot_images, image_list) {
        !           610:                if (diskStructure->verbose_level > 0) {
1.9       dyoung    611:                        printf("Writing boot image from %s to sectors %d\n",
                    612:                            t->filename, t->sector);
                    613:                }
1.17.2.3! yamt      614:                cd9660_copy_file(diskStructure, fd, t->sector, t->filename);
1.15      christos  615:
                    616:                if (t->system == ET_SYS_MAC)
                    617:                        apm_partitions++;
                    618:                if (t->system == ET_SYS_PPC)
                    619:                        mbr_partitions++;
                    620:        }
                    621:
                    622:        /* some systems need partition tables as well */
1.17.2.3! yamt      623:        if (mbr_partitions > 0 || diskStructure->chrp_boot) {
1.15      christos  624:                uint16_t sig;
                    625:
                    626:                fseek(fd, 0x1fe, SEEK_SET);
                    627:                sig = htole16(0xaa55);
                    628:                fwrite(&sig, sizeof(sig), 1, fd);
                    629:
                    630:                mbr_partitions = 0;
                    631:
                    632:                /* Write ISO9660 descriptor, enclosing the whole disk */
1.17.2.3! yamt      633:                if (diskStructure->chrp_boot)
1.15      christos  634:                        cd9660_write_mbr_partition_entry(fd, mbr_partitions++,
1.17.2.3! yamt      635:                            0, diskStructure->totalSectors *
        !           636:                            (diskStructure->sectorSize / 512), 0x96);
1.15      christos  637:
                    638:                /* Write all partition entries */
1.17.2.3! yamt      639:                TAILQ_FOREACH(t, &diskStructure->boot_images, image_list) {
1.15      christos  640:                        if (t->system != ET_SYS_PPC)
                    641:                                continue;
                    642:                        cd9660_write_mbr_partition_entry(fd, mbr_partitions++,
1.17.2.3! yamt      643:                            t->sector * (diskStructure->sectorSize / 512),
        !           644:                            t->num_sectors * (diskStructure->sectorSize / 512),
1.15      christos  645:                            0x41 /* PReP Boot */);
                    646:                }
                    647:        }
                    648:
                    649:        if (apm_partitions > 0) {
                    650:                /* Write DDR and global APM info */
                    651:                uint32_t apm32;
                    652:                uint16_t apm16;
                    653:                int total_parts;
                    654:
                    655:                fseek(fd, 0, SEEK_SET);
                    656:                apm16 = htobe16(0x4552);
                    657:                fwrite(&apm16, sizeof(apm16), 1, fd);
                    658:                /* Device block size */
                    659:                apm16 = htobe16(512);
                    660:                fwrite(&apm16, sizeof(apm16), 1, fd);
                    661:                /* Device block count */
1.17.2.3! yamt      662:                apm32 = htobe32(diskStructure->totalSectors *
        !           663:                    (diskStructure->sectorSize / 512));
1.15      christos  664:                fwrite(&apm32, sizeof(apm32), 1, fd);
                    665:                /* Device type/id */
                    666:                apm16 = htobe16(1);
                    667:                fwrite(&apm16, sizeof(apm16), 1, fd);
                    668:                fwrite(&apm16, sizeof(apm16), 1, fd);
                    669:
                    670:                /* Count total needed entries */
                    671:                total_parts = 2 + apm_partitions; /* Self + ISO9660 */
                    672:
                    673:                /* Write self-descriptor */
                    674:                cd9660_write_apm_partition_entry(fd, 0, total_parts, 1,
                    675:                    total_parts, 512, "Apple", "Apple_partition_map");
                    676:
                    677:                /* Write all partition entries */
                    678:                apm_partitions = 0;
1.17.2.3! yamt      679:                TAILQ_FOREACH(t, &diskStructure->boot_images, image_list) {
1.15      christos  680:                        if (t->system != ET_SYS_MAC)
                    681:                                continue;
                    682:
                    683:                        cd9660_write_apm_partition_entry(fd,
1.17.2.1  yamt      684:                            1 + apm_partitions++, total_parts,
1.17.2.3! yamt      685:                            t->sector * (diskStructure->sectorSize / 512),
        !           686:                            t->num_sectors * (diskStructure->sectorSize / 512),
1.15      christos  687:                            512, "CD Boot", "Apple_Bootstrap");
                    688:                }
1.17.2.1  yamt      689:
                    690:                /* Write ISO9660 descriptor, enclosing the whole disk */
                    691:                cd9660_write_apm_partition_entry(fd, 2 + apm_partitions,
1.17.2.3! yamt      692:                    total_parts, 0, diskStructure->totalSectors *
        !           693:                    (diskStructure->sectorSize / 512), 512, "ISO9660",
1.17.2.1  yamt      694:                    "CD_ROM_Mode_1");
1.1       fvdl      695:        }
                    696:
                    697:        return 0;
                    698: }

CVSweb <webmaster@jp.NetBSD.org>