Obtained from: Whistle Communications

control program to control the facility of the bootblocks
to fetch a default bootstring from a fixed location on the disk.

See the manpage for more info.
This commit is contained in:
julian 1996-07-09 02:04:32 +00:00
parent 7dbcea9d7a
commit 6afeabc6cb
6 changed files with 656 additions and 0 deletions

View File

@ -0,0 +1,9 @@
# @(#)Makefile 1.1 (Julian Elischer) 3/28/93
#
#
PROG= nextboot
SRCS= nextboot.c
MAN8= nextboot.8
.include <bsd.prog.mk>

View File

@ -0,0 +1,87 @@
.Dd July 9, 1996
.Dt NEXTBOOT 8
.\".Os BSD 4
.Sh NAME
.Nm nextboot
.Nd Install a default bootstring block on the boot disk
.Sh SYNOPSIS
.Nm
.Op Fl b
.Ar filename bootstring ...
.Pp
.Nm
.Op Fl e
.Op Fl d
.Ar filename
.Bl -tag -width time
.It Fl b
Is used for bootstrapping (initially configuring) the nameblock. Without
this,
.Nm
will refuse to write to a block that does not already contain the magic
number.
.It Fl d
temporarily disables an existing name block by changing a bit
in the magic number.
.It Fl e
restores the good magic number on a block disabled by -d.
.El
.Sh PROLOGUE
The FreeBSD program
.Nm
controls the actions of the boot blocks at the time of the next boot.
If compiled with the correct option,
the boot blocks will check the nameblock for a magic number and a
default name to use for booting. If compiled to do so they will also
delete the name from the block, ensuring that if the boot should fail,
then it will not be tried again. It is the job of /etc/rc to use
.Nm
to re-install the string if that boot is found to have succeeded.
This allows a one-time only boot string to be used for such applications
as remote debugging, and installation of new, untrusted kernels.
The nameblock is defined at compile time to be the second physical block
on the disk.
.Pp
.Sh DESCRIPTION
.Nm
first checks that the disk has an fdisk table and checks that none of the
partitions defined in that table include the nameblock. If the name block is
shown to be unused, it will install the bootstrings given as arguments,
one after the other, each preceded by a small magic number, and NULL
terminated. The end of the list of strings is delimited by a sequence of
0xff bytes. If the boot blocks are compiled to write back the nameblock
after each boot, it will zero out the supplied names as it uses them,
one per boot,
until it reaches the 0xff, at which time it will revert to the compiled in
boot string. At this time the nameblock will contain only zeroed out names.
.Pp
An example of usage might be:
.Bd -literal
nextboot -b /dev/rwd0 1:sd(0,a)/kernel.experimental wd(0,a)/kernel.old
.Ed
.Pp
Which would instruct the boot blocks at the next boot,
to try boot the experimental kernel off the scsi disk.
If for any reason this failed, the next boot attempt would
boot the kernel
.Em /kernel.old
off the IDE drive. (assuming the write-back option were enabled) If this
in turn failed. the compiled in default would be used.
.Pp
If the write-back feature is disabled, the nextboot program is a convenient way
to change the default boot string. Note, that should the file specified in
the nameblock be non-existant, then the name compiled into the boot blocks
will be used for the boot rather than the next name in the nameblock. The
nameblock is only consulted ONCE per boot.
.Sh SEE ALSO
.Xr boot 8
.Xr disklabel 8
.Xr fdisk 8
.Sh BUGS
The entire program should be made more user-friendly.
.Pp
Whether to write back or not should be specified at run-time in the nameblock
so that the boot blocks need not be altered to get this feature.
.Pp

View File

