1 /* $OpenBSD: softraid.c,v 1.9 2022/11/14 13:39:37 kn Exp $ */ 2 /* 3 * Copyright (c) 2012 Joel Sing <jsing@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/types.h> 19 #include <sys/disklabel.h> 20 #include <sys/dkio.h> 21 #include <sys/ioctl.h> 22 23 #include <dev/biovar.h> 24 25 #include <err.h> 26 #include <fcntl.h> 27 #include <stdio.h> 28 #include <string.h> 29 #include <unistd.h> 30 #include <util.h> 31 32 #include "installboot.h" 33 34 static int sr_volume(int, char *, int *, int *); 35 36 static void 37 sr_prepare_chunk(int devfd, int vol, int disk) 38 { 39 struct bioc_disk bd; 40 char *realdev; 41 char part; 42 int diskfd; 43 44 diskfd = sr_open_chunk(devfd, vol, disk, &bd, &realdev, &part); 45 if (diskfd == -1) 46 return; 47 48 /* Prepare file system on device. */ 49 md_prepareboot(diskfd, realdev); 50 51 close(diskfd); 52 } 53 54 void 55 sr_prepareboot(int devfd, char *dev) 56 { 57 int vol = -1, ndisks = 0, disk; 58 59 /* Use the normal process if this is not a softraid volume. */ 60 if (!sr_volume(devfd, dev, &vol, &ndisks)) { 61 md_prepareboot(devfd, dev); 62 return; 63 } 64 65 /* Prepare file system on each disk that is part of this volume. */ 66 for (disk = 0; disk < ndisks; disk++) 67 sr_prepare_chunk(devfd, vol, disk); 68 } 69 70 void 71 sr_installboot(int devfd, char *dev) 72 { 73 int vol = -1, ndisks = 0, disk; 74 75 /* Use the normal process if this is not a softraid volume. */ 76 if (!sr_volume(devfd, dev, &vol, &ndisks)) { 77 md_installboot(devfd, dev); 78 return; 79 } 80 81 /* Install boot loader in softraid volume. */ 82 sr_install_bootldr(devfd, dev); 83 84 /* Install boot block on each disk that is part of this volume. */ 85 for (disk = 0; disk < ndisks; disk++) 86 sr_install_bootblk(devfd, vol, disk); 87 } 88 89 int 90 sr_volume(int devfd, char *dev, int *vol, int *disks) 91 { 92 struct bioc_inq bi; 93 struct bioc_vol bv; 94 int i; 95 96 /* 97 * Determine if the given device is a softraid volume. 98 */ 99 100 /* Get volume information. */ 101 memset(&bi, 0, sizeof(bi)); 102 if (ioctl(devfd, BIOCINQ, &bi) == -1) 103 return 0; 104 105 /* XXX - softraid volumes will always have a "softraid0" controller. */ 106 if (strncmp(bi.bi_dev, "softraid0", sizeof("softraid0"))) 107 return 0; 108 109 /* 110 * XXX - this only works with the real disk name (e.g. sd0) - this 111 * should be extracted from the device name, or better yet, fixed in 112 * the softraid ioctl. 113 */ 114 /* Locate specific softraid volume. */ 115 for (i = 0; i < bi.bi_novol; i++) { 116 memset(&bv, 0, sizeof(bv)); 117 bv.bv_volid = i; 118 if (ioctl(devfd, BIOCVOL, &bv) == -1) 119 err(1, "BIOCVOL"); 120 121 if (strncmp(dev, bv.bv_dev, sizeof(bv.bv_dev)) == 0) { 122 *vol = i; 123 *disks = bv.bv_nodisk; 124 break; 125 } 126 } 127 128 if (verbose) 129 fprintf(stderr, "%s: softraid volume with %i disk(s)\n", 130 dev, *disks); 131 132 return 1; 133 } 134 135 void 136 sr_status(struct bio_status *bs) 137 { 138 int i; 139 140 for (i = 0; i < bs->bs_msg_count; i++) 141 warnx("%s", bs->bs_msgs[i].bm_msg); 142 143 if (bs->bs_status == BIO_STATUS_ERROR) { 144 if (bs->bs_msg_count == 0) 145 errx(1, "unknown error"); 146 else 147 exit(1); 148 } 149 } 150 151 int 152 sr_open_chunk(int devfd, int vol, int disk, struct bioc_disk *bd, 153 char **realdev, char *part) 154 { 155 int diskfd; 156 157 /* Get device name for this disk/chunk. */ 158 memset(bd, 0, sizeof(*bd)); 159 bd->bd_volid = vol; 160 bd->bd_diskid = disk; 161 if (ioctl(devfd, BIOCDISK, bd) == -1) 162 err(1, "BIOCDISK"); 163 164 /* Check disk status. */ 165 if (bd->bd_status != BIOC_SDONLINE && 166 bd->bd_status != BIOC_SDREBUILD) { 167 fprintf(stderr, "softraid chunk %u not online - skipping...\n", 168 disk); 169 return -1; 170 } 171 172 /* Keydisks always have a size of zero. */ 173 if (bd->bd_size == 0) 174 return -1; 175 176 if (strlen(bd->bd_vendor) < 1) 177 errx(1, "invalid disk name"); 178 *part = bd->bd_vendor[strlen(bd->bd_vendor) - 1]; 179 if (*part < 'a' || *part >= 'a' + MAXPARTITIONS) 180 errx(1, "invalid partition %c\n", *part); 181 bd->bd_vendor[strlen(bd->bd_vendor) - 1] = '\0'; 182 183 /* Open device. */ 184 if ((diskfd = opendev(bd->bd_vendor, (nowrite ? O_RDONLY : O_RDWR), 185 OPENDEV_PART, realdev)) == -1) 186 err(1, "open: %s", *realdev); 187 188 return diskfd; 189 } 190