xref: /openbsd-src/usr.sbin/installboot/softraid.c (revision 092d89168f10fe60c196d3252fccc8f13df20433)
1 /*	$OpenBSD: softraid.c,v 1.6 2022/11/07 15:56:09 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 <util.h>
30 
31 #include "installboot.h"
32 
33 static int sr_volume(int, char *, int *, int *);
34 
35 void
36 sr_installboot(int devfd, char *dev)
37 {
38 	int	vol = -1, ndisks = 0, disk;
39 
40 	/* Use the normal process if this is not a softraid volume. */
41 	if (!sr_volume(devfd, dev, &vol, &ndisks)) {
42 		md_installboot(devfd, dev);
43 		return;
44 	}
45 
46 	/* Install boot loader in softraid volume. */
47 	sr_install_bootldr(devfd, dev);
48 
49 	/* Install boot block on each disk that is part of this volume. */
50 	for (disk = 0; disk < ndisks; disk++)
51 		sr_install_bootblk(devfd, vol, disk);
52 }
53 
54 int
55 sr_volume(int devfd, char *dev, int *vol, int *disks)
56 {
57 	struct	bioc_inq bi;
58 	struct	bioc_vol bv;
59 	int	i;
60 
61 	/*
62 	 * Determine if the given device is a softraid volume.
63 	 */
64 
65 	/* Get volume information. */
66 	memset(&bi, 0, sizeof(bi));
67 	if (ioctl(devfd, BIOCINQ, &bi) == -1)
68 		return 0;
69 
70 	/* XXX - softraid volumes will always have a "softraid0" controller. */
71 	if (strncmp(bi.bi_dev, "softraid0", sizeof("softraid0")))
72 		return 0;
73 
74 	/*
75 	 * XXX - this only works with the real disk name (e.g. sd0) - this
76 	 * should be extracted from the device name, or better yet, fixed in
77 	 * the softraid ioctl.
78 	 */
79 	/* Locate specific softraid volume. */
80 	for (i = 0; i < bi.bi_novol; i++) {
81 		memset(&bv, 0, sizeof(bv));
82 		bv.bv_volid = i;
83 		if (ioctl(devfd, BIOCVOL, &bv) == -1)
84 			err(1, "BIOCVOL");
85 
86 		if (strncmp(dev, bv.bv_dev, sizeof(bv.bv_dev)) == 0) {
87 			*vol = i;
88 			*disks = bv.bv_nodisk;
89 			break;
90 		}
91 	}
92 
93 	if (verbose)
94 		fprintf(stderr, "%s: softraid volume with %i disk(s)\n",
95 		    dev, *disks);
96 
97 	return 1;
98 }
99 
100 void
101 sr_status(struct bio_status *bs)
102 {
103 	int	i;
104 
105 	for (i = 0; i < bs->bs_msg_count; i++)
106 		warnx("%s", bs->bs_msgs[i].bm_msg);
107 
108 	if (bs->bs_status == BIO_STATUS_ERROR) {
109 		if (bs->bs_msg_count == 0)
110 			errx(1, "unknown error");
111 		else
112 			exit(1);
113 	}
114 }
115 
116 int
117 sr_open_chunk(int devfd, int vol, int disk, struct bioc_disk *bd,
118     char **realdev, char *part)
119 {
120 	int diskfd;
121 
122 	/* Get device name for this disk/chunk. */
123 	memset(bd, 0, sizeof(*bd));
124 	bd->bd_volid = vol;
125 	bd->bd_diskid = disk;
126 	if (ioctl(devfd, BIOCDISK, bd) == -1)
127 		err(1, "BIOCDISK");
128 
129 	/* Check disk status. */
130 	if (bd->bd_status != BIOC_SDONLINE &&
131 	    bd->bd_status != BIOC_SDREBUILD) {
132 		fprintf(stderr, "softraid chunk %u not online - skipping...\n",
133 		    disk);
134 		return -1;
135 	}
136 
137 	/* Keydisks always have a size of zero. */
138 	if (bd->bd_size == 0) {
139 		fprintf(stderr, "softraid chunk %u is keydisk - skipping...\n",
140 		    disk);
141 		return -1;
142 	}
143 
144 	if (strlen(bd->bd_vendor) < 1)
145 		errx(1, "invalid disk name");
146 	*part = bd->bd_vendor[strlen(bd->bd_vendor) - 1];
147 	if (*part < 'a' || *part >= 'a' + MAXPARTITIONS)
148 		errx(1, "invalid partition %c\n", *part);
149 	bd->bd_vendor[strlen(bd->bd_vendor) - 1] = '\0';
150 
151 	/* Open device. */
152 	if ((diskfd = opendev(bd->bd_vendor, (nowrite ? O_RDONLY : O_RDWR),
153 	    OPENDEV_PART, realdev)) == -1)
154 		err(1, "open: %s", *realdev);
155 
156 	return diskfd;
157 }
158