@ -0,0 +1,232 @@
/*
* Copyright (c) 1996 Whistle Communications
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* Whistle Communications allows free use of this software in its "as is"
* condition. Whistle Communications disclaims any liability of any kind for
* any damages whatsoever resulting from the use of this software.
*/
#include <sys/types.h>
#include <sys/disklabel.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <unistd.h>
struct mboot
{
unsigned char padding[2]; /* force the longs to be long alligned */
unsigned char bootinst[DOSPARTOFF];
struct dos_partition parts[4];
unsigned short int signature;
};
struct mboot mboot;
#define NAMEBLOCK 1 /* 2nd block */
#define BLOCKSIZE 512
#define ENABLE_MAGIC 0xdeafc0de
#define DISABLE_MAGIC 0xdeadc0de
static int bflag;
static int eflag;
static int dflag;
static int nameblock = NAMEBLOCK;
char * myname;
#define BOOT_MAGIC 0xAA55
static void usage(void) {
printf (" usage: %s [-b] device bootstring [bootstring] ...\n"
,myname);
printf (" or: %s {-e,-d} device \n"
,myname);
printf (" flags are mutually exclusive\n");
exit(1);
}
main (int argc, char** argv)
{
int fd = -1;
char namebuf[1024], *cp = namebuf;
int i,j;
int ch;
int part;
bflag = 0;
myname = argv[0];
while ((ch = getopt(argc, argv, "bde")) != EOF) {
switch(ch) {
case 'b':
bflag = 1;
break;
case 'd':
dflag = 1;
break;
case 'e':
eflag = 1;
break;
case '?':
default:
usage();
}
}
argc -= optind;
argv += optind;
if ( (dflag + eflag + bflag) > 1 ) {
usage();
}
if (dflag + eflag){
if(argc != 1 ) {
usage();
}
} else {
if (argc <2) {
usage();
}
}
if ((fd = open(argv[0], O_RDWR, 0)) < 0) {
perror("open");
printf ("file: %s\n",argv[0]);
usage();
}
argc--;
argv++;
/*******************************************
* Check that we have an MBR
*/
if (lseek(fd,0,0) == -1) {
perror("lseek");
exit(1);
}
if (read (fd,&mboot.bootinst[0],BLOCKSIZE ) != BLOCKSIZE) {
perror("read0");
exit(1);
}
if(mboot.signature != (unsigned short)BOOT_MAGIC) {
printf(" no fdisk part.. not touching block 1\n");
exit(1);
}
/*******************************************
* And check that none of the partitions in it cover the name block;
*/
for ( part = 0; part < 4; part++) {
if( mboot.parts[part].dp_size
&& (mboot.parts[part].dp_start <= NAMEBLOCK)
&& (mboot.parts[part].dp_start
+ mboot.parts[part].dp_size > NAMEBLOCK)) {
printf(" Name sector lies within a Bios partition.\n");
printf(" Aborting write.\n");
exit(1);
}
}
/*******************************************
* Now check the name sector itself to see if it's been initialised.
*/
if (lseek(fd,NAMEBLOCK * BLOCKSIZE,0) == -1) {
perror("lseek");
exit(1);
}
if ( read (fd,namebuf,BLOCKSIZE ) != BLOCKSIZE) {
perror("read1");
exit(1);
}
/*******************************************
* check if we are just enabling or disabling
* Remember the flags are exlusive..
*/
if(!bflag) { /* don't care what's there if bflag is set */
switch(*(unsigned long *)cp)
{
case DISABLE_MAGIC:
case ENABLE_MAGIC:
break;
default:
fprintf(stderr,
"namesector not initialised.."
"use the -b flag..\n");
exit(1);
}
}
/*******************************************
* If the z or r flag is set, damage or restore the magic number..
* to disable/enable the feature
*/
if(dflag) {
*(unsigned long *)cp = DISABLE_MAGIC;
} else {
*(unsigned long *)cp = ENABLE_MAGIC;
}
if ((!dflag) && (!eflag)) {
/*******************************************
* Create a new namesector in ram
*/
cp += 4;
for ( i = 0 ; i < argc ; i++ ) {
*cp++ = 'D';
*cp++ = 'N';
j = strlen(argv[i]);
strncpy(cp,argv[i],j);
cp += j;
*cp++ = 0;
}
*cp++ = 0xff;
*cp++ = 0xff;
*cp++ = 0xff;
namebuf[BLOCKSIZE-1] = 0; /* paranoid */
namebuf[BLOCKSIZE] = 0xff;
}
/*******************************************
* write it to disk.
*/
if (lseek(fd,NAMEBLOCK * BLOCKSIZE,0) == -1) {
perror("lseek");
exit(1);
}
if(write (fd,namebuf,BLOCKSIZE ) != BLOCKSIZE) {
perror("write");
exit(1);
}
#if 0
/*******************************************
* just to be safe/paranoid.. read it back..
* and print it..
*/
if (lseek(fd,NAMEBLOCK * BLOCKSIZE,0) == -1) {
perror("lseek (second) ");
exit(1);
}
read (fd,namebuf,512);
for (i = 0;i< 16;i++) {
for ( j = 0; j < 16; j++) {
printf("%02x ",(unsigned char )namebuf[(i*16) + j ]);
}
printf("\n");
}
#endif
exit(0);
}

