/* $OpenBSD: softraid.c,v 1.9 2022/11/14 13:39:37 kn Exp $ */ /* * Copyright (c) 2012 Joel Sing * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #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; /* Prepare file system on device. */ md_prepareboot(diskfd, realdev); close(diskfd); } void sr_prepareboot(int devfd, char *dev) { int vol = -1, ndisks = 0, disk; /* Use the normal process if this is not a softraid volume. */ if (!sr_volume(devfd, dev, &vol, &ndisks)) { md_prepareboot(devfd, dev); return; } /* Prepare file system on each disk that is part of this volume. */ 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; /* Use the normal process if this is not a softraid volume. */ if (!sr_volume(devfd, dev, &vol, &ndisks)) { md_installboot(devfd, dev); return; } /* Install boot loader in softraid volume. */ sr_install_bootldr(devfd, dev); /* Install boot block on each disk that is part of this volume. */ 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; /* * Determine if the given device is a softraid volume. */ /* Get volume information. */ memset(&bi, 0, sizeof(bi)); if (ioctl(devfd, BIOCINQ, &bi) == -1) return 0; /* XXX - softraid volumes will always have a "softraid0" controller. */ if (strncmp(bi.bi_dev, "softraid0", sizeof("softraid0"))) return 0; /* * XXX - this only works with the real disk name (e.g. sd0) - this * should be extracted from the device name, or better yet, fixed in * the softraid ioctl. */ /* Locate specific softraid volume. */ 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; /* Get device name for this disk/chunk. */ memset(bd, 0, sizeof(*bd)); bd->bd_volid = vol; bd->bd_diskid = disk; if (ioctl(devfd, BIOCDISK, bd) == -1) err(1, "BIOCDISK"); /* Check disk status. */ if (bd->bd_status != BIOC_SDONLINE && bd->bd_status != BIOC_SDREBUILD) { fprintf(stderr, "softraid chunk %u not online - skipping...\n", disk); return -1; } /* Keydisks always have a size of zero. */ 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 (*part < 'a' || *part >= 'a' + MAXPARTITIONS) errx(1, "invalid partition %c\n", *part); bd->bd_vendor[strlen(bd->bd_vendor) - 1] = '\0'; /* Open device. */ if ((diskfd = opendev(bd->bd_vendor, (nowrite ? O_RDONLY : O_RDWR), OPENDEV_PART, realdev)) == -1) err(1, "open: %s", *realdev); return diskfd; }