Separate access to filesystem and access to raw device, mount
device only if needed. This allows to work on unmounted disks in securelevel 1.
This commit is contained in:
parent
4d323b75fe
commit
444a854ad2
@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: installboot.8,v 1.1 1997/03/14 02:40:32 perry Exp $
|
||||
.\" $NetBSD: installboot.8,v 1.2 1997/06/13 22:15:06 drochner Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1997 Perry E. Metzger. All rights reserved.
|
||||
.\" Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved.
|
||||
@ -29,7 +29,7 @@
|
||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd March 14, 1997
|
||||
.Dd June 13, 1997
|
||||
.Dt INSTALLBOOT 8 i386
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -45,9 +45,7 @@ The
|
||||
.Nm installboot
|
||||
utility prepares a disk for bootstrapping.
|
||||
.Pp
|
||||
The
|
||||
.Nx /i386
|
||||
disk bootstrap software is split into two parts:
|
||||
The NetBSD/i386 disk bootstrap software is split into two parts:
|
||||
a small first-stage boot program that is written into the disklabel
|
||||
area of a disk and a second-stage boot program that resides in a FFS file
|
||||
system on the disk (named
|
||||
@ -64,13 +62,6 @@ have been hard-coded into it by
|
||||
during execution.
|
||||
The second-stage boot program then locates and loads the kernel.
|
||||
.Pp
|
||||
Note: so that the
|
||||
.Pa /boot
|
||||
file can be installed on the bootable partition, the partition must be
|
||||
mounted before
|
||||
.Nm
|
||||
is run.
|
||||
.Pp
|
||||
The options recognized by
|
||||
.Nm installboot
|
||||
are as follows:
|
||||
@ -94,22 +85,21 @@ The name of the special object file
|
||||
.Pa /usr/mdec/biosboot.sym )
|
||||
where the first and second stage boot programs to be installed reside.
|
||||
.It Ar rawdiskdevice
|
||||
The name of the device corresponding to the raw whole-disk partition (the
|
||||
.Dq raw partition )
|
||||
of the disk on which the first-stage boot program is to be installed.
|
||||
The name of the raw device corresponding to the partition on which
|
||||
the boot program is to be installed. The partition should
|
||||
start at the beginning of the
|
||||
.Nx
|
||||
portion of the disk and must contain a FFS filesystem. The
|
||||
.Nm
|
||||
program enforces its name to be in the form
|
||||
.Dq /dev/r*a
|
||||
\&.
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
Assuming the file containing the boot program is in its typical place,
|
||||
and you wished to make
|
||||
.Pa /dev/fd0a
|
||||
bootable. One might first mount
|
||||
.Pa /dev/fd0a
|
||||
on
|
||||
.Pa /mnt ,
|
||||
and in the case that there is already a file named
|
||||
.Pa boot
|
||||
in that directory, remove it.
|
||||
To install the boot blocks, one then would issue the command:
|
||||
bootable. To install the boot blocks, one then would issue the command:
|
||||
.Bd -literal -offset indent
|
||||
installboot -f /usr/mdec/biosboot.sym /dev/rfd0a
|
||||
.Ed
|
||||
@ -122,9 +112,16 @@ it is advisable that
|
||||
.Dq a
|
||||
partitions reside entirely within the first 1024 cylinders.
|
||||
.Pp
|
||||
The BIOS partition
|
||||
table must reflect the correct location of the
|
||||
.Nx
|
||||
portion according to disk geometry used by the BIOS. (This is automatically
|
||||
the case if the
|
||||
.Nx
|
||||
portion is located at the beginning of the disk.)
|
||||
.Pp
|
||||
.Nm
|
||||
requires simultaneous access to the mounted file system and
|
||||
the disks' raw partition.
|
||||
requires access to the disks' raw partition.
|
||||
That is not allowed with the kernel
|
||||
.Dv securelevel
|
||||
variable
|
||||
@ -136,7 +133,7 @@ set to a value greater than one, or with
|
||||
.Dv securelevel
|
||||
set to one if the
|
||||
.Dq boot
|
||||
program resides in a file system on the disk's raw partition.
|
||||
partition is mounted.
|
||||
.Sh "SEE ALSO"
|
||||
.Xr boot 8 ,
|
||||
.Xr disklabel 8 ,
|
||||
|
@ -1,8 +1,10 @@
|
||||
# $NetBSD: Makefile,v 1.2 1997/03/22 00:16:56 thorpej Exp $
|
||||
# $NetBSD: Makefile,v 1.3 1997/06/13 22:14:58 drochner Exp $
|
||||
|
||||
BINDIR= /usr/mdec
|
||||
PROG= installboot
|
||||
|
||||
SRCS= installboot.c bootblks.c getmount.c
|
||||
|
||||
MAN= installboot.8
|
||||
MANSUBDIR=/i386
|
||||
|
||||
|
111
sys/arch/i386/stand/installboot/bootblks.c
Normal file
111
sys/arch/i386/stand/installboot/bootblks.c
Normal file
@ -0,0 +1,111 @@
|
||||
/* $NetBSD: bootblks.c,v 1.1 1997/06/13 22:15:02 drochner Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1996
|
||||
* Matthias Drochner. All rights reserved.
|
||||
*
|
||||
* 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 for the NetBSD Project
|
||||
* by Matthias Drochner.
|
||||
* 4. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <err.h>
|
||||
|
||||
#include "installboot.h"
|
||||
|
||||
static char bootblkpath[MAXPATHLEN];
|
||||
|
||||
ino_t
|
||||
createfileondev(diskdev, bootblkname, nowrite, bp, size)
|
||||
char *diskdev, *bootblkname;
|
||||
int nowrite;
|
||||
char *bp;
|
||||
int size;
|
||||
{
|
||||
char *mntpoint;
|
||||
int fd = -1;
|
||||
struct stat statbuf;
|
||||
int allok = 0;
|
||||
|
||||
if ((mntpoint = getmountpoint(diskdev)) == NULL)
|
||||
return ((ino_t) - 1);
|
||||
|
||||
/*
|
||||
* create file in fs root for bootloader data
|
||||
* don't overwrite existing file if "nowrite"
|
||||
*/
|
||||
sprintf(bootblkpath, "%s/%s", mntpoint, bootblkname);
|
||||
fd = open(bootblkpath, O_RDWR | O_CREAT | (nowrite ? O_EXCL : 0), 0444);
|
||||
if (fd < 0) {
|
||||
warn("open %s", bootblkpath);
|
||||
goto out;
|
||||
}
|
||||
/*
|
||||
* do the write, flush, get inode number
|
||||
*/
|
||||
if (write(fd, bp, size) < 0) {
|
||||
warn("write %s", bootblkpath);
|
||||
goto out;
|
||||
}
|
||||
if (fsync(fd) != 0) {
|
||||
warn("fsync: %s", bootblkpath);
|
||||
goto out;
|
||||
}
|
||||
if (fstat(fd, &statbuf) != 0) {
|
||||
warn("fstat: %s", bootblkpath);
|
||||
goto out;
|
||||
}
|
||||
allok = 1;
|
||||
|
||||
out:
|
||||
if (fd != -1) {
|
||||
close(fd);
|
||||
if (!allok)
|
||||
unlink(bootblkpath);
|
||||
}
|
||||
cleanupmount(mntpoint);
|
||||
return (allok ? statbuf.st_ino : (ino_t) - 1);
|
||||
}
|
||||
|
||||
void
|
||||
cleanupfileondev(diskdev, bootblkname)
|
||||
char *diskdev, *bootblkname;
|
||||
{
|
||||
char *mntpoint;
|
||||
|
||||
if ((mntpoint = getmountpoint(diskdev)) == NULL)
|
||||
return;
|
||||
|
||||
sprintf(bootblkpath, "%s/%s", mntpoint, bootblkname);
|
||||
unlink(bootblkpath);
|
||||
|
||||
cleanupmount(mntpoint);
|
||||
}
|
155
sys/arch/i386/stand/installboot/getmount.c
Normal file
155
sys/arch/i386/stand/installboot/getmount.c
Normal file
@ -0,0 +1,155 @@
|
||||
/* $NetBSD: getmount.c,v 1.1 1997/06/13 22:15:04 drochner Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1996
|
||||
* Matthias Drochner. All rights reserved.
|
||||
*
|
||||
* 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 for the NetBSD Project
|
||||
* by Matthias Drochner.
|
||||
* 4. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <err.h>
|
||||
|
||||
#include "installboot.h"
|
||||
|
||||
static int tempmounted = 0;
|
||||
|
||||
/* make block device name from character device name */
|
||||
static char *
|
||||
getbdev(dev)
|
||||
char *dev;
|
||||
{
|
||||
static char bdiskdev[MAXPATHLEN];
|
||||
|
||||
if (strncmp(dev, "/dev/r", 6)) {
|
||||
warnx("bad device name %s", dev);
|
||||
return (0);
|
||||
}
|
||||
sprintf(bdiskdev, "/dev/%s", dev + 6);
|
||||
return (bdiskdev);
|
||||
}
|
||||
|
||||
/*
|
||||
* create mountpoint and mount given block device there, return
|
||||
* mountpoint
|
||||
*/
|
||||
static char *
|
||||
dotempmount(bdiskdev)
|
||||
char *bdiskdev;
|
||||
{
|
||||
static char dir[] = "/tmp/installbootXXXXXX";
|
||||
struct ufs_args data;
|
||||
|
||||
if (mktemp(dir) == NULL) {
|
||||
warnx("mktemp failed");
|
||||
return (0);
|
||||
}
|
||||
if (mkdir(dir, 0700)) {
|
||||
warn("could not create temporary dir %s", dir);
|
||||
return (0);
|
||||
}
|
||||
bzero(&data, sizeof(data));
|
||||
data.fspec = bdiskdev;
|
||||
|
||||
/* this code if FFS only */
|
||||
if (mount(MOUNT_FFS, dir, 0, &data) == -1) {
|
||||
warn("mount %s->%s failed", bdiskdev, dir);
|
||||
rmdir(dir);
|
||||
return (0);
|
||||
}
|
||||
if (verbose)
|
||||
printf("mounted %s at %s\n", bdiskdev, dir);
|
||||
tempmounted = 1;
|
||||
return (dir);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find out if given character device is already mounted. If not, mount it
|
||||
* temporarily.
|
||||
*/
|
||||
char *
|
||||
getmountpoint(diskdev)
|
||||
char *diskdev;
|
||||
{
|
||||
char *bdiskdev;
|
||||
struct statfs *buf;
|
||||
int num, i;
|
||||
|
||||
bdiskdev = getbdev(diskdev);
|
||||
if (bdiskdev == NULL)
|
||||
return (0);
|
||||
|
||||
num = getmntinfo(&buf, MNT_WAIT);
|
||||
if (num == 0) {
|
||||
warn("getmntinfo");
|
||||
return (0);
|
||||
}
|
||||
for (i = 0; i < num; i++)
|
||||
if (strncmp(bdiskdev, buf[i].f_mntfromname, MNAMELEN) == 0) {
|
||||
int j;
|
||||
|
||||
/* Device is mounted. If there are more devices mounted
|
||||
at the same point, the fs could be hidden. Don't think
|
||||
too much about layering order - simply refuse. */
|
||||
for (j = 0; j < num; j++)
|
||||
if ((i != j) && (strncmp(buf[i].f_mntonname,
|
||||
buf[j].f_mntonname,
|
||||
MNAMELEN) == 0)) {
|
||||
warnx("there is more than 1 mount at %s",
|
||||
buf[i].f_mntonname);
|
||||
return (0);
|
||||
}
|
||||
/* this code is FFS only */
|
||||
if (strncmp(buf[i].f_fstypename, MOUNT_FFS, MFSNAMELEN)) {
|
||||
warnx("%s: must be a FFS filesystem", bdiskdev);
|
||||
return (0);
|
||||
}
|
||||
return (buf[i].f_mntonname);
|
||||
}
|
||||
if (verbose)
|
||||
printf("%s is not mounted\n", bdiskdev);
|
||||
return (dotempmount(bdiskdev));
|
||||
}
|
||||
|
||||
void
|
||||
cleanupmount(dir)
|
||||
char *dir;
|
||||
{
|
||||
if (tempmounted) {
|
||||
if (verbose)
|
||||
printf("unmounting\n");
|
||||
unmount(dir, 0);
|
||||
rmdir(dir);
|
||||
tempmounted = 0;
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: installboot.8,v 1.1.1.1 1997/03/14 02:40:32 perry Exp $
|
||||
.\" $NetBSD: installboot.8,v 1.2 1997/06/13 22:15:06 drochner Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1997 Perry E. Metzger. All rights reserved.
|
||||
.\" Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved.
|
||||
@ -29,7 +29,7 @@
|
||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd March 14, 1997
|
||||
.Dd June 13, 1997
|
||||
.Dt INSTALLBOOT 8 i386
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -45,9 +45,7 @@ The
|
||||
.Nm installboot
|
||||
utility prepares a disk for bootstrapping.
|
||||
.Pp
|
||||
The
|
||||
.Nx /i386
|
||||
disk bootstrap software is split into two parts:
|
||||
The NetBSD/i386 disk bootstrap software is split into two parts:
|
||||
a small first-stage boot program that is written into the disklabel
|
||||
area of a disk and a second-stage boot program that resides in a FFS file
|
||||
system on the disk (named
|
||||
@ -64,13 +62,6 @@ have been hard-coded into it by
|
||||
during execution.
|
||||
The second-stage boot program then locates and loads the kernel.
|
||||
.Pp
|
||||
Note: so that the
|
||||
.Pa /boot
|
||||
file can be installed on the bootable partition, the partition must be
|
||||
mounted before
|
||||
.Nm
|
||||
is run.
|
||||
.Pp
|
||||
The options recognized by
|
||||
.Nm installboot
|
||||
are as follows:
|
||||
@ -94,22 +85,21 @@ The name of the special object file
|
||||
.Pa /usr/mdec/biosboot.sym )
|
||||
where the first and second stage boot programs to be installed reside.
|
||||
.It Ar rawdiskdevice
|
||||
The name of the device corresponding to the raw whole-disk partition (the
|
||||
.Dq raw partition )
|
||||
of the disk on which the first-stage boot program is to be installed.
|
||||
The name of the raw device corresponding to the partition on which
|
||||
the boot program is to be installed. The partition should
|
||||
start at the beginning of the
|
||||
.Nx
|
||||
portion of the disk and must contain a FFS filesystem. The
|
||||
.Nm
|
||||
program enforces its name to be in the form
|
||||
.Dq /dev/r*a
|
||||
\&.
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
Assuming the file containing the boot program is in its typical place,
|
||||
and you wished to make
|
||||
.Pa /dev/fd0a
|
||||
bootable. One might first mount
|
||||
.Pa /dev/fd0a
|
||||
on
|
||||
.Pa /mnt ,
|
||||
and in the case that there is already a file named
|
||||
.Pa boot
|
||||
in that directory, remove it.
|
||||
To install the boot blocks, one then would issue the command:
|
||||
bootable. To install the boot blocks, one then would issue the command:
|
||||
.Bd -literal -offset indent
|
||||
installboot -f /usr/mdec/biosboot.sym /dev/rfd0a
|
||||
.Ed
|
||||
@ -122,9 +112,16 @@ it is advisable that
|
||||
.Dq a
|
||||
partitions reside entirely within the first 1024 cylinders.
|
||||
.Pp
|
||||
The BIOS partition
|
||||
table must reflect the correct location of the
|
||||
.Nx
|
||||
portion according to disk geometry used by the BIOS. (This is automatically
|
||||
the case if the
|
||||
.Nx
|
||||
portion is located at the beginning of the disk.)
|
||||
.Pp
|
||||
.Nm
|
||||
requires simultaneous access to the mounted file system and
|
||||
the disks' raw partition.
|
||||
requires access to the disks' raw partition.
|
||||
That is not allowed with the kernel
|
||||
.Dv securelevel
|
||||
variable
|
||||
@ -136,7 +133,7 @@ set to a value greater than one, or with
|
||||
.Dv securelevel
|
||||
set to one if the
|
||||
.Dq boot
|
||||
program resides in a file system on the disk's raw partition.
|
||||
partition is mounted.
|
||||
.Sh "SEE ALSO"
|
||||
.Xr boot 8 ,
|
||||
.Xr disklabel 8 ,
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: installboot.c,v 1.1.1.1 1997/03/14 02:40:32 perry Exp $ */
|
||||
/* $NetBSD: installboot.c,v 1.2 1997/06/13 22:15:09 drochner Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1994 Paul Kranenburg
|
||||
@ -39,9 +39,6 @@
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/disklabel.h>
|
||||
#include <sys/dkio.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
@ -58,6 +55,8 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "installboot.h"
|
||||
|
||||
#include "bbinfo.h"
|
||||
|
||||
#define DEFBBLKNAME "boot"
|
||||
@ -71,22 +70,18 @@ struct nlist nl[] = {
|
||||
};
|
||||
|
||||
int verbose = 0;
|
||||
int nowrite = 0;
|
||||
|
||||
char bootblkpath[MAXPATHLEN];
|
||||
int bootblkscreated = 0; /* flag for error handling */
|
||||
|
||||
char *
|
||||
loadprotoblocks(fname, size)
|
||||
char *fname;
|
||||
long *size;
|
||||
{
|
||||
int fd;
|
||||
size_t tdsize; /* text+data size */
|
||||
size_t bbsize; /* boot block size (block aligned) */
|
||||
char *bp;
|
||||
struct nlist *nlp;
|
||||
struct exec eh;
|
||||
int fd;
|
||||
size_t tdsize; /* text+data size */
|
||||
size_t bbsize; /* boot block size (block aligned) */
|
||||
char *bp;
|
||||
struct nlist *nlp;
|
||||
struct exec eh;
|
||||
|
||||
fd = -1;
|
||||
bp = NULL;
|
||||
@ -117,18 +112,11 @@ loadprotoblocks(fname, size)
|
||||
goto bad;
|
||||
}
|
||||
/*
|
||||
* We have to include the exec header in the beginning of
|
||||
* the buffer, and leave extra space at the end in case
|
||||
* the actual write to disk wants to skip the header.
|
||||
* We need only text and data.
|
||||
*/
|
||||
tdsize = eh.a_text + eh.a_data;
|
||||
bbsize = roundup(tdsize, DEV_BSIZE);
|
||||
|
||||
/*
|
||||
* Allocate extra space here because the caller may copy
|
||||
* the boot block starting at the end of the exec header.
|
||||
* This prevents reading beyond the end of the buffer.
|
||||
*/
|
||||
if ((bp = calloc(bbsize, 1)) == NULL) {
|
||||
warnx("malloc: %s: no memory", fname);
|
||||
goto bad;
|
||||
@ -138,27 +126,24 @@ loadprotoblocks(fname, size)
|
||||
warn("read: %s", fname);
|
||||
goto bad;
|
||||
}
|
||||
*size = bbsize; /* aligned to DEV_BSIZE */
|
||||
|
||||
*size = bbsize; /* aligned to DEV_BSIZE */
|
||||
|
||||
fraglist = (struct fraglist*)(bp + nl[X_fraglist].n_value);
|
||||
fraglist = (struct fraglist *) (bp + nl[X_fraglist].n_value);
|
||||
|
||||
if (fraglist->magic != FRAGLISTMAGIC) {
|
||||
printf("invalid bootblock version\n");
|
||||
goto bad;
|
||||
printf("invalid bootblock version\n");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
printf("%s: entry point %#lx\n", fname, eh.a_entry);
|
||||
printf("proto bootblock size %ld\n", *size);
|
||||
printf("room for %d filesystem blocks at %#lx\n",
|
||||
fraglist->maxentries, nl[X_fraglist].n_value);
|
||||
fraglist->maxentries, nl[X_fraglist].n_value);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return bp;
|
||||
|
||||
bad:
|
||||
bad:
|
||||
if (bp)
|
||||
free(bp);
|
||||
if (fd >= 0)
|
||||
@ -168,186 +153,103 @@ loadprotoblocks(fname, size)
|
||||
|
||||
static int
|
||||
devread(fd, buf, blk, size, msg)
|
||||
int fd;
|
||||
void *buf;
|
||||
daddr_t blk;
|
||||
size_t size;
|
||||
char *msg;
|
||||
int fd;
|
||||
void *buf;
|
||||
daddr_t blk;
|
||||
size_t size;
|
||||
char *msg;
|
||||
{
|
||||
if (lseek(fd, dbtob(blk), SEEK_SET) != dbtob(blk)) {
|
||||
warn("%s: devread: lseek", msg);
|
||||
return(1);
|
||||
warn("%s: devread: lseek", msg);
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (read(fd, buf, size) != size) {
|
||||
warn("%s: devread: read", msg);
|
||||
return(1);
|
||||
warn("%s: devread: read", msg);
|
||||
return (1);
|
||||
}
|
||||
|
||||
return(0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* add file system blocks to fraglist */
|
||||
static int add_fsblk(fs, blk, blcnt)
|
||||
struct fs *fs;
|
||||
daddr_t blk;
|
||||
int blcnt;
|
||||
static int
|
||||
add_fsblk(fs, blk, blcnt)
|
||||
struct fs *fs;
|
||||
daddr_t blk;
|
||||
int blcnt;
|
||||
{
|
||||
int nblk;
|
||||
int nblk;
|
||||
|
||||
/* convert to disk blocks */
|
||||
blk = fsbtodb(fs, blk);
|
||||
nblk = fs->fs_bsize / DEV_BSIZE;
|
||||
if(nblk > blcnt)
|
||||
nblk = blcnt;
|
||||
/* convert to disk blocks */
|
||||
blk = fsbtodb(fs, blk);
|
||||
nblk = fs->fs_bsize / DEV_BSIZE;
|
||||
if (nblk > blcnt)
|
||||
nblk = blcnt;
|
||||
|
||||
if (verbose)
|
||||
printf("dblk: %d, num: %d\n", blk, nblk);
|
||||
if (verbose)
|
||||
printf("dblk: %d, num: %d\n", blk, nblk);
|
||||
|
||||
/* start new entry or append to previous? */
|
||||
if(!fraglist->numentries ||
|
||||
(fraglist->entries[fraglist->numentries - 1].offset
|
||||
+ fraglist->entries[fraglist->numentries - 1].num != blk)) {
|
||||
/* start new entry or append to previous? */
|
||||
if (!fraglist->numentries ||
|
||||
(fraglist->entries[fraglist->numentries - 1].offset
|
||||
+ fraglist->entries[fraglist->numentries - 1].num != blk)) {
|
||||
|
||||
/* need new entry */
|
||||
if(fraglist->numentries > fraglist->maxentries - 1)
|
||||
errx(1, "not enough fragment space in bootcode\n");
|
||||
/* need new entry */
|
||||
if (fraglist->numentries > fraglist->maxentries - 1) {
|
||||
errx(1, "not enough fragment space in bootcode\n");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
fraglist->entries[fraglist->numentries].offset = blk;
|
||||
fraglist->entries[fraglist->numentries++].num = 0;
|
||||
}
|
||||
fraglist->entries[fraglist->numentries].offset = blk;
|
||||
fraglist->entries[fraglist->numentries++].num = 0;
|
||||
}
|
||||
fraglist->entries[fraglist->numentries - 1].num += nblk;
|
||||
|
||||
fraglist->entries[fraglist->numentries - 1].num += nblk;
|
||||
|
||||
return(blcnt - nblk);
|
||||
return (blcnt - nblk);
|
||||
}
|
||||
|
||||
static char sblock[SBSIZE];
|
||||
|
||||
int
|
||||
loadblocknums(diskdev, bootblkname, bp, size)
|
||||
char *diskdev, *bootblkname;
|
||||
char *bp;
|
||||
int size;
|
||||
loadblocknums(diskdev, inode)
|
||||
char *diskdev;
|
||||
ino_t inode;
|
||||
{
|
||||
int devfd = -1, fd = -1;
|
||||
struct stat statbuf;
|
||||
struct statfs statfsbuf;
|
||||
struct fs *fs;
|
||||
char *buf = 0;
|
||||
daddr_t blk, *ap;
|
||||
struct dinode *ip;
|
||||
int i, ndb;
|
||||
char *p;
|
||||
int devfd = -1;
|
||||
struct fs *fs;
|
||||
char *buf = 0;
|
||||
daddr_t blk, *ap;
|
||||
struct dinode *ip;
|
||||
int i, ndb;
|
||||
int allok = 0;
|
||||
|
||||
devfd = open(diskdev, O_RDONLY, 0);
|
||||
if(devfd < 0) {
|
||||
warn("open raw partition");
|
||||
return(1);
|
||||
if (devfd < 0) {
|
||||
warn("open raw partition");
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Read superblock */
|
||||
if(devread(devfd, sblock, SBLOCK, SBSIZE, "superblock"))
|
||||
goto out;
|
||||
fs = (struct fs *)sblock;
|
||||
if (devread(devfd, sblock, SBLOCK, SBSIZE, "superblock"))
|
||||
goto out;
|
||||
fs = (struct fs *) sblock;
|
||||
|
||||
if(fs->fs_magic != FS_MAGIC) {
|
||||
warnx("invalid super block");
|
||||
goto out;
|
||||
if (fs->fs_magic != FS_MAGIC) {
|
||||
warnx("invalid super block");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if(verbose)
|
||||
printf("last mountpoint: %s\n", fs->fs_fsmnt);
|
||||
|
||||
/*
|
||||
* create file in (assumed) fs root for bootloader data
|
||||
*/
|
||||
sprintf(bootblkpath, "%s/%s", fs->fs_fsmnt, bootblkname);
|
||||
fd = open(bootblkpath, O_RDWR | O_CREAT | O_EXCL, 0444);
|
||||
if(fd < 0) {
|
||||
/* should overwrite if (!nowrite)???
|
||||
for now, be cautious */
|
||||
warn("open %s", bootblkpath);
|
||||
goto out;
|
||||
}
|
||||
|
||||
bootblkscreated = 1;
|
||||
|
||||
/*
|
||||
* some checks to make sure the disk is mounted
|
||||
*/
|
||||
|
||||
/* get info where we are really putting the file */
|
||||
if (fstatfs(fd, &statfsbuf) != 0) {
|
||||
warn("statfs: %s", bootblkpath);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* f_mntfromname should be the block device
|
||||
which corresponds to our raw device */
|
||||
if((p = rindex(statfsbuf.f_mntfromname, '/'))) p++;
|
||||
else p = statfsbuf.f_mntfromname;
|
||||
if(strcmp(p, diskdev + strlen(diskdev) - strlen(p))) {
|
||||
warnx("%s is not mounted", diskdev);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* perhaps redundant: (last) mountpoint of our device
|
||||
should be mountpoint belonging to the file */
|
||||
if(strncmp(fs->fs_fsmnt, statfsbuf.f_mntonname, MFSNAMELEN)) {
|
||||
warnx("inconsistent mount info");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* this code is FFS only */
|
||||
if (strncmp(statfsbuf.f_fstypename, MOUNT_FFS, MFSNAMELEN)) {
|
||||
warnx("%s: must be on a FFS filesystem", bootblkpath);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* do the real write, flush, get inode number
|
||||
*/
|
||||
if(write(fd, bp, size) < 0) {
|
||||
warn("write %s", bootblkpath);
|
||||
goto out;
|
||||
}
|
||||
if (fsync(fd) != 0) {
|
||||
warn("fsync: %s", bootblkpath);
|
||||
goto out;
|
||||
}
|
||||
if (fstat(fd, &statbuf) != 0) {
|
||||
warn("fstat: %s", bootblkpath);
|
||||
goto out;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
fd = -1;
|
||||
|
||||
/* paranoia */
|
||||
sync();
|
||||
sleep(3);
|
||||
|
||||
/* Read inode */
|
||||
if ((buf = malloc(fs->fs_bsize)) == NULL) {
|
||||
warnx("No memory for filesystem block");
|
||||
goto out;
|
||||
warnx("No memory for filesystem block");
|
||||
goto out;
|
||||
}
|
||||
|
||||
blk = fsbtodb(fs, ino_to_fsba(fs, statbuf.st_ino));
|
||||
if(devread(devfd, buf, blk, fs->fs_bsize, "inode"))
|
||||
goto out;
|
||||
ip = (struct dinode *)(buf) + ino_to_fsbo(fs, statbuf.st_ino);
|
||||
blk = fsbtodb(fs, ino_to_fsba(fs, inode));
|
||||
if (devread(devfd, buf, blk, fs->fs_bsize, "inode"))
|
||||
goto out;
|
||||
ip = (struct dinode *) (buf) + ino_to_fsbo(fs, inode);
|
||||
|
||||
/*
|
||||
* Have the inode. Figure out how many blocks we need.
|
||||
*/
|
||||
if(size != ip->di_size) {
|
||||
warnx("size inconsistency");
|
||||
goto out;
|
||||
}
|
||||
ndb = size / DEV_BSIZE; /* size is rounded! */
|
||||
ndb = ip->di_size / DEV_BSIZE; /* size is rounded! */
|
||||
|
||||
if (verbose)
|
||||
printf("Will load %d blocks.\n", ndb);
|
||||
@ -356,38 +258,38 @@ int size;
|
||||
* Get the block numbers, first direct blocks
|
||||
*/
|
||||
ap = ip->di_db;
|
||||
for (i = 0; i < NDADDR && *ap && ndb; i++, ap++)
|
||||
ndb = add_fsblk(fs, *ap, ndb);
|
||||
|
||||
if (ndb) {
|
||||
/*
|
||||
* Just one level of indirections; there isn't much room
|
||||
* for more in the 1st-level bootblocks anyway.
|
||||
*/
|
||||
blk = fsbtodb(fs, ip->di_ib[0]);
|
||||
if(devread(devfd, buf, blk, fs->fs_bsize, "indirect block"))
|
||||
goto out;
|
||||
ap = (daddr_t *)buf;
|
||||
for (; i < NINDIR(fs) && *ap && ndb; i++, ap++) {
|
||||
for (i = 0; i < NDADDR && *ap && ndb > 0; i++, ap++)
|
||||
ndb = add_fsblk(fs, *ap, ndb);
|
||||
}
|
||||
|
||||
if(ndb) {
|
||||
warnx("too many fs blocks");
|
||||
goto out;
|
||||
}
|
||||
if (ndb > 0) {
|
||||
/*
|
||||
* Just one level of indirections; there isn't much room
|
||||
* for more in the 1st-level bootblocks anyway.
|
||||
*/
|
||||
blk = fsbtodb(fs, ip->di_ib[0]);
|
||||
if (devread(devfd, buf, blk, fs->fs_bsize, "indirect block"))
|
||||
goto out;
|
||||
ap = (daddr_t *) buf;
|
||||
for (; i < NINDIR(fs) && *ap && ndb > 0; i++, ap++) {
|
||||
ndb = add_fsblk(fs, *ap, ndb);
|
||||
}
|
||||
}
|
||||
|
||||
allok = 1;
|
||||
if (!ndb)
|
||||
allok = 1;
|
||||
else {
|
||||
if (ndb > 0)
|
||||
warnx("too many fs blocks");
|
||||
/* else, ie ndb < 0, add_fsblk returned error */
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
if(buf)
|
||||
free(buf);
|
||||
if(fd >= 0)
|
||||
close(fd);
|
||||
if(devfd >= 0)
|
||||
close(devfd);
|
||||
return(!allok);
|
||||
if (buf)
|
||||
free(buf);
|
||||
if (devfd >= 0)
|
||||
close(devfd);
|
||||
return (!allok);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -398,122 +300,130 @@ usage()
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
char c, *bp = 0;
|
||||
long size;
|
||||
int devfd = -1;
|
||||
struct disklabel dl;
|
||||
int bsdoffs;
|
||||
int i;
|
||||
int res;
|
||||
int forceifnolabel = 0;
|
||||
char *bootblkname = DEFBBLKNAME;
|
||||
int allok = 0;
|
||||
char c, *bp = 0;
|
||||
long size;
|
||||
ino_t inode = (ino_t) -1;
|
||||
int devfd = -1;
|
||||
struct disklabel dl;
|
||||
int bsdoffs;
|
||||
int i, res;
|
||||
int forceifnolabel = 0;
|
||||
char *bootblkname = DEFBBLKNAME;
|
||||
int nowrite = 0;
|
||||
int allok = 0;
|
||||
|
||||
while ((c = getopt(argc, argv, "vnf")) != EOF) {
|
||||
switch (c) {
|
||||
case 'n':
|
||||
/* Do not actually write the bootblock to disk */
|
||||
nowrite = 1;
|
||||
break;
|
||||
case 'v':
|
||||
/* Chat */
|
||||
verbose = 1;
|
||||
break;
|
||||
case 'f':
|
||||
/* assume zero offset if no disklabel */
|
||||
forceifnolabel = 1;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
while ((c = getopt(argc, argv, "vnf")) != EOF) {
|
||||
switch (c) {
|
||||
case 'n':
|
||||
/* Do not actually write the bootblock to disk */
|
||||
nowrite = 1;
|
||||
break;
|
||||
case 'v':
|
||||
/* Chat */
|
||||
verbose = 1;
|
||||
break;
|
||||
case 'f':
|
||||
/* assume zero offset if no disklabel */
|
||||
forceifnolabel = 1;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
if (argc - optind != 2) {
|
||||
usage();
|
||||
}
|
||||
if (argc - optind != 2) {
|
||||
usage();
|
||||
}
|
||||
if (argv[optind + 1][strlen(argv[optind + 1]) - 1] != 'a')
|
||||
errx(1, "use partition 'a'!");
|
||||
|
||||
if(argv[optind + 1][strlen(argv[optind + 1]) - 1] != 'a')
|
||||
errx(1, "use partition 'a'!");
|
||||
bp = loadprotoblocks(argv[optind], &size);
|
||||
if (!bp)
|
||||
errx(1, "error reading bootblocks");
|
||||
|
||||
bp = loadprotoblocks(argv[optind], &size);
|
||||
if(!bp)
|
||||
errx(1, "error reading bootblocks");
|
||||
fraglist->numentries = 0;
|
||||
|
||||
fraglist->numentries = 0;
|
||||
/* do we need the fraglist? */
|
||||
if (size > fraglist->loadsz * DEV_BSIZE) {
|
||||
|
||||
/* do we need the fraglist? */
|
||||
if(size > fraglist->loadsz * DEV_BSIZE) {
|
||||
inode = createfileondev(argv[optind + 1], bootblkname, nowrite,
|
||||
bp + fraglist->loadsz * DEV_BSIZE,
|
||||
size - fraglist->loadsz * DEV_BSIZE);
|
||||
if (inode == (ino_t) - 1)
|
||||
goto out;
|
||||
|
||||
if(loadblocknums(argv[optind + 1], bootblkname,
|
||||
bp + fraglist->loadsz * DEV_BSIZE,
|
||||
size - fraglist->loadsz * DEV_BSIZE))
|
||||
goto out;
|
||||
/* paranoia */
|
||||
sync();
|
||||
sleep(3);
|
||||
|
||||
size = fraglist->loadsz * DEV_BSIZE;
|
||||
/* size to be written to bootsect */
|
||||
}
|
||||
if (loadblocknums(argv[optind + 1], inode))
|
||||
goto out;
|
||||
|
||||
devfd = open(argv[optind + 1], O_RDWR, 0);
|
||||
if(devfd < 0) {
|
||||
warn("open raw partition RW");
|
||||
goto out;
|
||||
}
|
||||
size = fraglist->loadsz * DEV_BSIZE;
|
||||
/* size to be written to bootsect */
|
||||
}
|
||||
|
||||
if(ioctl(devfd, DIOCGDINFO, &dl) < 0) {
|
||||
if((errno == EINVAL) || (errno == ENOTTY)){
|
||||
if(forceifnolabel)
|
||||
bsdoffs = 0;
|
||||
else {
|
||||
warnx("no disklabel, use -f to install anyway");
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
warn("get disklabel");
|
||||
goto out;
|
||||
}
|
||||
} else
|
||||
bsdoffs = dl.d_partitions[0].p_offset;
|
||||
devfd = open(argv[optind + 1], O_RDWR, 0);
|
||||
if (devfd < 0) {
|
||||
warn("open raw partition RW");
|
||||
goto out;
|
||||
}
|
||||
if (ioctl(devfd, DIOCGDINFO, &dl) < 0) {
|
||||
if ((errno == EINVAL) || (errno == ENOTTY)) {
|
||||
if (forceifnolabel)
|
||||
bsdoffs = 0;
|
||||
else {
|
||||
warnx("no disklabel, use -f to install anyway");
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
warn("get disklabel");
|
||||
goto out;
|
||||
}
|
||||
} else
|
||||
bsdoffs = dl.d_partitions[0].p_offset;
|
||||
|
||||
if(verbose)
|
||||
printf("BSD partition starts at sector %d\n", bsdoffs);
|
||||
if (verbose)
|
||||
printf("BSD partition starts at sector %d\n", bsdoffs);
|
||||
|
||||
/*
|
||||
* add offset of BSD partition to fraglist entries
|
||||
*/
|
||||
for(i=0; i < fraglist->numentries; i++)
|
||||
fraglist->entries[i].offset += bsdoffs;
|
||||
/*
|
||||
* add offset of BSD partition to fraglist entries
|
||||
*/
|
||||
for (i = 0; i < fraglist->numentries; i++)
|
||||
fraglist->entries[i].offset += bsdoffs;
|
||||
|
||||
if(!nowrite) {
|
||||
/*
|
||||
* write first blocks (max loadsz) to start of BSD partition,
|
||||
* skip disklabel (in second disk block)
|
||||
*/
|
||||
lseek(devfd, 0, SEEK_SET);
|
||||
res = write(devfd, bp, DEV_BSIZE);
|
||||
if(res < 0) {
|
||||
warn("final write1");
|
||||
goto out;
|
||||
}
|
||||
lseek(devfd, 2 * DEV_BSIZE, SEEK_SET);
|
||||
res = write(devfd, bp + 2 * DEV_BSIZE, size - 2 * DEV_BSIZE);
|
||||
if(res < 0) {
|
||||
warn("final write2");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
allok = 1;
|
||||
if (!nowrite) {
|
||||
/*
|
||||
* write first blocks (max loadsz) to start of BSD partition,
|
||||
* skip disklabel (in second disk block)
|
||||
*/
|
||||
lseek(devfd, 0, SEEK_SET);
|
||||
res = write(devfd, bp, DEV_BSIZE);
|
||||
if (res < 0) {
|
||||
warn("final write1");
|
||||
goto out;
|
||||
}
|
||||
lseek(devfd, 2 * DEV_BSIZE, SEEK_SET);
|
||||
res = write(devfd, bp + 2 * DEV_BSIZE, size - 2 * DEV_BSIZE);
|
||||
if (res < 0) {
|
||||
warn("final write2");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
allok = 1;
|
||||
|
||||
out:
|
||||
if(devfd >= 0)
|
||||
close(devfd);
|
||||
if(bp)
|
||||
free(bp);
|
||||
if(bootblkscreated && (!allok || nowrite))
|
||||
unlink(bootblkpath);
|
||||
return(!allok);
|
||||
if (devfd >= 0)
|
||||
close(devfd);
|
||||
if (bp)
|
||||
free(bp);
|
||||
if (inode != (ino_t) - 1 && (!allok || nowrite)) {
|
||||
cleanupfileondev(argv[optind + 1], bootblkname);
|
||||
}
|
||||
return (!allok);
|
||||
}
|
||||
|
7
sys/arch/i386/stand/installboot/installboot.h
Normal file
7
sys/arch/i386/stand/installboot/installboot.h
Normal file
@ -0,0 +1,7 @@
|
||||
ino_t createfileondev __P((char *, char *, int, char *, int));
|
||||
void cleanupfileondev __P((char *, char *));
|
||||
|
||||
char *getmountpoint __P((char *));
|
||||
void cleanupmount __P((char *));
|
||||
|
||||
extern int verbose;
|
Loading…
Reference in New Issue
Block a user