blob: 4c41dfdf799192455e79ef571f71f2885506a90e [file] [log] [blame]
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) Hewlett-Packard (Paul Bame) paul_bame@hp.com
*/
#if !(defined hpux || defined __hpux)
# define LONG_OPTIONS 1
#endif
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <assert.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
#if LONG_OPTIONS
# define _GNU_SOURCE
# include <getopt.h>
#endif
#include "load.h"
#include "palo.h"
#define B32(x) __be32_to_cpu((x))
/* maximum allowed HP boot loader (IPL) size */
#define MAXBLSIZE (256 * 1024)
static int Install = 0;
int verbose = 0;
int disk_2gb_limit = 0;
/* compute the sum of words in an 4-byte aligned region */
int
checksum(void *p, size_t len)
{
int xsum = 0;
int *x = (int *)p;
int i;
if (verbose) printf("checksum(%p, %u) = ", p, len);
len /= 4;
for (i = 0; i < len; i++)
{
xsum += B32(x[i]);
}
if (verbose) printf("0x%08x\n", xsum);
return (xsum);
}
static void
fb_init(struct firstblock *f)
{
f->lifmagic0 = 0x80;
f->lifmagic1 = 0x00;
f->rd_sz = f->kern32_sz = f->kern64_sz = 0;
f->kern32_native_sz = f->kern64_native_sz = 0;
f->rd_offset = f->kern32_offset = f->kern64_offset = 0;
strcpy(f->palomagic, PALOMAGIC);
f->version = PALOHDRVERSION;
f->flags = 0;
if (Install)
f->flags |= PFLAG_INSTALL;
}
int
check_bootloader(int media, int line)
{
struct firstblock f;
int ipl_words;
int xsum;
unsigned int *ipl;
if (verbose) printf("check_bootloader %d\n", line);
STRUCTREAD(media, f, 0);
if (f.lifmagic0 != 0x80 || f.lifmagic1 != 0x00)
{
fprintf(stderr, "0x%x 0x%x\n", f.lifmagic0, f.lifmagic1);
error(6, "LIF header");
}
if (B32(f.ipl_addr) < 2048 ||
(B32(f.ipl_addr) % 2048) != 0)
error(6, "ipl_addr");
if (B32(f.ipl_size) <= 0 ||
B32(f.ipl_size) >= MAXBLSIZE ||
(B32(f.ipl_size) % 2048) != 0)
error(6, "ipl_size");
if (B32(f.ipl_entry) >= B32(f.ipl_size) ||
B32(f.ipl_entry) < 0 ||
(B32(f.ipl_entry) % 4) != 0)
error(6, "ipl_entry");
ipl_words = B32(f.ipl_size) / sizeof ipl[0];
/* seekread the IPL */
ipl = calloc(ipl_words, sizeof ipl[0]);
/* would be a good idea to check this call? */
if (seekread(media, (char *)ipl, B32(f.ipl_size), B32(f.ipl_addr)) == -1)
error(6, "read failed");
/* calculate xsum */
xsum = checksum(ipl, B32(f.ipl_size));
if (xsum != 0)
{
fprintf(stderr, "calculated xsum 0x%x got 0x%x\n",
-xsum, ipl[ipl_words - 1]);
xsum -= B32(ipl[ipl_words - 1]);
fprintf(stderr, "calculated xsum 0x%x got 0x%x\n",
-xsum, ipl[ipl_words - 1]);
exit(2);
}
printf("ipl: addr %d size %d entry 0x%x\n",
B32(f.ipl_addr),
B32(f.ipl_size),
B32(f.ipl_entry));
if (strncmp(f.palomagic, PALOMAGIC, 4) != 0)
{
error(6, "bad magic");
}
if (f.version != PALOHDRVERSION)
{
fprintf(stderr, "Warning!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
"Boot loader header version is %d, I only know how\n"
"to handle version %d. It MIGHT work anyway.\n",
f.version, PALOHDRVERSION);
}
#if 1
printf(" ko 0x%x ksz %d knsz %d k64o 0x%x k64sz %d k64nsz %d rdo %d rdsz %d\n<%s>\n",
B32(f.kern32_offset), B32(f.kern32_sz), B32(f.kern32_native_sz),
B32(f.kern64_offset), B32(f.kern64_sz), B32(f.kern64_native_sz),
B32(f.rd_offset), B32(f.rd_sz),
f.cmdline[0] ? f.cmdline : f.cmdline_old);
#endif
return 1;
}
unsigned
write_bootloader(int media, int bootloader,
unsigned where,
unsigned f0end,
struct firstblock *f)
{
size_t rblsize; /* sector-rounded boot loader size */
struct loadable loadable;
int xsum1;
void *blimage;
int r;
int wide;
/* We want prepare_ to fail, otherwise we've been given the output */
/* of the linker instead of mkbootable */
r = prepare_loadable(bootloader, &loadable, &wide);
if (r)
error(12);
/* make sure max size boot loader would fit */
if (where + MAXBLSIZE > f0end) {
printf("where %d, where+MAX=%d f0end=%d\n",
where, where + MAXBLSIZE, f0end);
error(9);
}
/* load the boot loader into RAM */
rblsize = fsize(bootloader);
assert((rblsize % FW_BLOCKSIZE) == 0);
blimage = (void *)calloc(1, rblsize);
assert(blimage != NULL);
if ((r = seekread(bootloader, blimage, rblsize, 0)) != rblsize)
error(13);
/* Is it really a boot loader? */
#define BLWORD1 0xe8000032 /* palo 2.00 and above */
if (BLWORD1 != __be32_to_cpu(*(unsigned *)blimage))
{
fprintf(stderr, "ERROR: first word of boot loader was 0x%08x,"
" expected 0x%08x\n", __be32_to_cpu(*(unsigned *)blimage),
BLWORD1);
exit(2);
}
/* write it out */
seekwrite(media, blimage, rblsize, where);
close(bootloader);
f->ipl_addr = __cpu_to_be32(where);
f->ipl_size = __cpu_to_be32(rblsize);
/* entry point relative to where IPL is loaded in RAM by firmware */
f->ipl_entry = __cpu_to_be32(loadable.entry - loadable.first);
STRUCTWRITE(media, *f, 0);
check_bootloader(media, __LINE__);
free(blimage);
return where + rblsize;
}
unsigned
write_kernel32(int media, int kernel, unsigned where, unsigned end,
struct firstblock *f, int native_size)
{
/* always allow max size boot loader */
f->kern32_offset = __cpu_to_be32(where);
f->kern32_sz = __cpu_to_be32(fsize(kernel));
f->kern32_native_sz = __cpu_to_be32(native_size);
if (B32(f->kern32_sz) + where >= end)
error(14, "32-bit-kernel");
lseek(media, where, SEEK_SET);
return where + cat(media, kernel);
}
unsigned
write_kernel64(int media, int kernel, unsigned where, unsigned end,
struct firstblock *f, int native_size)
{
/* always allow max size boot loader */
f->kern64_offset = __cpu_to_be32(where);
f->kern64_sz = __cpu_to_be32(fsize(kernel));
f->kern64_native_sz = __cpu_to_be32(native_size);
if (B32(f->kern64_sz) + where >= end)
error(14, "64-bit-kernel");
lseek(media, where, SEEK_SET);
return where + cat(media, kernel);
}
unsigned
write_ramdisk(int media, int rd, unsigned where, unsigned end,
struct firstblock *f)
{
/* always allow max size boot loader */
f->rd_offset = __cpu_to_be32(where);
f->rd_sz = __cpu_to_be32(fsize(rd));
if (B32(f->rd_sz) + where >= end)
error(14, "ramdisk");
lseek(media, where, SEEK_SET);
where += cat(media, rd);
return where;
}
/* assumes the previous contents of the file are to be overwritten, */
/* that kernel and bootloader are valid file pointers, and that */
/* commandline will fit given size in fixed_pm. */
void
do_sequential(int media, int kernel32, int kernel64,
const char *commandline, int bootloader, int ramdisk,
int kern32_nsz, int kern64_nsz)
{
struct firstblock f;
/* always load IPL at second 2k block on sequential media */
int where = 1 * FW_BLOCKSIZE;
unsigned end = 800 * 1024 * 1024;
/* must have a boot loader for initialization */
assert(bootloader != -1);
assert(kernel32 != -1 || kernel64 != 1);
memset(&f, 0, sizeof f);
fb_init(&f);
/* Update the boot loader, ignore size in this case */
where = write_bootloader(media, bootloader, where, end, &f);
if (kernel32 != -1)
where = write_kernel32(media, kernel32, where, end, &f, kern32_nsz);
/* write some padding to the 2k boundary */
where += write(media, &f, FW_BLOCKSIZE - (where % FW_BLOCKSIZE));
if (kernel64 != -1)
where = write_kernel64(media, kernel64, where, end, &f, kern64_nsz);
/* write some padding to the 2k boundary */
where += write(media, &f, FW_BLOCKSIZE - (where % FW_BLOCKSIZE));
if (ramdisk != -1)
where = write_ramdisk(media, ramdisk, where, end, &f);
/* write some padding to the 2k boundary */
where += write(media, &f, FW_BLOCKSIZE - (where % FW_BLOCKSIZE));
if (commandline != 0)
strncpy(f.cmdline, commandline, sizeof(f.cmdline)-1);
STRUCTWRITE(media, f, 0);
check_bootloader(media, __LINE__);
}
/* look on each 2k boundary for the file 'target' on 'media'. Assumes
* that 'target' is at least 2k in length.
*/
static int
lookfor(int media, int target)
{
char *targetptr;
char *mbuf;
int offset;
int r = -1;
int targetsize = fsize(target);
float mediasize = fsize(media);
targetptr = mmap(0, targetsize, PROT_READ, MAP_SHARED, target, 0);
if ((long) targetptr == -1)
{
perror("mmap(targetptr)");
return -1;
}
mbuf = malloc(targetsize);
assert(mbuf != NULL);
for (offset = 0; 1; offset += 2048)
{
int n;
const int PREVIEW = 512;
n = seekread(media, mbuf, PREVIEW, offset);
if (n < PREVIEW)
break;
if (memcmp(mbuf, targetptr, PREVIEW) == 0)
{
n = seekread(media, mbuf, targetsize, offset);
if (n < targetsize)
break;
if (memcmp(mbuf, targetptr, targetsize) == 0)
{
r = offset;
break;
}
}
}
munmap(targetptr, targetsize);
free(mbuf);
return r;
}
/* Given a writeable ISO9660 CD image containing within its file system
* both the boot loader and kernel specified also on the palo command line,
* write a "sequential" or "F0" type boot header.
*/
void
do_cdrom(int media, int kernel32, int kernel64,
const char *commandline, int bootloader, int ramdisk,
int kern32_nsz, int kern64_nsz)
{
struct firstblock f;
/* always load IPL at second 2k block on sequential media */
int where = 1 * FW_BLOCKSIZE;
unsigned end = 800 * 1024 * 1024;
/* int is safe since CD-ROM is < 2G */
int bootloader_offset;
int kernel32_offset;
int kernel64_offset;
int ramdisk_offset;
/* must have a boot loader and kernel */
assert(bootloader != -1);
assert(kernel32 != -1 || kernel64 != 1);
/* read the first block/sector, which is FW_BLOCKSIZE, which also */
/* conveniently is the CD block size too */
/* STRUCTREAD(media, f, 0); Probably don't need to read it... */
memset(&f, 0, sizeof f);
fb_init(&f);
/* search the ISO image for the boot loader and kernel files */
if ((bootloader_offset = lookfor(media, bootloader)) == -1)
{
error(15, "boot loader");
}
if (kernel32 != -1 && (kernel32_offset = lookfor(media, kernel32)) == -1)
error(15, "32-bit-kernel image");
if (kernel64 != -1 && (kernel64_offset = lookfor(media, kernel64)) == -1)
error(15, "64-bit-kernel image");
if (ramdisk != -1)
{
if ((ramdisk_offset = lookfor(media, ramdisk)) == -1)
error(15, "ramdisk image");
}
/* Overwrite the boot loader because write_bootloader() is easy to use */
write_bootloader(media, bootloader, bootloader_offset, end, &f);
/* Overwrite the kernel because write_kernel() is easy to use */
if (kernel32 != -1)
write_kernel32(media, kernel32, kernel32_offset, end, &f, kern32_nsz);
if (kernel64 != -1)
write_kernel64(media, kernel64, kernel64_offset, end, &f, kern64_nsz);
if (ramdisk != -1)
{
write_ramdisk(media, ramdisk, ramdisk_offset, end, &f);
}
if (commandline != 0)
strncpy(f.cmdline, commandline, sizeof(f.cmdline)-1);
STRUCTWRITE(media, f, 0);
check_bootloader(media, __LINE__);
}
#define KSIZE (2 * 1024 * 1024)
/* Blocksize for the ext2/3 fs in the palo partition */
#define EXT2_BLOCKSIZE 1024
/* size in ext2 blocks of hole for bootloader */
#define EXT2_HOLE ((MAXBLSIZE + 1) / EXT2_BLOCKSIZE)
/* offset in bytes before start of hole, ext2 doesn't allow holes at
* to cover the first four blocks of the filesystem
*
* Note: modern ext2/3 has a resize_inode covering blocks 3-258 so you
* must either always include the -O^resize_inode when creating the
* filesystem or define EXT2_OFFSET to (259*EXT2_BLOCKSIZE)*/
#define EXT2_OFFSET (4*EXT2_BLOCKSIZE)
int
do_at_start(int init, int media, int start,
int bootloaderfd, const char *commandline)
{
struct firstblock f;
STRUCTREAD(media, f, 0);
if (init) {
fb_init(&f);
} else if (f.ipl_addr != start) {
printf("Current IPL start not consistent with disklabel, use -I to reinitialise\n");
error(11);
}
if(commandline)
strncpy(f.cmdline, commandline, sizeof(f.cmdline)-1);
write_bootloader(media, bootloaderfd, start,
start + MAXBLSIZE, &f);
STRUCTWRITE(media, f, 0);
}
int
do_formatted(int init, int media, const char *medianame, int partition,
int f0start, int f0length, int bootloaderfd, int do_format,
const char *commandline)
{
char partitionname[256];
struct firstblock f;
int partitionfd;
/* FIXME: assuming we can simply add the partition to the end
* of the whole disc device isn't always true */
snprintf(partitionname, sizeof(partitionname), "%s%d", medianame,
partition);
if ((partitionfd = open(partitionname, O_RDWR)) < 0) {
perror(partitionname);
exit(1);
}
close(partitionfd);
if (init) {
/* make the bootloader align at 256k */
unsigned int holestart = (f0start + 0x3ffff + EXT2_OFFSET) & ~0x3ffff;
unsigned int partition_offset = holestart - f0start;
char badblockfilename[256];
int fd, i;
char cmd[512];
printf("Initializing %s as ext%d\n", partitionname, do_format);
if (verbose)
printf("f0 partition starts %d, hole %d-%d, end %d\n",
f0start, holestart, holestart + EXT2_HOLE*EXT2_BLOCKSIZE,
f0start + f0length);
if(partition_offset + EXT2_HOLE > f0length)
error(14, "bootloader");
sprintf(badblockfilename, "/tmp/paloblk-%d", getpid());
if ((fd = open(badblockfilename, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) < 0) {
perror(badblockfilename);
exit(1);
}
for (i = (holestart - f0start)/EXT2_BLOCKSIZE;
i < (holestart - f0start)/EXT2_BLOCKSIZE + EXT2_HOLE; i++) {
char buf[128];
int len;
sprintf(buf, "%d\n", i);
len = strlen(buf);
if (len != write(fd, buf, len)) {
perror("Error writing badblock file");
exit(1);
}
}
sprintf(cmd, "mke2fs -t ext%d -O^resize_inode -b %d -l %s %s",
do_format, EXT2_BLOCKSIZE, badblockfilename, partitionname);
if (verbose)
printf("Executing: %s\n", cmd);
else
strcat(cmd, " > /dev/null 2>&1");
i = system(cmd);
unlink(badblockfilename);
if(WEXITSTATUS(i) != 0)
error(19, WEXITSTATUS(i));
STRUCTREAD(media, f, 0);
fb_init(&f);
f.flags |= PFLAG_EXT2;
if(commandline)
strncpy(f.cmdline, commandline, sizeof(f.cmdline)-1);
write_bootloader(media, bootloaderfd, holestart,
holestart + EXT2_HOLE*EXT2_BLOCKSIZE, &f);
STRUCTWRITE(media, f, 0);
} else {
STRUCTREAD(media, f, 0);
if(verbose)
printf("Updating formatted ver=%d, start=%d\n",
f.version, f.ipl_addr);
if ((f.version < 4) || (!f.flags & PFLAG_EXT2)) {
printf("Can not update %s. Please initialize first.\n",
partitionname);
return -1;
}
if(commandline)
strncpy(f.cmdline, commandline, sizeof(f.cmdline)-1);
write_bootloader(media, bootloaderfd, f.ipl_addr,
f.ipl_addr + EXT2_HOLE*EXT2_BLOCKSIZE, &f);
STRUCTWRITE(media, f, 0);
}
return 0;
}
void
do_randomaccess(int init, int media, int kernel32, int kernel64,
const char *commandline, int bootloader, int ramdisk,
unsigned f0start, unsigned f0length, int kern32_nsz, int kern64_nsz)
{
struct firstblock f;
int bstart = 0;
if (verbose) printf("do_ra(%d, %d, %d, %d, '%s', %d, %d, %u, %u)\n",
init, media, kernel32, kernel64, commandline, bootloader, ramdisk, f0start,
f0length);
assert((f0start % 512) == 0);
/* figure out where the boot loader should be */
/* f0start is a sector (512-byte) multiple. IPL must be aligned 2k */
bstart = (f0start + 2047) & ~2047;
if (init)
{
/* initialize a partitioned medium */
unsigned where = bstart;
unsigned end = f0start + f0length;
/* must have a boot loader for initialization */
assert(bootloader != -1);
STRUCTREAD(media, f, 0);
fb_init(&f);
/* Update the boot loader, ignore size in this case */
write_bootloader(media, bootloader, where, end, &f);
where += MAXBLSIZE;
if (kernel32 != -1)
{
unsigned p, ksize;
p = write_kernel32(media, kernel32, where, end, &f, kern32_nsz);
ksize = p - where;
/* allow for bigger kernels */
if (ksize < KSIZE)
ksize = KSIZE;
where = p;
}
if (kernel64 != -1)
{
unsigned p, ksize;
p = write_kernel64(media, kernel64, where, end, &f, kern64_nsz);
ksize = p - where;
/* allow for bigger kernels */
if (ksize < KSIZE)
ksize = KSIZE;
where = p;
}
if (ramdisk != -1)
where = write_ramdisk(media, ramdisk, where, end, &f);
if (commandline != 0)
strncpy(f.cmdline, commandline, sizeof(f.cmdline)-1);
STRUCTWRITE(media, f, 0);
}
else /* update */
{
unsigned end = f0start + f0length;
fprintf(stderr, "palo -U on unformatted (non-ext2) palo partitions doesn't work yet\n"); exit(2);
#if 0
/* make sure we have a good bootloader on there now */
check_bootloader(media, __LINE__);
/* update a partitioned medium */
STRUCTREAD(media, f, 0);
if (bootloader != -1)
{
write_bootloader(media, bootloader, bstart, B32(f.kern_offset), &f);
}
if (kernel != -1)
{
write_kernel(media, kernel, B32(f.kern_offset),
B32(f.rd_offset), &f);
}
if (kernel != -1)
{
write_kernel(media, kernel, B32(f.kern_offset),
B32(f.rd_offset), &f);
}
if (ramdisk != -1)
{
write_ramdisk(media, ramdisk, B32(f.rd_offset), end, &f);
}
if (commandline != 0)
strncpy(f.cmdline, commandline, sizeof(f.cmdline)-1);
STRUCTWRITE(media, f, 0);
#endif
}
check_bootloader(media, __LINE__);
}
#define MAXARGS 200
#if LONG_OPTIONS
static struct option Longopts[] =
{
{"configfile", 1, 0, 'f'},
{"commandline", 1, 0, 'c'},
{"recoverykernel", 1, 0, 'k'},
{"bootloader", 1, 0, 'b'},
{"ramdisk", 1, 0, 'r'},
{"init-partitioned", 1, 0, 'I'},
{"format-as", 1, 0, 'e'},
{"update-partitioned", 1, 0, 'U'},
{"init-tape", 1, 0, 's'},
{"init-cdrom", 1, 0, 'C'},
{"verbose", 0, 0, 'v'},
{"help", 0, 0, '?'},
{"version", 0, 0, 'V'},
{0, 0, 0, 0}
};
# define GETOPT(argc, argv, optstring) \
getopt_long(argc, argv, optstring, Longopts, 0)
#else
# define GETOPT(argc, argv, optstring) getopt(argc, argv, optstring)
#endif
int
main(int argc, char *argv[])
{
int c;
enum {SEQUENTIAL, PARTITIONED, CDROM} mediatype = PARTITIONED;
int bootloader = -1;
int kernel32 = -1;
int kernel64 = -1;
int kern32_nsz = 0, kern64_nsz = 0;
int fd;
struct loadable loadable;
int wide;
char *commandline = 0;
int media = -1;
int ramdisk = -1;
int cdrom = 0;
char *medianame = NULL;
char *bootloaderfile = "/usr/share/palo/iplboot";
int init = 0;
extern const char bld_info[];
const char gargs[] = "f:C:s:b:k:c:r:I:e:U:v?V";
char *config_file = "/etc/palo.conf";
char *newargv[MAXARGS];
int newargc, format_as = 0;
FILE *fconfig;
assert(sizeof (struct firstblock) == 2048);
{
struct firstblock f;
assert((unsigned long)&f.kern32_offset - (unsigned long)&f == 8);
assert((unsigned long)&f.ipl_addr - (unsigned long)&f == 0xf0);
}
fputs("palo " PALOVERSION " - boot media management tool for PA-RISC/HPPA.\n", stdout);
/* do we have a -f? */
while ((c = GETOPT(argc, argv, gargs)) != EOF)
{
switch(c)
{
case 'f':
config_file = optarg;
break;
case '?':
error(0, argv[0]);
break;
case 'V':
fputs("palo version " PALOVERSION "\n", stdout);
puts(bld_info);
return 0;
}
}
newargc = 0;
newargv[newargc++] = argv[0];
/* grab args from the config file */
if ((fconfig = fopen(config_file, "r")) == NULL)
{
fprintf(stderr, "Warning: ");
perror(config_file);
}
else
{
char buf[256];
while(newargc < MAXARGS && fgets(buf, sizeof buf, fconfig) != NULL)
{
char *ptr = buf;
char *end;
/* skip over leading whitespace */
while (isspace(*ptr))
ptr++;
/* skip comment */
if (*ptr == '#')
continue;
/* strip trailing whitespace */
end = ptr + strlen(ptr) - 1;
while (isspace(*end))
end--;
*++end = '\0';
/* skip blank lines */
if (*ptr == '\0')
continue;
newargv[newargc++] = strdup(buf);
}
fclose(fconfig);
}
/* add the original command-line args */
for (c = 1; c < argc && newargc < MAXARGS; c++)
{
newargv[newargc++] = argv[c];
}
/* NULL pointer for good measure */
if (newargc < MAXARGS)
newargv[newargc] = 0;
/* convince getopt to re-start */
optind = 1;
while ((c = GETOPT(newargc, newargv, gargs)) != EOF)
{
switch(c)
{
case 'f':
break;
case 'C':
mediatype = CDROM;
medianame = optarg;
break;
case 'I':
init = 1;
mediatype = PARTITIONED;
medianame = optarg;
break;
case 'U':
init = 0;
mediatype = PARTITIONED;
medianame = optarg;
break;
case 's':
mediatype = SEQUENTIAL;
medianame = optarg;
break;
case 'b':
bootloaderfile = optarg;
break;
case 'k':
if ((fd = open(optarg, O_RDONLY)) == -1)
{
perror(optarg);
return 2;
}
if (!prepare_loadable(fd, &loadable, &wide))
error(16, optarg);
if ((wide && kernel64 != -1) || (!wide && kernel32 != -1))
error(17, optarg);
lseek(fd, 0, SEEK_SET); /* rewind */
if (wide) {
kernel64 = fd;
kern64_nsz = loadable.uncompressed_size;
} else {
kernel32 = fd;
kern32_nsz = loadable.uncompressed_size;
}
break;
case 'r':
if ((ramdisk = open(optarg, O_RDONLY)) == -1)
{
perror(optarg);
return 2;
}
break;
case 'c':
commandline = optarg;
if (strlen(commandline) >= CMDLINELEN)
error(3,CMDLINELEN-1,strlen(commandline));
break;
case 'e':
if(strcmp(optarg, "2") == 0)
format_as = 2;
else if(strcmp(optarg, "3") == 0)
format_as = 3;
else if (strcmp(optarg, "4") == 0)
format_as = 4;
else
error(0, argv[0]);
break;
case 'v':
verbose = 1;
break;
default:
error(0, argv[0]);
break;
}
}
if ((bootloader = open(bootloaderfile, O_RDONLY)) == -1)
{
perror(bootloaderfile);
return 2;
}
if (optind < argc)
{
error(0, argv[0]);
}
if (medianame == NULL)
{
fprintf(stderr, "%s: Need one of -CIs or -U\n", argv[0]);
error(0, argv[0]);
}
switch (mediatype)
{
case SEQUENTIAL:
if ((media = open(medianame, O_RDWR|O_CREAT|O_TRUNC, 0666)) == -1)
{
perror(medianame);
return 2;
}
do_sequential(media, kernel32, kernel64, commandline, bootloader,
ramdisk, kern32_nsz, kern64_nsz);
break;
case PARTITIONED:
{
struct diskpartition ptab[MAXPARTS];
int partitioned;
int f0;
struct firstblock f;
int at_start = 0; /* place ipl before first partition */
memset(ptab, 0, sizeof ptab);
/* non-sequential boot creation requires a file/device */
if ((media = open(medianame, O_RDWR)) == -1)
{
perror(medianame);
if (errno == ENOENT) /* file probably doesn't exist */
{
error(1);
}
return 2;
}
/* it better have a partition table too... */
partitioned = load_partitions(media, ptab, MAXPARTS);
if (!partitioned)
{
error(10);
}
/* find the F0 partition */
for (f0 = 0; f0 < MAXPARTS; f0++)
{
if (ptab[f0].id == PALO_PARTITION)
break;
}
if (f0 == MAXPARTS) {
/* is the partition layout sufficient to support
* iplboot before the first parition. Allow 64
* sectors for the gpt label (like we'll ever support
* gpt, but just in case) allow for 8 extra sectors to
* align the iplboot */
if (ptab[0].start > 64 + MAXBLSIZE/512 + 8)
at_start = (ptab[0].start * 512 - MAXBLSIZE) & ~0xfff;
else
error(11);
}
if(verbose) {
print_ptab_pretty(ptab, MAXPARTS);
if (at_start)
printf("Placing bootloader within disk label at %d\n",
at_start/512);
else
printf("F0 partition start sector %d length %d\n",
ptab[f0].start, ptab[f0].length);
}
if (at_start) {
if (format_as)
printf("No F0(palo) partition found, placing iplboot inside label\n");
do_at_start(init, media, at_start, bootloader, commandline);
} else if (format_as) {
/* if we're going to be a formatted partition, we can't
* load anything into it, so check we haven't been asked
* to */
if(kernel32 != -1 || kernel64 != -1 || ramdisk != -1)
error(18);
if (do_formatted(init, media, medianame, f0 + 1,
ptab[f0].start * 512, ptab[f0].length * 512,
bootloader, format_as, commandline))
error(20);
} else
do_randomaccess(init, media, kernel32, kernel64, commandline,
bootloader, ramdisk, ptab[f0].start * 512,
ptab[f0].length * 512,
kern32_nsz, kern64_nsz);
}
break;
case CDROM:
if ((media = open(medianame, O_RDWR)) == -1)
{
perror(medianame);
return 2;
}
do_cdrom(media, kernel32, kernel64, commandline, bootloader, ramdisk,
kern32_nsz, kern64_nsz);
break;
}
fsync(media);
close(media);
return 0;
}