xref: /openbsd/sbin/bioctl/bioctl.c (revision c6446370)
1*c6446370Sjsing /* $OpenBSD: bioctl.c,v 1.85 2009/11/24 02:19:35 jsing Exp $       */
2cf6503d7Sderaadt 
33af9de98Smarco /*
42f39728eSdlg  * Copyright (c) 2004, 2005 Marco Peereboom
53af9de98Smarco  * All rights reserved.
63af9de98Smarco  *
73af9de98Smarco  * Redistribution and use in source and binary forms, with or without
83af9de98Smarco  * modification, are permitted provided that the following conditions
93af9de98Smarco  * are met:
103af9de98Smarco  * 1. Redistributions of source code must retain the above copyright
113af9de98Smarco  *    notice, this list of conditions and the following disclaimer.
123af9de98Smarco  * 2. Redistributions in binary form must reproduce the above copyright
133af9de98Smarco  *    notice, this list of conditions and the following disclaimer in the
143af9de98Smarco  *    documentation and/or other materials provided with the distribution.
153af9de98Smarco  *
163af9de98Smarco  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
173af9de98Smarco  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
183af9de98Smarco  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
193af9de98Smarco  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
203af9de98Smarco  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
213af9de98Smarco  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
223af9de98Smarco  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
233af9de98Smarco  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
243af9de98Smarco  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
253af9de98Smarco  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
263af9de98Smarco  * SUCH DAMAGE.
273af9de98Smarco  *
283af9de98Smarco  */
293af9de98Smarco 
30c2126c9aSmarco #include <sys/ioctl.h>
31c2126c9aSmarco #include <sys/param.h>
32c2126c9aSmarco #include <sys/queue.h>
3346bc198bSmarco #include <sys/types.h>
3446bc198bSmarco #include <sys/stat.h>
35c2126c9aSmarco #include <scsi/scsi_disk.h>
362b69df39Smarco #include <scsi/scsi_all.h>
373af9de98Smarco #include <dev/biovar.h>
38aef7fe28Shshoexer #include <dev/softraidvar.h>
3986735da2Smarco #include <sys/types.h>
4086735da2Smarco #include <sys/stat.h>
413af9de98Smarco 
42db2730c1Smarco #include <errno.h>
43db2730c1Smarco #include <err.h>
44db2730c1Smarco #include <fcntl.h>
458ccdd032Sderaadt #include <util.h>
46db2730c1Smarco #include <stdio.h>
47db2730c1Smarco #include <stdlib.h>
48db2730c1Smarco #include <string.h>
49db2730c1Smarco #include <unistd.h>
50e4e14ad7Sderaadt #include <ctype.h>
51db2730c1Smarco #include <util.h>
5203b2dfbfShenning #include <vis.h>
539e8c6f5bShshoexer #include <readpassphrase.h>
54db2730c1Smarco 
555c1f8f6bSdjm #include "pbkdf2.h"
56aef7fe28Shshoexer 
576de960dcSmarco struct locator {
586de960dcSmarco 	int		channel;
596de960dcSmarco 	int		target;
606de960dcSmarco 	int		lun;
616de960dcSmarco };
626de960dcSmarco 
638ccdd032Sderaadt void			usage(void);
6441eccc89Sderaadt const char 		*str2locator(const char *, struct locator *);
658ccdd032Sderaadt void			cleanup(void);
6646bc198bSmarco int			bio_parse_devlist(char *, dev_t *);
67aef7fe28Shshoexer void			bio_kdf_derive(struct sr_crypto_kdfinfo *,
68*c6446370Sjsing 			    struct sr_crypto_kdf_pbkdf2 *, char *, int);
69aef7fe28Shshoexer void			bio_kdf_generate(struct sr_crypto_kdfinfo *);
709e8c6f5bShshoexer void			derive_key_pkcs(int, u_int8_t *, size_t, u_int8_t *,
71*c6446370Sjsing 			    size_t, char *, int);
728ccdd032Sderaadt 
738ccdd032Sderaadt void			bio_inq(char *);
748ccdd032Sderaadt void			bio_alarm(char *);
75a15048bbSmarco int			bio_getvolbyname(char *);
76a15048bbSmarco void			bio_setstate(char *, int, char *);
77a928c459Sderaadt void			bio_setblink(char *, char *, int);
78a928c459Sderaadt void			bio_blink(char *, int, int);
797195049bSmarco void			bio_createraid(u_int16_t, char *);
80c7c3e8aaSmarco void			bio_deleteraid(char *);
81*c6446370Sjsing void			bio_changepass(char *);
82e8a57fdeSmarco u_int32_t		bio_createflags(char *);
8303b2dfbfShenning char			*bio_vis(char *);
8403b2dfbfShenning void			bio_diskinq(char *);
853af9de98Smarco 
863af9de98Smarco int			devh = -1;
87abe9d68eSderaadt int			human;
88abe9d68eSderaadt int			verbose;
89e8a57fdeSmarco u_int32_t		cflags = 0;
90aedd4f07Sdjm int			rflag = 8192;
9186735da2Smarco char			*password;
923af9de98Smarco 
933af9de98Smarco struct bio_locate	bl;
943af9de98Smarco 
953af9de98Smarco int
963af9de98Smarco main(int argc, char *argv[])
973af9de98Smarco {
983af9de98Smarco 	extern char		*optarg;
99db2730c1Smarco 	u_int64_t		func = 0;
100db2730c1Smarco 	/* u_int64_t subfunc = 0; */
101cf6503d7Sderaadt 	char			*bioc_dev = NULL, *sd_dev = NULL;
102cf6503d7Sderaadt 	char			*realname = NULL, *al_arg = NULL;
1037195049bSmarco 	char			*bl_arg = NULL, *dev_list = NULL;
104aedd4f07Sdjm 	const char		*errstr;
105*c6446370Sjsing 	int			ch, rv, blink = 0, changepass = 0, diskinq = 0;
106*c6446370Sjsing 	int			ss_func = 0;
1079ecba717Sderaadt 	u_int16_t		cr_level = 0;
1083af9de98Smarco 
1093af9de98Smarco 	if (argc < 2)
1103af9de98Smarco 		usage();
1113af9de98Smarco 
112*c6446370Sjsing 	while ((ch = getopt(argc, argv, "a:b:C:c:dH:hil:Pp:qr:R:vu:")) !=
113*c6446370Sjsing 	    -1) {
1143af9de98Smarco 		switch (ch) {
115edfd9792Smarco 		case 'a': /* alarm */
116edfd9792Smarco 			func |= BIOC_ALARM;
117edfd9792Smarco 			al_arg = optarg;
118edfd9792Smarco 			break;
119c55617f1Sdlg 		case 'b': /* blink */
120c55617f1Sdlg 			func |= BIOC_BLINK;
121a928c459Sderaadt 			blink = BIOC_SBBLINK;
122a928c459Sderaadt 			bl_arg = optarg;
123a928c459Sderaadt 			break;
124e8a57fdeSmarco 		case 'C': /* creation flags */
125e8a57fdeSmarco 			cflags = bio_createflags(optarg);
126e8a57fdeSmarco 			break;
1277195049bSmarco 		case 'c': /* create */
1287195049bSmarco 			func |= BIOC_CREATERAID;
12998b750e4Stedu 			if (isdigit(*optarg))
1307195049bSmarco 				cr_level = atoi(optarg);
13198b750e4Stedu 			else
13298b750e4Stedu 				cr_level = *optarg;
1337195049bSmarco 			break;
134c7c3e8aaSmarco 		case 'd':
135c7c3e8aaSmarco 			/* delete volume */
136c7c3e8aaSmarco 			func |= BIOC_DELETERAID;
137c7c3e8aaSmarco 			break;
138a928c459Sderaadt 		case 'u': /* unblink */
139a928c459Sderaadt 			func |= BIOC_BLINK;
140a928c459Sderaadt 			blink = BIOC_SBUNBLINK;
141c55617f1Sdlg 			bl_arg = optarg;
142c55617f1Sdlg 			break;
1436de960dcSmarco 		case 'H': /* set hotspare */
1446de960dcSmarco 			func |= BIOC_SETSTATE;
145a15048bbSmarco 			ss_func = BIOC_SSHOTSPARE;
1466de960dcSmarco 			al_arg = optarg;
1476de960dcSmarco 			break;
1488ccdd032Sderaadt 		case 'h':
1498ccdd032Sderaadt 			human = 1;
1508ccdd032Sderaadt 			break;
151db2730c1Smarco 		case 'i': /* inquiry */
152db2730c1Smarco 			func |= BIOC_INQ;
1533af9de98Smarco 			break;
1547195049bSmarco 		case 'l': /* device list */
1557195049bSmarco 			func |= BIOC_DEVLIST;
1567195049bSmarco 			dev_list = optarg;
1577195049bSmarco 			break;
158*c6446370Sjsing 		case 'P':
159*c6446370Sjsing 			/* Change passphrase. */
160*c6446370Sjsing 			changepass = 1;
161*c6446370Sjsing 			break;
16286735da2Smarco 		case 'p':
16386735da2Smarco 			password = optarg;
16486735da2Smarco 			break;
165aedd4f07Sdjm 		case 'r':
166aedd4f07Sdjm 			rflag = strtonum(optarg, 1000, 1<<30, &errstr);
167aedd4f07Sdjm 			if (errstr != NULL)
168aedd4f07Sdjm 				errx(1, "Number of rounds is %s: %s",
169aedd4f07Sdjm 				    errstr, optarg);
170aedd4f07Sdjm 			break;
171a15048bbSmarco 		case 'R':
172a15048bbSmarco 			/* rebuild to provided chunk/CTL */
173a15048bbSmarco 			func |= BIOC_SETSTATE;
174a15048bbSmarco 			ss_func = BIOC_SSREBUILD;
175a15048bbSmarco 			al_arg = optarg;
176a15048bbSmarco 			break;
177abe9d68eSderaadt 		case 'v':
178abe9d68eSderaadt 			verbose = 1;
179abe9d68eSderaadt 			break;
18003b2dfbfShenning 		case 'q':
18103b2dfbfShenning 			diskinq = 1;
18203b2dfbfShenning 			break;
1833af9de98Smarco 		default:
1843af9de98Smarco 			usage();
1853af9de98Smarco 			/* NOTREACHED */
1863af9de98Smarco 		}
1873af9de98Smarco 	}
188cf6503d7Sderaadt 	argc -= optind;
189cf6503d7Sderaadt 	argv += optind;
1903af9de98Smarco 
191*c6446370Sjsing 	if (argc != 1 || (changepass && func != 0))
192cf6503d7Sderaadt 		usage();
193cf6503d7Sderaadt 
194dcbaf4c8Sderaadt 	if (func == 0)
195dcbaf4c8Sderaadt 		func |= BIOC_INQ;
196dcbaf4c8Sderaadt 
197e4e14ad7Sderaadt 	/* if at least glob sd[0-9]*, it is a drive identifier */
198e4e14ad7Sderaadt 	if (strncmp(argv[0], "sd", 2) == 0 && strlen(argv[0]) > 2 &&
199e4e14ad7Sderaadt 	    isdigit(argv[0][2]))
200cf6503d7Sderaadt 		sd_dev = argv[0];
201cf6503d7Sderaadt 	else
202cf6503d7Sderaadt 		bioc_dev = argv[0];
20310b411a7Smarco 
20410b411a7Smarco 	if (bioc_dev) {
20541eccc89Sderaadt 		devh = open("/dev/bio", O_RDWR);
2063af9de98Smarco 		if (devh == -1)
20741eccc89Sderaadt 			err(1, "Can't open %s", "/dev/bio");
2083af9de98Smarco 
2098ccdd032Sderaadt 		bl.bl_name = bioc_dev;
2103af9de98Smarco 		rv = ioctl(devh, BIOCLOCATE, &bl);
2113af9de98Smarco 		if (rv == -1)
21210b411a7Smarco 			errx(1, "Can't locate %s device via %s",
21341eccc89Sderaadt 			    bl.bl_name, "/dev/bio");
214db2730c1Smarco 	} else if (sd_dev) {
21510b411a7Smarco 		devh = opendev(sd_dev, O_RDWR, OPENDEV_PART, &realname);
21610b411a7Smarco 		if (devh == -1)
21710b411a7Smarco 			err(1, "Can't open %s", sd_dev);
218db2730c1Smarco 	} else
21986735da2Smarco 		errx(1, "need device");
2203af9de98Smarco 
22103b2dfbfShenning 	if (diskinq) {
22203b2dfbfShenning 		bio_diskinq(sd_dev);
223*c6446370Sjsing 	} else if (changepass && sd_dev != NULL) {
224*c6446370Sjsing 		bio_changepass(sd_dev);
22503b2dfbfShenning 	} else if (func & BIOC_INQ) {
2268ccdd032Sderaadt 		bio_inq(sd_dev);
227edfd9792Smarco 	} else if (func == BIOC_ALARM) {
228edfd9792Smarco 		bio_alarm(al_arg);
229c55617f1Sdlg 	} else if (func == BIOC_BLINK) {
230a928c459Sderaadt 		bio_setblink(sd_dev, bl_arg, blink);
2316de960dcSmarco 	} else if (func == BIOC_SETSTATE) {
232a15048bbSmarco 		bio_setstate(al_arg, ss_func, argv[0]);
233c7c3e8aaSmarco 	} else if (func == BIOC_DELETERAID && sd_dev != NULL) {
234c7c3e8aaSmarco 		bio_deleteraid(sd_dev);
2357195049bSmarco 	} else if (func & BIOC_CREATERAID || func & BIOC_DEVLIST) {
2367195049bSmarco 		if (!(func & BIOC_CREATERAID))
2377195049bSmarco 			errx(1, "need -c parameter");
2387195049bSmarco 		if (!(func & BIOC_DEVLIST))
2397195049bSmarco 			errx(1, "need -l parameter");
2407195049bSmarco 		if (sd_dev)
2417195049bSmarco 			errx(1, "can't use sd device");
2427195049bSmarco 		bio_createraid(cr_level, dev_list);
2433af9de98Smarco 	}
2443af9de98Smarco 
2453af9de98Smarco 	return (0);
2463af9de98Smarco }
2473af9de98Smarco 
2483af9de98Smarco void
2493af9de98Smarco usage(void)
2503af9de98Smarco {
2513af9de98Smarco 	extern char		*__progname;
2523af9de98Smarco 
253d90b5d8bSjmc 	fprintf(stderr,
254d0b772c8Sjmc 		"usage: %s [-hiqv] [-a alarm-function] "
255d90b5d8bSjmc 		"[-b channel:target[.lun]]\n"
256d0b772c8Sjmc 		"\t[-H channel:target[.lun]] "
257d0b772c8Sjmc 		"[-R device | channel:target[.lun]\n"
258d0b772c8Sjmc 		"\t[-u channel:target[.lun]] "
259d0b772c8Sjmc 		"device\n"
260*c6446370Sjsing                 "       %s [-Pdhiqv] "
261d0b772c8Sjmc                 "[-C flag[,flag,...]] [-c raidlevel]\n"
26278702060Sjmc                 "\t[-l special[,special,...]] [-p passfile]\n"
26378702060Sjmc                 "\t[-R device | channel:target[.lun] [-r rounds] "
264d0b772c8Sjmc 		"device\n", __progname, __progname);
265d90b5d8bSjmc 
2663af9de98Smarco 	exit(1);
2673af9de98Smarco }
2683af9de98Smarco 
26941eccc89Sderaadt const char *
2706de960dcSmarco str2locator(const char *string, struct locator *location)
2716de960dcSmarco {
27250d3c4dcSdlg 	const char		*errstr;
27341eccc89Sderaadt 	char			parse[80], *targ, *lun;
2746de960dcSmarco 
27541eccc89Sderaadt 	strlcpy(parse, string, sizeof parse);
27641eccc89Sderaadt 	targ = strchr(parse, ':');
2776de960dcSmarco 	if (targ == NULL)
27841eccc89Sderaadt 		return ("target not specified");
2796de960dcSmarco 	*targ++ = '\0';
2806de960dcSmarco 
28150d3c4dcSdlg 	lun = strchr(targ, '.');
2826de960dcSmarco 	if (lun != NULL) {
2836de960dcSmarco 		*lun++ = '\0';
28450d3c4dcSdlg 		location->lun = strtonum(lun, 0, 256, &errstr);
28550d3c4dcSdlg 		if (errstr)
28641eccc89Sderaadt 			return (errstr);
2876de960dcSmarco 	} else
2886de960dcSmarco 		location->lun = 0;
2896de960dcSmarco 
29050d3c4dcSdlg 	location->target = strtonum(targ, 0, 256, &errstr);
29150d3c4dcSdlg 	if (errstr)
29241eccc89Sderaadt 		return (errstr);
29341eccc89Sderaadt 	location->channel = strtonum(parse, 0, 256, &errstr);
29450d3c4dcSdlg 	if (errstr)
29541eccc89Sderaadt 		return (errstr);
29641eccc89Sderaadt 	return (NULL);
2976de960dcSmarco }
2986de960dcSmarco 
2993af9de98Smarco void
3008ccdd032Sderaadt bio_inq(char *name)
301d4546a56Sdlg {
3029017fb97Sderaadt 	char 			*status, size[64], scsiname[16], volname[32];
303a4d3c4a2Sderaadt 	char			percent[10], seconds[20];
304b9950701Smarco 	int			rv, i, d, volheader, hotspare, unused;
305aa65acf1Sderaadt 	char			encname[16], serial[32];
3068ccdd032Sderaadt 	struct bioc_disk	bd;
3078ccdd032Sderaadt 	struct bioc_inq		bi;
3088ccdd032Sderaadt 	struct bioc_vol		bv;
309db2730c1Smarco 
310db2730c1Smarco 	memset(&bi, 0, sizeof(bi));
3113af9de98Smarco 
3128ccdd032Sderaadt 	bi.bi_cookie = bl.bl_cookie;
3133af9de98Smarco 
314db2730c1Smarco 	rv = ioctl(devh, BIOCINQ, &bi);
3153af9de98Smarco 	if (rv == -1) {
31603b2dfbfShenning 		if (errno == ENOTTY)
31703b2dfbfShenning 			bio_diskinq(name);
31803b2dfbfShenning 		else
319da3b0664Shenning 			err(1, "BIOCINQ");
3203af9de98Smarco 		return;
3213af9de98Smarco 	}
3223af9de98Smarco 
3238ccdd032Sderaadt 	volheader = 0;
3248ccdd032Sderaadt 	for (i = 0; i < bi.bi_novol; i++) {
325db2730c1Smarco 		memset(&bv, 0, sizeof(bv));
3268ccdd032Sderaadt 		bv.bv_cookie = bl.bl_cookie;
3278ccdd032Sderaadt 		bv.bv_volid = i;
3280a92ff65Sderaadt 		bv.bv_percent = -1;
3299017fb97Sderaadt 		bv.bv_seconds = 0;
33070a2ae7bSmarco 
331db2730c1Smarco 		rv = ioctl(devh, BIOCVOL, &bv);
332da3b0664Shenning 		if (rv == -1)
333da3b0664Shenning 			err(1, "BIOCVOL");
3343af9de98Smarco 
3358ccdd032Sderaadt 		if (name && strcmp(name, bv.bv_dev) != 0)
3368ccdd032Sderaadt 			continue;
3378ccdd032Sderaadt 
3388ccdd032Sderaadt 		if (!volheader) {
3398ccdd032Sderaadt 			volheader = 1;
340c9377e3bSmickey 			printf("%-7s %-10s %14s %-8s\n",
3418ccdd032Sderaadt 			    "Volume", "Status", "Size", "Device");
3428ccdd032Sderaadt 		}
3438ccdd032Sderaadt 
3440a92ff65Sderaadt 		percent[0] = '\0';
3459017fb97Sderaadt 		seconds[0] = '\0';
3460a92ff65Sderaadt 		if (bv.bv_percent != -1)
3470a92ff65Sderaadt 			snprintf(percent, sizeof percent,
3480a92ff65Sderaadt 			    " %d%% done", bv.bv_percent);
3499017fb97Sderaadt 		if (bv.bv_seconds)
3509017fb97Sderaadt 			snprintf(seconds, sizeof seconds,
3519017fb97Sderaadt 			    " %u seconds", bv.bv_seconds);
3528ccdd032Sderaadt 		switch (bv.bv_status) {
353db2730c1Smarco 		case BIOC_SVONLINE:
3548ccdd032Sderaadt 			status = BIOC_SVONLINE_S;
355db2730c1Smarco 			break;
356db2730c1Smarco 		case BIOC_SVOFFLINE:
3578ccdd032Sderaadt 			status = BIOC_SVOFFLINE_S;
358db2730c1Smarco 			break;
359db2730c1Smarco 		case BIOC_SVDEGRADED:
3608ccdd032Sderaadt 			status = BIOC_SVDEGRADED_S;
361db2730c1Smarco 			break;
3620a92ff65Sderaadt 		case BIOC_SVBUILDING:
3630a92ff65Sderaadt 			status = BIOC_SVBUILDING_S;
3640a92ff65Sderaadt 			break;
3650a92ff65Sderaadt 		case BIOC_SVREBUILD:
3660a92ff65Sderaadt 			status = BIOC_SVREBUILD_S;
3670a92ff65Sderaadt 			break;
3680a92ff65Sderaadt 		case BIOC_SVSCRUB:
3690a92ff65Sderaadt 			status = BIOC_SVSCRUB_S;
3700a92ff65Sderaadt 			break;
371db2730c1Smarco 		case BIOC_SVINVALID:
372db2730c1Smarco 		default:
3738ccdd032Sderaadt 			status = BIOC_SVINVALID_S;
374d4546a56Sdlg 		}
3753af9de98Smarco 
376aa65acf1Sderaadt 		snprintf(volname, sizeof volname, "%s %u",
3778ccdd032Sderaadt 		    bi.bi_dev, bv.bv_volid);
378b9950701Smarco 
3799ecba717Sderaadt 		unused = 0;
3809ecba717Sderaadt 		hotspare = 0;
381aa65acf1Sderaadt 		if (bv.bv_level == -1 && bv.bv_nodisk == 1)
382aa65acf1Sderaadt 			hotspare = 1;
383b9950701Smarco 		else if (bv.bv_level == -2 && bv.bv_nodisk == 1)
384b9950701Smarco 			unused = 1;
385aa65acf1Sderaadt 		else {
3868ccdd032Sderaadt 			if (human)
3878ccdd032Sderaadt 				fmt_scaled(bv.bv_size, size);
3888ccdd032Sderaadt 			else
3898ccdd032Sderaadt 				snprintf(size, sizeof size, "%14llu",
3908ccdd032Sderaadt 				    bv.bv_size);
391da935596Stodd 			switch (bv.bv_level) {
392da935596Stodd 			case 'C':
393da935596Stodd 				printf("%7s %-10s %14s %-7s CRYPTO%s%s\n",
394da935596Stodd 				    volname, status, size, bv.bv_dev,
395da935596Stodd 				    percent, seconds);
396da935596Stodd 				break;
397da935596Stodd 			default:
3989017fb97Sderaadt 				printf("%7s %-10s %14s %-7s RAID%u%s%s\n",
3990a92ff65Sderaadt 				    volname, status, size, bv.bv_dev,
4009017fb97Sderaadt 				    bv.bv_level, percent, seconds);
401da935596Stodd 				break;
402da935596Stodd 			}
403da935596Stodd 
404aa65acf1Sderaadt 		}
4058ccdd032Sderaadt 
4068ccdd032Sderaadt 		for (d = 0; d < bv.bv_nodisk; d++) {
407db2730c1Smarco 			memset(&bd, 0, sizeof(bd));
4088ccdd032Sderaadt 			bd.bd_cookie = bl.bl_cookie;
4098ccdd032Sderaadt 			bd.bd_diskid = d;
4108ccdd032Sderaadt 			bd.bd_volid = i;
4113af9de98Smarco 
412db2730c1Smarco 			rv = ioctl(devh, BIOCDISK, &bd);
413da3b0664Shenning 			if (rv == -1)
414da3b0664Shenning 				err(1, "BIOCDISK");
4153af9de98Smarco 
4168ccdd032Sderaadt 			switch (bd.bd_status) {
417db2730c1Smarco 			case BIOC_SDONLINE:
4188ccdd032Sderaadt 				status = BIOC_SDONLINE_S;
419d4546a56Sdlg 				break;
420db2730c1Smarco 			case BIOC_SDOFFLINE:
4218ccdd032Sderaadt 				status = BIOC_SDOFFLINE_S;
422d4546a56Sdlg 				break;
423db2730c1Smarco 			case BIOC_SDFAILED:
4248ccdd032Sderaadt 				status = BIOC_SDFAILED_S;
425db2730c1Smarco 				break;
426db2730c1Smarco 			case BIOC_SDREBUILD:
4278ccdd032Sderaadt 				status = BIOC_SDREBUILD_S;
428db2730c1Smarco 				break;
429db2730c1Smarco 			case BIOC_SDHOTSPARE:
4308ccdd032Sderaadt 				status = BIOC_SDHOTSPARE_S;
431db2730c1Smarco 				break;
432db2730c1Smarco 			case BIOC_SDUNUSED:
4338ccdd032Sderaadt 				status = BIOC_SDUNUSED_S;
434db2730c1Smarco 				break;
435e1dfb373Sderaadt 			case BIOC_SDSCRUB:
436e1dfb373Sderaadt 				status = BIOC_SDSCRUB_S;
437e1dfb373Sderaadt 				break;
438db2730c1Smarco 			case BIOC_SDINVALID:
439d4546a56Sdlg 			default:
4408ccdd032Sderaadt 				status = BIOC_SDINVALID_S;
441d4546a56Sdlg 			}
442aa65acf1Sderaadt 
443b9950701Smarco 			if (hotspare || unused)
444aa65acf1Sderaadt 				;	/* use volname from parent volume */
445aa65acf1Sderaadt 			else
446aa65acf1Sderaadt 				snprintf(volname, sizeof volname, "    %3u",
447aa65acf1Sderaadt 				    bd.bd_diskid);
448aa65acf1Sderaadt 
4498ccdd032Sderaadt 			if (human)
4508ccdd032Sderaadt 				fmt_scaled(bd.bd_size, size);
4518ccdd032Sderaadt 			else
4528ccdd032Sderaadt 				snprintf(size, sizeof size, "%14llu",
4538ccdd032Sderaadt 				    bd.bd_size);
4548ccdd032Sderaadt 			snprintf(scsiname, sizeof scsiname,
45543d61178Sderaadt 			    "%u:%u.%u",
45643d61178Sderaadt 			    bd.bd_channel, bd.bd_target, bd.bd_lun);
4575978b28dSderaadt 			if (bd.bd_procdev[0])
458abe9d68eSderaadt 				strlcpy(encname, bd.bd_procdev, sizeof encname);
4595978b28dSderaadt 			else
460abe9d68eSderaadt 				strlcpy(encname, "noencl", sizeof encname);
461abe9d68eSderaadt 			if (bd.bd_serial[0])
462abe9d68eSderaadt 				strlcpy(serial, bd.bd_serial, sizeof serial);
463abe9d68eSderaadt 			else
464abe9d68eSderaadt 				strlcpy(serial, "unknown serial", sizeof serial);
4658ccdd032Sderaadt 
466aa65acf1Sderaadt 			printf("%7s %-10s %14s %-7s %-6s <%s>\n",
467aa65acf1Sderaadt 			    volname, status, size, scsiname, encname,
4688ccdd032Sderaadt 			    bd.bd_vendor);
469abe9d68eSderaadt 			if (verbose)
470aa65acf1Sderaadt 				printf("%7s %-10s %14s %-7s %-6s '%s'\n",
471abe9d68eSderaadt 				    "", "", "", "", "", serial);
472d4546a56Sdlg 		}
473d4546a56Sdlg 	}
474d4546a56Sdlg }
475edfd9792Smarco 
476edfd9792Smarco void
477edfd9792Smarco bio_alarm(char *arg)
478edfd9792Smarco {
479edfd9792Smarco 	int			rv;
4808ccdd032Sderaadt 	struct bioc_alarm	ba;
481edfd9792Smarco 
4828ccdd032Sderaadt 	ba.ba_cookie = bl.bl_cookie;
483edfd9792Smarco 
484edfd9792Smarco 	switch (arg[0]) {
485edfd9792Smarco 	case 'q': /* silence alarm */
486edfd9792Smarco 		/* FALLTHROUGH */
487edfd9792Smarco 	case 's':
4888ccdd032Sderaadt 		ba.ba_opcode = BIOC_SASILENCE;
489edfd9792Smarco 		break;
490edfd9792Smarco 
491edfd9792Smarco 	case 'e': /* enable alarm */
4928ccdd032Sderaadt 		ba.ba_opcode = BIOC_SAENABLE;
493edfd9792Smarco 		break;
494edfd9792Smarco 
495edfd9792Smarco 	case 'd': /* disable alarm */
4968ccdd032Sderaadt 		ba.ba_opcode = BIOC_SADISABLE;
497edfd9792Smarco 		break;
498edfd9792Smarco 
499edfd9792Smarco 	case 't': /* test alarm */
5008ccdd032Sderaadt 		ba.ba_opcode = BIOC_SATEST;
501edfd9792Smarco 		break;
502edfd9792Smarco 
503edfd9792Smarco 	case 'g': /* get alarm state */
5048ccdd032Sderaadt 		ba.ba_opcode = BIOC_GASTATUS;
505edfd9792Smarco 		break;
506edfd9792Smarco 
507edfd9792Smarco 	default:
508da3b0664Shenning 		errx(1, "invalid alarm function: %s", arg);
509edfd9792Smarco 	}
510edfd9792Smarco 
511edfd9792Smarco 	rv = ioctl(devh, BIOCALARM, &ba);
512da3b0664Shenning 	if (rv == -1)
513da3b0664Shenning 		err(1, "BIOCALARM");
514edfd9792Smarco 
515edfd9792Smarco 	if (arg[0] == 'g') {
516edfd9792Smarco 		printf("alarm is currently %s\n",
5178ccdd032Sderaadt 		    ba.ba_status ? "enabled" : "disabled");
5188ccdd032Sderaadt 
519edfd9792Smarco 	}
520edfd9792Smarco }
5216de960dcSmarco 
522a15048bbSmarco int
523a15048bbSmarco bio_getvolbyname(char *name)
524a15048bbSmarco {
525a15048bbSmarco 	int			id = -1, i, rv;
526a15048bbSmarco 	struct bioc_inq		bi;
527a15048bbSmarco 	struct bioc_vol		bv;
528a15048bbSmarco 
529a15048bbSmarco 	memset(&bi, 0, sizeof(bi));
530a15048bbSmarco 	bi.bi_cookie = bl.bl_cookie;
531a15048bbSmarco 	rv = ioctl(devh, BIOCINQ, &bi);
532a15048bbSmarco 	if (rv == -1)
533a15048bbSmarco 		err(1, "BIOCINQ");
534a15048bbSmarco 
535a15048bbSmarco 	for (i = 0; i < bi.bi_novol; i++) {
536a15048bbSmarco 		memset(&bv, 0, sizeof(bv));
537a15048bbSmarco 		bv.bv_cookie = bl.bl_cookie;
538a15048bbSmarco 		bv.bv_volid = i;
539a15048bbSmarco 		rv = ioctl(devh, BIOCVOL, &bv);
540a15048bbSmarco 		if (rv == -1)
541a15048bbSmarco 			err(1, "BIOCVOL");
542a15048bbSmarco 
543a15048bbSmarco 		if (name && strcmp(name, bv.bv_dev) != 0)
544a15048bbSmarco 			continue;
545a15048bbSmarco 		id = i;
546a15048bbSmarco 		break;
547a15048bbSmarco 	}
548a15048bbSmarco 
549a15048bbSmarco 	return (id);
550a15048bbSmarco }
551a15048bbSmarco 
552ebaf584eSderaadt void
5538d8693a2Sdtucker bio_setstate(char *arg, int status, char *devicename)
5546de960dcSmarco {
5556de960dcSmarco 	struct bioc_setstate	bs;
5566de960dcSmarco 	struct locator		location;
557a15048bbSmarco 	struct stat		sb;
55841eccc89Sderaadt 	const char		*errstr;
559ebaf584eSderaadt 	int			rv;
5606de960dcSmarco 
561a15048bbSmarco 	memset(&bs, 0, sizeof(bs));
562a15048bbSmarco 	if (stat(arg, &sb) == -1) {
563a15048bbSmarco 		/* use CTL */
56441eccc89Sderaadt 		errstr = str2locator(arg, &location);
56541eccc89Sderaadt 		if (errstr)
56641eccc89Sderaadt 			errx(1, "Target %s: %s", arg, errstr);
5676de960dcSmarco 		bs.bs_channel = location.channel;
5686de960dcSmarco 		bs.bs_target = location.target;
5696de960dcSmarco 		bs.bs_lun = location.lun;
570a15048bbSmarco 	} else {
571a15048bbSmarco 		/* use other id */
572a15048bbSmarco 		bs.bs_other_id = sb.st_rdev;
573a15048bbSmarco 		bs.bs_other_id_type = BIOC_SSOTHER_DEVT;
574a15048bbSmarco 	}
575a15048bbSmarco 
576a15048bbSmarco 	bs.bs_cookie = bl.bl_cookie;
577a15048bbSmarco 	bs.bs_status = status;
578a15048bbSmarco 
579d2647ac1Sjsing 	if (status != BIOC_SSHOTSPARE) {
580a15048bbSmarco 		/* make sure user supplied a sd device */
5818d8693a2Sdtucker 		bs.bs_volid = bio_getvolbyname(devicename);
582a15048bbSmarco 		if (bs.bs_volid == -1)
5838d8693a2Sdtucker 			errx(1, "invalid device %s", devicename);
584d2647ac1Sjsing 	}
5856de960dcSmarco 
5866de960dcSmarco 	rv = ioctl(devh, BIOCSETSTATE, &bs);
587da3b0664Shenning 	if (rv == -1)
588da3b0664Shenning 		err(1, "BIOCSETSTATE");
5896de960dcSmarco }
590c55617f1Sdlg 
591c55617f1Sdlg void
592a928c459Sderaadt bio_setblink(char *name, char *arg, int blink)
593c55617f1Sdlg {
59450d3c4dcSdlg 	struct locator		location;
59550d3c4dcSdlg 	struct bioc_inq		bi;
59650d3c4dcSdlg 	struct bioc_vol		bv;
59750d3c4dcSdlg 	struct bioc_disk	bd;
5980505205bSdlg 	struct bioc_blink	bb;
59941eccc89Sderaadt 	const char		*errstr;
60050d3c4dcSdlg 	int			v, d, rv;
601c55617f1Sdlg 
60241eccc89Sderaadt 	errstr = str2locator(arg, &location);
60341eccc89Sderaadt 	if (errstr)
60441eccc89Sderaadt 		errx(1, "Target %s: %s", arg, errstr);
60550d3c4dcSdlg 
6060505205bSdlg 	/* try setting blink on the device directly */
6070505205bSdlg 	memset(&bb, 0, sizeof(bb));
6080505205bSdlg 	bb.bb_cookie = bl.bl_cookie;
6090505205bSdlg 	bb.bb_status = blink;
6100505205bSdlg 	bb.bb_target = location.target;
611649724a4Smarco 	bb.bb_channel = location.channel;
6120505205bSdlg 	rv = ioctl(devh, BIOCBLINK, &bb);
6130505205bSdlg 	if (rv == 0)
6140505205bSdlg 		return;
6150505205bSdlg 
6160505205bSdlg 	/* if the blink didnt work, try to find something that will */
6170505205bSdlg 
61850d3c4dcSdlg 	memset(&bi, 0, sizeof(bi));
61950d3c4dcSdlg 	bi.bi_cookie = bl.bl_cookie;
62050d3c4dcSdlg 	rv = ioctl(devh, BIOCINQ, &bi);
621da3b0664Shenning 	if (rv == -1)
622da3b0664Shenning 		err(1, "BIOCINQ");
62350d3c4dcSdlg 
62450d3c4dcSdlg 	for (v = 0; v < bi.bi_novol; v++) {
62550d3c4dcSdlg 		memset(&bv, 0, sizeof(bv));
62650d3c4dcSdlg 		bv.bv_cookie = bl.bl_cookie;
62750d3c4dcSdlg 		bv.bv_volid = v;
62850d3c4dcSdlg 		rv = ioctl(devh, BIOCVOL, &bv);
629da3b0664Shenning 		if (rv == -1)
630da3b0664Shenning 			err(1, "BIOCVOL");
63150d3c4dcSdlg 
63250d3c4dcSdlg 		if (name && strcmp(name, bv.bv_dev) != 0)
63350d3c4dcSdlg 			continue;
63450d3c4dcSdlg 
63550d3c4dcSdlg 		for (d = 0; d < bv.bv_nodisk; d++) {
63650d3c4dcSdlg 			memset(&bd, 0, sizeof(bd));
63750d3c4dcSdlg 			bd.bd_cookie = bl.bl_cookie;
63850d3c4dcSdlg 			bd.bd_volid = v;
63950d3c4dcSdlg 			bd.bd_diskid = d;
64050d3c4dcSdlg 
64150d3c4dcSdlg 			rv = ioctl(devh, BIOCDISK, &bd);
642da3b0664Shenning 			if (rv == -1)
643da3b0664Shenning 				err(1, "BIOCDISK");
64450d3c4dcSdlg 
64550d3c4dcSdlg 			if (bd.bd_channel == location.channel &&
64650d3c4dcSdlg 			    bd.bd_target == location.target &&
64750d3c4dcSdlg 			    bd.bd_lun == location.lun) {
64850d3c4dcSdlg 				if (bd.bd_procdev[0] != '\0') {
64950d3c4dcSdlg 					bio_blink(bd.bd_procdev,
650a928c459Sderaadt 					    location.target, blink);
65150d3c4dcSdlg 				} else
65241eccc89Sderaadt 					warnx("Disk %s is not in an enclosure", arg);
65350d3c4dcSdlg 				return;
65450d3c4dcSdlg 			}
65550d3c4dcSdlg 		}
65650d3c4dcSdlg 	}
65750d3c4dcSdlg 
65841eccc89Sderaadt 	warnx("Disk %s does not exist", arg);
65950d3c4dcSdlg 	return;
66050d3c4dcSdlg }
66150d3c4dcSdlg 
66250d3c4dcSdlg void
663a928c459Sderaadt bio_blink(char *enclosure, int target, int blinktype)
66450d3c4dcSdlg {
66550d3c4dcSdlg 	int			bioh;
66650d3c4dcSdlg 	struct bio_locate	bio;
66750d3c4dcSdlg 	struct bioc_blink	blink;
66850d3c4dcSdlg 	int			rv;
66950d3c4dcSdlg 
67041eccc89Sderaadt 	bioh = open("/dev/bio", O_RDWR);
67150d3c4dcSdlg 	if (bioh == -1)
67241eccc89Sderaadt 		err(1, "Can't open %s", "/dev/bio");
67350d3c4dcSdlg 
67450d3c4dcSdlg 	bio.bl_name = enclosure;
67550d3c4dcSdlg 	rv = ioctl(bioh, BIOCLOCATE, &bio);
67650d3c4dcSdlg 	if (rv == -1)
67741eccc89Sderaadt 		errx(1, "Can't locate %s device via %s", enclosure, "/dev/bio");
678c55617f1Sdlg 
679c55617f1Sdlg 	memset(&blink, 0, sizeof(blink));
68050d3c4dcSdlg 	blink.bb_cookie = bio.bl_cookie;
681a928c459Sderaadt 	blink.bb_status = blinktype;
682c55617f1Sdlg 	blink.bb_target = target;
683c55617f1Sdlg 
68450d3c4dcSdlg 	rv = ioctl(bioh, BIOCBLINK, &blink);
685c55617f1Sdlg 	if (rv == -1)
686da3b0664Shenning 		err(1, "BIOCBLINK");
68750d3c4dcSdlg 
68850d3c4dcSdlg 	close(bioh);
689c55617f1Sdlg }
6907195049bSmarco 
6917195049bSmarco void
6927195049bSmarco bio_createraid(u_int16_t level, char *dev_list)
6937195049bSmarco {
6947195049bSmarco 	struct bioc_createraid	create;
695aef7fe28Shshoexer 	struct sr_crypto_kdfinfo kdfinfo;
696aef7fe28Shshoexer 	struct sr_crypto_kdf_pbkdf2 kdfhint;
69746bc198bSmarco 	int			rv, no_dev;
69846bc198bSmarco 	dev_t			*dt;
6997195049bSmarco 	u_int16_t		min_disks = 0;
7007195049bSmarco 
7017195049bSmarco 	if (!dev_list)
7027195049bSmarco 		errx(1, "no devices specified");
7037195049bSmarco 
70446bc198bSmarco 	dt = (dev_t *)malloc(BIOC_CRMAXLEN);
70546bc198bSmarco 	if (!dt)
70646bc198bSmarco 		err(1, "not enough memory for dev_t list");
70746bc198bSmarco 	memset(dt, 0, BIOC_CRMAXLEN);
70846bc198bSmarco 
70946bc198bSmarco 	no_dev = bio_parse_devlist(dev_list, dt);
71046bc198bSmarco 
7117195049bSmarco 	switch (level) {
7127195049bSmarco 	case 0:
71384e48fabSmarco 		min_disks = 2;
7147195049bSmarco 		break;
7157195049bSmarco 	case 1:
7167195049bSmarco 		min_disks = 2;
7177195049bSmarco 		break;
718e717853eSmarco 	case 4:
719e717853eSmarco 	case 5:
720e717853eSmarco 		min_disks = 3;
721e717853eSmarco 		break;
72284e48fabSmarco 	case 'C':
723aef7fe28Shshoexer 		min_disks = 1;
72484e48fabSmarco 		break;
72598b750e4Stedu 	case 'c':
72698b750e4Stedu 		min_disks = 1;
72798b750e4Stedu 		break;
7287195049bSmarco 	default:
72923afedbfSgrunk 		errx(1, "unsupported raid level");
7307195049bSmarco 	}
7317195049bSmarco 
73284e48fabSmarco 	if (no_dev < min_disks)
73384e48fabSmarco 		errx(1, "not enough disks");
73484e48fabSmarco 
735aef7fe28Shshoexer 	/* for crypto raid we only allow one single chunk */
736aef7fe28Shshoexer 	if (level == 'C' && no_dev != min_disks)
737818b0595Shalex 		errx(1, "not exactly one partition");
738aef7fe28Shshoexer 
7397195049bSmarco 	memset(&create, 0, sizeof(create));
7407195049bSmarco 	create.bc_cookie = bl.bl_cookie;
7417195049bSmarco 	create.bc_level = level;
74246bc198bSmarco 	create.bc_dev_list_len = no_dev * sizeof(dev_t);
74346bc198bSmarco 	create.bc_dev_list = dt;
744e8a57fdeSmarco 	create.bc_flags = BIOC_SCDEVT | cflags;
7457195049bSmarco 
746aef7fe28Shshoexer 	if (level == 'C') {
747aef7fe28Shshoexer 		memset(&kdfinfo, 0, sizeof(kdfinfo));
748aef7fe28Shshoexer 		memset(&kdfhint, 0, sizeof(kdfhint));
749aef7fe28Shshoexer 
750aef7fe28Shshoexer 		create.bc_opaque = &kdfhint;
751aef7fe28Shshoexer 		create.bc_opaque_size = sizeof(kdfhint);
752aef7fe28Shshoexer 		create.bc_opaque_flags = BIOC_SOOUT;
753aef7fe28Shshoexer 
754aef7fe28Shshoexer 		/* try to get KDF hint */
75583e979edShshoexer 		if (ioctl(devh, BIOCCREATERAID, &create) == -1)
75683e979edShshoexer 			err(1, "ioctl");
75783e979edShshoexer 
75883e979edShshoexer 		if (create.bc_opaque_status == BIOC_SOINOUT_OK) {
759*c6446370Sjsing 			bio_kdf_derive(&kdfinfo, &kdfhint, "Passphrase: ", 0);
760aef7fe28Shshoexer 			memset(&kdfhint, 0, sizeof(kdfhint));
761aef7fe28Shshoexer 		} else  {
762aef7fe28Shshoexer 			bio_kdf_generate(&kdfinfo);
763aef7fe28Shshoexer 			/* no auto assembling */
764aef7fe28Shshoexer 			create.bc_flags |= BIOC_SCNOAUTOASSEMBLE;
765aef7fe28Shshoexer 		}
766aef7fe28Shshoexer 
767aef7fe28Shshoexer 		create.bc_opaque = &kdfinfo;
768aef7fe28Shshoexer 		create.bc_opaque_size = sizeof(kdfinfo);
769aef7fe28Shshoexer 		create.bc_opaque_flags = BIOC_SOIN;
770aef7fe28Shshoexer 	}
771aef7fe28Shshoexer 
7727195049bSmarco 	rv = ioctl(devh, BIOCCREATERAID, &create);
773aef7fe28Shshoexer 	memset(&kdfinfo, 0, sizeof(kdfinfo));
77483e979edShshoexer 	memset(&create, 0, sizeof(create));
775a83e4577Sdjm 	if (rv == -1) {
776a83e4577Sdjm 		if (errno == EPERM)
777a83e4577Sdjm 			errx(1, "Incorrect passphrase");
778da3b0664Shenning 		err(1, "BIOCCREATERAID");
779a83e4577Sdjm 	}
78046bc198bSmarco 
78146bc198bSmarco 	free(dt);
78246bc198bSmarco }
78346bc198bSmarco 
784aef7fe28Shshoexer void
785aef7fe28Shshoexer bio_kdf_derive(struct sr_crypto_kdfinfo *kdfinfo, struct sr_crypto_kdf_pbkdf2
786*c6446370Sjsing     *kdfhint, char* prompt, int verify)
787aef7fe28Shshoexer {
788aef7fe28Shshoexer 	if (!kdfinfo)
789aef7fe28Shshoexer 		errx(1, "invalid KDF info");
790aef7fe28Shshoexer 	if (!kdfhint)
791aef7fe28Shshoexer 		errx(1, "invalid KDF hint");
792aef7fe28Shshoexer 
793aef7fe28Shshoexer 	if (kdfhint->len != sizeof(*kdfhint))
794aef7fe28Shshoexer 		errx(1, "KDF hint has invalid size");
795aef7fe28Shshoexer 	if (kdfhint->type != SR_CRYPTOKDFT_PBKDF2)
796aef7fe28Shshoexer 		errx(1, "unknown KDF type %d", kdfhint->type);
797aef7fe28Shshoexer 	if (kdfhint->rounds < 1000)
798aef7fe28Shshoexer 		errx(1, "number of KDF rounds too low: %d", kdfhint->rounds);
799aef7fe28Shshoexer 
800aef7fe28Shshoexer 	kdfinfo->flags = SR_CRYPTOKDF_KEY;
801aef7fe28Shshoexer 	kdfinfo->len = sizeof(*kdfinfo);
802aef7fe28Shshoexer 
8039e8c6f5bShshoexer 	derive_key_pkcs(kdfhint->rounds,
804aef7fe28Shshoexer 	    kdfinfo->maskkey, sizeof(kdfinfo->maskkey),
805*c6446370Sjsing 	    kdfhint->salt, sizeof(kdfhint->salt), prompt, verify);
806aef7fe28Shshoexer }
807aef7fe28Shshoexer 
808aef7fe28Shshoexer void
809aef7fe28Shshoexer bio_kdf_generate(struct sr_crypto_kdfinfo *kdfinfo)
810aef7fe28Shshoexer {
811aef7fe28Shshoexer 	if (!kdfinfo)
812aef7fe28Shshoexer 		errx(1, "invalid KDF info");
813aef7fe28Shshoexer 
814aef7fe28Shshoexer 	kdfinfo->pbkdf2.len = sizeof(kdfinfo->pbkdf2);
815aef7fe28Shshoexer 	kdfinfo->pbkdf2.type = SR_CRYPTOKDFT_PBKDF2;
816aedd4f07Sdjm 	kdfinfo->pbkdf2.rounds = rflag;
817aef7fe28Shshoexer 	kdfinfo->len = sizeof(*kdfinfo);
818aef7fe28Shshoexer 	kdfinfo->flags = (SR_CRYPTOKDF_KEY | SR_CRYPTOKDF_HINT);
819aef7fe28Shshoexer 
820aef7fe28Shshoexer 	/* generate salt */
821aef7fe28Shshoexer 	arc4random_buf(kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt));
822aef7fe28Shshoexer 
8239e8c6f5bShshoexer 	derive_key_pkcs(kdfinfo->pbkdf2.rounds,
824aef7fe28Shshoexer 	    kdfinfo->maskkey, sizeof(kdfinfo->maskkey),
825*c6446370Sjsing 	    kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt),
826*c6446370Sjsing 	    "New passphrase: ", 1);
827aef7fe28Shshoexer }
828aef7fe28Shshoexer 
82946bc198bSmarco int
83046bc198bSmarco bio_parse_devlist(char *lst, dev_t *dt)
83146bc198bSmarco {
83246bc198bSmarco 	char			*s, *e;
83346bc198bSmarco 	u_int32_t		sz = 0;
83446bc198bSmarco 	int			no_dev = 0, i, x;
83546bc198bSmarco 	struct stat		sb;
8365c1f8f6bSdjm 	char			dev[MAXPATHLEN];
83746bc198bSmarco 
83846bc198bSmarco 	if (!lst)
83946bc198bSmarco 		errx(1, "invalid device list");
84046bc198bSmarco 
84146bc198bSmarco 	s = e = lst;
84246bc198bSmarco 	/* make sure we have a valid device list like /dev/sdNa,/dev/sdNNa */
84346bc198bSmarco 	while (*e != '\0') {
84446bc198bSmarco 		if (*e == ',')
84546bc198bSmarco 			s = e + 1;
84646bc198bSmarco 		else if (*(e + 1) == '\0' || *(e + 1) == ',') {
84746bc198bSmarco 			/* got one */
84846bc198bSmarco 			sz = e - s + 1;
8495c1f8f6bSdjm 			strlcpy(dev, s, sz + 1);
8505c1f8f6bSdjm 			if (stat(dev, &sb) == -1)
8515c1f8f6bSdjm 				err(1, "could not stat %s", dev);
85246bc198bSmarco 			dt[no_dev] = sb.st_rdev;
85346bc198bSmarco 			no_dev++;
8545c1f8f6bSdjm 			if (no_dev > (int)(BIOC_CRMAXLEN / sizeof(dev_t)))
85546bc198bSmarco 				errx(1, "too many devices on device list");
85646bc198bSmarco 		}
85746bc198bSmarco 		e++;
85846bc198bSmarco 	}
85946bc198bSmarco 
86046bc198bSmarco 	for (i = 0; i < no_dev; i++)
86146bc198bSmarco 		for (x = 0; x < no_dev; x++)
86246bc198bSmarco 			if (dt[i] == dt[x] && x != i)
86346bc198bSmarco 				errx(1, "duplicate device in list");
86446bc198bSmarco 
86546bc198bSmarco 	return (no_dev);
8667195049bSmarco }
867e8a57fdeSmarco 
868e8a57fdeSmarco u_int32_t
869e8a57fdeSmarco bio_createflags(char *lst)
870e8a57fdeSmarco {
871e8a57fdeSmarco 	char			*s, *e, fs[32];
872e8a57fdeSmarco 	u_int32_t		sz = 0;
873e8a57fdeSmarco 	u_int32_t		flags = 0;
874e8a57fdeSmarco 
875e8a57fdeSmarco 	if (!lst)
876e8a57fdeSmarco 		errx(1, "invalid flags list");
877e8a57fdeSmarco 
878e8a57fdeSmarco 	s = e = lst;
879e8a57fdeSmarco 	/* make sure we have a valid flags list like force,noassemeble */
880e8a57fdeSmarco 	while (*e != '\0') {
881e8a57fdeSmarco 		if (*e == ',')
882e8a57fdeSmarco 			s = e + 1;
883e8a57fdeSmarco 		else if (*(e + 1) == '\0' || *(e + 1) == ',') {
884e8a57fdeSmarco 			/* got one */
885e8a57fdeSmarco 			sz = e - s + 1;
886e8a57fdeSmarco 			switch (s[0]) {
887e8a57fdeSmarco 			case 'f':
888e8a57fdeSmarco 				flags |= BIOC_SCFORCE;
889e8a57fdeSmarco 				break;
890e8a57fdeSmarco 			case 'n':
891e8a57fdeSmarco 				flags |= BIOC_SCNOAUTOASSEMBLE;
892e8a57fdeSmarco 				break;
893e8a57fdeSmarco 			default:
894e8a57fdeSmarco 				strlcpy(fs, s, sz + 1);
895e8a57fdeSmarco 				errx(1, "invalid flag %s", fs);
896e8a57fdeSmarco 			}
897e8a57fdeSmarco 		}
898e8a57fdeSmarco 		e++;
899e8a57fdeSmarco 	}
900e8a57fdeSmarco 
901e8a57fdeSmarco 	return (flags);
902e8a57fdeSmarco }
90303b2dfbfShenning 
904c7c3e8aaSmarco void
905c7c3e8aaSmarco bio_deleteraid(char *dev)
906c7c3e8aaSmarco {
907c7c3e8aaSmarco 	struct bioc_deleteraid	bd;
908c7c3e8aaSmarco 	memset(&bd, 0, sizeof(bd));
909c7c3e8aaSmarco 
910c7c3e8aaSmarco 	bd.bd_cookie = bd.bd_cookie;
911a15048bbSmarco 	/* XXX make this a dev_t instead of a string */
912c7c3e8aaSmarco 	strlcpy(bd.bd_dev, dev, sizeof bd.bd_dev);
913c7c3e8aaSmarco 	if (ioctl(devh, BIOCDELETERAID, &bd))
914c7c3e8aaSmarco 		errx(1, "delete volume %s failed", dev);
915c7c3e8aaSmarco }
916c7c3e8aaSmarco 
917*c6446370Sjsing void
918*c6446370Sjsing bio_changepass(char *dev)
919*c6446370Sjsing {
920*c6446370Sjsing 	struct bioc_discipline bd;
921*c6446370Sjsing 	struct sr_crypto_kdfpair kdfpair;
922*c6446370Sjsing 	struct sr_crypto_kdfinfo kdfinfo1, kdfinfo2;
923*c6446370Sjsing 	struct sr_crypto_kdf_pbkdf2 kdfhint;
924*c6446370Sjsing 	int rv;
925*c6446370Sjsing 
926*c6446370Sjsing 	memset(&bd, 0, sizeof(bd));
927*c6446370Sjsing 	memset(&kdfhint, 0, sizeof(kdfhint));
928*c6446370Sjsing 	memset(&kdfinfo1, 0, sizeof(kdfinfo1));
929*c6446370Sjsing 	memset(&kdfinfo2, 0, sizeof(kdfinfo2));
930*c6446370Sjsing 
931*c6446370Sjsing 	/* XXX use dev_t instead of string. */
932*c6446370Sjsing 	strlcpy(bd.bd_dev, dev, sizeof(bd.bd_dev));
933*c6446370Sjsing 	bd.bd_cmd = SR_IOCTL_GET_KDFHINT;
934*c6446370Sjsing 	bd.bd_size = sizeof(kdfhint);
935*c6446370Sjsing 	bd.bd_data = &kdfhint;
936*c6446370Sjsing 
937*c6446370Sjsing 	if (ioctl(devh, BIOCDISCIPLINE, &bd))
938*c6446370Sjsing 		errx(1, "%s: failed to get KDF hint", dev);
939*c6446370Sjsing 
940*c6446370Sjsing 	/* Current passphrase. */
941*c6446370Sjsing 	bio_kdf_derive(&kdfinfo1, &kdfhint, "Old passphrase: ", 0);
942*c6446370Sjsing 
943*c6446370Sjsing 	/* New passphrase. */
944*c6446370Sjsing 	bio_kdf_derive(&kdfinfo2, &kdfhint, "New passphrase: ", 1);
945*c6446370Sjsing 
946*c6446370Sjsing 	kdfpair.kdfinfo1 = &kdfinfo1;
947*c6446370Sjsing 	kdfpair.kdfsize1 = sizeof(kdfinfo1);
948*c6446370Sjsing 	kdfpair.kdfinfo2 = &kdfinfo2;
949*c6446370Sjsing 	kdfpair.kdfsize2 = sizeof(kdfinfo2);
950*c6446370Sjsing 
951*c6446370Sjsing 	bd.bd_cmd = SR_IOCTL_CHANGE_PASSPHRASE;
952*c6446370Sjsing 	bd.bd_size = sizeof(kdfpair);
953*c6446370Sjsing 	bd.bd_data = &kdfpair;
954*c6446370Sjsing 
955*c6446370Sjsing 	rv = ioctl(devh, BIOCDISCIPLINE, &bd);
956*c6446370Sjsing 
957*c6446370Sjsing 	memset(&kdfhint, 0, sizeof(kdfhint));
958*c6446370Sjsing 	memset(&kdfinfo1, 0, sizeof(kdfinfo1));
959*c6446370Sjsing 	memset(&kdfinfo2, 0, sizeof(kdfinfo2));
960*c6446370Sjsing 
961*c6446370Sjsing 	if (rv) {
962*c6446370Sjsing 		if (errno == EPERM)
963*c6446370Sjsing 			errx(1, "%s: incorrect passphrase", dev);
964*c6446370Sjsing 		else
965*c6446370Sjsing 			errx(1, "%s: failed to change passphrase", dev);
966*c6446370Sjsing 	}
967*c6446370Sjsing }
968*c6446370Sjsing 
96903b2dfbfShenning #define BIOCTL_VIS_NBUF		4
97003b2dfbfShenning #define BIOCTL_VIS_BUFLEN	80
97103b2dfbfShenning 
97203b2dfbfShenning char *
97303b2dfbfShenning bio_vis(char *s)
97403b2dfbfShenning {
97503b2dfbfShenning 	static char	 rbuf[BIOCTL_VIS_NBUF][BIOCTL_VIS_BUFLEN];
97603b2dfbfShenning 	static uint	 idx = 0;
97703b2dfbfShenning 	char		*buf;
97803b2dfbfShenning 
97903b2dfbfShenning 	buf = rbuf[idx++];
98003b2dfbfShenning 	if (idx == BIOCTL_VIS_NBUF)
98103b2dfbfShenning 		idx = 0;
98203b2dfbfShenning 
98303b2dfbfShenning 	strnvis(buf, s, BIOCTL_VIS_BUFLEN, VIS_NL|VIS_CSTYLE);
98403b2dfbfShenning 	return (buf);
98503b2dfbfShenning }
98603b2dfbfShenning 
98703b2dfbfShenning void
98803b2dfbfShenning bio_diskinq(char *sd_dev)
98903b2dfbfShenning {
99003b2dfbfShenning 	struct dk_inquiry	di;
99103b2dfbfShenning 
992da3b0664Shenning 	if (ioctl(devh, DIOCINQ, &di) == -1)
993da3b0664Shenning 		err(1, "DIOCINQ");
99403b2dfbfShenning 
99503b2dfbfShenning 	printf("%s: <%s, %s, %s>, serial %s\n", sd_dev, bio_vis(di.vendor),
99603b2dfbfShenning 	    bio_vis(di.product), bio_vis(di.revision), bio_vis(di.serial));
99703b2dfbfShenning }
998aef7fe28Shshoexer 
999aef7fe28Shshoexer void
10009e8c6f5bShshoexer derive_key_pkcs(int rounds, u_int8_t *key, size_t keysz, u_int8_t *salt,
1001*c6446370Sjsing     size_t saltsz, char *prompt, int verify)
1002aef7fe28Shshoexer {
100386735da2Smarco 	FILE		*f;
100486735da2Smarco 	size_t		pl;
100586735da2Smarco 	struct stat	sb;
10069e8c6f5bShshoexer 	char		passphrase[1024], verifybuf[1024];
1007aef7fe28Shshoexer 
1008aef7fe28Shshoexer 	if (!key)
1009aef7fe28Shshoexer 		errx(1, "Invalid key");
1010aef7fe28Shshoexer 	if (!salt)
1011aef7fe28Shshoexer 		errx(1, "Invalid salt");
1012aef7fe28Shshoexer 	if (rounds < 1000)
1013aef7fe28Shshoexer 		errx(1, "Too less rounds: %d", rounds);
1014aef7fe28Shshoexer 
1015aef7fe28Shshoexer 	/* get passphrase */
1016ba3d8661Smarco 	if (password && verify)
1017ba3d8661Smarco 		errx(1, "can't specify passphrase file during initial "
1018ba3d8661Smarco 		    "creation of crypto volume");
1019ba3d8661Smarco 	if (password) {
102086735da2Smarco 		if ((f = fopen(password, "r")) == NULL)
102186735da2Smarco 			err(1, "invalid passphrase file");
102286735da2Smarco 
102386735da2Smarco 		if (fstat(fileno(f), &sb) == -1)
102486735da2Smarco 			err(1, "can't stat passphrase file");
102586735da2Smarco 		if (sb.st_uid != 0)
102686735da2Smarco 			errx(1, "passphrase file must be owned by root");
102786735da2Smarco 		if ((sb.st_mode & ~S_IFMT) != (S_IRUSR | S_IWUSR))
102886735da2Smarco 			errx(1, "passphrase file has the wrong permissions");
102986735da2Smarco 
103086735da2Smarco 		if (fgets(passphrase, sizeof(passphrase), f) == NULL)
103186735da2Smarco 			err(1, "can't read passphrase file");
103286735da2Smarco 		pl = strlen(passphrase);
103386735da2Smarco 		if (pl > 0 && passphrase[pl - 1] == '\n')
103486735da2Smarco 			passphrase[pl - 1] = '\0';
103586735da2Smarco 		else
103686735da2Smarco 			errx(1, "invalid passphrase length");
103786735da2Smarco 
103886735da2Smarco 		fclose(f);
1039ba3d8661Smarco 	} else {
1040*c6446370Sjsing 		if (readpassphrase(prompt, passphrase, sizeof(passphrase),
1041*c6446370Sjsing 		    RPP_REQUIRE_TTY) == NULL)
10429e8c6f5bShshoexer 			errx(1, "unable to read passphrase");
1043ba3d8661Smarco 	}
10449e8c6f5bShshoexer 
10459e8c6f5bShshoexer 	if (verify) {
10469e8c6f5bShshoexer 		/* request user to re-type it */
10479e8c6f5bShshoexer 		if (readpassphrase("Re-type passphrase: ", verifybuf,
10489e8c6f5bShshoexer 		    sizeof(verifybuf), RPP_REQUIRE_TTY) == NULL) {
10499e8c6f5bShshoexer 			memset(passphrase, 0, sizeof(passphrase));
10509e8c6f5bShshoexer 			errx(1, "unable to read passphrase");
10519e8c6f5bShshoexer 		}
10529e8c6f5bShshoexer 		if ((strlen(passphrase) != strlen(verifybuf)) ||
10539e8c6f5bShshoexer 		    (strcmp(passphrase, verifybuf) != 0)) {
10549e8c6f5bShshoexer 			memset(passphrase, 0, sizeof(passphrase));
10559e8c6f5bShshoexer 			memset(verifybuf, 0, sizeof(verifybuf));
10569e8c6f5bShshoexer 			errx(1, "Passphrases did not match");
10579e8c6f5bShshoexer 		}
10589e8c6f5bShshoexer 		/* forget the re-typed one */
10599e8c6f5bShshoexer 		memset(verifybuf, 0, strlen(verifybuf));
10609e8c6f5bShshoexer 	}
1061aef7fe28Shshoexer 
1062aef7fe28Shshoexer 	/* derive key from passphrase */
10635c1f8f6bSdjm 	if (pkcs5_pbkdf2(passphrase, strlen(passphrase), salt, saltsz,
10645c1f8f6bSdjm 	    key, keysz, rounds) != 0)
10655c1f8f6bSdjm 		errx(1, "pbkdf2 failed");
1066aef7fe28Shshoexer 
1067aef7fe28Shshoexer 	/* forget passphrase */
10689e8c6f5bShshoexer 	memset(passphrase, 0, sizeof(passphrase));
1069aef7fe28Shshoexer 
1070aef7fe28Shshoexer 	return;
1071aef7fe28Shshoexer }
1072