259 lines
6.8 KiB
C
259 lines
6.8 KiB
C
/* $NetBSD: mksunbootcd.c,v 1.6 2000/11/29 19:47:31 tv Exp $ */
|
|
|
|
/*-
|
|
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
* by Ignatios Souvatzis.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by the NetBSD
|
|
* Foundation, Inc. and its contributors.
|
|
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
/*
|
|
* add bootable Sun partitions to a CD-ROM image
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/mman.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include <dev/sun/disklabel.h>
|
|
|
|
#include <err.h>
|
|
#include <fcntl.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
/*
|
|
* How we work:
|
|
*
|
|
* a) get length of cd image
|
|
* b) if there is already a disk image, complain (later: allow to add or
|
|
* overwrite old ufs images)
|
|
* c) get length of miniroots
|
|
* d) round all the lengthes to some convenient size, set that as cylinder
|
|
* size. (Sun uses 640 sector (320 k) cylinders)
|
|
* e) create label
|
|
* f) seek to start of cd image
|
|
* g) write label
|
|
* h) foreach ufs image
|
|
* h1) seek to its start
|
|
* h2) copy it it over
|
|
*/
|
|
|
|
void usage __P((void));
|
|
int main __P((int, char *[]));
|
|
|
|
#define Dprintf(x) if (debug) printf x
|
|
#define Vprintf(x) if (verbose) printf x
|
|
|
|
int
|
|
main(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
extern char *optarg;
|
|
extern int optind;
|
|
extern int optopt;
|
|
extern int opterr;
|
|
extern int optreset;
|
|
|
|
struct sun_disklabel sdl;
|
|
int ch, debug, verbose;
|
|
int cylsz;
|
|
u_short *sp, sum;
|
|
int pfd[8], npart; /* cd filesystem descriptor; partition */
|
|
#define cdfd pfd[0] /* fs descriptors & info */
|
|
int psz[8], totalsz;
|
|
int pstart[8];
|
|
struct stat sbs[8];
|
|
char buf[8192];
|
|
int i, j, nothing, rc, rc2;
|
|
|
|
/* code starts here */
|
|
verbose = debug = 0;
|
|
cylsz = 640; /* in 512-sector units */
|
|
|
|
while ((ch = getopt(argc, argv, "vdc:")) != -1)
|
|
switch(ch) {
|
|
case 'c':
|
|
cylsz = atoi(optarg);
|
|
if (cylsz % 4)
|
|
errx(1, "cylinder size must be multiple of 4");
|
|
break;
|
|
case 'd':
|
|
debug = 1;
|
|
break;
|
|
case 'v':
|
|
verbose = 1;
|
|
break;
|
|
case '?':
|
|
default:
|
|
usage();
|
|
}
|
|
|
|
argc -= optind;
|
|
argv += optind;
|
|
|
|
npart = argc;
|
|
if (npart < 1)
|
|
usage();
|
|
|
|
if (npart > 8)
|
|
npart = 8;
|
|
|
|
Vprintf(("%d partitions.\n", npart ));
|
|
for (i = 0; i < npart; i++) {
|
|
pfd[i] = open(argv[i], i ? O_RDONLY : O_RDWR, 0666);
|
|
if (pfd[i] == -1)
|
|
err(2, argv[i]);
|
|
|
|
rc = fstat(pfd[i], &sbs[i]);
|
|
if (rc)
|
|
err(2, "can't get %s status", argv[i]);
|
|
|
|
Dprintf(("%-30s: size %10d", argv[i], (int)sbs[i].st_size));
|
|
|
|
psz[i] = (sbs[i].st_size + 512 * cylsz - 1) / (512 * cylsz);
|
|
psz[i] *= cylsz;
|
|
|
|
Dprintf((" rounded to %5ds\n", psz[i]));
|
|
}
|
|
|
|
pstart[0] = 0;
|
|
Dprintf(("\n%-30s: start %10dc\n", argv[0], pstart[0]));
|
|
|
|
for (i = 1; i < npart; i++) {
|
|
for (nothing = 1, j = 1; j < i; j++) {
|
|
if (sbs[i].st_ino == sbs[j].st_ino &&
|
|
sbs[i].st_dev == sbs[j].st_dev) { /* same as me */
|
|
pstart[i] = pstart[j];
|
|
nothing = 0;
|
|
break;
|
|
}
|
|
}
|
|
if (nothing)
|
|
pstart[i] = pstart[i-1] + psz[i-1] / cylsz;
|
|
Dprintf(("%-30s: start %10dc\n", argv[i], pstart[i]));
|
|
}
|
|
totalsz = pstart[npart-1] + psz[npart-1] / cylsz;
|
|
|
|
/* initialize label template */
|
|
(void)memset(&sdl, 0, sizeof(sdl));
|
|
|
|
if (read(pfd[0], &sdl, sizeof(sdl)) < 0)
|
|
err(2, "reading block 0 of CD image");
|
|
|
|
/* clear sun boot info segment */
|
|
(void)memset(((char *)&sdl) + offsetof(struct sun_disklabel, sl_rpm),
|
|
0, sizeof(sdl) - offsetof(struct sun_disklabel, sl_rpm));
|
|
|
|
sdl.sl_magic = htons(SUN_DKMAGIC);
|
|
sdl.sl_rpm = htons(300);
|
|
sdl.sl_nsectors = htons(cylsz);
|
|
sdl.sl_ntracks = htons(1);
|
|
sdl.sl_pcylinders = sdl.sl_ncylinders = htons(totalsz);
|
|
sdl.sl_acylinders = htons(0);
|
|
sdl.sl_sparespercyl = htons(0);
|
|
sdl.sl_interleave = htons(0);
|
|
|
|
for (i = 0; i < npart; i++) {
|
|
sdl.sl_part[i].sdkp_cyloffset = htonl(pstart[i]);
|
|
sdl.sl_part[i].sdkp_nsectors = htonl(psz[i]);
|
|
}
|
|
|
|
/* insert geometry */
|
|
|
|
/* insert partition info */
|
|
/* compute checksum */
|
|
sp = (u_short *)&sdl;
|
|
sum = 0;
|
|
while (sp < (u_short *)((&sdl)+1) - 1) {
|
|
sum ^= *sp++; /* XXX no need to ntohs/htons for XOR */
|
|
}
|
|
sdl.sl_cksum = sum;
|
|
Dprintf(("label size is %lu\n", (long)sizeof(sdl)));
|
|
Dprintf(("cksum computed is 0x%04x\n", ntohs(sum)));
|
|
|
|
/* copy partition data to cd image */
|
|
for (i = 1; i < npart; i++) {
|
|
rc = lseek(pfd[0],
|
|
(off_t)pstart[i] * (off_t)cylsz * (off_t)512, SEEK_SET);
|
|
|
|
if (rc < 0)
|
|
err(2, "positioning cd image");
|
|
|
|
while ((rc = read(pfd[i], buf, sizeof(buf))) > 0) {
|
|
rc2 = write(pfd[0], buf, rc);
|
|
if (rc2 < 0)
|
|
err(2, "writing");
|
|
if (rc2 < rc)
|
|
errx(2, "short write (partition data)");
|
|
}
|
|
|
|
if (rc < 0)
|
|
err(2, "reading");
|
|
}
|
|
|
|
/* ensure even size in case we rounded the partition size earlier */
|
|
rc = ftruncate(pfd[0], (off_t) cylsz * (off_t)totalsz * (off_t)512);
|
|
if (rc < 0)
|
|
err(2, "truncating cd image");
|
|
|
|
/*
|
|
* Write label now. Partition data isn't valid before the partitions
|
|
* are written!
|
|
*/
|
|
|
|
rc = lseek(pfd[0], 0, SEEK_SET);
|
|
if (rc)
|
|
err(2, "rewinding cd image");
|
|
|
|
rc = write(pfd[0], (void *)&sdl, sizeof(sdl));
|
|
if (rc < 0)
|
|
err(2, "writing label");
|
|
|
|
if (rc < sizeof(sdl))
|
|
errx(2, "short write on label write");
|
|
|
|
exit(0);
|
|
}
|
|
|
|
void
|
|
usage()
|
|
{
|
|
|
|
errx(1, "Usage: mksunbootcd [-v] [-c cylsize] cdimage part1 part2...");
|
|
}
|