Home | History | Annotate | Line # | Download | only in installboot
      1 /*	$NetBSD: installboot.c,v 1.9 2024/09/15 03:56:57 tsutsui Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2005 Izumi Tsutsui.  All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #if HAVE_NBTOOL_CONFIG_H
     28 #include "nbtool_config.h"
     29 #endif
     30 
     31 #include <err.h>
     32 #include <fcntl.h>
     33 #include <stdio.h>
     34 #include <stdlib.h>
     35 #include <string.h>
     36 #include <unistd.h>
     37 #include <sys/stat.h>
     38 #include <sys/types.h>
     39 
     40 #include "installboot.h"
     41 
     42 #define BSIZE		512
     43 #define MAX_SB_SIZE	(64 * 1024)	/* XXX */
     44 #define roundup(x, y)	((((x)+((y)-1))/(y))*(y))
     45 
     46 static	void usage(void);
     47 
     48 static	ib_params	installboot_params;
     49 
     50 static	struct ib_fs cd9660_fstype = {
     51 	.name = "cd9660",
     52 	.match = cd9660_match,
     53 	.findstage2 = cd9660_findstage2
     54 };
     55 
     56 int
     57 main(int argc, char **argv)
     58 {
     59 	ib_params *params;
     60 	uint8_t *bb;
     61 	struct apple_part_map_entry pme;
     62 	size_t bbi;
     63 	struct shared_bbinfo *bbinfop;
     64 	off_t partoff;
     65 	uint32_t nblk, maxblk, blk_i;
     66 	int rv;
     67 	ib_block *blocks;
     68 	uint64_t block;
     69 
     70 	setprogname(argv[0]);
     71 	params = &installboot_params;
     72 	memset(params, 0, sizeof(*params));
     73 	params->fsfd = -1;
     74 	params->s1fd = -1;
     75 
     76 	if (argc != 4)
     77 		usage();
     78 
     79 	params->filesystem = argv[1];
     80 	params->fstype = &cd9660_fstype;
     81 
     82 	if ((params->fsfd = open(params->filesystem, O_RDWR, 0600)) == -1)
     83 		err(1, "Opening file system `%s' read", params->filesystem);
     84 	if (fstat(params->fsfd, &params->fsstat) == -1)
     85 		err(1, "Examining file system `%s'", params->filesystem);
     86 	if (!params->fstype->match(params))
     87 		errx(1, "File system `%s' is not of type %s",
     88 		    params->filesystem, params->fstype->name);
     89 
     90 #ifdef DEBUG
     91 	printf("file system: %s, %ld bytes\n",
     92 	    params->filesystem, (long)params->fsstat.st_size);
     93 #endif
     94 
     95 	/*
     96 	 * Find space for primary boot from the second (NetBSD_BootBlock)
     97 	 * partition.
     98 	 */
     99 	if (pread(params->fsfd, &pme, sizeof pme, BSIZE * 2) != sizeof(pme))
    100 		err(1, "read pme from file system `%s'", params->filesystem);
    101 
    102 	if (strcmp((char *)pme.pmPartName, "NetBSD_BootBlock"))
    103 		err(1, "invalid partition map in file system `%s'",
    104 		    params->filesystem);
    105 
    106 	/* pmPyPartStart is written by mkisofs */
    107 	partoff = BSIZE * be32toh(pme.pmPyPartStart);
    108 
    109 #ifdef DEBUG
    110 	printf("NetBSD partition offset = %ld\n", (long)partoff);
    111 #endif
    112 
    113 	params->stage1 = argv[2];
    114 
    115 	if ((params->s1fd = open(params->stage1, O_RDONLY, 0600)) == -1)
    116 		err(1, "Opening primary bootstrap `%s'", params->stage1);
    117 	if (fstat(params->s1fd, &params->s1stat) == -1)
    118 		err(1, "Examining primary bootstrap `%s'", params->stage1);
    119 	if (!S_ISREG(params->s1stat.st_mode))
    120 		err(1, "`%s' must be a regular file", params->stage1);
    121 
    122 	if (params->s1stat.st_size > MACPPC_BOOT_BLOCK_MAX_SIZE)
    123 		err(1, "primary bootrap `%s' too large (%ld bytes)",
    124 		    params->stage1, (long)params->s1stat.st_size);
    125 
    126 #ifdef DEBUG
    127 	printf("primary boot: %s, %ld bytes\n",
    128 	    params->stage1, (long)params->s1stat.st_size);
    129 #endif
    130 
    131 	params->stage2 = argv[3];
    132 
    133 	bb = calloc(1, MACPPC_BOOT_BLOCK_MAX_SIZE);
    134 	if (bb == NULL)
    135 		err(1, "Allocating %ul bytes for bbinfo",
    136 		    MACPPC_BOOT_BLOCK_MAX_SIZE);
    137 
    138 	rv = read(params->s1fd, bb, params->s1stat.st_size);
    139 
    140 	if (rv == -1)
    141 		err(1, "Reading `%s'", params->stage1);
    142 
    143 	if (memcmp(bb + 1, "ELF", strlen("ELF")) == 0) {
    144 		warnx("`%s' is an ELF executable; need raw binary",
    145 		    params->stage1);
    146 	}
    147 
    148 	/* look for the bbinfo structure */
    149 	for (bbi = 0; bbi < MACPPC_BOOT_BLOCK_MAX_SIZE;
    150 	    bbi += sizeof(uint32_t)) {
    151 		bbinfop = (void *)(bb + bbi);
    152 		if (memcmp(bbinfop->bbi_magic, MACPPC_BBINFO_MAGIC,
    153 		    sizeof(bbinfop->bbi_magic)) == 0) {
    154 #ifdef DEBUG
    155 			printf("magic found: %s\n", bbinfop->bbi_magic);
    156 #endif
    157 			break;
    158 		}
    159 	}
    160 	if (bbi >= MACPPC_BOOT_BLOCK_MAX_SIZE)
    161 		err(1, "bbinfo structure not found in `%s'", params->stage1);
    162 
    163 	maxblk = be32toh(bbinfop->bbi_block_count);
    164 	if (maxblk == 0 ||
    165 	    maxblk > (MACPPC_BOOT_BLOCK_MAX_SIZE / sizeof(uint32_t)))
    166 		err(1, "bbinfo structure in `%s' has preposterous size `%u'",
    167 		    params->stage1, maxblk);
    168 
    169 	blocks = malloc(sizeof(*blocks) * maxblk);
    170 	if (blocks == NULL) {
    171 		err(1, "Allocating %lu bytes for blocks",
    172 		    (unsigned long)sizeof(*blocks) * maxblk);
    173 	}
    174 
    175 	if (S_ISREG(params->fsstat.st_mode)) {
    176 		if (fsync(params->fsfd) == -1)
    177 			err(1, "Synchronising file system `%s'",
    178 			    params->filesystem);
    179 	}
    180 
    181 	nblk = maxblk;
    182 	if (!params->fstype->findstage2(params, &nblk, blocks)) {
    183 		exit(1);
    184 	}
    185 
    186 	bbinfop->bbi_block_count = htobe32(nblk);
    187 	bbinfop->bbi_block_size = htobe32(blocks[0].blocksize);
    188 	for (blk_i = 0; blk_i < nblk; blk_i++) {
    189 		/* XXX bootxx assumes blocksize is 512 */
    190 		block = blocks[blk_i].block * (params->fstype->blocksize / 512);
    191 		bbinfop->bbi_block_table[blk_i] = htobe32(block);
    192 		if (blocks[blk_i].blocksize < blocks[0].blocksize &&
    193 		    blk_i + 1 != nblk) {
    194 			warnx("Secondary bootstrap `%s' blocks do not have "
    195 			    "a uniform size", params->stage2);
    196 			exit(1);
    197 		}
    198 	}
    199 
    200 	/* XXX no write option */
    201 
    202 	if (pwrite(params->fsfd, bb, MACPPC_BOOT_BLOCK_MAX_SIZE, partoff) !=
    203 	    MACPPC_BOOT_BLOCK_MAX_SIZE)
    204 		err(1, "write bootblock");
    205 
    206 	if (S_ISREG(params->fsstat.st_mode)) {
    207 		if (fsync(params->fsfd) == -1)
    208 			err(1, "Synchronising file system `%s'",
    209 			    params->filesystem);
    210 	}
    211 
    212 	free(bb);
    213 
    214 	if (close(params->fsfd) == -1)
    215 		err(1, "Closing file system `%s'", params->filesystem);
    216 	if (close(params->s1fd) == -1)
    217 		err(1, "Closing primary bootstrap `%s'", params->stage1);
    218 
    219 	return 0;
    220 }
    221 
    222 static void
    223 usage(void)
    224 {
    225 	const char *prog;
    226 
    227 	prog = getprogname();
    228 	fprintf(stderr, "usage: %s hybrid-cd-image primary secondary\n", prog);
    229 	exit(1);
    230 }
    231