xref: /openbsd/sbin/bioctl/bioctl.c (revision ffb4dd05)
1*ffb4dd05Sguenther /* $OpenBSD: bioctl.c,v 1.121 2014/07/20 01:38:40 guenther 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 
30e7d4f752Sderaadt #include <sys/param.h>
31c2126c9aSmarco #include <sys/ioctl.h>
3291f4f7d8Sdlg #include <sys/dkio.h>
3346bc198bSmarco #include <sys/stat.h>
34aef7fe28Shshoexer #include <dev/softraidvar.h>
35e7d4f752Sderaadt #include <dev/biovar.h>
363af9de98Smarco 
37db2730c1Smarco #include <errno.h>
38db2730c1Smarco #include <err.h>
39db2730c1Smarco #include <fcntl.h>
408ccdd032Sderaadt #include <util.h>
41934f30d8Sderaadt #include <ctype.h>
42db2730c1Smarco #include <stdio.h>
43db2730c1Smarco #include <stdlib.h>
44db2730c1Smarco #include <string.h>
45db2730c1Smarco #include <unistd.h>
4603b2dfbfShenning #include <vis.h>
479e8c6f5bShshoexer #include <readpassphrase.h>
48db2730c1Smarco 
49e7d4f752Sderaadt #ifdef AOE
50e7d4f752Sderaadt #include <net/if.h>
51e7d4f752Sderaadt #include <netinet/in.h>
52e7d4f752Sderaadt #include <netinet/if_ether.h>
53e7d4f752Sderaadt 
54e7d4f752Sderaadt struct sr_aoe_config 	*create_aoe(u_int16_t, char *);
55e7d4f752Sderaadt #endif /* AOE */
56e7d4f752Sderaadt 
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 *);
65d313c28bSjsing void			bio_status(struct bio_status *);
6646bc198bSmarco int			bio_parse_devlist(char *, dev_t *);
67aef7fe28Shshoexer void			bio_kdf_derive(struct sr_crypto_kdfinfo *,
68c6446370Sjsing 			    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 *,
71c6446370Sjsing 			    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);
790054cd36Sjsing void			bio_createraid(u_int16_t, char *, char *);
80c7c3e8aaSmarco void			bio_deleteraid(char *);
81c6446370Sjsing 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 
93545c4d7fSjsing void			*bio_cookie;
94545c4d7fSjsing 
95b96c6ce2Sckuethe int rpp_flag = RPP_REQUIRE_TTY;
963af9de98Smarco 
973af9de98Smarco int
983af9de98Smarco main(int argc, char *argv[])
993af9de98Smarco {
100545c4d7fSjsing 	struct bio_locate	bl;
1013af9de98Smarco 	extern char		*optarg;
102db2730c1Smarco 	u_int64_t		func = 0;
103e63d8b1dSdtucker 	char			*devicename = NULL;
104cf6503d7Sderaadt 	char			*realname = NULL, *al_arg = NULL;
1057195049bSmarco 	char			*bl_arg = NULL, *dev_list = NULL;
1060054cd36Sjsing 	char			*key_disk = NULL;
107aedd4f07Sdjm 	const char		*errstr;
108d313c28bSjsing 	int			ch, blink = 0, changepass = 0, diskinq = 0;
109c6446370Sjsing 	int			ss_func = 0;
1109ecba717Sderaadt 	u_int16_t		cr_level = 0;
111e37c64dbSjsing 	int			biodev = 0;
1123af9de98Smarco 
1133af9de98Smarco 	if (argc < 2)
1143af9de98Smarco 		usage();
1153af9de98Smarco 
11650e55a42Sjsing 	while ((ch = getopt(argc, argv, "a:b:C:c:dH:hik:l:O:Pp:qr:R:svu:")) !=
117c6446370Sjsing 	    -1) {
1183af9de98Smarco 		switch (ch) {
119edfd9792Smarco 		case 'a': /* alarm */
120edfd9792Smarco 			func |= BIOC_ALARM;
121edfd9792Smarco 			al_arg = optarg;
122edfd9792Smarco 			break;
123c55617f1Sdlg 		case 'b': /* blink */
124c55617f1Sdlg 			func |= BIOC_BLINK;
125a928c459Sderaadt 			blink = BIOC_SBBLINK;
126a928c459Sderaadt 			bl_arg = optarg;
127a928c459Sderaadt 			break;
128e8a57fdeSmarco 		case 'C': /* creation flags */
129e8a57fdeSmarco 			cflags = bio_createflags(optarg);
130e8a57fdeSmarco 			break;
1317195049bSmarco 		case 'c': /* create */
1327195049bSmarco 			func |= BIOC_CREATERAID;
133025f5691Sderaadt 			if (isdigit((unsigned char)*optarg)) {
13492d21b5cStedu 				cr_level = strtonum(optarg, 0, 10, &errstr);
13592d21b5cStedu 				if (errstr != NULL)
13692d21b5cStedu 					errx(1, "Invalid RAID level");
13792d21b5cStedu 			} else
13898b750e4Stedu 				cr_level = *optarg;
1397195049bSmarco 			break;
140c7c3e8aaSmarco 		case 'd':
141c7c3e8aaSmarco 			/* delete volume */
142c7c3e8aaSmarco 			func |= BIOC_DELETERAID;
143c7c3e8aaSmarco 			break;
144a928c459Sderaadt 		case 'u': /* unblink */
145a928c459Sderaadt 			func |= BIOC_BLINK;
146a928c459Sderaadt 			blink = BIOC_SBUNBLINK;
147c55617f1Sdlg 			bl_arg = optarg;
148c55617f1Sdlg 			break;
1496de960dcSmarco 		case 'H': /* set hotspare */
1506de960dcSmarco 			func |= BIOC_SETSTATE;
151a15048bbSmarco 			ss_func = BIOC_SSHOTSPARE;
1526de960dcSmarco 			al_arg = optarg;
1536de960dcSmarco 			break;
1548ccdd032Sderaadt 		case 'h':
1558ccdd032Sderaadt 			human = 1;
1568ccdd032Sderaadt 			break;
157db2730c1Smarco 		case 'i': /* inquiry */
158db2730c1Smarco 			func |= BIOC_INQ;
1593af9de98Smarco 			break;
1600054cd36Sjsing 		case 'k': /* Key disk. */
1610054cd36Sjsing 			key_disk = optarg;
1620054cd36Sjsing 			break;
1637195049bSmarco 		case 'l': /* device list */
1647195049bSmarco 			func |= BIOC_DEVLIST;
1657195049bSmarco 			dev_list = optarg;
1667195049bSmarco 			break;
167c6446370Sjsing 		case 'P':
168c6446370Sjsing 			/* Change passphrase. */
169c6446370Sjsing 			changepass = 1;
170c6446370Sjsing 			break;
17186735da2Smarco 		case 'p':
17286735da2Smarco 			password = optarg;
17386735da2Smarco 			break;
174aedd4f07Sdjm 		case 'r':
175aedd4f07Sdjm 			rflag = strtonum(optarg, 1000, 1<<30, &errstr);
176aedd4f07Sdjm 			if (errstr != NULL)
177aedd4f07Sdjm 				errx(1, "Number of rounds is %s: %s",
178aedd4f07Sdjm 				    errstr, optarg);
179aedd4f07Sdjm 			break;
18050e55a42Sjsing 		case 'O':
18150e55a42Sjsing 			/* set a chunk to offline */
18250e55a42Sjsing 			func |= BIOC_SETSTATE;
18350e55a42Sjsing 			ss_func = BIOC_SSOFFLINE;
18450e55a42Sjsing 			al_arg = optarg;
18550e55a42Sjsing 			break;
186a15048bbSmarco 		case 'R':
187a15048bbSmarco 			/* rebuild to provided chunk/CTL */
188a15048bbSmarco 			func |= BIOC_SETSTATE;
189a15048bbSmarco 			ss_func = BIOC_SSREBUILD;
190a15048bbSmarco 			al_arg = optarg;
191a15048bbSmarco 			break;
192b96c6ce2Sckuethe 		case 's':
193b96c6ce2Sckuethe 			rpp_flag = RPP_STDIN;
194b96c6ce2Sckuethe 			break;
195abe9d68eSderaadt 		case 'v':
196abe9d68eSderaadt 			verbose = 1;
197abe9d68eSderaadt 			break;
19803b2dfbfShenning 		case 'q':
19903b2dfbfShenning 			diskinq = 1;
20003b2dfbfShenning 			break;
2013af9de98Smarco 		default:
2023af9de98Smarco 			usage();
2033af9de98Smarco 			/* NOTREACHED */
2043af9de98Smarco 		}
2053af9de98Smarco 	}
206cf6503d7Sderaadt 	argc -= optind;
207cf6503d7Sderaadt 	argv += optind;
2083af9de98Smarco 
209c6446370Sjsing 	if (argc != 1 || (changepass && func != 0))
210cf6503d7Sderaadt 		usage();
211cf6503d7Sderaadt 
212dcbaf4c8Sderaadt 	if (func == 0)
213dcbaf4c8Sderaadt 		func |= BIOC_INQ;
214dcbaf4c8Sderaadt 
215e63d8b1dSdtucker 	devicename = argv[0];
216e63d8b1dSdtucker 	if (devicename == NULL)
217e37c64dbSjsing 		errx(1, "need device");
21810b411a7Smarco 
219e63d8b1dSdtucker 	devh = opendev(devicename, O_RDWR, OPENDEV_PART, &realname);
220e37c64dbSjsing 	if (devh == -1) {
22141eccc89Sderaadt 		devh = open("/dev/bio", O_RDWR);
2223af9de98Smarco 		if (devh == -1)
22341eccc89Sderaadt 			err(1, "Can't open %s", "/dev/bio");
2243af9de98Smarco 
225e63d8b1dSdtucker 		bl.bl_name = devicename;
226d313c28bSjsing 		if (ioctl(devh, BIOCLOCATE, &bl))
22710b411a7Smarco 			errx(1, "Can't locate %s device via %s",
22841eccc89Sderaadt 			    bl.bl_name, "/dev/bio");
229d313c28bSjsing 
230d313c28bSjsing 		bio_status(&bl.bl_bio.bio_status);
231d313c28bSjsing 
232545c4d7fSjsing 		bio_cookie = bl.bl_bio.bio_cookie;
233e37c64dbSjsing 		biodev = 1;
234e63d8b1dSdtucker 		devicename = NULL;
235e37c64dbSjsing 	}
2363af9de98Smarco 
23703b2dfbfShenning 	if (diskinq) {
238e63d8b1dSdtucker 		bio_diskinq(devicename);
239e37c64dbSjsing 	} else if (changepass && !biodev) {
240e63d8b1dSdtucker 		bio_changepass(devicename);
24103b2dfbfShenning 	} else if (func & BIOC_INQ) {
242e63d8b1dSdtucker 		bio_inq(devicename);
243edfd9792Smarco 	} else if (func == BIOC_ALARM) {
244edfd9792Smarco 		bio_alarm(al_arg);
245c55617f1Sdlg 	} else if (func == BIOC_BLINK) {
246e63d8b1dSdtucker 		bio_setblink(devicename, bl_arg, blink);
2476de960dcSmarco 	} else if (func == BIOC_SETSTATE) {
248a15048bbSmarco 		bio_setstate(al_arg, ss_func, argv[0]);
249e37c64dbSjsing 	} else if (func == BIOC_DELETERAID && !biodev) {
250e63d8b1dSdtucker 		bio_deleteraid(devicename);
2517195049bSmarco 	} else if (func & BIOC_CREATERAID || func & BIOC_DEVLIST) {
2527195049bSmarco 		if (!(func & BIOC_CREATERAID))
2537195049bSmarco 			errx(1, "need -c parameter");
2547195049bSmarco 		if (!(func & BIOC_DEVLIST))
2557195049bSmarco 			errx(1, "need -l parameter");
256e37c64dbSjsing 		if (!biodev)
257e37c64dbSjsing 			errx(1, "must use bio device");
2580054cd36Sjsing 		bio_createraid(cr_level, dev_list, key_disk);
2593af9de98Smarco 	}
2603af9de98Smarco 
2613af9de98Smarco 	return (0);
2623af9de98Smarco }
2633af9de98Smarco 
2643af9de98Smarco void
2653af9de98Smarco usage(void)
2663af9de98Smarco {
2673af9de98Smarco 	extern char		*__progname;
2683af9de98Smarco 
269d90b5d8bSjmc 	fprintf(stderr,
270d0b772c8Sjmc 		"usage: %s [-hiqv] [-a alarm-function] "
271d90b5d8bSjmc 		"[-b channel:target[.lun]]\n"
272d0b772c8Sjmc 		"\t[-H channel:target[.lun]] "
273af56bbe7Smatthieu 		"[-R device | channel:target[.lun]]\n"
274d0b772c8Sjmc 		"\t[-u channel:target[.lun]] "
275d0b772c8Sjmc 		"device\n"
276b96c6ce2Sckuethe 		"       %s [-dhiPqsv] "
277b90fdff5Sjmc 		"[-C flag[,flag,...]] [-c raidlevel] [-k keydisk]\n"
27850e55a42Sjsing 		"\t[-l special[,special,...]] "
27950e55a42Sjsing 		"[-O device | channel:target[.lun]]\n"
28050e55a42Sjsing 		"\t[-p passfile] [-R device | channel:target[.lun]]\n"
28150e55a42Sjsing 		"\t[-r rounds] "
282d0b772c8Sjmc 		"device\n", __progname, __progname);
283d90b5d8bSjmc 
2843af9de98Smarco 	exit(1);
2853af9de98Smarco }
2863af9de98Smarco 
28741eccc89Sderaadt const char *
2886de960dcSmarco str2locator(const char *string, struct locator *location)
2896de960dcSmarco {
29050d3c4dcSdlg 	const char		*errstr;
29141eccc89Sderaadt 	char			parse[80], *targ, *lun;
2926de960dcSmarco 
29341eccc89Sderaadt 	strlcpy(parse, string, sizeof parse);
29441eccc89Sderaadt 	targ = strchr(parse, ':');
2956de960dcSmarco 	if (targ == NULL)
29641eccc89Sderaadt 		return ("target not specified");
2976de960dcSmarco 	*targ++ = '\0';
2986de960dcSmarco 
29950d3c4dcSdlg 	lun = strchr(targ, '.');
3006de960dcSmarco 	if (lun != NULL) {
3016de960dcSmarco 		*lun++ = '\0';
30250d3c4dcSdlg 		location->lun = strtonum(lun, 0, 256, &errstr);
30350d3c4dcSdlg 		if (errstr)
30441eccc89Sderaadt 			return (errstr);
3056de960dcSmarco 	} else
3066de960dcSmarco 		location->lun = 0;
3076de960dcSmarco 
30850d3c4dcSdlg 	location->target = strtonum(targ, 0, 256, &errstr);
30950d3c4dcSdlg 	if (errstr)
31041eccc89Sderaadt 		return (errstr);
31141eccc89Sderaadt 	location->channel = strtonum(parse, 0, 256, &errstr);
31250d3c4dcSdlg 	if (errstr)
31341eccc89Sderaadt 		return (errstr);
31441eccc89Sderaadt 	return (NULL);
3156de960dcSmarco }
3166de960dcSmarco 
3173af9de98Smarco void
318d313c28bSjsing bio_status(struct bio_status *bs)
319d313c28bSjsing {
3200a69bfccSjsing 	extern char		*__progname;
3210a69bfccSjsing 	char			*prefix;
322d313c28bSjsing 	int			i;
323d313c28bSjsing 
324d313c28bSjsing 	if (strlen(bs->bs_controller))
3250a69bfccSjsing 		prefix = bs->bs_controller;
3260a69bfccSjsing 	else
3270a69bfccSjsing 		prefix = __progname;
328d313c28bSjsing 
3290a69bfccSjsing 	for (i = 0; i < bs->bs_msg_count; i++)
3300a69bfccSjsing 		printf("%s: %s\n", prefix, bs->bs_msgs[i].bm_msg);
3310a69bfccSjsing 
3320a69bfccSjsing 	if (bs->bs_status == BIO_STATUS_ERROR) {
3330a69bfccSjsing 		if (bs->bs_msg_count == 0)
3340a69bfccSjsing 			errx(1, "unknown error");
3350a69bfccSjsing 		else
336d313c28bSjsing 			exit(1);
337d313c28bSjsing 	}
3380a69bfccSjsing }
339d313c28bSjsing 
340d313c28bSjsing void
3418ccdd032Sderaadt bio_inq(char *name)
342d4546a56Sdlg {
343cc711184Skettenis 	char 			*status, *cache;
344cc711184Skettenis 	char			size[64], scsiname[16], volname[32];
345a4d3c4a2Sderaadt 	char			percent[10], seconds[20];
346d313c28bSjsing 	int			i, d, volheader, hotspare, unused;
347aa65acf1Sderaadt 	char			encname[16], serial[32];
3488ccdd032Sderaadt 	struct bioc_inq		bi;
3498ccdd032Sderaadt 	struct bioc_vol		bv;
350c2b1f828Sderaadt 	struct bioc_disk	bd;
351db2730c1Smarco 
352db2730c1Smarco 	memset(&bi, 0, sizeof(bi));
3533af9de98Smarco 
354545c4d7fSjsing 	bi.bi_bio.bio_cookie = bio_cookie;
3553af9de98Smarco 
356d313c28bSjsing 	if (ioctl(devh, BIOCINQ, &bi)) {
35703b2dfbfShenning 		if (errno == ENOTTY)
35803b2dfbfShenning 			bio_diskinq(name);
35903b2dfbfShenning 		else
360da3b0664Shenning 			err(1, "BIOCINQ");
3613af9de98Smarco 		return;
3623af9de98Smarco 	}
3633af9de98Smarco 
364d313c28bSjsing 	bio_status(&bi.bi_bio.bio_status);
365d313c28bSjsing 
3668ccdd032Sderaadt 	volheader = 0;
3678ccdd032Sderaadt 	for (i = 0; i < bi.bi_novol; i++) {
368db2730c1Smarco 		memset(&bv, 0, sizeof(bv));
369545c4d7fSjsing 		bv.bv_bio.bio_cookie = bio_cookie;
3708ccdd032Sderaadt 		bv.bv_volid = i;
3710a92ff65Sderaadt 		bv.bv_percent = -1;
3729017fb97Sderaadt 		bv.bv_seconds = 0;
37370a2ae7bSmarco 
374d313c28bSjsing 		if (ioctl(devh, BIOCVOL, &bv))
375da3b0664Shenning 			err(1, "BIOCVOL");
3763af9de98Smarco 
377d313c28bSjsing 		bio_status(&bv.bv_bio.bio_status);
378d313c28bSjsing 
3798ccdd032Sderaadt 		if (name && strcmp(name, bv.bv_dev) != 0)
3808ccdd032Sderaadt 			continue;
3818ccdd032Sderaadt 
3828ccdd032Sderaadt 		if (!volheader) {
3838ccdd032Sderaadt 			volheader = 1;
384150c22bbSjcs 			printf("%-11s %-10s %14s %-8s\n",
3858ccdd032Sderaadt 			    "Volume", "Status", "Size", "Device");
3868ccdd032Sderaadt 		}
3878ccdd032Sderaadt 
3880a92ff65Sderaadt 		percent[0] = '\0';
3899017fb97Sderaadt 		seconds[0] = '\0';
3900a92ff65Sderaadt 		if (bv.bv_percent != -1)
3910a92ff65Sderaadt 			snprintf(percent, sizeof percent,
3920a92ff65Sderaadt 			    " %d%% done", bv.bv_percent);
3939017fb97Sderaadt 		if (bv.bv_seconds)
3949017fb97Sderaadt 			snprintf(seconds, sizeof seconds,
3959017fb97Sderaadt 			    " %u seconds", bv.bv_seconds);
3968ccdd032Sderaadt 		switch (bv.bv_status) {
397db2730c1Smarco 		case BIOC_SVONLINE:
3988ccdd032Sderaadt 			status = BIOC_SVONLINE_S;
399db2730c1Smarco 			break;
400db2730c1Smarco 		case BIOC_SVOFFLINE:
4018ccdd032Sderaadt 			status = BIOC_SVOFFLINE_S;
402db2730c1Smarco 			break;
403db2730c1Smarco 		case BIOC_SVDEGRADED:
4048ccdd032Sderaadt 			status = BIOC_SVDEGRADED_S;
405db2730c1Smarco 			break;
4060a92ff65Sderaadt 		case BIOC_SVBUILDING:
4070a92ff65Sderaadt 			status = BIOC_SVBUILDING_S;
4080a92ff65Sderaadt 			break;
4090a92ff65Sderaadt 		case BIOC_SVREBUILD:
4100a92ff65Sderaadt 			status = BIOC_SVREBUILD_S;
4110a92ff65Sderaadt 			break;
4120a92ff65Sderaadt 		case BIOC_SVSCRUB:
4130a92ff65Sderaadt 			status = BIOC_SVSCRUB_S;
4140a92ff65Sderaadt 			break;
415db2730c1Smarco 		case BIOC_SVINVALID:
416db2730c1Smarco 		default:
4178ccdd032Sderaadt 			status = BIOC_SVINVALID_S;
418d4546a56Sdlg 		}
419cc711184Skettenis 		switch (bv.bv_cache) {
420cc711184Skettenis 		case BIOC_CVWRITEBACK:
421cc711184Skettenis 			cache = BIOC_CVWRITEBACK_S;
422cc711184Skettenis 			break;
423cc711184Skettenis 		case BIOC_CVWRITETHROUGH:
424cc711184Skettenis 			cache = BIOC_CVWRITETHROUGH_S;
425cc711184Skettenis 			break;
426cc711184Skettenis 		case BIOC_CVUNKNOWN:
427cc711184Skettenis 		default:
428cc711184Skettenis 			cache = BIOC_CVUNKNOWN_S;
429cc711184Skettenis 		}
4303af9de98Smarco 
431aa65acf1Sderaadt 		snprintf(volname, sizeof volname, "%s %u",
4328ccdd032Sderaadt 		    bi.bi_dev, bv.bv_volid);
433b9950701Smarco 
4349ecba717Sderaadt 		unused = 0;
4359ecba717Sderaadt 		hotspare = 0;
436aa65acf1Sderaadt 		if (bv.bv_level == -1 && bv.bv_nodisk == 1)
437aa65acf1Sderaadt 			hotspare = 1;
438b9950701Smarco 		else if (bv.bv_level == -2 && bv.bv_nodisk == 1)
439b9950701Smarco 			unused = 1;
440aa65acf1Sderaadt 		else {
4418ccdd032Sderaadt 			if (human)
4428ccdd032Sderaadt 				fmt_scaled(bv.bv_size, size);
4438ccdd032Sderaadt 			else
4448ccdd032Sderaadt 				snprintf(size, sizeof size, "%14llu",
4458ccdd032Sderaadt 				    bv.bv_size);
446da935596Stodd 			switch (bv.bv_level) {
447da935596Stodd 			case 'C':
448150c22bbSjcs 				printf("%11s %-10s %14s %-7s CRYPTO%s%s\n",
449da935596Stodd 				    volname, status, size, bv.bv_dev,
450da935596Stodd 				    percent, seconds);
451da935596Stodd 				break;
4522b5fc845Sjsing 			case 'c':
4532b5fc845Sjsing 				printf("%11s %-10s %14s %-7s CONCAT%s%s\n",
4542b5fc845Sjsing 				    volname, status, size, bv.bv_dev,
4552b5fc845Sjsing 				    percent, seconds);
4562b5fc845Sjsing 				break;
457da935596Stodd 			default:
458cc711184Skettenis 				printf("%11s %-10s %14s %-7s RAID%u%s%s %s\n",
4590a92ff65Sderaadt 				    volname, status, size, bv.bv_dev,
460cc711184Skettenis 				    bv.bv_level, percent, seconds, cache);
461da935596Stodd 				break;
462da935596Stodd 			}
463da935596Stodd 
464aa65acf1Sderaadt 		}
4658ccdd032Sderaadt 
4668ccdd032Sderaadt 		for (d = 0; d < bv.bv_nodisk; d++) {
467db2730c1Smarco 			memset(&bd, 0, sizeof(bd));
468545c4d7fSjsing 			bd.bd_bio.bio_cookie = bio_cookie;
4698ccdd032Sderaadt 			bd.bd_diskid = d;
4708ccdd032Sderaadt 			bd.bd_volid = i;
4713af9de98Smarco 
472d313c28bSjsing 			if (ioctl(devh, BIOCDISK, &bd))
473da3b0664Shenning 				err(1, "BIOCDISK");
4743af9de98Smarco 
475d313c28bSjsing 			bio_status(&bd.bd_bio.bio_status);
476d313c28bSjsing 
4778ccdd032Sderaadt 			switch (bd.bd_status) {
478db2730c1Smarco 			case BIOC_SDONLINE:
4798ccdd032Sderaadt 				status = BIOC_SDONLINE_S;
480d4546a56Sdlg 				break;
481db2730c1Smarco 			case BIOC_SDOFFLINE:
4828ccdd032Sderaadt 				status = BIOC_SDOFFLINE_S;
483d4546a56Sdlg 				break;
484db2730c1Smarco 			case BIOC_SDFAILED:
4858ccdd032Sderaadt 				status = BIOC_SDFAILED_S;
486db2730c1Smarco 				break;
487db2730c1Smarco 			case BIOC_SDREBUILD:
4888ccdd032Sderaadt 				status = BIOC_SDREBUILD_S;
489db2730c1Smarco 				break;
490db2730c1Smarco 			case BIOC_SDHOTSPARE:
4918ccdd032Sderaadt 				status = BIOC_SDHOTSPARE_S;
492db2730c1Smarco 				break;
493db2730c1Smarco 			case BIOC_SDUNUSED:
4948ccdd032Sderaadt 				status = BIOC_SDUNUSED_S;
495db2730c1Smarco 				break;
496e1dfb373Sderaadt 			case BIOC_SDSCRUB:
497e1dfb373Sderaadt 				status = BIOC_SDSCRUB_S;
498e1dfb373Sderaadt 				break;
499db2730c1Smarco 			case BIOC_SDINVALID:
500d4546a56Sdlg 			default:
5018ccdd032Sderaadt 				status = BIOC_SDINVALID_S;
502d4546a56Sdlg 			}
503aa65acf1Sderaadt 
504b9950701Smarco 			if (hotspare || unused)
505aa65acf1Sderaadt 				;	/* use volname from parent volume */
506aa65acf1Sderaadt 			else
507aa65acf1Sderaadt 				snprintf(volname, sizeof volname, "    %3u",
508aa65acf1Sderaadt 				    bd.bd_diskid);
509aa65acf1Sderaadt 
5100054cd36Sjsing 			if (bv.bv_level == 'C' && bd.bd_size == 0)
5110054cd36Sjsing 				snprintf(size, sizeof size, "%14s", "key disk");
5120054cd36Sjsing 			else if (human)
5138ccdd032Sderaadt 				fmt_scaled(bd.bd_size, size);
5148ccdd032Sderaadt 			else
5158ccdd032Sderaadt 				snprintf(size, sizeof size, "%14llu",
5168ccdd032Sderaadt 				    bd.bd_size);
5178ccdd032Sderaadt 			snprintf(scsiname, sizeof scsiname,
51843d61178Sderaadt 			    "%u:%u.%u",
51943d61178Sderaadt 			    bd.bd_channel, bd.bd_target, bd.bd_lun);
5205978b28dSderaadt 			if (bd.bd_procdev[0])
521abe9d68eSderaadt 				strlcpy(encname, bd.bd_procdev, sizeof encname);
5225978b28dSderaadt 			else
523abe9d68eSderaadt 				strlcpy(encname, "noencl", sizeof encname);
524abe9d68eSderaadt 			if (bd.bd_serial[0])
525abe9d68eSderaadt 				strlcpy(serial, bd.bd_serial, sizeof serial);
526abe9d68eSderaadt 			else
527abe9d68eSderaadt 				strlcpy(serial, "unknown serial", sizeof serial);
5288ccdd032Sderaadt 
529150c22bbSjcs 			printf("%11s %-10s %14s %-7s %-6s <%s>\n",
530aa65acf1Sderaadt 			    volname, status, size, scsiname, encname,
5318ccdd032Sderaadt 			    bd.bd_vendor);
532abe9d68eSderaadt 			if (verbose)
533959b5194Skettenis 				printf("%11s %-10s %14s %-7s %-6s '%s'\n",
534abe9d68eSderaadt 				    "", "", "", "", "", serial);
535d4546a56Sdlg 		}
536d4546a56Sdlg 	}
537d4546a56Sdlg }
538edfd9792Smarco 
539edfd9792Smarco void
540edfd9792Smarco bio_alarm(char *arg)
541edfd9792Smarco {
5428ccdd032Sderaadt 	struct bioc_alarm	ba;
543edfd9792Smarco 
544c2b1f828Sderaadt 	memset(&ba, 0, sizeof(ba));
545545c4d7fSjsing 	ba.ba_bio.bio_cookie = bio_cookie;
546edfd9792Smarco 
547edfd9792Smarco 	switch (arg[0]) {
548edfd9792Smarco 	case 'q': /* silence alarm */
549edfd9792Smarco 		/* FALLTHROUGH */
550edfd9792Smarco 	case 's':
5518ccdd032Sderaadt 		ba.ba_opcode = BIOC_SASILENCE;
552edfd9792Smarco 		break;
553edfd9792Smarco 
554edfd9792Smarco 	case 'e': /* enable alarm */
5558ccdd032Sderaadt 		ba.ba_opcode = BIOC_SAENABLE;
556edfd9792Smarco 		break;
557edfd9792Smarco 
558edfd9792Smarco 	case 'd': /* disable alarm */
5598ccdd032Sderaadt 		ba.ba_opcode = BIOC_SADISABLE;
560edfd9792Smarco 		break;
561edfd9792Smarco 
562edfd9792Smarco 	case 't': /* test alarm */
5638ccdd032Sderaadt 		ba.ba_opcode = BIOC_SATEST;
564edfd9792Smarco 		break;
565edfd9792Smarco 
566edfd9792Smarco 	case 'g': /* get alarm state */
5678ccdd032Sderaadt 		ba.ba_opcode = BIOC_GASTATUS;
568edfd9792Smarco 		break;
569edfd9792Smarco 
570edfd9792Smarco 	default:
571da3b0664Shenning 		errx(1, "invalid alarm function: %s", arg);
572edfd9792Smarco 	}
573edfd9792Smarco 
574d313c28bSjsing 	if (ioctl(devh, BIOCALARM, &ba))
575da3b0664Shenning 		err(1, "BIOCALARM");
576edfd9792Smarco 
577d313c28bSjsing 	bio_status(&ba.ba_bio.bio_status);
578d313c28bSjsing 
579d313c28bSjsing 	if (arg[0] == 'g')
580edfd9792Smarco 		printf("alarm is currently %s\n",
5818ccdd032Sderaadt 		    ba.ba_status ? "enabled" : "disabled");
582edfd9792Smarco }
5836de960dcSmarco 
584a15048bbSmarco int
585a15048bbSmarco bio_getvolbyname(char *name)
586a15048bbSmarco {
587d313c28bSjsing 	int			id = -1, i;
588a15048bbSmarco 	struct bioc_inq		bi;
589a15048bbSmarco 	struct bioc_vol		bv;
590a15048bbSmarco 
591a15048bbSmarco 	memset(&bi, 0, sizeof(bi));
592545c4d7fSjsing 	bi.bi_bio.bio_cookie = bio_cookie;
593d313c28bSjsing 	if (ioctl(devh, BIOCINQ, &bi))
594a15048bbSmarco 		err(1, "BIOCINQ");
595a15048bbSmarco 
596d313c28bSjsing 	bio_status(&bi.bi_bio.bio_status);
597d313c28bSjsing 
598a15048bbSmarco 	for (i = 0; i < bi.bi_novol; i++) {
599a15048bbSmarco 		memset(&bv, 0, sizeof(bv));
600545c4d7fSjsing 		bv.bv_bio.bio_cookie = bio_cookie;
601a15048bbSmarco 		bv.bv_volid = i;
602d313c28bSjsing 		if (ioctl(devh, BIOCVOL, &bv))
603a15048bbSmarco 			err(1, "BIOCVOL");
604a15048bbSmarco 
605d313c28bSjsing 		bio_status(&bv.bv_bio.bio_status);
606d313c28bSjsing 
607a15048bbSmarco 		if (name && strcmp(name, bv.bv_dev) != 0)
608a15048bbSmarco 			continue;
609a15048bbSmarco 		id = i;
610a15048bbSmarco 		break;
611a15048bbSmarco 	}
612a15048bbSmarco 
613a15048bbSmarco 	return (id);
614a15048bbSmarco }
615a15048bbSmarco 
616ebaf584eSderaadt void
6178d8693a2Sdtucker bio_setstate(char *arg, int status, char *devicename)
6186de960dcSmarco {
6196de960dcSmarco 	struct bioc_setstate	bs;
6206de960dcSmarco 	struct locator		location;
621a15048bbSmarco 	struct stat		sb;
62241eccc89Sderaadt 	const char		*errstr;
6236de960dcSmarco 
624a15048bbSmarco 	memset(&bs, 0, sizeof(bs));
625a15048bbSmarco 	if (stat(arg, &sb) == -1) {
626a15048bbSmarco 		/* use CTL */
62741eccc89Sderaadt 		errstr = str2locator(arg, &location);
62841eccc89Sderaadt 		if (errstr)
62941eccc89Sderaadt 			errx(1, "Target %s: %s", arg, errstr);
6306de960dcSmarco 		bs.bs_channel = location.channel;
6316de960dcSmarco 		bs.bs_target = location.target;
6326de960dcSmarco 		bs.bs_lun = location.lun;
633a15048bbSmarco 	} else {
634a15048bbSmarco 		/* use other id */
635a15048bbSmarco 		bs.bs_other_id = sb.st_rdev;
636a15048bbSmarco 		bs.bs_other_id_type = BIOC_SSOTHER_DEVT;
637a15048bbSmarco 	}
638a15048bbSmarco 
639545c4d7fSjsing 	bs.bs_bio.bio_cookie = bio_cookie;
640a15048bbSmarco 	bs.bs_status = status;
641a15048bbSmarco 
642d2647ac1Sjsing 	if (status != BIOC_SSHOTSPARE) {
643a15048bbSmarco 		/* make sure user supplied a sd device */
6448d8693a2Sdtucker 		bs.bs_volid = bio_getvolbyname(devicename);
645a15048bbSmarco 		if (bs.bs_volid == -1)
6468d8693a2Sdtucker 			errx(1, "invalid device %s", devicename);
647d2647ac1Sjsing 	}
6486de960dcSmarco 
649d313c28bSjsing 	if (ioctl(devh, BIOCSETSTATE, &bs))
650da3b0664Shenning 		err(1, "BIOCSETSTATE");
651d313c28bSjsing 
652d313c28bSjsing 	bio_status(&bs.bs_bio.bio_status);
6536de960dcSmarco }
654c55617f1Sdlg 
655c55617f1Sdlg void
656a928c459Sderaadt bio_setblink(char *name, char *arg, int blink)
657c55617f1Sdlg {
65850d3c4dcSdlg 	struct locator		location;
659c2b1f828Sderaadt 	struct bioc_blink	bb;
66050d3c4dcSdlg 	struct bioc_inq		bi;
66150d3c4dcSdlg 	struct bioc_vol		bv;
66250d3c4dcSdlg 	struct bioc_disk	bd;
66341eccc89Sderaadt 	const char		*errstr;
66450d3c4dcSdlg 	int			v, d, rv;
665c55617f1Sdlg 
66641eccc89Sderaadt 	errstr = str2locator(arg, &location);
66741eccc89Sderaadt 	if (errstr)
66841eccc89Sderaadt 		errx(1, "Target %s: %s", arg, errstr);
66950d3c4dcSdlg 
6700505205bSdlg 	/* try setting blink on the device directly */
6710505205bSdlg 	memset(&bb, 0, sizeof(bb));
672545c4d7fSjsing 	bb.bb_bio.bio_cookie = bio_cookie;
6730505205bSdlg 	bb.bb_status = blink;
6740505205bSdlg 	bb.bb_target = location.target;
675649724a4Smarco 	bb.bb_channel = location.channel;
6760505205bSdlg 	rv = ioctl(devh, BIOCBLINK, &bb);
677d313c28bSjsing 
678d313c28bSjsing 	if (rv == 0 && bb.bb_bio.bio_status.bs_status == BIO_STATUS_UNKNOWN)
6790505205bSdlg 		return;
6800505205bSdlg 
681d313c28bSjsing 	if (rv == 0 && bb.bb_bio.bio_status.bs_status == BIO_STATUS_SUCCESS) {
682d313c28bSjsing 		bio_status(&bb.bb_bio.bio_status);
683d313c28bSjsing 		return;
684d313c28bSjsing 	}
685d313c28bSjsing 
686855d4e83Ssobrado 	/* if the blink didn't work, try to find something that will */
6870505205bSdlg 
68850d3c4dcSdlg 	memset(&bi, 0, sizeof(bi));
689545c4d7fSjsing 	bi.bi_bio.bio_cookie = bio_cookie;
690d313c28bSjsing 	if (ioctl(devh, BIOCINQ, &bi))
691da3b0664Shenning 		err(1, "BIOCINQ");
69250d3c4dcSdlg 
693d313c28bSjsing 	bio_status(&bi.bi_bio.bio_status);
694d313c28bSjsing 
69550d3c4dcSdlg 	for (v = 0; v < bi.bi_novol; v++) {
69650d3c4dcSdlg 		memset(&bv, 0, sizeof(bv));
697545c4d7fSjsing 		bv.bv_bio.bio_cookie = bio_cookie;
69850d3c4dcSdlg 		bv.bv_volid = v;
699d313c28bSjsing 		if (ioctl(devh, BIOCVOL, &bv))
700da3b0664Shenning 			err(1, "BIOCVOL");
70150d3c4dcSdlg 
702d313c28bSjsing 		bio_status(&bv.bv_bio.bio_status);
703d313c28bSjsing 
70450d3c4dcSdlg 		if (name && strcmp(name, bv.bv_dev) != 0)
70550d3c4dcSdlg 			continue;
70650d3c4dcSdlg 
70750d3c4dcSdlg 		for (d = 0; d < bv.bv_nodisk; d++) {
70850d3c4dcSdlg 			memset(&bd, 0, sizeof(bd));
709545c4d7fSjsing 			bd.bd_bio.bio_cookie = bio_cookie;
71050d3c4dcSdlg 			bd.bd_volid = v;
71150d3c4dcSdlg 			bd.bd_diskid = d;
71250d3c4dcSdlg 
713d313c28bSjsing 			if (ioctl(devh, BIOCDISK, &bd))
714da3b0664Shenning 				err(1, "BIOCDISK");
71550d3c4dcSdlg 
716d313c28bSjsing 			bio_status(&bd.bd_bio.bio_status);
717d313c28bSjsing 
71850d3c4dcSdlg 			if (bd.bd_channel == location.channel &&
71950d3c4dcSdlg 			    bd.bd_target == location.target &&
72050d3c4dcSdlg 			    bd.bd_lun == location.lun) {
721d313c28bSjsing 				if (bd.bd_procdev[0] != '\0')
72250d3c4dcSdlg 					bio_blink(bd.bd_procdev,
723a928c459Sderaadt 					    location.target, blink);
724d313c28bSjsing 				else
725d313c28bSjsing 					warnx("Disk %s is not in an enclosure",
726d313c28bSjsing 					    arg);
72750d3c4dcSdlg 				return;
72850d3c4dcSdlg 			}
72950d3c4dcSdlg 		}
73050d3c4dcSdlg 	}
73150d3c4dcSdlg 
73241eccc89Sderaadt 	warnx("Disk %s does not exist", arg);
733d313c28bSjsing 
73450d3c4dcSdlg 	return;
73550d3c4dcSdlg }
73650d3c4dcSdlg 
73750d3c4dcSdlg void
738a928c459Sderaadt bio_blink(char *enclosure, int target, int blinktype)
73950d3c4dcSdlg {
74050d3c4dcSdlg 	int			bioh;
741d313c28bSjsing 	struct bio_locate	bl;
74250d3c4dcSdlg 	struct bioc_blink	blink;
74350d3c4dcSdlg 
74441eccc89Sderaadt 	bioh = open("/dev/bio", O_RDWR);
74550d3c4dcSdlg 	if (bioh == -1)
74641eccc89Sderaadt 		err(1, "Can't open %s", "/dev/bio");
74750d3c4dcSdlg 
748c2b1f828Sderaadt 	memset(&bl, 0, sizeof(bl));
749d313c28bSjsing 	bl.bl_name = enclosure;
750d313c28bSjsing 	if (ioctl(bioh, BIOCLOCATE, &bl))
75141eccc89Sderaadt 		errx(1, "Can't locate %s device via %s", enclosure, "/dev/bio");
752c55617f1Sdlg 
753d313c28bSjsing 	bio_status(&bl.bl_bio.bio_status);
754d313c28bSjsing 
755c55617f1Sdlg 	memset(&blink, 0, sizeof(blink));
756545c4d7fSjsing 	blink.bb_bio.bio_cookie = bio_cookie;
757a928c459Sderaadt 	blink.bb_status = blinktype;
758c55617f1Sdlg 	blink.bb_target = target;
759c55617f1Sdlg 
760d313c28bSjsing 	if (ioctl(bioh, BIOCBLINK, &blink))
761da3b0664Shenning 		err(1, "BIOCBLINK");
76250d3c4dcSdlg 
763d313c28bSjsing 	bio_status(&blink.bb_bio.bio_status);
764d313c28bSjsing 
76550d3c4dcSdlg 	close(bioh);
766c55617f1Sdlg }
7677195049bSmarco 
768e7d4f752Sderaadt #ifdef AOE
769a2fc2d65Stedu struct sr_aoe_config *
770a2fc2d65Stedu create_aoe(u_int16_t level, char *dev_list)
771a2fc2d65Stedu {
772a2fc2d65Stedu 	static struct sr_aoe_config sac;
773a2fc2d65Stedu 	char *nic;
774a2fc2d65Stedu 	char *dsteaddr;
775a2fc2d65Stedu 	char *shelf;
776a2fc2d65Stedu 	char *slot;
777a2fc2d65Stedu 	struct ether_addr *eaddr;
778a2fc2d65Stedu 	const char *errstr;
779a2fc2d65Stedu 
780a2fc2d65Stedu 	nic = dsteaddr = slot = shelf = 0;
781a2fc2d65Stedu 
782a2fc2d65Stedu 	memset(&sac, 0, sizeof(sac));
783a2fc2d65Stedu 	nic = dev_list;
784a2fc2d65Stedu 	dsteaddr = strchr(nic, ',');
785a2fc2d65Stedu 	if (!dsteaddr)
786a2fc2d65Stedu 		goto invalid;
787a2fc2d65Stedu 	*dsteaddr++ = '\0';
788a2fc2d65Stedu 	shelf = strchr(dsteaddr, ',');
789a2fc2d65Stedu 	if (!shelf)
790a2fc2d65Stedu 		goto invalid;
791a2fc2d65Stedu 	*shelf++ = '\0';
792a2fc2d65Stedu 	slot = strchr(shelf, ',');
793a2fc2d65Stedu 	if (!slot)
794a2fc2d65Stedu 		goto invalid;
795a2fc2d65Stedu 	*slot++ = '\0';
796a2fc2d65Stedu 	strlcpy(sac.nic, nic, sizeof(sac.nic));
797a2fc2d65Stedu 	eaddr = ether_aton(dsteaddr);
798a2fc2d65Stedu 	if (!eaddr)
799a2fc2d65Stedu 		goto invalid;
800a2fc2d65Stedu 	sac.dsteaddr = *eaddr;
801a2fc2d65Stedu 	sac.shelf = htons(strtonum(shelf, 0, 0xfffe, &errstr));
802a2fc2d65Stedu 	if (errstr)
803a2fc2d65Stedu 		goto invalid;
804a2fc2d65Stedu 	sac.slot = strtonum(slot, 0, 0xfe, &errstr);
805a2fc2d65Stedu 	if (errstr)
806a2fc2d65Stedu 		goto invalid;
807a2fc2d65Stedu 
808a2fc2d65Stedu 	return &sac;
809a2fc2d65Stedu invalid:
810a2fc2d65Stedu 	errx(1, "invalid AOE dev list: use nic,dsteaddr,shelf,slot");
811a2fc2d65Stedu }
812e7d4f752Sderaadt #endif /* AOE */
813a2fc2d65Stedu 
8147195049bSmarco void
8150054cd36Sjsing bio_createraid(u_int16_t level, char *dev_list, char *key_disk)
8167195049bSmarco {
8177195049bSmarco 	struct bioc_createraid	create;
818aef7fe28Shshoexer 	struct sr_crypto_kdfinfo kdfinfo;
819aef7fe28Shshoexer 	struct sr_crypto_kdf_pbkdf2 kdfhint;
820934f30d8Sderaadt #ifdef AOE
821a2fc2d65Stedu 	struct sr_aoe_config	*sac;
822934f30d8Sderaadt #endif /* AOE */
8230054cd36Sjsing 	struct stat		sb;
8248b0d0f28Sjsing 	int			rv, no_dev, fd;
8257f8eae2bSnicm 	dev_t			*dt;
8267195049bSmarco 	u_int16_t		min_disks = 0;
8277195049bSmarco 
8287195049bSmarco 	if (!dev_list)
8297195049bSmarco 		errx(1, "no devices specified");
8307195049bSmarco 
831e7d4f752Sderaadt #ifdef AOE
832a2fc2d65Stedu 	if (level == 'a') {
833a2fc2d65Stedu 		sac = create_aoe(level, dev_list);
834a2fc2d65Stedu 		no_dev = 0;
835a2fc2d65Stedu 		dt = NULL;
836e7d4f752Sderaadt 	} else
837e7d4f752Sderaadt #endif /* AOE */
838e7d4f752Sderaadt 	{
839f9b0dfcfStedu 		dt = calloc(1, BIOC_CRMAXLEN);
84046bc198bSmarco 		if (!dt)
84146bc198bSmarco 			err(1, "not enough memory for dev_t list");
84246bc198bSmarco 
84346bc198bSmarco 		no_dev = bio_parse_devlist(dev_list, dt);
844a2fc2d65Stedu 	}
84546bc198bSmarco 
8467195049bSmarco 	switch (level) {
8477195049bSmarco 	case 0:
84884e48fabSmarco 		min_disks = 2;
8497195049bSmarco 		break;
8507195049bSmarco 	case 1:
8517195049bSmarco 		min_disks = 2;
8527195049bSmarco 		break;
853c231d813Sjsing #ifdef RAID5
854e717853eSmarco 	case 5:
855e717853eSmarco 		min_disks = 3;
856e717853eSmarco 		break;
857c231d813Sjsing #endif /* RAID5 */
85884e48fabSmarco 	case 'C':
859aef7fe28Shshoexer 		min_disks = 1;
86084e48fabSmarco 		break;
86198b750e4Stedu 	case 'c':
8628fe6c343Sjsing 		min_disks = 2;
86398b750e4Stedu 		break;
864c231d813Sjsing #ifdef AOE
865a2fc2d65Stedu 	case 'a':
866a2fc2d65Stedu 		break;
867c231d813Sjsing #endif /* AOE */
8687195049bSmarco 	default:
86923afedbfSgrunk 		errx(1, "unsupported raid level");
8707195049bSmarco 	}
8717195049bSmarco 
87284e48fabSmarco 	if (no_dev < min_disks)
87384e48fabSmarco 		errx(1, "not enough disks");
87484e48fabSmarco 
875aef7fe28Shshoexer 	/* for crypto raid we only allow one single chunk */
876aef7fe28Shshoexer 	if (level == 'C' && no_dev != min_disks)
877818b0595Shalex 		errx(1, "not exactly one partition");
878aef7fe28Shshoexer 
8797195049bSmarco 	memset(&create, 0, sizeof(create));
880545c4d7fSjsing 	create.bc_bio.bio_cookie = bio_cookie;
8817195049bSmarco 	create.bc_level = level;
88246bc198bSmarco 	create.bc_dev_list_len = no_dev * sizeof(dev_t);
88346bc198bSmarco 	create.bc_dev_list = dt;
884e8a57fdeSmarco 	create.bc_flags = BIOC_SCDEVT | cflags;
8850054cd36Sjsing 	create.bc_key_disk = NODEV;
8867195049bSmarco 
887e7d4f752Sderaadt #ifdef AOE
888a2fc2d65Stedu 	if (level == 'a') {
889a2fc2d65Stedu 		create.bc_opaque = sac;
890a2fc2d65Stedu 		create.bc_opaque_size = sizeof(*sac);
891a2fc2d65Stedu 		create.bc_opaque_flags = BIOC_SOIN;
892e7d4f752Sderaadt 	} else
893e7d4f752Sderaadt #endif /* AOE */
894e7d4f752Sderaadt 	if (level == 'C' && key_disk == NULL) {
8950054cd36Sjsing 
896aef7fe28Shshoexer 		memset(&kdfinfo, 0, sizeof(kdfinfo));
897aef7fe28Shshoexer 		memset(&kdfhint, 0, sizeof(kdfhint));
898aef7fe28Shshoexer 
8990054cd36Sjsing 		create.bc_flags |= BIOC_SCNOAUTOASSEMBLE;
9000054cd36Sjsing 
901aef7fe28Shshoexer 		create.bc_opaque = &kdfhint;
902aef7fe28Shshoexer 		create.bc_opaque_size = sizeof(kdfhint);
903aef7fe28Shshoexer 		create.bc_opaque_flags = BIOC_SOOUT;
904aef7fe28Shshoexer 
905aef7fe28Shshoexer 		/* try to get KDF hint */
906d313c28bSjsing 		if (ioctl(devh, BIOCCREATERAID, &create))
90783e979edShshoexer 			err(1, "ioctl");
90883e979edShshoexer 
909d313c28bSjsing 		bio_status(&create.bc_bio.bio_status);
910d313c28bSjsing 
91183e979edShshoexer 		if (create.bc_opaque_status == BIOC_SOINOUT_OK) {
912c6446370Sjsing 			bio_kdf_derive(&kdfinfo, &kdfhint, "Passphrase: ", 0);
913aef7fe28Shshoexer 			memset(&kdfhint, 0, sizeof(kdfhint));
914aef7fe28Shshoexer 		} else {
915aef7fe28Shshoexer 			bio_kdf_generate(&kdfinfo);
916aef7fe28Shshoexer 		}
917aef7fe28Shshoexer 
918aef7fe28Shshoexer 		create.bc_opaque = &kdfinfo;
919aef7fe28Shshoexer 		create.bc_opaque_size = sizeof(kdfinfo);
920aef7fe28Shshoexer 		create.bc_opaque_flags = BIOC_SOIN;
9210054cd36Sjsing 
9220054cd36Sjsing 	} else if (level == 'C' && key_disk != NULL) {
9230054cd36Sjsing 
9248b0d0f28Sjsing 		/* Get device number for key disk. */
9258b0d0f28Sjsing 		fd = opendev(key_disk, O_RDONLY, OPENDEV_BLCK, NULL);
9268b0d0f28Sjsing 		if (fd == -1)
9278b0d0f28Sjsing 			err(1, "could not open %s", key_disk);
9288b0d0f28Sjsing 		if (fstat(fd, &sb) == -1) {
929*ffb4dd05Sguenther 			int saved_errno = errno;
9308b0d0f28Sjsing 			close(fd);
931*ffb4dd05Sguenther 			errc(1, saved_errno, "could not stat %s", key_disk);
9328b0d0f28Sjsing 		}
9338b0d0f28Sjsing 		close(fd);
9340054cd36Sjsing 		create.bc_key_disk = sb.st_rdev;
9350054cd36Sjsing 
9360054cd36Sjsing 		memset(&kdfinfo, 0, sizeof(kdfinfo));
9370054cd36Sjsing 
9380054cd36Sjsing 		kdfinfo.genkdf.len = sizeof(kdfinfo.genkdf);
9390054cd36Sjsing 		kdfinfo.genkdf.type = SR_CRYPTOKDFT_KEYDISK;
9400054cd36Sjsing 		kdfinfo.len = sizeof(kdfinfo);
9410054cd36Sjsing 		kdfinfo.flags = SR_CRYPTOKDF_HINT;
9420054cd36Sjsing 
9430054cd36Sjsing 		create.bc_opaque = &kdfinfo;
9440054cd36Sjsing 		create.bc_opaque_size = sizeof(kdfinfo);
9450054cd36Sjsing 		create.bc_opaque_flags = BIOC_SOIN;
9460054cd36Sjsing 
947aef7fe28Shshoexer 	}
948aef7fe28Shshoexer 
9497195049bSmarco 	rv = ioctl(devh, BIOCCREATERAID, &create);
950aef7fe28Shshoexer 	memset(&kdfinfo, 0, sizeof(kdfinfo));
951d313c28bSjsing 	if (rv == -1)
952da3b0664Shenning 		err(1, "BIOCCREATERAID");
953d313c28bSjsing 
954d313c28bSjsing 	bio_status(&create.bc_bio.bio_status);
95546bc198bSmarco 
95646bc198bSmarco 	free(dt);
95746bc198bSmarco }
95846bc198bSmarco 
959aef7fe28Shshoexer void
960aef7fe28Shshoexer bio_kdf_derive(struct sr_crypto_kdfinfo *kdfinfo, struct sr_crypto_kdf_pbkdf2
961c6446370Sjsing     *kdfhint, char* prompt, int verify)
962aef7fe28Shshoexer {
963aef7fe28Shshoexer 	if (!kdfinfo)
964aef7fe28Shshoexer 		errx(1, "invalid KDF info");
965aef7fe28Shshoexer 	if (!kdfhint)
966aef7fe28Shshoexer 		errx(1, "invalid KDF hint");
967aef7fe28Shshoexer 
968aef7fe28Shshoexer 	if (kdfhint->len != sizeof(*kdfhint))
969aef7fe28Shshoexer 		errx(1, "KDF hint has invalid size");
970aef7fe28Shshoexer 	if (kdfhint->type != SR_CRYPTOKDFT_PBKDF2)
971aef7fe28Shshoexer 		errx(1, "unknown KDF type %d", kdfhint->type);
972aef7fe28Shshoexer 	if (kdfhint->rounds < 1000)
973aef7fe28Shshoexer 		errx(1, "number of KDF rounds too low: %d", kdfhint->rounds);
974aef7fe28Shshoexer 
975aef7fe28Shshoexer 	kdfinfo->flags = SR_CRYPTOKDF_KEY;
976aef7fe28Shshoexer 	kdfinfo->len = sizeof(*kdfinfo);
977aef7fe28Shshoexer 
9789e8c6f5bShshoexer 	derive_key_pkcs(kdfhint->rounds,
979aef7fe28Shshoexer 	    kdfinfo->maskkey, sizeof(kdfinfo->maskkey),
980c6446370Sjsing 	    kdfhint->salt, sizeof(kdfhint->salt), prompt, verify);
981aef7fe28Shshoexer }
982aef7fe28Shshoexer 
983aef7fe28Shshoexer void
984aef7fe28Shshoexer bio_kdf_generate(struct sr_crypto_kdfinfo *kdfinfo)
985aef7fe28Shshoexer {
986aef7fe28Shshoexer 	if (!kdfinfo)
987aef7fe28Shshoexer 		errx(1, "invalid KDF info");
988aef7fe28Shshoexer 
989aef7fe28Shshoexer 	kdfinfo->pbkdf2.len = sizeof(kdfinfo->pbkdf2);
990aef7fe28Shshoexer 	kdfinfo->pbkdf2.type = SR_CRYPTOKDFT_PBKDF2;
991aedd4f07Sdjm 	kdfinfo->pbkdf2.rounds = rflag;
992aef7fe28Shshoexer 	kdfinfo->len = sizeof(*kdfinfo);
9930054cd36Sjsing 	kdfinfo->flags = SR_CRYPTOKDF_KEY | SR_CRYPTOKDF_HINT;
994aef7fe28Shshoexer 
995aef7fe28Shshoexer 	/* generate salt */
996aef7fe28Shshoexer 	arc4random_buf(kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt));
997aef7fe28Shshoexer 
9989e8c6f5bShshoexer 	derive_key_pkcs(kdfinfo->pbkdf2.rounds,
999aef7fe28Shshoexer 	    kdfinfo->maskkey, sizeof(kdfinfo->maskkey),
1000c6446370Sjsing 	    kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt),
1001c6446370Sjsing 	    "New passphrase: ", 1);
1002aef7fe28Shshoexer }
1003aef7fe28Shshoexer 
100446bc198bSmarco int
100546bc198bSmarco bio_parse_devlist(char *lst, dev_t *dt)
100646bc198bSmarco {
100746bc198bSmarco 	char			*s, *e;
100846bc198bSmarco 	u_int32_t		sz = 0;
100946bc198bSmarco 	int			no_dev = 0, i, x;
101046bc198bSmarco 	struct stat		sb;
10115c1f8f6bSdjm 	char			dev[MAXPATHLEN];
1012e37c64dbSjsing 	int			fd;
101346bc198bSmarco 
101446bc198bSmarco 	if (!lst)
101546bc198bSmarco 		errx(1, "invalid device list");
101646bc198bSmarco 
101746bc198bSmarco 	s = e = lst;
101846bc198bSmarco 	/* make sure we have a valid device list like /dev/sdNa,/dev/sdNNa */
101946bc198bSmarco 	while (*e != '\0') {
102046bc198bSmarco 		if (*e == ',')
102146bc198bSmarco 			s = e + 1;
102246bc198bSmarco 		else if (*(e + 1) == '\0' || *(e + 1) == ',') {
102346bc198bSmarco 			/* got one */
102446bc198bSmarco 			sz = e - s + 1;
10255c1f8f6bSdjm 			strlcpy(dev, s, sz + 1);
1026e37c64dbSjsing 			fd = opendev(dev, O_RDONLY, OPENDEV_BLCK, NULL);
1027e37c64dbSjsing 			if (fd == -1)
1028e37c64dbSjsing 				err(1, "could not open %s", dev);
1029e37c64dbSjsing 			if (fstat(fd, &sb) == -1) {
1030*ffb4dd05Sguenther 				int saved_errno = errno;
1031e37c64dbSjsing 				close(fd);
1032*ffb4dd05Sguenther 				errc(1, saved_errno, "could not stat %s", dev);
1033e37c64dbSjsing 			}
1034e37c64dbSjsing 			close(fd);
103546bc198bSmarco 			dt[no_dev] = sb.st_rdev;
103646bc198bSmarco 			no_dev++;
10375c1f8f6bSdjm 			if (no_dev > (int)(BIOC_CRMAXLEN / sizeof(dev_t)))
103846bc198bSmarco 				errx(1, "too many devices on device list");
103946bc198bSmarco 		}
104046bc198bSmarco 		e++;
104146bc198bSmarco 	}
104246bc198bSmarco 
104346bc198bSmarco 	for (i = 0; i < no_dev; i++)
104446bc198bSmarco 		for (x = 0; x < no_dev; x++)
104546bc198bSmarco 			if (dt[i] == dt[x] && x != i)
104646bc198bSmarco 				errx(1, "duplicate device in list");
104746bc198bSmarco 
104846bc198bSmarco 	return (no_dev);
10497195049bSmarco }
1050e8a57fdeSmarco 
1051e8a57fdeSmarco u_int32_t
1052e8a57fdeSmarco bio_createflags(char *lst)
1053e8a57fdeSmarco {
1054e8a57fdeSmarco 	char			*s, *e, fs[32];
1055e8a57fdeSmarco 	u_int32_t		sz = 0;
1056e8a57fdeSmarco 	u_int32_t		flags = 0;
1057e8a57fdeSmarco 
1058e8a57fdeSmarco 	if (!lst)
1059e8a57fdeSmarco 		errx(1, "invalid flags list");
1060e8a57fdeSmarco 
1061e8a57fdeSmarco 	s = e = lst;
1062e8a57fdeSmarco 	/* make sure we have a valid flags list like force,noassemeble */
1063e8a57fdeSmarco 	while (*e != '\0') {
1064e8a57fdeSmarco 		if (*e == ',')
1065e8a57fdeSmarco 			s = e + 1;
1066e8a57fdeSmarco 		else if (*(e + 1) == '\0' || *(e + 1) == ',') {
1067e8a57fdeSmarco 			/* got one */
1068e8a57fdeSmarco 			sz = e - s + 1;
1069e8a57fdeSmarco 			switch (s[0]) {
1070e8a57fdeSmarco 			case 'f':
1071e8a57fdeSmarco 				flags |= BIOC_SCFORCE;
1072e8a57fdeSmarco 				break;
1073e8a57fdeSmarco 			case 'n':
1074e8a57fdeSmarco 				flags |= BIOC_SCNOAUTOASSEMBLE;
1075e8a57fdeSmarco 				break;
1076e8a57fdeSmarco 			default:
1077e8a57fdeSmarco 				strlcpy(fs, s, sz + 1);
1078e8a57fdeSmarco 				errx(1, "invalid flag %s", fs);
1079e8a57fdeSmarco 			}
1080e8a57fdeSmarco 		}
1081e8a57fdeSmarco 		e++;
1082e8a57fdeSmarco 	}
1083e8a57fdeSmarco 
1084e8a57fdeSmarco 	return (flags);
1085e8a57fdeSmarco }
108603b2dfbfShenning 
1087c7c3e8aaSmarco void
1088c7c3e8aaSmarco bio_deleteraid(char *dev)
1089c7c3e8aaSmarco {
1090c7c3e8aaSmarco 	struct bioc_deleteraid	bd;
1091c7c3e8aaSmarco 	memset(&bd, 0, sizeof(bd));
1092c7c3e8aaSmarco 
1093545c4d7fSjsing 	bd.bd_bio.bio_cookie = bio_cookie;
1094a15048bbSmarco 	/* XXX make this a dev_t instead of a string */
1095c7c3e8aaSmarco 	strlcpy(bd.bd_dev, dev, sizeof bd.bd_dev);
1096c7c3e8aaSmarco 	if (ioctl(devh, BIOCDELETERAID, &bd))
1097d313c28bSjsing 		err(1, "BIOCDELETERAID");
1098d313c28bSjsing 
1099d313c28bSjsing 	bio_status(&bd.bd_bio.bio_status);
1100c7c3e8aaSmarco }
1101c7c3e8aaSmarco 
1102c6446370Sjsing void
1103c6446370Sjsing bio_changepass(char *dev)
1104c6446370Sjsing {
1105c6446370Sjsing 	struct bioc_discipline bd;
1106c6446370Sjsing 	struct sr_crypto_kdfpair kdfpair;
1107c6446370Sjsing 	struct sr_crypto_kdfinfo kdfinfo1, kdfinfo2;
1108c6446370Sjsing 	struct sr_crypto_kdf_pbkdf2 kdfhint;
1109c6446370Sjsing 	int rv;
1110c6446370Sjsing 
1111c6446370Sjsing 	memset(&bd, 0, sizeof(bd));
1112c6446370Sjsing 	memset(&kdfhint, 0, sizeof(kdfhint));
1113c6446370Sjsing 	memset(&kdfinfo1, 0, sizeof(kdfinfo1));
1114c6446370Sjsing 	memset(&kdfinfo2, 0, sizeof(kdfinfo2));
1115c6446370Sjsing 
1116c6446370Sjsing 	/* XXX use dev_t instead of string. */
1117c6446370Sjsing 	strlcpy(bd.bd_dev, dev, sizeof(bd.bd_dev));
1118c6446370Sjsing 	bd.bd_cmd = SR_IOCTL_GET_KDFHINT;
1119c6446370Sjsing 	bd.bd_size = sizeof(kdfhint);
1120c6446370Sjsing 	bd.bd_data = &kdfhint;
1121c6446370Sjsing 
1122c6446370Sjsing 	if (ioctl(devh, BIOCDISCIPLINE, &bd))
1123d313c28bSjsing 		err(1, "BIOCDISCIPLINE");
1124d313c28bSjsing 
1125d313c28bSjsing 	bio_status(&bd.bd_bio.bio_status);
1126c6446370Sjsing 
1127c6446370Sjsing 	/* Current passphrase. */
1128c6446370Sjsing 	bio_kdf_derive(&kdfinfo1, &kdfhint, "Old passphrase: ", 0);
1129c6446370Sjsing 
1130c6446370Sjsing 	/* New passphrase. */
1131c6446370Sjsing 	bio_kdf_derive(&kdfinfo2, &kdfhint, "New passphrase: ", 1);
1132c6446370Sjsing 
1133c6446370Sjsing 	kdfpair.kdfinfo1 = &kdfinfo1;
1134c6446370Sjsing 	kdfpair.kdfsize1 = sizeof(kdfinfo1);
1135c6446370Sjsing 	kdfpair.kdfinfo2 = &kdfinfo2;
1136c6446370Sjsing 	kdfpair.kdfsize2 = sizeof(kdfinfo2);
1137c6446370Sjsing 
1138c6446370Sjsing 	bd.bd_cmd = SR_IOCTL_CHANGE_PASSPHRASE;
1139c6446370Sjsing 	bd.bd_size = sizeof(kdfpair);
1140c6446370Sjsing 	bd.bd_data = &kdfpair;
1141c6446370Sjsing 
1142c6446370Sjsing 	rv = ioctl(devh, BIOCDISCIPLINE, &bd);
1143c6446370Sjsing 
1144c6446370Sjsing 	memset(&kdfhint, 0, sizeof(kdfhint));
1145c6446370Sjsing 	memset(&kdfinfo1, 0, sizeof(kdfinfo1));
1146c6446370Sjsing 	memset(&kdfinfo2, 0, sizeof(kdfinfo2));
1147c6446370Sjsing 
1148d313c28bSjsing 	if (rv)
1149d313c28bSjsing 		err(1, "BIOCDISCIPLINE");
1150d313c28bSjsing 
1151d313c28bSjsing 	bio_status(&bd.bd_bio.bio_status);
1152c6446370Sjsing }
1153c6446370Sjsing 
115403b2dfbfShenning #define BIOCTL_VIS_NBUF		4
115503b2dfbfShenning #define BIOCTL_VIS_BUFLEN	80
115603b2dfbfShenning 
115703b2dfbfShenning char *
115803b2dfbfShenning bio_vis(char *s)
115903b2dfbfShenning {
116003b2dfbfShenning 	static char	 rbuf[BIOCTL_VIS_NBUF][BIOCTL_VIS_BUFLEN];
116103b2dfbfShenning 	static uint	 idx = 0;
116203b2dfbfShenning 	char		*buf;
116303b2dfbfShenning 
116403b2dfbfShenning 	buf = rbuf[idx++];
116503b2dfbfShenning 	if (idx == BIOCTL_VIS_NBUF)
116603b2dfbfShenning 		idx = 0;
116703b2dfbfShenning 
116803b2dfbfShenning 	strnvis(buf, s, BIOCTL_VIS_BUFLEN, VIS_NL|VIS_CSTYLE);
116903b2dfbfShenning 	return (buf);
117003b2dfbfShenning }
117103b2dfbfShenning 
117203b2dfbfShenning void
117303b2dfbfShenning bio_diskinq(char *sd_dev)
117403b2dfbfShenning {
117503b2dfbfShenning 	struct dk_inquiry	di;
117603b2dfbfShenning 
1177da3b0664Shenning 	if (ioctl(devh, DIOCINQ, &di) == -1)
1178da3b0664Shenning 		err(1, "DIOCINQ");
117903b2dfbfShenning 
118003b2dfbfShenning 	printf("%s: <%s, %s, %s>, serial %s\n", sd_dev, bio_vis(di.vendor),
118103b2dfbfShenning 	    bio_vis(di.product), bio_vis(di.revision), bio_vis(di.serial));
118203b2dfbfShenning }
1183aef7fe28Shshoexer 
1184aef7fe28Shshoexer void
11859e8c6f5bShshoexer derive_key_pkcs(int rounds, u_int8_t *key, size_t keysz, u_int8_t *salt,
1186c6446370Sjsing     size_t saltsz, char *prompt, int verify)
1187aef7fe28Shshoexer {
118886735da2Smarco 	FILE		*f;
118986735da2Smarco 	size_t		pl;
119086735da2Smarco 	struct stat	sb;
11919e8c6f5bShshoexer 	char		passphrase[1024], verifybuf[1024];
1192aef7fe28Shshoexer 
1193aef7fe28Shshoexer 	if (!key)
1194aef7fe28Shshoexer 		errx(1, "Invalid key");
1195aef7fe28Shshoexer 	if (!salt)
1196aef7fe28Shshoexer 		errx(1, "Invalid salt");
1197aef7fe28Shshoexer 	if (rounds < 1000)
1198b4604b5cShalex 		errx(1, "Too few rounds: %d", rounds);
1199aef7fe28Shshoexer 
1200aef7fe28Shshoexer 	/* get passphrase */
1201ba3d8661Smarco 	if (password && verify)
1202ba3d8661Smarco 		errx(1, "can't specify passphrase file during initial "
1203ba3d8661Smarco 		    "creation of crypto volume");
1204ba3d8661Smarco 	if (password) {
120586735da2Smarco 		if ((f = fopen(password, "r")) == NULL)
120686735da2Smarco 			err(1, "invalid passphrase file");
120786735da2Smarco 
120886735da2Smarco 		if (fstat(fileno(f), &sb) == -1)
120986735da2Smarco 			err(1, "can't stat passphrase file");
121086735da2Smarco 		if (sb.st_uid != 0)
121186735da2Smarco 			errx(1, "passphrase file must be owned by root");
121286735da2Smarco 		if ((sb.st_mode & ~S_IFMT) != (S_IRUSR | S_IWUSR))
121386735da2Smarco 			errx(1, "passphrase file has the wrong permissions");
121486735da2Smarco 
121586735da2Smarco 		if (fgets(passphrase, sizeof(passphrase), f) == NULL)
121686735da2Smarco 			err(1, "can't read passphrase file");
121786735da2Smarco 		pl = strlen(passphrase);
121886735da2Smarco 		if (pl > 0 && passphrase[pl - 1] == '\n')
121986735da2Smarco 			passphrase[pl - 1] = '\0';
122086735da2Smarco 		else
122186735da2Smarco 			errx(1, "invalid passphrase length");
122286735da2Smarco 
122386735da2Smarco 		fclose(f);
1224ba3d8661Smarco 	} else {
1225c6446370Sjsing 		if (readpassphrase(prompt, passphrase, sizeof(passphrase),
1226b96c6ce2Sckuethe 		    rpp_flag) == NULL)
12279e8c6f5bShshoexer 			errx(1, "unable to read passphrase");
1228ba3d8661Smarco 	}
12299e8c6f5bShshoexer 
12309e8c6f5bShshoexer 	if (verify) {
12319e8c6f5bShshoexer 		/* request user to re-type it */
12329e8c6f5bShshoexer 		if (readpassphrase("Re-type passphrase: ", verifybuf,
1233b96c6ce2Sckuethe 		    sizeof(verifybuf), rpp_flag) == NULL) {
12349e8c6f5bShshoexer 			memset(passphrase, 0, sizeof(passphrase));
12359e8c6f5bShshoexer 			errx(1, "unable to read passphrase");
12369e8c6f5bShshoexer 		}
12379e8c6f5bShshoexer 		if ((strlen(passphrase) != strlen(verifybuf)) ||
12389e8c6f5bShshoexer 		    (strcmp(passphrase, verifybuf) != 0)) {
12399e8c6f5bShshoexer 			memset(passphrase, 0, sizeof(passphrase));
12409e8c6f5bShshoexer 			memset(verifybuf, 0, sizeof(verifybuf));
12419e8c6f5bShshoexer 			errx(1, "Passphrases did not match");
12429e8c6f5bShshoexer 		}
12439e8c6f5bShshoexer 		/* forget the re-typed one */
12449e8c6f5bShshoexer 		memset(verifybuf, 0, strlen(verifybuf));
12459e8c6f5bShshoexer 	}
1246aef7fe28Shshoexer 
1247aef7fe28Shshoexer 	/* derive key from passphrase */
12485c1f8f6bSdjm 	if (pkcs5_pbkdf2(passphrase, strlen(passphrase), salt, saltsz,
12495c1f8f6bSdjm 	    key, keysz, rounds) != 0)
12505c1f8f6bSdjm 		errx(1, "pbkdf2 failed");
1251aef7fe28Shshoexer 
1252aef7fe28Shshoexer 	/* forget passphrase */
12539e8c6f5bShshoexer 	memset(passphrase, 0, sizeof(passphrase));
1254aef7fe28Shshoexer 
1255aef7fe28Shshoexer 	return;
1256aef7fe28Shshoexer }
1257