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:
drochner 1997-06-13 22:14:58 +00:00
parent 4d323b75fe
commit 444a854ad2
7 changed files with 536 additions and 357 deletions

View File

@ -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 ,

View File

@ -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

View 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);
}

View 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;
}
}

View File

@ -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 ,

View File

@ -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);
}

View 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;