#include <sys/types.h>
#include <sys/disklabel.h>
#include <sys/dkio.h>
#include <sys/ioctl.h>
#include <dev/biovar.h>
#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <util.h>
#include "installboot.h"
static int sr_volume(int, char *, int *, int *);
static void
sr_prepare_chunk(int devfd, int vol, int disk)
{
struct bioc_disk bd;
char *realdev;
char part;
int diskfd;
diskfd = sr_open_chunk(devfd, vol, disk, &bd, &realdev, &part);
if (diskfd == -1)
return;
md_prepareboot(diskfd, realdev);
close(diskfd);
}
void
sr_prepareboot(int devfd, char *dev)
{
int vol = -1, ndisks = 0, disk;
if (!sr_volume(devfd, dev, &vol, &ndisks)) {
md_prepareboot(devfd, dev);
return;
}
for (disk = 0; disk < ndisks; disk++)
sr_prepare_chunk(devfd, vol, disk);
}
void
sr_installboot(int devfd, char *dev)
{
int vol = -1, ndisks = 0, disk;
if (!sr_volume(devfd, dev, &vol, &ndisks)) {
md_installboot(devfd, dev);
return;
}
sr_install_bootldr(devfd, dev);
for (disk = 0; disk < ndisks; disk++)
sr_install_bootblk(devfd, vol, disk);
}
int
sr_volume(int devfd, char *dev, int *vol, int *disks)
{
struct bioc_inq bi;
struct bioc_vol bv;
int i;
memset(&bi, 0, sizeof(bi));
if (ioctl(devfd, BIOCINQ, &bi) == -1)
return 0;
if (strncmp(bi.bi_dev, "softraid0", sizeof("softraid0")))
return 0;
for (i = 0; i < bi.bi_novol; i++) {
memset(&bv, 0, sizeof(bv));
bv.bv_volid = i;
if (ioctl(devfd, BIOCVOL, &bv) == -1)
err(1, "BIOCVOL");
if (strncmp(dev, bv.bv_dev, sizeof(bv.bv_dev)) == 0) {
*vol = i;
*disks = bv.bv_nodisk;
break;
}
}
if (verbose)
fprintf(stderr, "%s: softraid volume with %i disk(s)\n",
dev, *disks);
return 1;
}
void
sr_status(struct bio_status *bs)
{
int i;
for (i = 0; i < bs->bs_msg_count; i++)
warnx("%s", bs->bs_msgs[i].bm_msg);
if (bs->bs_status == BIO_STATUS_ERROR) {
if (bs->bs_msg_count == 0)
errx(1, "unknown error");
else
exit(1);
}
}
int
sr_open_chunk(int devfd, int vol, int disk, struct bioc_disk *bd,
char **realdev, char *part)
{
int diskfd;
memset(bd, 0, sizeof(*bd));
bd->bd_volid = vol;
bd->bd_diskid = disk;
if (ioctl(devfd, BIOCDISK, bd) == -1)
err(1, "BIOCDISK");
if (bd->bd_status != BIOC_SDONLINE &&
bd->bd_status != BIOC_SDREBUILD) {
fprintf(stderr, "softraid chunk %u not online - skipping...\n",
disk);
return -1;
}
if (bd->bd_size == 0)
return -1;
if (strlen(bd->bd_vendor) < 1)
errx(1, "invalid disk name");
*part = bd->bd_vendor[strlen(bd->bd_vendor) - 1];
if (DL_PARTNAME2NUM(*part) == -1)
errx(1, "invalid partition %c\n", *part);
bd->bd_vendor[strlen(bd->bd_vendor) - 1] = '\0';
if ((diskfd = opendev(bd->bd_vendor, (nowrite ? O_RDONLY : O_RDWR),
OPENDEV_PART, realdev)) == -1)
err(1, "open: %s", *realdev);
return diskfd;
}