9
sbin/nextboot/Makefile Normal file
View File

@ -0,0 +1,9 @@
# @(#)Makefile 1.1 (Julian Elischer) 3/28/93
#
#
PROG= nextboot
SRCS= nextboot.c
MAN8= nextboot.8
.include <bsd.prog.mk>

87
sbin/nextboot/nextboot.8 Normal file
View File

@ -0,0 +1,87 @@
.Dd July 9, 1996
.Dt NEXTBOOT 8
.\".Os BSD 4
.Sh NAME
.Nm nextboot
.Nd Install a default bootstring block on the boot disk
.Sh SYNOPSIS
.Nm
.Op Fl b
.Ar filename bootstring ...
.Pp
.Nm
.Op Fl e
.Op Fl d
.Ar filename
.Bl -tag -width time
.It Fl b
Is used for bootstrapping (initially configuring) the nameblock. Without
this,
.Nm
will refuse to write to a block that does not already contain the magic
number.
.It Fl d
temporarily disables an existing name block by changing a bit
in the magic number.
.It Fl e
restores the good magic number on a block disabled by -d.
.El
.Sh PROLOGUE
The FreeBSD program
.Nm
controls the actions of the boot blocks at the time of the next boot.
If compiled with the correct option,
the boot blocks will check the nameblock for a magic number and a
default name to use for booting. If compiled to do so they will also
delete the name from the block, ensuring that if the boot should fail,
then it will not be tried again. It is the job of /etc/rc to use
.Nm
to re-install the string if that boot is found to have succeeded.
This allows a one-time only boot string to be used for such applications
as remote debugging, and installation of new, untrusted kernels.
The nameblock is defined at compile time to be the second physical block
on the disk.
.Pp
.Sh DESCRIPTION
.Nm
first checks that the disk has an fdisk table and checks that none of the
partitions defined in that table include the nameblock. If the name block is
shown to be unused, it will install the bootstrings given as arguments,
one after the other, each preceded by a small magic number, and NULL
terminated. The end of the list of strings is delimited by a sequence of
0xff bytes. If the boot blocks are compiled to write back the nameblock
after each boot, it will zero out the supplied names as it uses them,
one per boot,
until it reaches the 0xff, at which time it will revert to the compiled in
boot string. At this time the nameblock will contain only zeroed out names.
.Pp
An example of usage might be:
.Bd -literal
nextboot -b /dev/rwd0 1:sd(0,a)/kernel.experimental wd(0,a)/kernel.old
.Ed
.Pp
Which would instruct the boot blocks at the next boot,
to try boot the experimental kernel off the scsi disk.
If for any reason this failed, the next boot attempt would
boot the kernel
.Em /kernel.old
off the IDE drive. (assuming the write-back option were enabled) If this
in turn failed. the compiled in default would be used.
.Pp
If the write-back feature is disabled, the nextboot program is a convenient way
to change the default boot string. Note, that should the file specified in
the nameblock be non-existant, then the name compiled into the boot blocks
will be used for the boot rather than the next name in the nameblock. The
nameblock is only consulted ONCE per boot.
.Sh SEE ALSO
.Xr boot 8
.Xr disklabel 8
.Xr fdisk 8
.Sh BUGS
The entire program should be made more user-friendly.
.Pp
Whether to write back or not should be specified at run-time in the nameblock
so that the boot blocks need not be altered to get this feature.
.Pp

232
sbin/nextboot/nextboot.c Normal file
View File

