xref: /openbsd/sbin/bioctl/bioctl.c (revision 61f93244)
1*61f93244Sjsing /* $OpenBSD: bioctl.c,v 1.133 2016/09/08 18:41:04 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 
30b9fc9a72Sderaadt #include <sys/param.h>	/* NODEV */
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>
46b9fc9a72Sderaadt #include <limits.h>
4703b2dfbfShenning #include <vis.h>
489e8c6f5bShshoexer #include <readpassphrase.h>
49db2730c1Smarco 
506de960dcSmarco struct locator {
516de960dcSmarco 	int		channel;
526de960dcSmarco 	int		target;
536de960dcSmarco 	int		lun;
546de960dcSmarco };
556de960dcSmarco 
56d865b7d2Suebayasi struct timing {
57d865b7d2Suebayasi 	int		interval;
58d865b7d2Suebayasi 	int		start;
59d865b7d2Suebayasi };
60d865b7d2Suebayasi 
618ccdd032Sderaadt void			usage(void);
6241eccc89Sderaadt const char 		*str2locator(const char *, struct locator *);
63d865b7d2Suebayasi const char 		*str2patrol(const char *, struct timing *);
64d313c28bSjsing void			bio_status(struct bio_status *);
6546bc198bSmarco int			bio_parse_devlist(char *, dev_t *);
66aef7fe28Shshoexer void			bio_kdf_derive(struct sr_crypto_kdfinfo *,
67c6446370Sjsing 			    struct sr_crypto_kdf_pbkdf2 *, char *, int);
68aef7fe28Shshoexer void			bio_kdf_generate(struct sr_crypto_kdfinfo *);
69*61f93244Sjsing void			derive_key_pkcs(u_int32_t, int, u_int8_t *, size_t,
70*61f93244Sjsing 			    u_int8_t *, size_t, char *, int);
718ccdd032Sderaadt 
728ccdd032Sderaadt void			bio_inq(char *);
738ccdd032Sderaadt void			bio_alarm(char *);
74a15048bbSmarco int			bio_getvolbyname(char *);
75a15048bbSmarco void			bio_setstate(char *, int, char *);
76a928c459Sderaadt void			bio_setblink(char *, char *, int);
77a928c459Sderaadt void			bio_blink(char *, int, int);
780054cd36Sjsing void			bio_createraid(u_int16_t, char *, char *);
79c7c3e8aaSmarco void			bio_deleteraid(char *);
80c6446370Sjsing void			bio_changepass(char *);
81e8a57fdeSmarco u_int32_t		bio_createflags(char *);
8203b2dfbfShenning char			*bio_vis(char *);
8303b2dfbfShenning void			bio_diskinq(char *);
84d865b7d2Suebayasi void			bio_patrol(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 
116d865b7d2Suebayasi 	while ((ch = getopt(argc, argv, "a:b:C:c:dH:hik:l:O:Pp:qr:R:st:u:v")) !=
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)
177*61f93244Sjsing 				errx(1, "number of KDF 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;
195d865b7d2Suebayasi 		case 't': /* patrol */
196d865b7d2Suebayasi 			func |= BIOC_PATROL;
197d865b7d2Suebayasi 			al_arg = optarg;
198d865b7d2Suebayasi 			break;
199abe9d68eSderaadt 		case 'v':
200abe9d68eSderaadt 			verbose = 1;
201abe9d68eSderaadt 			break;
20203b2dfbfShenning 		case 'q':
20303b2dfbfShenning 			diskinq = 1;
20403b2dfbfShenning 			break;
2053af9de98Smarco 		default:
2063af9de98Smarco 			usage();
2073af9de98Smarco 			/* NOTREACHED */
2083af9de98Smarco 		}
2093af9de98Smarco 	}
210cf6503d7Sderaadt 	argc -= optind;
211cf6503d7Sderaadt 	argv += optind;
2123af9de98Smarco 
213c6446370Sjsing 	if (argc != 1 || (changepass && func != 0))
214cf6503d7Sderaadt 		usage();
215cf6503d7Sderaadt 
216dcbaf4c8Sderaadt 	if (func == 0)
217dcbaf4c8Sderaadt 		func |= BIOC_INQ;
218dcbaf4c8Sderaadt 
219e63d8b1dSdtucker 	devicename = argv[0];
220e63d8b1dSdtucker 	if (devicename == NULL)
221e37c64dbSjsing 		errx(1, "need device");
22210b411a7Smarco 
223e63d8b1dSdtucker 	devh = opendev(devicename, O_RDWR, OPENDEV_PART, &realname);
224e37c64dbSjsing 	if (devh == -1) {
22541eccc89Sderaadt 		devh = open("/dev/bio", O_RDWR);
2263af9de98Smarco 		if (devh == -1)
22741eccc89Sderaadt 			err(1, "Can't open %s", "/dev/bio");
2283af9de98Smarco 
229e63d8b1dSdtucker 		bl.bl_name = devicename;
230d313c28bSjsing 		if (ioctl(devh, BIOCLOCATE, &bl))
23110b411a7Smarco 			errx(1, "Can't locate %s device via %s",
23241eccc89Sderaadt 			    bl.bl_name, "/dev/bio");
233d313c28bSjsing 
234d313c28bSjsing 		bio_status(&bl.bl_bio.bio_status);
235d313c28bSjsing 
236545c4d7fSjsing 		bio_cookie = bl.bl_bio.bio_cookie;
237e37c64dbSjsing 		biodev = 1;
238e63d8b1dSdtucker 		devicename = NULL;
239e37c64dbSjsing 	}
2403af9de98Smarco 
24103b2dfbfShenning 	if (diskinq) {
242e63d8b1dSdtucker 		bio_diskinq(devicename);
243e37c64dbSjsing 	} else if (changepass && !biodev) {
244e63d8b1dSdtucker 		bio_changepass(devicename);
24503b2dfbfShenning 	} else if (func & BIOC_INQ) {
246e63d8b1dSdtucker 		bio_inq(devicename);
247edfd9792Smarco 	} else if (func == BIOC_ALARM) {
248edfd9792Smarco 		bio_alarm(al_arg);
249c55617f1Sdlg 	} else if (func == BIOC_BLINK) {
250e63d8b1dSdtucker 		bio_setblink(devicename, bl_arg, blink);
251d865b7d2Suebayasi 	} else if (func == BIOC_PATROL) {
252d865b7d2Suebayasi 		bio_patrol(al_arg);
2536de960dcSmarco 	} else if (func == BIOC_SETSTATE) {
254a15048bbSmarco 		bio_setstate(al_arg, ss_func, argv[0]);
255e37c64dbSjsing 	} else if (func == BIOC_DELETERAID && !biodev) {
256e63d8b1dSdtucker 		bio_deleteraid(devicename);
2577195049bSmarco 	} else if (func & BIOC_CREATERAID || func & BIOC_DEVLIST) {
2587195049bSmarco 		if (!(func & BIOC_CREATERAID))
2597195049bSmarco 			errx(1, "need -c parameter");
2607195049bSmarco 		if (!(func & BIOC_DEVLIST))
2617195049bSmarco 			errx(1, "need -l parameter");
262e37c64dbSjsing 		if (!biodev)
263e37c64dbSjsing 			errx(1, "must use bio device");
2640054cd36Sjsing 		bio_createraid(cr_level, dev_list, key_disk);
2653af9de98Smarco 	}
2663af9de98Smarco 
2673af9de98Smarco 	return (0);
2683af9de98Smarco }
2693af9de98Smarco 
2703af9de98Smarco void
2713af9de98Smarco usage(void)
2723af9de98Smarco {
2733af9de98Smarco 	extern char		*__progname;
2743af9de98Smarco 
275d90b5d8bSjmc 	fprintf(stderr,
276d0b772c8Sjmc 		"usage: %s [-hiqv] [-a alarm-function] "
277d90b5d8bSjmc 		"[-b channel:target[.lun]]\n"
278d0b772c8Sjmc 		"\t[-H channel:target[.lun]] "
279af56bbe7Smatthieu 		"[-R device | channel:target[.lun]]\n"
2802e6b119fSjmc 		"\t[-t patrol-function] "
2812e6b119fSjmc 		"[-u channel:target[.lun]] "
282d0b772c8Sjmc 		"device\n"
283b96c6ce2Sckuethe 		"       %s [-dhiPqsv] "
284b90fdff5Sjmc 		"[-C flag[,flag,...]] [-c raidlevel] [-k keydisk]\n"
28550e55a42Sjsing 		"\t[-l special[,special,...]] "
28650e55a42Sjsing 		"[-O device | channel:target[.lun]]\n"
28750e55a42Sjsing 		"\t[-p passfile] [-R device | channel:target[.lun]]\n"
2882e6b119fSjmc 		"\t[-r rounds] "
289d0b772c8Sjmc 		"device\n", __progname, __progname);
290d90b5d8bSjmc 
2913af9de98Smarco 	exit(1);
2923af9de98Smarco }
2933af9de98Smarco 
29441eccc89Sderaadt const char *
2956de960dcSmarco str2locator(const char *string, struct locator *location)
2966de960dcSmarco {
29750d3c4dcSdlg 	const char		*errstr;
29841eccc89Sderaadt 	char			parse[80], *targ, *lun;
2996de960dcSmarco 
30041eccc89Sderaadt 	strlcpy(parse, string, sizeof parse);
30141eccc89Sderaadt 	targ = strchr(parse, ':');
3026de960dcSmarco 	if (targ == NULL)
30341eccc89Sderaadt 		return ("target not specified");
3046de960dcSmarco 	*targ++ = '\0';
3056de960dcSmarco 
30650d3c4dcSdlg 	lun = strchr(targ, '.');
3076de960dcSmarco 	if (lun != NULL) {
3086de960dcSmarco 		*lun++ = '\0';
30950d3c4dcSdlg 		location->lun = strtonum(lun, 0, 256, &errstr);
31050d3c4dcSdlg 		if (errstr)
31141eccc89Sderaadt 			return (errstr);
3126de960dcSmarco 	} else
3136de960dcSmarco 		location->lun = 0;
3146de960dcSmarco 
31550d3c4dcSdlg 	location->target = strtonum(targ, 0, 256, &errstr);
31650d3c4dcSdlg 	if (errstr)
31741eccc89Sderaadt 		return (errstr);
31841eccc89Sderaadt 	location->channel = strtonum(parse, 0, 256, &errstr);
31950d3c4dcSdlg 	if (errstr)
32041eccc89Sderaadt 		return (errstr);
32141eccc89Sderaadt 	return (NULL);
3226de960dcSmarco }
3236de960dcSmarco 
324d865b7d2Suebayasi const char *
325d865b7d2Suebayasi str2patrol(const char *string, struct timing *timing)
326d865b7d2Suebayasi {
327d865b7d2Suebayasi 	const char		*errstr;
328d865b7d2Suebayasi 	char			parse[80], *interval = NULL, *start = NULL;
329d865b7d2Suebayasi 
330d865b7d2Suebayasi 	timing->interval = 0;
331d865b7d2Suebayasi 	timing->start = 0;
332d865b7d2Suebayasi 
333d865b7d2Suebayasi 	strlcpy(parse, string, sizeof parse);
334d865b7d2Suebayasi 
335d865b7d2Suebayasi 	interval = strchr(parse, '.');
336d865b7d2Suebayasi 	if (interval != NULL) {
337d865b7d2Suebayasi 		*interval++ = '\0';
338d865b7d2Suebayasi 		start = strchr(interval, '.');
339d865b7d2Suebayasi 		if (start != NULL)
340d865b7d2Suebayasi 			*start++ = '\0';
341d865b7d2Suebayasi 	}
342d865b7d2Suebayasi 	if (interval != NULL) {
343d865b7d2Suebayasi 		/* -1 == continuously */
344d865b7d2Suebayasi 		timing->interval = strtonum(interval, -1, INT_MAX, &errstr);
345d865b7d2Suebayasi 		if (errstr)
346d865b7d2Suebayasi 			return (errstr);
347d865b7d2Suebayasi 	}
348d865b7d2Suebayasi 	if (start != NULL) {
349d865b7d2Suebayasi 		timing->start = strtonum(start, 0, INT_MAX, &errstr);
350d865b7d2Suebayasi 		if (errstr)
351d865b7d2Suebayasi 			return (errstr);
352d865b7d2Suebayasi 	}
353d865b7d2Suebayasi 
354d865b7d2Suebayasi 	return (NULL);
355d865b7d2Suebayasi }
356d865b7d2Suebayasi 
3573af9de98Smarco void
358d313c28bSjsing bio_status(struct bio_status *bs)
359d313c28bSjsing {
3600a69bfccSjsing 	extern char		*__progname;
3610a69bfccSjsing 	char			*prefix;
362d313c28bSjsing 	int			i;
363d313c28bSjsing 
364d313c28bSjsing 	if (strlen(bs->bs_controller))
3650a69bfccSjsing 		prefix = bs->bs_controller;
3660a69bfccSjsing 	else
3670a69bfccSjsing 		prefix = __progname;
368d313c28bSjsing 
3690a69bfccSjsing 	for (i = 0; i < bs->bs_msg_count; i++)
3700a69bfccSjsing 		printf("%s: %s\n", prefix, bs->bs_msgs[i].bm_msg);
3710a69bfccSjsing 
3720a69bfccSjsing 	if (bs->bs_status == BIO_STATUS_ERROR) {
3730a69bfccSjsing 		if (bs->bs_msg_count == 0)
3740a69bfccSjsing 			errx(1, "unknown error");
3750a69bfccSjsing 		else
376d313c28bSjsing 			exit(1);
377d313c28bSjsing 	}
3780a69bfccSjsing }
379d313c28bSjsing 
380d313c28bSjsing void
3818ccdd032Sderaadt bio_inq(char *name)
382d4546a56Sdlg {
383cc711184Skettenis 	char 			*status, *cache;
384cc711184Skettenis 	char			size[64], scsiname[16], volname[32];
385d865b7d2Suebayasi 	char			percent[20], seconds[20];
386d313c28bSjsing 	int			i, d, volheader, hotspare, unused;
387aa65acf1Sderaadt 	char			encname[16], serial[32];
3888ccdd032Sderaadt 	struct bioc_inq		bi;
3898ccdd032Sderaadt 	struct bioc_vol		bv;
390c2b1f828Sderaadt 	struct bioc_disk	bd;
391db2730c1Smarco 
392db2730c1Smarco 	memset(&bi, 0, sizeof(bi));
3933af9de98Smarco 
394545c4d7fSjsing 	bi.bi_bio.bio_cookie = bio_cookie;
3953af9de98Smarco 
396d313c28bSjsing 	if (ioctl(devh, BIOCINQ, &bi)) {
39703b2dfbfShenning 		if (errno == ENOTTY)
39803b2dfbfShenning 			bio_diskinq(name);
39903b2dfbfShenning 		else
400da3b0664Shenning 			err(1, "BIOCINQ");
4013af9de98Smarco 		return;
4023af9de98Smarco 	}
4033af9de98Smarco 
404d313c28bSjsing 	bio_status(&bi.bi_bio.bio_status);
405d313c28bSjsing 
4068ccdd032Sderaadt 	volheader = 0;
4078ccdd032Sderaadt 	for (i = 0; i < bi.bi_novol; i++) {
408db2730c1Smarco 		memset(&bv, 0, sizeof(bv));
409545c4d7fSjsing 		bv.bv_bio.bio_cookie = bio_cookie;
4108ccdd032Sderaadt 		bv.bv_volid = i;
4110a92ff65Sderaadt 		bv.bv_percent = -1;
4129017fb97Sderaadt 		bv.bv_seconds = 0;
41370a2ae7bSmarco 
414d313c28bSjsing 		if (ioctl(devh, BIOCVOL, &bv))
415da3b0664Shenning 			err(1, "BIOCVOL");
4163af9de98Smarco 
417d313c28bSjsing 		bio_status(&bv.bv_bio.bio_status);
418d313c28bSjsing 
4198ccdd032Sderaadt 		if (name && strcmp(name, bv.bv_dev) != 0)
4208ccdd032Sderaadt 			continue;
4218ccdd032Sderaadt 
4228ccdd032Sderaadt 		if (!volheader) {
4238ccdd032Sderaadt 			volheader = 1;
424150c22bbSjcs 			printf("%-11s %-10s %14s %-8s\n",
4258ccdd032Sderaadt 			    "Volume", "Status", "Size", "Device");
4268ccdd032Sderaadt 		}
4278ccdd032Sderaadt 
4280a92ff65Sderaadt 		percent[0] = '\0';
4299017fb97Sderaadt 		seconds[0] = '\0';
4300a92ff65Sderaadt 		if (bv.bv_percent != -1)
4310a92ff65Sderaadt 			snprintf(percent, sizeof percent,
4320a92ff65Sderaadt 			    " %d%% done", bv.bv_percent);
4339017fb97Sderaadt 		if (bv.bv_seconds)
4349017fb97Sderaadt 			snprintf(seconds, sizeof seconds,
4359017fb97Sderaadt 			    " %u seconds", bv.bv_seconds);
4368ccdd032Sderaadt 		switch (bv.bv_status) {
437db2730c1Smarco 		case BIOC_SVONLINE:
4388ccdd032Sderaadt 			status = BIOC_SVONLINE_S;
439db2730c1Smarco 			break;
440db2730c1Smarco 		case BIOC_SVOFFLINE:
4418ccdd032Sderaadt 			status = BIOC_SVOFFLINE_S;
442db2730c1Smarco 			break;
443db2730c1Smarco 		case BIOC_SVDEGRADED:
4448ccdd032Sderaadt 			status = BIOC_SVDEGRADED_S;
445db2730c1Smarco 			break;
4460a92ff65Sderaadt 		case BIOC_SVBUILDING:
4470a92ff65Sderaadt 			status = BIOC_SVBUILDING_S;
4480a92ff65Sderaadt 			break;
4490a92ff65Sderaadt 		case BIOC_SVREBUILD:
4500a92ff65Sderaadt 			status = BIOC_SVREBUILD_S;
4510a92ff65Sderaadt 			break;
4520a92ff65Sderaadt 		case BIOC_SVSCRUB:
4530a92ff65Sderaadt 			status = BIOC_SVSCRUB_S;
4540a92ff65Sderaadt 			break;
455db2730c1Smarco 		case BIOC_SVINVALID:
456db2730c1Smarco 		default:
4578ccdd032Sderaadt 			status = BIOC_SVINVALID_S;
458d4546a56Sdlg 		}
459cc711184Skettenis 		switch (bv.bv_cache) {
460cc711184Skettenis 		case BIOC_CVWRITEBACK:
461cc711184Skettenis 			cache = BIOC_CVWRITEBACK_S;
462cc711184Skettenis 			break;
463cc711184Skettenis 		case BIOC_CVWRITETHROUGH:
464cc711184Skettenis 			cache = BIOC_CVWRITETHROUGH_S;
465cc711184Skettenis 			break;
466cc711184Skettenis 		case BIOC_CVUNKNOWN:
467cc711184Skettenis 		default:
468cc711184Skettenis 			cache = BIOC_CVUNKNOWN_S;
469cc711184Skettenis 		}
4703af9de98Smarco 
471aa65acf1Sderaadt 		snprintf(volname, sizeof volname, "%s %u",
4728ccdd032Sderaadt 		    bi.bi_dev, bv.bv_volid);
473b9950701Smarco 
4749ecba717Sderaadt 		unused = 0;
4759ecba717Sderaadt 		hotspare = 0;
476aa65acf1Sderaadt 		if (bv.bv_level == -1 && bv.bv_nodisk == 1)
477aa65acf1Sderaadt 			hotspare = 1;
478b9950701Smarco 		else if (bv.bv_level == -2 && bv.bv_nodisk == 1)
479b9950701Smarco 			unused = 1;
480aa65acf1Sderaadt 		else {
4818ccdd032Sderaadt 			if (human)
4828ccdd032Sderaadt 				fmt_scaled(bv.bv_size, size);
4838ccdd032Sderaadt 			else
4848ccdd032Sderaadt 				snprintf(size, sizeof size, "%14llu",
4858ccdd032Sderaadt 				    bv.bv_size);
486da935596Stodd 			switch (bv.bv_level) {
487da935596Stodd 			case 'C':
488150c22bbSjcs 				printf("%11s %-10s %14s %-7s CRYPTO%s%s\n",
489da935596Stodd 				    volname, status, size, bv.bv_dev,
490da935596Stodd 				    percent, seconds);
491da935596Stodd 				break;
4922b5fc845Sjsing 			case 'c':
4932b5fc845Sjsing 				printf("%11s %-10s %14s %-7s CONCAT%s%s\n",
4942b5fc845Sjsing 				    volname, status, size, bv.bv_dev,
4952b5fc845Sjsing 				    percent, seconds);
4962b5fc845Sjsing 				break;
497da935596Stodd 			default:
498cc711184Skettenis 				printf("%11s %-10s %14s %-7s RAID%u%s%s %s\n",
4990a92ff65Sderaadt 				    volname, status, size, bv.bv_dev,
500cc711184Skettenis 				    bv.bv_level, percent, seconds, cache);
501da935596Stodd 				break;
502da935596Stodd 			}
503da935596Stodd 
504aa65acf1Sderaadt 		}
5058ccdd032Sderaadt 
5068ccdd032Sderaadt 		for (d = 0; d < bv.bv_nodisk; d++) {
507db2730c1Smarco 			memset(&bd, 0, sizeof(bd));
508545c4d7fSjsing 			bd.bd_bio.bio_cookie = bio_cookie;
5098ccdd032Sderaadt 			bd.bd_diskid = d;
5108ccdd032Sderaadt 			bd.bd_volid = i;
511d865b7d2Suebayasi 			bd.bd_patrol.bdp_percent = -1;
512d865b7d2Suebayasi 			bd.bd_patrol.bdp_seconds = 0;
5133af9de98Smarco 
514d313c28bSjsing 			if (ioctl(devh, BIOCDISK, &bd))
515da3b0664Shenning 				err(1, "BIOCDISK");
5163af9de98Smarco 
517d313c28bSjsing 			bio_status(&bd.bd_bio.bio_status);
518d313c28bSjsing 
5198ccdd032Sderaadt 			switch (bd.bd_status) {
520db2730c1Smarco 			case BIOC_SDONLINE:
5218ccdd032Sderaadt 				status = BIOC_SDONLINE_S;
522d4546a56Sdlg 				break;
523db2730c1Smarco 			case BIOC_SDOFFLINE:
5248ccdd032Sderaadt 				status = BIOC_SDOFFLINE_S;
525d4546a56Sdlg 				break;
526db2730c1Smarco 			case BIOC_SDFAILED:
5278ccdd032Sderaadt 				status = BIOC_SDFAILED_S;
528db2730c1Smarco 				break;
529db2730c1Smarco 			case BIOC_SDREBUILD:
5308ccdd032Sderaadt 				status = BIOC_SDREBUILD_S;
531db2730c1Smarco 				break;
532db2730c1Smarco 			case BIOC_SDHOTSPARE:
5338ccdd032Sderaadt 				status = BIOC_SDHOTSPARE_S;
534db2730c1Smarco 				break;
535db2730c1Smarco 			case BIOC_SDUNUSED:
5368ccdd032Sderaadt 				status = BIOC_SDUNUSED_S;
537db2730c1Smarco 				break;
538e1dfb373Sderaadt 			case BIOC_SDSCRUB:
539e1dfb373Sderaadt 				status = BIOC_SDSCRUB_S;
540e1dfb373Sderaadt 				break;
541db2730c1Smarco 			case BIOC_SDINVALID:
542d4546a56Sdlg 			default:
5438ccdd032Sderaadt 				status = BIOC_SDINVALID_S;
544d4546a56Sdlg 			}
545aa65acf1Sderaadt 
546b9950701Smarco 			if (hotspare || unused)
547aa65acf1Sderaadt 				;	/* use volname from parent volume */
548aa65acf1Sderaadt 			else
549aa65acf1Sderaadt 				snprintf(volname, sizeof volname, "    %3u",
550aa65acf1Sderaadt 				    bd.bd_diskid);
551aa65acf1Sderaadt 
5520054cd36Sjsing 			if (bv.bv_level == 'C' && bd.bd_size == 0)
5530054cd36Sjsing 				snprintf(size, sizeof size, "%14s", "key disk");
5540054cd36Sjsing 			else if (human)
5558ccdd032Sderaadt 				fmt_scaled(bd.bd_size, size);
5568ccdd032Sderaadt 			else
5578ccdd032Sderaadt 				snprintf(size, sizeof size, "%14llu",
5588ccdd032Sderaadt 				    bd.bd_size);
5598ccdd032Sderaadt 			snprintf(scsiname, sizeof scsiname,
56043d61178Sderaadt 			    "%u:%u.%u",
56143d61178Sderaadt 			    bd.bd_channel, bd.bd_target, bd.bd_lun);
5625978b28dSderaadt 			if (bd.bd_procdev[0])
563abe9d68eSderaadt 				strlcpy(encname, bd.bd_procdev, sizeof encname);
5645978b28dSderaadt 			else
565abe9d68eSderaadt 				strlcpy(encname, "noencl", sizeof encname);
566abe9d68eSderaadt 			if (bd.bd_serial[0])
567abe9d68eSderaadt 				strlcpy(serial, bd.bd_serial, sizeof serial);
568abe9d68eSderaadt 			else
569abe9d68eSderaadt 				strlcpy(serial, "unknown serial", sizeof serial);
5708ccdd032Sderaadt 
571d865b7d2Suebayasi 			percent[0] = '\0';
572d865b7d2Suebayasi 			seconds[0] = '\0';
573d865b7d2Suebayasi 			if (bd.bd_patrol.bdp_percent != -1)
574d865b7d2Suebayasi 				snprintf(percent, sizeof percent,
575d865b7d2Suebayasi 				    " patrol %d%% done", bd.bd_patrol.bdp_percent);
576d865b7d2Suebayasi 			if (bd.bd_patrol.bdp_seconds)
577d865b7d2Suebayasi 				snprintf(seconds, sizeof seconds,
578d865b7d2Suebayasi 				    " %u seconds", bd.bd_patrol.bdp_seconds);
579d865b7d2Suebayasi 
580150c22bbSjcs 			printf("%11s %-10s %14s %-7s %-6s <%s>\n",
581aa65acf1Sderaadt 			    volname, status, size, scsiname, encname,
5828ccdd032Sderaadt 			    bd.bd_vendor);
583abe9d68eSderaadt 			if (verbose)
584d865b7d2Suebayasi 				printf("%11s %-10s %14s %-7s %-6s '%s'%s%s\n",
585d865b7d2Suebayasi 				    "", "", "", "", "", serial, percent, seconds);
586d4546a56Sdlg 		}
587d4546a56Sdlg 	}
588d4546a56Sdlg }
589edfd9792Smarco 
590edfd9792Smarco void
591edfd9792Smarco bio_alarm(char *arg)
592edfd9792Smarco {
5938ccdd032Sderaadt 	struct bioc_alarm	ba;
594edfd9792Smarco 
595c2b1f828Sderaadt 	memset(&ba, 0, sizeof(ba));
596545c4d7fSjsing 	ba.ba_bio.bio_cookie = bio_cookie;
597edfd9792Smarco 
598edfd9792Smarco 	switch (arg[0]) {
599edfd9792Smarco 	case 'q': /* silence alarm */
600edfd9792Smarco 		/* FALLTHROUGH */
601edfd9792Smarco 	case 's':
6028ccdd032Sderaadt 		ba.ba_opcode = BIOC_SASILENCE;
603edfd9792Smarco 		break;
604edfd9792Smarco 
605edfd9792Smarco 	case 'e': /* enable alarm */
6068ccdd032Sderaadt 		ba.ba_opcode = BIOC_SAENABLE;
607edfd9792Smarco 		break;
608edfd9792Smarco 
609edfd9792Smarco 	case 'd': /* disable alarm */
6108ccdd032Sderaadt 		ba.ba_opcode = BIOC_SADISABLE;
611edfd9792Smarco 		break;
612edfd9792Smarco 
613edfd9792Smarco 	case 't': /* test alarm */
6148ccdd032Sderaadt 		ba.ba_opcode = BIOC_SATEST;
615edfd9792Smarco 		break;
616edfd9792Smarco 
617edfd9792Smarco 	case 'g': /* get alarm state */
6188ccdd032Sderaadt 		ba.ba_opcode = BIOC_GASTATUS;
619edfd9792Smarco 		break;
620edfd9792Smarco 
621edfd9792Smarco 	default:
622da3b0664Shenning 		errx(1, "invalid alarm function: %s", arg);
623edfd9792Smarco 	}
624edfd9792Smarco 
625d313c28bSjsing 	if (ioctl(devh, BIOCALARM, &ba))
626da3b0664Shenning 		err(1, "BIOCALARM");
627edfd9792Smarco 
628d313c28bSjsing 	bio_status(&ba.ba_bio.bio_status);
629d313c28bSjsing 
630d313c28bSjsing 	if (arg[0] == 'g')
631edfd9792Smarco 		printf("alarm is currently %s\n",
6328ccdd032Sderaadt 		    ba.ba_status ? "enabled" : "disabled");
633edfd9792Smarco }
6346de960dcSmarco 
635a15048bbSmarco int
636a15048bbSmarco bio_getvolbyname(char *name)
637a15048bbSmarco {
638d313c28bSjsing 	int			id = -1, i;
639a15048bbSmarco 	struct bioc_inq		bi;
640a15048bbSmarco 	struct bioc_vol		bv;
641a15048bbSmarco 
642a15048bbSmarco 	memset(&bi, 0, sizeof(bi));
643545c4d7fSjsing 	bi.bi_bio.bio_cookie = bio_cookie;
644d313c28bSjsing 	if (ioctl(devh, BIOCINQ, &bi))
645a15048bbSmarco 		err(1, "BIOCINQ");
646a15048bbSmarco 
647d313c28bSjsing 	bio_status(&bi.bi_bio.bio_status);
648d313c28bSjsing 
649a15048bbSmarco 	for (i = 0; i < bi.bi_novol; i++) {
650a15048bbSmarco 		memset(&bv, 0, sizeof(bv));
651545c4d7fSjsing 		bv.bv_bio.bio_cookie = bio_cookie;
652a15048bbSmarco 		bv.bv_volid = i;
653d313c28bSjsing 		if (ioctl(devh, BIOCVOL, &bv))
654a15048bbSmarco 			err(1, "BIOCVOL");
655a15048bbSmarco 
656d313c28bSjsing 		bio_status(&bv.bv_bio.bio_status);
657d313c28bSjsing 
658a15048bbSmarco 		if (name && strcmp(name, bv.bv_dev) != 0)
659a15048bbSmarco 			continue;
660a15048bbSmarco 		id = i;
661a15048bbSmarco 		break;
662a15048bbSmarco 	}
663a15048bbSmarco 
664a15048bbSmarco 	return (id);
665a15048bbSmarco }
666a15048bbSmarco 
667ebaf584eSderaadt void
6688d8693a2Sdtucker bio_setstate(char *arg, int status, char *devicename)
6696de960dcSmarco {
6706de960dcSmarco 	struct bioc_setstate	bs;
6716de960dcSmarco 	struct locator		location;
672a15048bbSmarco 	struct stat		sb;
67341eccc89Sderaadt 	const char		*errstr;
6746de960dcSmarco 
675a15048bbSmarco 	memset(&bs, 0, sizeof(bs));
676a15048bbSmarco 	if (stat(arg, &sb) == -1) {
677a15048bbSmarco 		/* use CTL */
67841eccc89Sderaadt 		errstr = str2locator(arg, &location);
67941eccc89Sderaadt 		if (errstr)
68041eccc89Sderaadt 			errx(1, "Target %s: %s", arg, errstr);
6816de960dcSmarco 		bs.bs_channel = location.channel;
6826de960dcSmarco 		bs.bs_target = location.target;
6836de960dcSmarco 		bs.bs_lun = location.lun;
684a15048bbSmarco 	} else {
685a15048bbSmarco 		/* use other id */
686a15048bbSmarco 		bs.bs_other_id = sb.st_rdev;
687a15048bbSmarco 		bs.bs_other_id_type = BIOC_SSOTHER_DEVT;
688a15048bbSmarco 	}
689a15048bbSmarco 
690545c4d7fSjsing 	bs.bs_bio.bio_cookie = bio_cookie;
691a15048bbSmarco 	bs.bs_status = status;
692a15048bbSmarco 
693d2647ac1Sjsing 	if (status != BIOC_SSHOTSPARE) {
694a15048bbSmarco 		/* make sure user supplied a sd device */
6958d8693a2Sdtucker 		bs.bs_volid = bio_getvolbyname(devicename);
696a15048bbSmarco 		if (bs.bs_volid == -1)
6978d8693a2Sdtucker 			errx(1, "invalid device %s", devicename);
698d2647ac1Sjsing 	}
6996de960dcSmarco 
700d313c28bSjsing 	if (ioctl(devh, BIOCSETSTATE, &bs))
701da3b0664Shenning 		err(1, "BIOCSETSTATE");
702d313c28bSjsing 
703d313c28bSjsing 	bio_status(&bs.bs_bio.bio_status);
7046de960dcSmarco }
705c55617f1Sdlg 
706c55617f1Sdlg void
707a928c459Sderaadt bio_setblink(char *name, char *arg, int blink)
708c55617f1Sdlg {
70950d3c4dcSdlg 	struct locator		location;
710c2b1f828Sderaadt 	struct bioc_blink	bb;
71150d3c4dcSdlg 	struct bioc_inq		bi;
71250d3c4dcSdlg 	struct bioc_vol		bv;
71350d3c4dcSdlg 	struct bioc_disk	bd;
71441eccc89Sderaadt 	const char		*errstr;
71550d3c4dcSdlg 	int			v, d, rv;
716c55617f1Sdlg 
71741eccc89Sderaadt 	errstr = str2locator(arg, &location);
71841eccc89Sderaadt 	if (errstr)
71941eccc89Sderaadt 		errx(1, "Target %s: %s", arg, errstr);
72050d3c4dcSdlg 
7210505205bSdlg 	/* try setting blink on the device directly */
7220505205bSdlg 	memset(&bb, 0, sizeof(bb));
723545c4d7fSjsing 	bb.bb_bio.bio_cookie = bio_cookie;
7240505205bSdlg 	bb.bb_status = blink;
7250505205bSdlg 	bb.bb_target = location.target;
726649724a4Smarco 	bb.bb_channel = location.channel;
7270505205bSdlg 	rv = ioctl(devh, BIOCBLINK, &bb);
728d313c28bSjsing 
729d313c28bSjsing 	if (rv == 0 && bb.bb_bio.bio_status.bs_status == BIO_STATUS_UNKNOWN)
7300505205bSdlg 		return;
7310505205bSdlg 
732d313c28bSjsing 	if (rv == 0 && bb.bb_bio.bio_status.bs_status == BIO_STATUS_SUCCESS) {
733d313c28bSjsing 		bio_status(&bb.bb_bio.bio_status);
734d313c28bSjsing 		return;
735d313c28bSjsing 	}
736d313c28bSjsing 
737855d4e83Ssobrado 	/* if the blink didn't work, try to find something that will */
7380505205bSdlg 
73950d3c4dcSdlg 	memset(&bi, 0, sizeof(bi));
740545c4d7fSjsing 	bi.bi_bio.bio_cookie = bio_cookie;
741d313c28bSjsing 	if (ioctl(devh, BIOCINQ, &bi))
742da3b0664Shenning 		err(1, "BIOCINQ");
74350d3c4dcSdlg 
744d313c28bSjsing 	bio_status(&bi.bi_bio.bio_status);
745d313c28bSjsing 
74650d3c4dcSdlg 	for (v = 0; v < bi.bi_novol; v++) {
74750d3c4dcSdlg 		memset(&bv, 0, sizeof(bv));
748545c4d7fSjsing 		bv.bv_bio.bio_cookie = bio_cookie;
74950d3c4dcSdlg 		bv.bv_volid = v;
750d313c28bSjsing 		if (ioctl(devh, BIOCVOL, &bv))
751da3b0664Shenning 			err(1, "BIOCVOL");
75250d3c4dcSdlg 
753d313c28bSjsing 		bio_status(&bv.bv_bio.bio_status);
754d313c28bSjsing 
75550d3c4dcSdlg 		if (name && strcmp(name, bv.bv_dev) != 0)
75650d3c4dcSdlg 			continue;
75750d3c4dcSdlg 
75850d3c4dcSdlg 		for (d = 0; d < bv.bv_nodisk; d++) {
75950d3c4dcSdlg 			memset(&bd, 0, sizeof(bd));
760545c4d7fSjsing 			bd.bd_bio.bio_cookie = bio_cookie;
76150d3c4dcSdlg 			bd.bd_volid = v;
76250d3c4dcSdlg 			bd.bd_diskid = d;
76350d3c4dcSdlg 
764d313c28bSjsing 			if (ioctl(devh, BIOCDISK, &bd))
765da3b0664Shenning 				err(1, "BIOCDISK");
76650d3c4dcSdlg 
767d313c28bSjsing 			bio_status(&bd.bd_bio.bio_status);
768d313c28bSjsing 
76950d3c4dcSdlg 			if (bd.bd_channel == location.channel &&
77050d3c4dcSdlg 			    bd.bd_target == location.target &&
77150d3c4dcSdlg 			    bd.bd_lun == location.lun) {
772d313c28bSjsing 				if (bd.bd_procdev[0] != '\0')
77350d3c4dcSdlg 					bio_blink(bd.bd_procdev,
774a928c459Sderaadt 					    location.target, blink);
775d313c28bSjsing 				else
776d313c28bSjsing 					warnx("Disk %s is not in an enclosure",
777d313c28bSjsing 					    arg);
77850d3c4dcSdlg 				return;
77950d3c4dcSdlg 			}
78050d3c4dcSdlg 		}
78150d3c4dcSdlg 	}
78250d3c4dcSdlg 
78341eccc89Sderaadt 	warnx("Disk %s does not exist", arg);
784d313c28bSjsing 
78550d3c4dcSdlg 	return;
78650d3c4dcSdlg }
78750d3c4dcSdlg 
78850d3c4dcSdlg void
789a928c459Sderaadt bio_blink(char *enclosure, int target, int blinktype)
79050d3c4dcSdlg {
79150d3c4dcSdlg 	int			bioh;
792d313c28bSjsing 	struct bio_locate	bl;
79350d3c4dcSdlg 	struct bioc_blink	blink;
79450d3c4dcSdlg 
79541eccc89Sderaadt 	bioh = open("/dev/bio", O_RDWR);
79650d3c4dcSdlg 	if (bioh == -1)
79741eccc89Sderaadt 		err(1, "Can't open %s", "/dev/bio");
79850d3c4dcSdlg 
799c2b1f828Sderaadt 	memset(&bl, 0, sizeof(bl));
800d313c28bSjsing 	bl.bl_name = enclosure;
801d313c28bSjsing 	if (ioctl(bioh, BIOCLOCATE, &bl))
80241eccc89Sderaadt 		errx(1, "Can't locate %s device via %s", enclosure, "/dev/bio");
803c55617f1Sdlg 
804d313c28bSjsing 	bio_status(&bl.bl_bio.bio_status);
805d313c28bSjsing 
806c55617f1Sdlg 	memset(&blink, 0, sizeof(blink));
807545c4d7fSjsing 	blink.bb_bio.bio_cookie = bio_cookie;
808a928c459Sderaadt 	blink.bb_status = blinktype;
809c55617f1Sdlg 	blink.bb_target = target;
810c55617f1Sdlg 
811d313c28bSjsing 	if (ioctl(bioh, BIOCBLINK, &blink))
812da3b0664Shenning 		err(1, "BIOCBLINK");
81350d3c4dcSdlg 
814d313c28bSjsing 	bio_status(&blink.bb_bio.bio_status);
815d313c28bSjsing 
81650d3c4dcSdlg 	close(bioh);
817c55617f1Sdlg }
8187195049bSmarco 
8197195049bSmarco void
8200054cd36Sjsing bio_createraid(u_int16_t level, char *dev_list, char *key_disk)
8217195049bSmarco {
8227195049bSmarco 	struct bioc_createraid	create;
823aef7fe28Shshoexer 	struct sr_crypto_kdfinfo kdfinfo;
824aef7fe28Shshoexer 	struct sr_crypto_kdf_pbkdf2 kdfhint;
8250054cd36Sjsing 	struct stat		sb;
8268b0d0f28Sjsing 	int			rv, no_dev, fd;
8277f8eae2bSnicm 	dev_t			*dt;
8287195049bSmarco 	u_int16_t		min_disks = 0;
8297195049bSmarco 
8307195049bSmarco 	if (!dev_list)
8317195049bSmarco 		errx(1, "no devices specified");
8327195049bSmarco 
833f9b0dfcfStedu 	dt = calloc(1, BIOC_CRMAXLEN);
83446bc198bSmarco 	if (!dt)
83546bc198bSmarco 		err(1, "not enough memory for dev_t list");
83646bc198bSmarco 
83746bc198bSmarco 	no_dev = bio_parse_devlist(dev_list, dt);
83846bc198bSmarco 
8397195049bSmarco 	switch (level) {
8407195049bSmarco 	case 0:
84184e48fabSmarco 		min_disks = 2;
8427195049bSmarco 		break;
8437195049bSmarco 	case 1:
8447195049bSmarco 		min_disks = 2;
8457195049bSmarco 		break;
846e717853eSmarco 	case 5:
847e717853eSmarco 		min_disks = 3;
848e717853eSmarco 		break;
84984e48fabSmarco 	case 'C':
850aef7fe28Shshoexer 		min_disks = 1;
85184e48fabSmarco 		break;
85298b750e4Stedu 	case 'c':
8538fe6c343Sjsing 		min_disks = 2;
85498b750e4Stedu 		break;
8557195049bSmarco 	default:
85623afedbfSgrunk 		errx(1, "unsupported raid level");
8577195049bSmarco 	}
8587195049bSmarco 
85984e48fabSmarco 	if (no_dev < min_disks)
86084e48fabSmarco 		errx(1, "not enough disks");
86184e48fabSmarco 
862aef7fe28Shshoexer 	/* for crypto raid we only allow one single chunk */
863aef7fe28Shshoexer 	if (level == 'C' && no_dev != min_disks)
864818b0595Shalex 		errx(1, "not exactly one partition");
865aef7fe28Shshoexer 
8667195049bSmarco 	memset(&create, 0, sizeof(create));
867545c4d7fSjsing 	create.bc_bio.bio_cookie = bio_cookie;
8687195049bSmarco 	create.bc_level = level;
86946bc198bSmarco 	create.bc_dev_list_len = no_dev * sizeof(dev_t);
87046bc198bSmarco 	create.bc_dev_list = dt;
871e8a57fdeSmarco 	create.bc_flags = BIOC_SCDEVT | cflags;
8720054cd36Sjsing 	create.bc_key_disk = NODEV;
8737195049bSmarco 
874e7d4f752Sderaadt 	if (level == 'C' && key_disk == NULL) {
8750054cd36Sjsing 
876aef7fe28Shshoexer 		memset(&kdfinfo, 0, sizeof(kdfinfo));
877aef7fe28Shshoexer 		memset(&kdfhint, 0, sizeof(kdfhint));
878aef7fe28Shshoexer 
8790054cd36Sjsing 		create.bc_flags |= BIOC_SCNOAUTOASSEMBLE;
8800054cd36Sjsing 
881aef7fe28Shshoexer 		create.bc_opaque = &kdfhint;
882aef7fe28Shshoexer 		create.bc_opaque_size = sizeof(kdfhint);
883aef7fe28Shshoexer 		create.bc_opaque_flags = BIOC_SOOUT;
884aef7fe28Shshoexer 
885aef7fe28Shshoexer 		/* try to get KDF hint */
886d313c28bSjsing 		if (ioctl(devh, BIOCCREATERAID, &create))
88783e979edShshoexer 			err(1, "ioctl");
88883e979edShshoexer 
889d313c28bSjsing 		bio_status(&create.bc_bio.bio_status);
890d313c28bSjsing 
89183e979edShshoexer 		if (create.bc_opaque_status == BIOC_SOINOUT_OK) {
892c6446370Sjsing 			bio_kdf_derive(&kdfinfo, &kdfhint, "Passphrase: ", 0);
893aef7fe28Shshoexer 			memset(&kdfhint, 0, sizeof(kdfhint));
894aef7fe28Shshoexer 		} else {
895aef7fe28Shshoexer 			bio_kdf_generate(&kdfinfo);
896aef7fe28Shshoexer 		}
897aef7fe28Shshoexer 
898aef7fe28Shshoexer 		create.bc_opaque = &kdfinfo;
899aef7fe28Shshoexer 		create.bc_opaque_size = sizeof(kdfinfo);
900aef7fe28Shshoexer 		create.bc_opaque_flags = BIOC_SOIN;
9010054cd36Sjsing 
9020054cd36Sjsing 	} else if (level == 'C' && key_disk != NULL) {
9030054cd36Sjsing 
9048b0d0f28Sjsing 		/* Get device number for key disk. */
9058b0d0f28Sjsing 		fd = opendev(key_disk, O_RDONLY, OPENDEV_BLCK, NULL);
9068b0d0f28Sjsing 		if (fd == -1)
9078b0d0f28Sjsing 			err(1, "could not open %s", key_disk);
9088b0d0f28Sjsing 		if (fstat(fd, &sb) == -1) {
909ffb4dd05Sguenther 			int saved_errno = errno;
9108b0d0f28Sjsing 			close(fd);
911ffb4dd05Sguenther 			errc(1, saved_errno, "could not stat %s", key_disk);
9128b0d0f28Sjsing 		}
9138b0d0f28Sjsing 		close(fd);
9140054cd36Sjsing 		create.bc_key_disk = sb.st_rdev;
9150054cd36Sjsing 
9160054cd36Sjsing 		memset(&kdfinfo, 0, sizeof(kdfinfo));
9170054cd36Sjsing 
9180054cd36Sjsing 		kdfinfo.genkdf.len = sizeof(kdfinfo.genkdf);
9190054cd36Sjsing 		kdfinfo.genkdf.type = SR_CRYPTOKDFT_KEYDISK;
9200054cd36Sjsing 		kdfinfo.len = sizeof(kdfinfo);
9210054cd36Sjsing 		kdfinfo.flags = SR_CRYPTOKDF_HINT;
9220054cd36Sjsing 
9230054cd36Sjsing 		create.bc_opaque = &kdfinfo;
9240054cd36Sjsing 		create.bc_opaque_size = sizeof(kdfinfo);
9250054cd36Sjsing 		create.bc_opaque_flags = BIOC_SOIN;
9260054cd36Sjsing 
927aef7fe28Shshoexer 	}
928aef7fe28Shshoexer 
9297195049bSmarco 	rv = ioctl(devh, BIOCCREATERAID, &create);
9300a488504Spelikan 	explicit_bzero(&kdfinfo, sizeof(kdfinfo));
931d313c28bSjsing 	if (rv == -1)
932da3b0664Shenning 		err(1, "BIOCCREATERAID");
933d313c28bSjsing 
934d313c28bSjsing 	bio_status(&create.bc_bio.bio_status);
93546bc198bSmarco 
93646bc198bSmarco 	free(dt);
93746bc198bSmarco }
93846bc198bSmarco 
939aef7fe28Shshoexer void
940aef7fe28Shshoexer bio_kdf_derive(struct sr_crypto_kdfinfo *kdfinfo, struct sr_crypto_kdf_pbkdf2
941c6446370Sjsing     *kdfhint, char* prompt, int verify)
942aef7fe28Shshoexer {
943aef7fe28Shshoexer 	if (!kdfinfo)
944aef7fe28Shshoexer 		errx(1, "invalid KDF info");
945aef7fe28Shshoexer 	if (!kdfhint)
946aef7fe28Shshoexer 		errx(1, "invalid KDF hint");
947aef7fe28Shshoexer 
948aef7fe28Shshoexer 	if (kdfhint->len != sizeof(*kdfhint))
949aef7fe28Shshoexer 		errx(1, "KDF hint has invalid size");
950aef7fe28Shshoexer 
951aef7fe28Shshoexer 	kdfinfo->flags = SR_CRYPTOKDF_KEY;
952aef7fe28Shshoexer 	kdfinfo->len = sizeof(*kdfinfo);
953aef7fe28Shshoexer 
954*61f93244Sjsing 	derive_key_pkcs(kdfhint->type, kdfhint->rounds,
955aef7fe28Shshoexer 	    kdfinfo->maskkey, sizeof(kdfinfo->maskkey),
956*61f93244Sjsing 	    kdfhint->salt, sizeof(kdfhint->salt),
957*61f93244Sjsing 	    prompt, verify);
958aef7fe28Shshoexer }
959aef7fe28Shshoexer 
960aef7fe28Shshoexer void
961aef7fe28Shshoexer bio_kdf_generate(struct sr_crypto_kdfinfo *kdfinfo)
962aef7fe28Shshoexer {
963aef7fe28Shshoexer 	if (!kdfinfo)
964aef7fe28Shshoexer 		errx(1, "invalid KDF info");
965aef7fe28Shshoexer 
966aef7fe28Shshoexer 	kdfinfo->pbkdf2.len = sizeof(kdfinfo->pbkdf2);
967aef7fe28Shshoexer 	kdfinfo->pbkdf2.type = SR_CRYPTOKDFT_PBKDF2;
968aedd4f07Sdjm 	kdfinfo->pbkdf2.rounds = rflag;
969*61f93244Sjsing 
9700054cd36Sjsing 	kdfinfo->flags = SR_CRYPTOKDF_KEY | SR_CRYPTOKDF_HINT;
971*61f93244Sjsing 	kdfinfo->len = sizeof(*kdfinfo);
972aef7fe28Shshoexer 
973aef7fe28Shshoexer 	/* generate salt */
974aef7fe28Shshoexer 	arc4random_buf(kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt));
975aef7fe28Shshoexer 
976*61f93244Sjsing 	derive_key_pkcs(kdfinfo->pbkdf2.type, kdfinfo->pbkdf2.rounds,
977aef7fe28Shshoexer 	    kdfinfo->maskkey, sizeof(kdfinfo->maskkey),
978c6446370Sjsing 	    kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt),
979c6446370Sjsing 	    "New passphrase: ", 1);
980aef7fe28Shshoexer }
981aef7fe28Shshoexer 
98246bc198bSmarco int
98346bc198bSmarco bio_parse_devlist(char *lst, dev_t *dt)
98446bc198bSmarco {
98546bc198bSmarco 	char			*s, *e;
98646bc198bSmarco 	u_int32_t		sz = 0;
98746bc198bSmarco 	int			no_dev = 0, i, x;
98846bc198bSmarco 	struct stat		sb;
989b9fc9a72Sderaadt 	char			dev[PATH_MAX];
990e37c64dbSjsing 	int			fd;
99146bc198bSmarco 
99246bc198bSmarco 	if (!lst)
99346bc198bSmarco 		errx(1, "invalid device list");
99446bc198bSmarco 
99546bc198bSmarco 	s = e = lst;
99646bc198bSmarco 	/* make sure we have a valid device list like /dev/sdNa,/dev/sdNNa */
99746bc198bSmarco 	while (*e != '\0') {
99846bc198bSmarco 		if (*e == ',')
99946bc198bSmarco 			s = e + 1;
100046bc198bSmarco 		else if (*(e + 1) == '\0' || *(e + 1) == ',') {
100146bc198bSmarco 			/* got one */
100246bc198bSmarco 			sz = e - s + 1;
10035c1f8f6bSdjm 			strlcpy(dev, s, sz + 1);
1004e37c64dbSjsing 			fd = opendev(dev, O_RDONLY, OPENDEV_BLCK, NULL);
1005e37c64dbSjsing 			if (fd == -1)
1006e37c64dbSjsing 				err(1, "could not open %s", dev);
1007e37c64dbSjsing 			if (fstat(fd, &sb) == -1) {
1008ffb4dd05Sguenther 				int saved_errno = errno;
1009e37c64dbSjsing 				close(fd);
1010ffb4dd05Sguenther 				errc(1, saved_errno, "could not stat %s", dev);
1011e37c64dbSjsing 			}
1012e37c64dbSjsing 			close(fd);
101346bc198bSmarco 			dt[no_dev] = sb.st_rdev;
101446bc198bSmarco 			no_dev++;
10155c1f8f6bSdjm 			if (no_dev > (int)(BIOC_CRMAXLEN / sizeof(dev_t)))
101646bc198bSmarco 				errx(1, "too many devices on device list");
101746bc198bSmarco 		}
101846bc198bSmarco 		e++;
101946bc198bSmarco 	}
102046bc198bSmarco 
102146bc198bSmarco 	for (i = 0; i < no_dev; i++)
102246bc198bSmarco 		for (x = 0; x < no_dev; x++)
102346bc198bSmarco 			if (dt[i] == dt[x] && x != i)
102446bc198bSmarco 				errx(1, "duplicate device in list");
102546bc198bSmarco 
102646bc198bSmarco 	return (no_dev);
10277195049bSmarco }
1028e8a57fdeSmarco 
1029e8a57fdeSmarco u_int32_t
1030e8a57fdeSmarco bio_createflags(char *lst)
1031e8a57fdeSmarco {
1032e8a57fdeSmarco 	char			*s, *e, fs[32];
1033e8a57fdeSmarco 	u_int32_t		sz = 0;
1034e8a57fdeSmarco 	u_int32_t		flags = 0;
1035e8a57fdeSmarco 
1036e8a57fdeSmarco 	if (!lst)
1037e8a57fdeSmarco 		errx(1, "invalid flags list");
1038e8a57fdeSmarco 
1039e8a57fdeSmarco 	s = e = lst;
1040e8a57fdeSmarco 	/* make sure we have a valid flags list like force,noassemeble */
1041e8a57fdeSmarco 	while (*e != '\0') {
1042e8a57fdeSmarco 		if (*e == ',')
1043e8a57fdeSmarco 			s = e + 1;
1044e8a57fdeSmarco 		else if (*(e + 1) == '\0' || *(e + 1) == ',') {
1045e8a57fdeSmarco 			/* got one */
1046e8a57fdeSmarco 			sz = e - s + 1;
1047e8a57fdeSmarco 			switch (s[0]) {
1048e8a57fdeSmarco 			case 'f':
1049e8a57fdeSmarco 				flags |= BIOC_SCFORCE;
1050e8a57fdeSmarco 				break;
1051e8a57fdeSmarco 			case 'n':
1052e8a57fdeSmarco 				flags |= BIOC_SCNOAUTOASSEMBLE;
1053e8a57fdeSmarco 				break;
1054e8a57fdeSmarco 			default:
1055e8a57fdeSmarco 				strlcpy(fs, s, sz + 1);
1056e8a57fdeSmarco 				errx(1, "invalid flag %s", fs);
1057e8a57fdeSmarco 			}
1058e8a57fdeSmarco 		}
1059e8a57fdeSmarco 		e++;
1060e8a57fdeSmarco 	}
1061e8a57fdeSmarco 
1062e8a57fdeSmarco 	return (flags);
1063e8a57fdeSmarco }
106403b2dfbfShenning 
1065c7c3e8aaSmarco void
1066c7c3e8aaSmarco bio_deleteraid(char *dev)
1067c7c3e8aaSmarco {
1068c7c3e8aaSmarco 	struct bioc_deleteraid	bd;
1069c7c3e8aaSmarco 	memset(&bd, 0, sizeof(bd));
1070c7c3e8aaSmarco 
1071545c4d7fSjsing 	bd.bd_bio.bio_cookie = bio_cookie;
1072a15048bbSmarco 	/* XXX make this a dev_t instead of a string */
1073c7c3e8aaSmarco 	strlcpy(bd.bd_dev, dev, sizeof bd.bd_dev);
1074c7c3e8aaSmarco 	if (ioctl(devh, BIOCDELETERAID, &bd))
1075d313c28bSjsing 		err(1, "BIOCDELETERAID");
1076d313c28bSjsing 
1077d313c28bSjsing 	bio_status(&bd.bd_bio.bio_status);
1078c7c3e8aaSmarco }
1079c7c3e8aaSmarco 
1080c6446370Sjsing void
1081c6446370Sjsing bio_changepass(char *dev)
1082c6446370Sjsing {
1083c6446370Sjsing 	struct bioc_discipline bd;
1084c6446370Sjsing 	struct sr_crypto_kdfpair kdfpair;
1085c6446370Sjsing 	struct sr_crypto_kdfinfo kdfinfo1, kdfinfo2;
1086c6446370Sjsing 	struct sr_crypto_kdf_pbkdf2 kdfhint;
1087c6446370Sjsing 	int rv;
1088c6446370Sjsing 
1089c6446370Sjsing 	memset(&bd, 0, sizeof(bd));
1090c6446370Sjsing 	memset(&kdfhint, 0, sizeof(kdfhint));
1091c6446370Sjsing 	memset(&kdfinfo1, 0, sizeof(kdfinfo1));
1092c6446370Sjsing 	memset(&kdfinfo2, 0, sizeof(kdfinfo2));
1093c6446370Sjsing 
1094c6446370Sjsing 	/* XXX use dev_t instead of string. */
1095c6446370Sjsing 	strlcpy(bd.bd_dev, dev, sizeof(bd.bd_dev));
1096c6446370Sjsing 	bd.bd_cmd = SR_IOCTL_GET_KDFHINT;
1097c6446370Sjsing 	bd.bd_size = sizeof(kdfhint);
1098c6446370Sjsing 	bd.bd_data = &kdfhint;
1099c6446370Sjsing 
1100c6446370Sjsing 	if (ioctl(devh, BIOCDISCIPLINE, &bd))
1101d313c28bSjsing 		err(1, "BIOCDISCIPLINE");
1102d313c28bSjsing 
1103d313c28bSjsing 	bio_status(&bd.bd_bio.bio_status);
1104c6446370Sjsing 
1105c6446370Sjsing 	/* Current passphrase. */
1106c6446370Sjsing 	bio_kdf_derive(&kdfinfo1, &kdfhint, "Old passphrase: ", 0);
1107c6446370Sjsing 
1108c6446370Sjsing 	/* New passphrase. */
11092c98a0f7Sjsing 	bio_kdf_generate(&kdfinfo2);
1110c6446370Sjsing 
1111c6446370Sjsing 	kdfpair.kdfinfo1 = &kdfinfo1;
1112c6446370Sjsing 	kdfpair.kdfsize1 = sizeof(kdfinfo1);
1113c6446370Sjsing 	kdfpair.kdfinfo2 = &kdfinfo2;
1114c6446370Sjsing 	kdfpair.kdfsize2 = sizeof(kdfinfo2);
1115c6446370Sjsing 
1116c6446370Sjsing 	bd.bd_cmd = SR_IOCTL_CHANGE_PASSPHRASE;
1117c6446370Sjsing 	bd.bd_size = sizeof(kdfpair);
1118c6446370Sjsing 	bd.bd_data = &kdfpair;
1119c6446370Sjsing 
1120c6446370Sjsing 	rv = ioctl(devh, BIOCDISCIPLINE, &bd);
1121c6446370Sjsing 
1122c6446370Sjsing 	memset(&kdfhint, 0, sizeof(kdfhint));
11230a488504Spelikan 	explicit_bzero(&kdfinfo1, sizeof(kdfinfo1));
11240a488504Spelikan 	explicit_bzero(&kdfinfo2, sizeof(kdfinfo2));
1125c6446370Sjsing 
1126d313c28bSjsing 	if (rv)
1127d313c28bSjsing 		err(1, "BIOCDISCIPLINE");
1128d313c28bSjsing 
1129d313c28bSjsing 	bio_status(&bd.bd_bio.bio_status);
1130c6446370Sjsing }
1131c6446370Sjsing 
113203b2dfbfShenning #define BIOCTL_VIS_NBUF		4
113303b2dfbfShenning #define BIOCTL_VIS_BUFLEN	80
113403b2dfbfShenning 
113503b2dfbfShenning char *
113603b2dfbfShenning bio_vis(char *s)
113703b2dfbfShenning {
113803b2dfbfShenning 	static char	 rbuf[BIOCTL_VIS_NBUF][BIOCTL_VIS_BUFLEN];
113903b2dfbfShenning 	static uint	 idx = 0;
114003b2dfbfShenning 	char		*buf;
114103b2dfbfShenning 
114203b2dfbfShenning 	buf = rbuf[idx++];
114303b2dfbfShenning 	if (idx == BIOCTL_VIS_NBUF)
114403b2dfbfShenning 		idx = 0;
114503b2dfbfShenning 
114603b2dfbfShenning 	strnvis(buf, s, BIOCTL_VIS_BUFLEN, VIS_NL|VIS_CSTYLE);
114703b2dfbfShenning 	return (buf);
114803b2dfbfShenning }
114903b2dfbfShenning 
115003b2dfbfShenning void
115103b2dfbfShenning bio_diskinq(char *sd_dev)
115203b2dfbfShenning {
115303b2dfbfShenning 	struct dk_inquiry	di;
115403b2dfbfShenning 
1155da3b0664Shenning 	if (ioctl(devh, DIOCINQ, &di) == -1)
1156da3b0664Shenning 		err(1, "DIOCINQ");
115703b2dfbfShenning 
115803b2dfbfShenning 	printf("%s: <%s, %s, %s>, serial %s\n", sd_dev, bio_vis(di.vendor),
115903b2dfbfShenning 	    bio_vis(di.product), bio_vis(di.revision), bio_vis(di.serial));
116003b2dfbfShenning }
1161aef7fe28Shshoexer 
1162aef7fe28Shshoexer void
1163d865b7d2Suebayasi bio_patrol(char *arg)
1164d865b7d2Suebayasi {
1165d865b7d2Suebayasi 	struct bioc_patrol	bp;
1166d865b7d2Suebayasi 	struct timing		timing;
1167d865b7d2Suebayasi 	const char		*errstr;
1168d865b7d2Suebayasi 
1169d865b7d2Suebayasi 	memset(&bp, 0, sizeof(bp));
1170d865b7d2Suebayasi 	bp.bp_bio.bio_cookie = bio_cookie;
1171d865b7d2Suebayasi 
1172d865b7d2Suebayasi 	switch (arg[0]) {
1173d865b7d2Suebayasi 	case 'a':
1174d865b7d2Suebayasi 		bp.bp_opcode = BIOC_SPAUTO;
1175d865b7d2Suebayasi 		break;
1176d865b7d2Suebayasi 
1177d865b7d2Suebayasi 	case 'm':
1178d865b7d2Suebayasi 		bp.bp_opcode = BIOC_SPMANUAL;
1179d865b7d2Suebayasi 		break;
1180d865b7d2Suebayasi 
1181d865b7d2Suebayasi 	case 'd':
1182d865b7d2Suebayasi 		bp.bp_opcode = BIOC_SPDISABLE;
1183d865b7d2Suebayasi 		break;
1184d865b7d2Suebayasi 
1185d865b7d2Suebayasi 	case 'g': /* get patrol state */
1186d865b7d2Suebayasi 		bp.bp_opcode = BIOC_GPSTATUS;
1187d865b7d2Suebayasi 		break;
1188d865b7d2Suebayasi 
1189d865b7d2Suebayasi 	case 's': /* start/stop patrol */
1190d865b7d2Suebayasi 		if (strncmp("sta", arg, 3) == 0)
1191d865b7d2Suebayasi 			bp.bp_opcode = BIOC_SPSTART;
1192d865b7d2Suebayasi 		else
1193d865b7d2Suebayasi 			bp.bp_opcode = BIOC_SPSTOP;
1194d865b7d2Suebayasi 		break;
1195d865b7d2Suebayasi 
1196d865b7d2Suebayasi 	default:
1197d865b7d2Suebayasi 		errx(1, "invalid patrol function: %s", arg);
1198d865b7d2Suebayasi 	}
1199d865b7d2Suebayasi 
1200d865b7d2Suebayasi 	switch (arg[0]) {
1201d865b7d2Suebayasi 	case 'a':
1202d865b7d2Suebayasi 		errstr = str2patrol(arg, &timing);
1203d865b7d2Suebayasi 		if (errstr)
1204d865b7d2Suebayasi 			errx(1, "Patrol %s: %s", arg, errstr);
1205d865b7d2Suebayasi 		bp.bp_autoival = timing.interval;
1206d865b7d2Suebayasi 		bp.bp_autonext = timing.start;
1207d865b7d2Suebayasi 		break;
1208d865b7d2Suebayasi 	}
1209d865b7d2Suebayasi 
1210d865b7d2Suebayasi 	if (ioctl(devh, BIOCPATROL, &bp))
1211d865b7d2Suebayasi 		err(1, "BIOCPATROL");
1212d865b7d2Suebayasi 
1213d865b7d2Suebayasi 	bio_status(&bp.bp_bio.bio_status);
1214d865b7d2Suebayasi 
1215d865b7d2Suebayasi 	if (arg[0] == 'g') {
1216d865b7d2Suebayasi 		const char *mode, *status;
1217d865b7d2Suebayasi 		char interval[40];
1218d865b7d2Suebayasi 
1219d865b7d2Suebayasi 		interval[0] = '\0';
1220d865b7d2Suebayasi 
1221d865b7d2Suebayasi 		switch (bp.bp_mode) {
1222d865b7d2Suebayasi 		case BIOC_SPMAUTO:
1223d865b7d2Suebayasi 			mode = "auto";
1224d865b7d2Suebayasi 			snprintf(interval, sizeof interval,
1225d865b7d2Suebayasi 			    " interval=%d next=%d", bp.bp_autoival,
1226d865b7d2Suebayasi 			    bp.bp_autonext - bp.bp_autonow);
1227d865b7d2Suebayasi 			break;
1228d865b7d2Suebayasi 		case BIOC_SPMMANUAL:
1229d865b7d2Suebayasi 			mode = "manual";
1230d865b7d2Suebayasi 			break;
1231d865b7d2Suebayasi 		case BIOC_SPMDISABLED:
1232d865b7d2Suebayasi 			mode = "disabled";
1233d865b7d2Suebayasi 			break;
1234d865b7d2Suebayasi 		default:
12352ad5ec6fSuebayasi 			mode = "unknown";
1236d865b7d2Suebayasi 			break;
1237d865b7d2Suebayasi 		}
1238d865b7d2Suebayasi 		switch (bp.bp_status) {
1239d865b7d2Suebayasi 		case BIOC_SPSSTOPPED:
1240d865b7d2Suebayasi 			status = "stopped";
1241d865b7d2Suebayasi 			break;
1242d865b7d2Suebayasi 		case BIOC_SPSREADY:
1243d865b7d2Suebayasi 			status = "ready";
1244d865b7d2Suebayasi 			break;
1245d865b7d2Suebayasi 		case BIOC_SPSACTIVE:
1246d865b7d2Suebayasi 			status = "active";
1247d865b7d2Suebayasi 			break;
1248d865b7d2Suebayasi 		case BIOC_SPSABORTED:
1249d865b7d2Suebayasi 			status = "aborted";
1250d865b7d2Suebayasi 			break;
1251d865b7d2Suebayasi 		default:
1252d865b7d2Suebayasi 			status = "unknown";
1253d865b7d2Suebayasi 			break;
1254d865b7d2Suebayasi 		}
1255d865b7d2Suebayasi 		printf("patrol mode: %s%s\n", mode, interval);
1256d865b7d2Suebayasi 		printf("patrol status: %s\n", status);
1257d865b7d2Suebayasi 	}
1258d865b7d2Suebayasi }
1259d865b7d2Suebayasi 
1260d865b7d2Suebayasi void
1261*61f93244Sjsing derive_key_pkcs(u_int32_t type, int rounds, u_int8_t *key, size_t keysz,
1262*61f93244Sjsing     u_int8_t *salt, size_t saltsz, char *prompt, int verify)
1263aef7fe28Shshoexer {
126486735da2Smarco 	FILE		*f;
126586735da2Smarco 	size_t		pl;
126686735da2Smarco 	struct stat	sb;
12679e8c6f5bShshoexer 	char		passphrase[1024], verifybuf[1024];
1268aef7fe28Shshoexer 
1269aef7fe28Shshoexer 	if (!key)
1270aef7fe28Shshoexer 		errx(1, "Invalid key");
1271aef7fe28Shshoexer 	if (!salt)
1272aef7fe28Shshoexer 		errx(1, "Invalid salt");
1273*61f93244Sjsing 
1274*61f93244Sjsing 	if (type != SR_CRYPTOKDFT_PBKDF2)
1275*61f93244Sjsing 		errx(1, "unknown KDF type %d", type);
1276aef7fe28Shshoexer 	if (rounds < 1000)
1277*61f93244Sjsing 		errx(1, "number of KDF rounds is too small: %d", rounds);
1278aef7fe28Shshoexer 
1279aef7fe28Shshoexer 	/* get passphrase */
1280ba3d8661Smarco 	if (password) {
128186735da2Smarco 		if ((f = fopen(password, "r")) == NULL)
128286735da2Smarco 			err(1, "invalid passphrase file");
128386735da2Smarco 
128486735da2Smarco 		if (fstat(fileno(f), &sb) == -1)
128586735da2Smarco 			err(1, "can't stat passphrase file");
128686735da2Smarco 		if (sb.st_uid != 0)
128786735da2Smarco 			errx(1, "passphrase file must be owned by root");
128886735da2Smarco 		if ((sb.st_mode & ~S_IFMT) != (S_IRUSR | S_IWUSR))
128986735da2Smarco 			errx(1, "passphrase file has the wrong permissions");
129086735da2Smarco 
129186735da2Smarco 		if (fgets(passphrase, sizeof(passphrase), f) == NULL)
129286735da2Smarco 			err(1, "can't read passphrase file");
129386735da2Smarco 		pl = strlen(passphrase);
129486735da2Smarco 		if (pl > 0 && passphrase[pl - 1] == '\n')
129586735da2Smarco 			passphrase[pl - 1] = '\0';
129686735da2Smarco 		else
129786735da2Smarco 			errx(1, "invalid passphrase length");
129886735da2Smarco 
129986735da2Smarco 		fclose(f);
1300ba3d8661Smarco 	} else {
1301c6446370Sjsing 		if (readpassphrase(prompt, passphrase, sizeof(passphrase),
1302b96c6ce2Sckuethe 		    rpp_flag) == NULL)
13037eef0726Stedu 			err(1, "unable to read passphrase");
1304ba3d8661Smarco 	}
13059e8c6f5bShshoexer 
13064c688d0dShalex 	if (verify && !password) {
13079e8c6f5bShshoexer 		/* request user to re-type it */
13089e8c6f5bShshoexer 		if (readpassphrase("Re-type passphrase: ", verifybuf,
1309b96c6ce2Sckuethe 		    sizeof(verifybuf), rpp_flag) == NULL) {
13100a488504Spelikan 			explicit_bzero(passphrase, sizeof(passphrase));
13117eef0726Stedu 			err(1, "unable to read passphrase");
13129e8c6f5bShshoexer 		}
13139e8c6f5bShshoexer 		if ((strlen(passphrase) != strlen(verifybuf)) ||
13149e8c6f5bShshoexer 		    (strcmp(passphrase, verifybuf) != 0)) {
13150a488504Spelikan 			explicit_bzero(passphrase, sizeof(passphrase));
13160a488504Spelikan 			explicit_bzero(verifybuf, sizeof(verifybuf));
13179e8c6f5bShshoexer 			errx(1, "Passphrases did not match");
13189e8c6f5bShshoexer 		}
13199e8c6f5bShshoexer 		/* forget the re-typed one */
13200a488504Spelikan 		explicit_bzero(verifybuf, sizeof(verifybuf));
13219e8c6f5bShshoexer 	}
1322aef7fe28Shshoexer 
1323aef7fe28Shshoexer 	/* derive key from passphrase */
13245c1f8f6bSdjm 	if (pkcs5_pbkdf2(passphrase, strlen(passphrase), salt, saltsz,
13255c1f8f6bSdjm 	    key, keysz, rounds) != 0)
13265c1f8f6bSdjm 		errx(1, "pbkdf2 failed");
1327aef7fe28Shshoexer 
1328aef7fe28Shshoexer 	/* forget passphrase */
13290a488504Spelikan 	explicit_bzero(passphrase, sizeof(passphrase));
1330aef7fe28Shshoexer 
1331aef7fe28Shshoexer 	return;
1332aef7fe28Shshoexer }
1333