@ -0,0 +1,232 @@
/*
* Copyright (c) 1996 Whistle Communications
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* Whistle Communications allows free use of this software in its "as is"
* condition. Whistle Communications disclaims any liability of any kind for
* any damages whatsoever resulting from the use of this software.
*/
#include <sys/types.h>
#include <sys/disklabel.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <unistd.h>
struct mboot
{
unsigned char padding[2]; /* force the longs to be long alligned */
unsigned char bootinst[DOSPARTOFF];
struct dos_partition parts[4];
unsigned short int signature;
};
struct mboot mboot;
#define NAMEBLOCK 1 /* 2nd block */
#define BLOCKSIZE 512
#define ENABLE_MAGIC 0xdeafc0de
#define DISABLE_MAGIC 0xdeadc0de
static int bflag;
static int eflag;
static int dflag;
static int nameblock = NAMEBLOCK;
char * myname;
#define BOOT_MAGIC 0xAA55
static void usage(void) {
printf (" usage: %s [-b] device bootstring [bootstring] ...\n"
,myname);
printf (" or: %s {-e,-d} device \n"
,myname);
printf (" flags are mutually exclusive\n");
exit(1);
}
main (int argc, char** argv)
{
int fd = -1;
char namebuf[1024], *cp = namebuf;
int i,j;
int ch;
int part;
bflag = 0;
myname = argv[0];
while ((ch = getopt(argc, argv, "bde")) != EOF) {
switch(ch) {
case 'b':
bflag = 1;
break;
case 'd':
dflag = 1;
break;
case 'e':
eflag = 1;
break;
case '?':
default:
usage();
}
}
argc -= optind;
argv += optind;
if ( (dflag + eflag + bflag) > 1 ) {
usage();
}
if (dflag + eflag){
if(argc != 1 ) {
usage();
}
} else {
if (argc <2) {
usage();
}
}
if ((fd = open(argv[0], O_RDWR, 0)) < 0) {
perror("open");
printf ("file: %s\n",argv[0]);
usage();
}
argc--;
argv++;
/*******************************************
* Check that we have an MBR
*/
if (lseek(fd,0,0) == -1) {
perror("lseek");
exit(1);
}
if (read (fd,&mboot.bootinst[0],BLOCKSIZE ) != BLOCKSIZE) {
perror("read0");
exit(1);
}
if(mboot.signature != (unsigned short)BOOT_MAGIC) {
printf(" no fdisk part.. not touching block 1\n");
exit(1);
}
/*******************************************
* And check that none of the partitions in it cover the name block;
*/
for ( part = 0; part < 4; part++) {
if( mboot.parts[part].dp_size
&& (mboot.parts[part].dp_start <= NAMEBLOCK)
&& (mboot.parts[part].dp_start
+ mboot.parts[part].dp_size > NAMEBLOCK)) {
printf(" Name sector lies within a Bios partition.\n");
printf(" Aborting write.\n");
exit(1);
}
}
/*******************************************
* Now check the name sector itself to see if it's been initialised.
*/
if (lseek(fd,NAMEBLOCK * BLOCKSIZE,0) == -1) {
perror("lseek");
exit(1);
}
if ( read (fd,namebuf,BLOCKSIZE ) != BLOCKSIZE) {
perror("read1");
exit(1);
}
/*******************************************
* check if we are just enabling or disabling
* Remember the flags are exlusive..
*/
if(!bflag) { /* don't care what's there if bflag is set */
switch(*(unsigned long *)cp)
{
case DISABLE_MAGIC:
case ENABLE_MAGIC:
break;
default:
fprintf(stderr,
"namesector not initialised.."
"use the -b flag..\n");
exit(1);
}
}
/*******************************************
* If the z or r flag is set, damage or restore the magic number..
* to disable/enable the feature
*/
if(dflag) {
*(unsigned long *)cp = DISABLE_MAGIC;
} else {
*(unsigned long *)cp = ENABLE_MAGIC;
}
if ((!dflag) && (!eflag)) {
/*******************************************
* Create a new namesector in ram
*/
cp += 4;
for ( i = 0 ; i < argc ; i++ ) {
*cp++ = 'D';
*cp++ = 'N';
j = strlen(argv[i]);
strncpy(cp,argv[i],j);
cp += j;
*cp++ = 0;
}
*cp++ = 0xff;
*cp++ = 0xff;
*cp++ = 0xff;
namebuf[BLOCKSIZE-1] = 0; /* paranoid */
namebuf[BLOCKSIZE] = 0xff;
}
/*******************************************
* write it to disk.
*/
if (lseek(fd,NAMEBLOCK * BLOCKSIZE,0) == -1) {
perror("lseek");
exit(1);
}
if(write (fd,namebuf,BLOCKSIZE ) != BLOCKSIZE) {
perror("write");
exit(1);
}
#if 0
/*******************************************
* just to be safe/paranoid.. read it back..
* and print it..
*/
if (lseek(fd,NAMEBLOCK * BLOCKSIZE,0) == -1) {
perror("lseek (second) ");
exit(1);
}
read (fd,namebuf,512);
for (i = 0;i< 16;i++) {
for ( j = 0; j < 16; j++) {
printf("%02x ",(unsigned char )namebuf[(i*16) + j ]);
}
printf("\n");
}
#endif
exit(0);
}