xref: /openbsd-src/sbin/bioctl/bioctl.c (revision 2b0358df1d88d06ef4139321dd05bd5e05d91eaf)
1 /* $OpenBSD: bioctl.c,v 1.78 2009/02/22 07:46:55 jmc Exp $       */
2 
3 /*
4  * Copyright (c) 2004, 2005 Marco Peereboom
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  */
29 
30 #include <sys/ioctl.h>
31 #include <sys/param.h>
32 #include <sys/queue.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <scsi/scsi_disk.h>
36 #include <scsi/scsi_all.h>
37 #include <dev/biovar.h>
38 #include <dev/softraidvar.h>
39 
40 #include <errno.h>
41 #include <err.h>
42 #include <fcntl.h>
43 #include <util.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <unistd.h>
48 #include <ctype.h>
49 #include <util.h>
50 #include <vis.h>
51 #include <readpassphrase.h>
52 
53 #include "pbkdf2.h"
54 
55 struct locator {
56 	int		channel;
57 	int		target;
58 	int		lun;
59 };
60 
61 void			usage(void);
62 const char 		*str2locator(const char *, struct locator *);
63 void			cleanup(void);
64 int			bio_parse_devlist(char *, dev_t *);
65 void			bio_kdf_derive(struct sr_crypto_kdfinfo *,
66 			    struct sr_crypto_kdf_pbkdf2 *);
67 void			bio_kdf_generate(struct sr_crypto_kdfinfo *);
68 void			derive_key_pkcs(int, u_int8_t *, size_t, u_int8_t *,
69 			    size_t, int);
70 
71 void			bio_inq(char *);
72 void			bio_alarm(char *);
73 int			bio_getvolbyname(char *);
74 void			bio_setstate(char *, int, char *);
75 void			bio_setblink(char *, char *, int);
76 void			bio_blink(char *, int, int);
77 void			bio_createraid(u_int16_t, char *);
78 void			bio_deleteraid(char *);
79 u_int32_t		bio_createflags(char *);
80 char			*bio_vis(char *);
81 void			bio_diskinq(char *);
82 
83 int			devh = -1;
84 int			human;
85 int			verbose;
86 u_int32_t		cflags = 0;
87 int			rflag = 8192;
88 
89 struct bio_locate	bl;
90 
91 int
92 main(int argc, char *argv[])
93 {
94 	extern char		*optarg;
95 	u_int64_t		func = 0;
96 	/* u_int64_t subfunc = 0; */
97 	char			*bioc_dev = NULL, *sd_dev = NULL;
98 	char			*realname = NULL, *al_arg = NULL;
99 	char			*bl_arg = NULL, *dev_list = NULL;
100 	const char		*errstr;
101 	int			ch, rv, blink = 0, diskinq = 0, ss_func = 0;
102 	u_int16_t		cr_level = 0;
103 
104 	if (argc < 2)
105 		usage();
106 
107 	while ((ch = getopt(argc, argv, "a:b:C:c:dH:hil:qr:R:vu:")) != -1) {
108 		switch (ch) {
109 		case 'a': /* alarm */
110 			func |= BIOC_ALARM;
111 			al_arg = optarg;
112 			break;
113 		case 'b': /* blink */
114 			func |= BIOC_BLINK;
115 			blink = BIOC_SBBLINK;
116 			bl_arg = optarg;
117 			break;
118 		case 'C': /* creation flags */
119 			cflags = bio_createflags(optarg);
120 			break;
121 		case 'c': /* create */
122 			func |= BIOC_CREATERAID;
123 			if (isdigit(*optarg))
124 				cr_level = atoi(optarg);
125 			else
126 				cr_level = *optarg;
127 			break;
128 		case 'd':
129 			/* delete volume */
130 			func |= BIOC_DELETERAID;
131 			break;
132 		case 'u': /* unblink */
133 			func |= BIOC_BLINK;
134 			blink = BIOC_SBUNBLINK;
135 			bl_arg = optarg;
136 			break;
137 		case 'H': /* set hotspare */
138 			func |= BIOC_SETSTATE;
139 			ss_func = BIOC_SSHOTSPARE;
140 			al_arg = optarg;
141 			break;
142 		case 'h':
143 			human = 1;
144 			break;
145 		case 'i': /* inquiry */
146 			func |= BIOC_INQ;
147 			break;
148 		case 'l': /* device list */
149 			func |= BIOC_DEVLIST;
150 			dev_list = optarg;
151 			break;
152 		case 'r':
153 			rflag = strtonum(optarg, 1000, 1<<30, &errstr);
154 			if (errstr != NULL)
155 				errx(1, "Number of rounds is %s: %s",
156 				    errstr, optarg);
157 			break;
158 		case 'R':
159 			/* rebuild to provided chunk/CTL */
160 			func |= BIOC_SETSTATE;
161 			ss_func = BIOC_SSREBUILD;
162 			al_arg = optarg;
163 			break;
164 		case 'v':
165 			verbose = 1;
166 			break;
167 		case 'q':
168 			diskinq = 1;
169 			break;
170 		default:
171 			usage();
172 			/* NOTREACHED */
173 		}
174 	}
175 	argc -= optind;
176 	argv += optind;
177 
178 	if (argc != 1)
179 		usage();
180 
181 	if (func == 0)
182 		func |= BIOC_INQ;
183 
184 	/* if at least glob sd[0-9]*, it is a drive identifier */
185 	if (strncmp(argv[0], "sd", 2) == 0 && strlen(argv[0]) > 2 &&
186 	    isdigit(argv[0][2]))
187 		sd_dev = argv[0];
188 	else
189 		bioc_dev = argv[0];
190 
191 	if (bioc_dev) {
192 		devh = open("/dev/bio", O_RDWR);
193 		if (devh == -1)
194 			err(1, "Can't open %s", "/dev/bio");
195 
196 		bl.bl_name = bioc_dev;
197 		rv = ioctl(devh, BIOCLOCATE, &bl);
198 		if (rv == -1)
199 			errx(1, "Can't locate %s device via %s",
200 			    bl.bl_name, "/dev/bio");
201 	} else if (sd_dev) {
202 		devh = opendev(sd_dev, O_RDWR, OPENDEV_PART, &realname);
203 		if (devh == -1)
204 			err(1, "Can't open %s", sd_dev);
205 	} else
206 		errx(1, "need -d or -f parameter");
207 
208 	if (diskinq) {
209 		bio_diskinq(sd_dev);
210 	} else if (func & BIOC_INQ) {
211 		bio_inq(sd_dev);
212 	} else if (func == BIOC_ALARM) {
213 		bio_alarm(al_arg);
214 	} else if (func == BIOC_BLINK) {
215 		bio_setblink(sd_dev, bl_arg, blink);
216 	} else if (func == BIOC_SETSTATE) {
217 		bio_setstate(al_arg, ss_func, argv[0]);
218 	} else if (func == BIOC_DELETERAID && sd_dev != NULL) {
219 		bio_deleteraid(sd_dev);
220 	} else if (func & BIOC_CREATERAID || func & BIOC_DEVLIST) {
221 		if (!(func & BIOC_CREATERAID))
222 			errx(1, "need -c parameter");
223 		if (!(func & BIOC_DEVLIST))
224 			errx(1, "need -l parameter");
225 		if (sd_dev)
226 			errx(1, "can't use sd device");
227 		bio_createraid(cr_level, dev_list);
228 	}
229 
230 	return (0);
231 }
232 
233 void
234 usage(void)
235 {
236 	extern char		*__progname;
237 
238 	fprintf(stderr,
239 		"usage: %s [-hiqv] [-a alarm-function] "
240 		"[-b channel:target[.lun]]\n"
241 		"\t[-H channel:target[.lun]] "
242 		"[-R device | channel:target[.lun]\n"
243 		"\t[-u channel:target[.lun]] "
244 		"device\n"
245                 "       %s [-dhiqv] "
246                 "[-C flag[,flag,...]] [-c raidlevel]\n"
247                 "\t[-l special[,special,...]] "
248                 "[-R device | channel:target[.lun]\n"
249                 "\t[-r rounds] "
250 		"device\n", __progname, __progname);
251 
252 	exit(1);
253 }
254 
255 const char *
256 str2locator(const char *string, struct locator *location)
257 {
258 	const char		*errstr;
259 	char			parse[80], *targ, *lun;
260 
261 	strlcpy(parse, string, sizeof parse);
262 	targ = strchr(parse, ':');
263 	if (targ == NULL)
264 		return ("target not specified");
265 	*targ++ = '\0';
266 
267 	lun = strchr(targ, '.');
268 	if (lun != NULL) {
269 		*lun++ = '\0';
270 		location->lun = strtonum(lun, 0, 256, &errstr);
271 		if (errstr)
272 			return (errstr);
273 	} else
274 		location->lun = 0;
275 
276 	location->target = strtonum(targ, 0, 256, &errstr);
277 	if (errstr)
278 		return (errstr);
279 	location->channel = strtonum(parse, 0, 256, &errstr);
280 	if (errstr)
281 		return (errstr);
282 	return (NULL);
283 }
284 
285 void
286 bio_inq(char *name)
287 {
288 	char 			*status, size[64], scsiname[16], volname[32];
289 	char			percent[10], seconds[20];
290 	int			rv, i, d, volheader, hotspare, unused;
291 	char			encname[16], serial[32];
292 	struct bioc_disk	bd;
293 	struct bioc_inq		bi;
294 	struct bioc_vol		bv;
295 
296 	memset(&bi, 0, sizeof(bi));
297 
298 	bi.bi_cookie = bl.bl_cookie;
299 
300 	rv = ioctl(devh, BIOCINQ, &bi);
301 	if (rv == -1) {
302 		if (errno == ENOTTY)
303 			bio_diskinq(name);
304 		else
305 			err(1, "BIOCINQ");
306 		return;
307 	}
308 
309 	volheader = 0;
310 	for (i = 0; i < bi.bi_novol; i++) {
311 		memset(&bv, 0, sizeof(bv));
312 		bv.bv_cookie = bl.bl_cookie;
313 		bv.bv_volid = i;
314 		bv.bv_percent = -1;
315 		bv.bv_seconds = 0;
316 
317 		rv = ioctl(devh, BIOCVOL, &bv);
318 		if (rv == -1)
319 			err(1, "BIOCVOL");
320 
321 		if (name && strcmp(name, bv.bv_dev) != 0)
322 			continue;
323 
324 		if (!volheader) {
325 			volheader = 1;
326 			printf("%-7s %-10s %14s %-8s\n",
327 			    "Volume", "Status", "Size", "Device");
328 		}
329 
330 		percent[0] = '\0';
331 		seconds[0] = '\0';
332 		if (bv.bv_percent != -1)
333 			snprintf(percent, sizeof percent,
334 			    " %d%% done", bv.bv_percent);
335 		if (bv.bv_seconds)
336 			snprintf(seconds, sizeof seconds,
337 			    " %u seconds", bv.bv_seconds);
338 		switch (bv.bv_status) {
339 		case BIOC_SVONLINE:
340 			status = BIOC_SVONLINE_S;
341 			break;
342 		case BIOC_SVOFFLINE:
343 			status = BIOC_SVOFFLINE_S;
344 			break;
345 		case BIOC_SVDEGRADED:
346 			status = BIOC_SVDEGRADED_S;
347 			break;
348 		case BIOC_SVBUILDING:
349 			status = BIOC_SVBUILDING_S;
350 			break;
351 		case BIOC_SVREBUILD:
352 			status = BIOC_SVREBUILD_S;
353 			break;
354 		case BIOC_SVSCRUB:
355 			status = BIOC_SVSCRUB_S;
356 			break;
357 		case BIOC_SVINVALID:
358 		default:
359 			status = BIOC_SVINVALID_S;
360 		}
361 
362 		snprintf(volname, sizeof volname, "%s %u",
363 		    bi.bi_dev, bv.bv_volid);
364 
365 		unused = 0;
366 		hotspare = 0;
367 		if (bv.bv_level == -1 && bv.bv_nodisk == 1)
368 			hotspare = 1;
369 		else if (bv.bv_level == -2 && bv.bv_nodisk == 1)
370 			unused = 1;
371 		else {
372 			if (human)
373 				fmt_scaled(bv.bv_size, size);
374 			else
375 				snprintf(size, sizeof size, "%14llu",
376 				    bv.bv_size);
377 			switch (bv.bv_level) {
378 			case 'C':
379 				printf("%7s %-10s %14s %-7s CRYPTO%s%s\n",
380 				    volname, status, size, bv.bv_dev,
381 				    percent, seconds);
382 				break;
383 			default:
384 				printf("%7s %-10s %14s %-7s RAID%u%s%s\n",
385 				    volname, status, size, bv.bv_dev,
386 				    bv.bv_level, percent, seconds);
387 				break;
388 			}
389 
390 		}
391 
392 		for (d = 0; d < bv.bv_nodisk; d++) {
393 			memset(&bd, 0, sizeof(bd));
394 			bd.bd_cookie = bl.bl_cookie;
395 			bd.bd_diskid = d;
396 			bd.bd_volid = i;
397 
398 			rv = ioctl(devh, BIOCDISK, &bd);
399 			if (rv == -1)
400 				err(1, "BIOCDISK");
401 
402 			switch (bd.bd_status) {
403 			case BIOC_SDONLINE:
404 				status = BIOC_SDONLINE_S;
405 				break;
406 			case BIOC_SDOFFLINE:
407 				status = BIOC_SDOFFLINE_S;
408 				break;
409 			case BIOC_SDFAILED:
410 				status = BIOC_SDFAILED_S;
411 				break;
412 			case BIOC_SDREBUILD:
413 				status = BIOC_SDREBUILD_S;
414 				break;
415 			case BIOC_SDHOTSPARE:
416 				status = BIOC_SDHOTSPARE_S;
417 				break;
418 			case BIOC_SDUNUSED:
419 				status = BIOC_SDUNUSED_S;
420 				break;
421 			case BIOC_SDSCRUB:
422 				status = BIOC_SDSCRUB_S;
423 				break;
424 			case BIOC_SDINVALID:
425 			default:
426 				status = BIOC_SDINVALID_S;
427 			}
428 
429 			if (hotspare || unused)
430 				;	/* use volname from parent volume */
431 			else
432 				snprintf(volname, sizeof volname, "    %3u",
433 				    bd.bd_diskid);
434 
435 			if (human)
436 				fmt_scaled(bd.bd_size, size);
437 			else
438 				snprintf(size, sizeof size, "%14llu",
439 				    bd.bd_size);
440 			snprintf(scsiname, sizeof scsiname,
441 			    "%u:%u.%u",
442 			    bd.bd_channel, bd.bd_target, bd.bd_lun);
443 			if (bd.bd_procdev[0])
444 				strlcpy(encname, bd.bd_procdev, sizeof encname);
445 			else
446 				strlcpy(encname, "noencl", sizeof encname);
447 			if (bd.bd_serial[0])
448 				strlcpy(serial, bd.bd_serial, sizeof serial);
449 			else
450 				strlcpy(serial, "unknown serial", sizeof serial);
451 
452 			printf("%7s %-10s %14s %-7s %-6s <%s>\n",
453 			    volname, status, size, scsiname, encname,
454 			    bd.bd_vendor);
455 			if (verbose)
456 				printf("%7s %-10s %14s %-7s %-6s '%s'\n",
457 				    "", "", "", "", "", serial);
458 		}
459 	}
460 }
461 
462 void
463 bio_alarm(char *arg)
464 {
465 	int			rv;
466 	struct bioc_alarm	ba;
467 
468 	ba.ba_cookie = bl.bl_cookie;
469 
470 	switch (arg[0]) {
471 	case 'q': /* silence alarm */
472 		/* FALLTHROUGH */
473 	case 's':
474 		ba.ba_opcode = BIOC_SASILENCE;
475 		break;
476 
477 	case 'e': /* enable alarm */
478 		ba.ba_opcode = BIOC_SAENABLE;
479 		break;
480 
481 	case 'd': /* disable alarm */
482 		ba.ba_opcode = BIOC_SADISABLE;
483 		break;
484 
485 	case 't': /* test alarm */
486 		ba.ba_opcode = BIOC_SATEST;
487 		break;
488 
489 	case 'g': /* get alarm state */
490 		ba.ba_opcode = BIOC_GASTATUS;
491 		break;
492 
493 	default:
494 		errx(1, "invalid alarm function: %s", arg);
495 	}
496 
497 	rv = ioctl(devh, BIOCALARM, &ba);
498 	if (rv == -1)
499 		err(1, "BIOCALARM");
500 
501 	if (arg[0] == 'g') {
502 		printf("alarm is currently %s\n",
503 		    ba.ba_status ? "enabled" : "disabled");
504 
505 	}
506 }
507 
508 int
509 bio_getvolbyname(char *name)
510 {
511 	int			id = -1, i, rv;
512 	struct bioc_inq		bi;
513 	struct bioc_vol		bv;
514 
515 	memset(&bi, 0, sizeof(bi));
516 	bi.bi_cookie = bl.bl_cookie;
517 	rv = ioctl(devh, BIOCINQ, &bi);
518 	if (rv == -1)
519 		err(1, "BIOCINQ");
520 
521 	for (i = 0; i < bi.bi_novol; i++) {
522 		memset(&bv, 0, sizeof(bv));
523 		bv.bv_cookie = bl.bl_cookie;
524 		bv.bv_volid = i;
525 		rv = ioctl(devh, BIOCVOL, &bv);
526 		if (rv == -1)
527 			err(1, "BIOCVOL");
528 
529 		if (name && strcmp(name, bv.bv_dev) != 0)
530 			continue;
531 		id = i;
532 		break;
533 	}
534 
535 	return (id);
536 }
537 
538 void
539 bio_setstate(char *arg, int status, char *devicename)
540 {
541 	struct bioc_setstate	bs;
542 	struct locator		location;
543 	struct stat		sb;
544 	const char		*errstr;
545 	int			rv;
546 
547 	memset(&bs, 0, sizeof(bs));
548 	if (stat(arg, &sb) == -1) {
549 		/* use CTL */
550 		errstr = str2locator(arg, &location);
551 		if (errstr)
552 			errx(1, "Target %s: %s", arg, errstr);
553 		bs.bs_channel = location.channel;
554 		bs.bs_target = location.target;
555 		bs.bs_lun = location.lun;
556 	} else {
557 		/* use other id */
558 		bs.bs_other_id = sb.st_rdev;
559 		bs.bs_other_id_type = BIOC_SSOTHER_DEVT;
560 	}
561 
562 	bs.bs_cookie = bl.bl_cookie;
563 	bs.bs_status = status;
564 
565 	/* make sure user supplied a sd device */
566 	bs.bs_volid = bio_getvolbyname(devicename);
567 	if (bs.bs_volid == -1)
568 		errx(1, "invalid device %s", devicename);
569 
570 	rv = ioctl(devh, BIOCSETSTATE, &bs);
571 	if (rv == -1)
572 		err(1, "BIOCSETSTATE");
573 }
574 
575 void
576 bio_setblink(char *name, char *arg, int blink)
577 {
578 	struct locator		location;
579 	struct bioc_inq		bi;
580 	struct bioc_vol		bv;
581 	struct bioc_disk	bd;
582 	struct bioc_blink	bb;
583 	const char		*errstr;
584 	int			v, d, rv;
585 
586 	errstr = str2locator(arg, &location);
587 	if (errstr)
588 		errx(1, "Target %s: %s", arg, errstr);
589 
590 	/* try setting blink on the device directly */
591 	memset(&bb, 0, sizeof(bb));
592 	bb.bb_cookie = bl.bl_cookie;
593 	bb.bb_status = blink;
594 	bb.bb_target = location.target;
595 	bb.bb_channel = location.channel;
596 	rv = ioctl(devh, BIOCBLINK, &bb);
597 	if (rv == 0)
598 		return;
599 
600 	/* if the blink didnt work, try to find something that will */
601 
602 	memset(&bi, 0, sizeof(bi));
603 	bi.bi_cookie = bl.bl_cookie;
604 	rv = ioctl(devh, BIOCINQ, &bi);
605 	if (rv == -1)
606 		err(1, "BIOCINQ");
607 
608 	for (v = 0; v < bi.bi_novol; v++) {
609 		memset(&bv, 0, sizeof(bv));
610 		bv.bv_cookie = bl.bl_cookie;
611 		bv.bv_volid = v;
612 		rv = ioctl(devh, BIOCVOL, &bv);
613 		if (rv == -1)
614 			err(1, "BIOCVOL");
615 
616 		if (name && strcmp(name, bv.bv_dev) != 0)
617 			continue;
618 
619 		for (d = 0; d < bv.bv_nodisk; d++) {
620 			memset(&bd, 0, sizeof(bd));
621 			bd.bd_cookie = bl.bl_cookie;
622 			bd.bd_volid = v;
623 			bd.bd_diskid = d;
624 
625 			rv = ioctl(devh, BIOCDISK, &bd);
626 			if (rv == -1)
627 				err(1, "BIOCDISK");
628 
629 			if (bd.bd_channel == location.channel &&
630 			    bd.bd_target == location.target &&
631 			    bd.bd_lun == location.lun) {
632 				if (bd.bd_procdev[0] != '\0') {
633 					bio_blink(bd.bd_procdev,
634 					    location.target, blink);
635 				} else
636 					warnx("Disk %s is not in an enclosure", arg);
637 				return;
638 			}
639 		}
640 	}
641 
642 	warnx("Disk %s does not exist", arg);
643 	return;
644 }
645 
646 void
647 bio_blink(char *enclosure, int target, int blinktype)
648 {
649 	int			bioh;
650 	struct bio_locate	bio;
651 	struct bioc_blink	blink;
652 	int			rv;
653 
654 	bioh = open("/dev/bio", O_RDWR);
655 	if (bioh == -1)
656 		err(1, "Can't open %s", "/dev/bio");
657 
658 	bio.bl_name = enclosure;
659 	rv = ioctl(bioh, BIOCLOCATE, &bio);
660 	if (rv == -1)
661 		errx(1, "Can't locate %s device via %s", enclosure, "/dev/bio");
662 
663 	memset(&blink, 0, sizeof(blink));
664 	blink.bb_cookie = bio.bl_cookie;
665 	blink.bb_status = blinktype;
666 	blink.bb_target = target;
667 
668 	rv = ioctl(bioh, BIOCBLINK, &blink);
669 	if (rv == -1)
670 		err(1, "BIOCBLINK");
671 
672 	close(bioh);
673 }
674 
675 void
676 bio_createraid(u_int16_t level, char *dev_list)
677 {
678 	struct bioc_createraid	create;
679 	struct sr_crypto_kdfinfo kdfinfo;
680 	struct sr_crypto_kdf_pbkdf2 kdfhint;
681 	int			rv, no_dev;
682 	dev_t			*dt;
683 	u_int16_t		min_disks = 0;
684 
685 	if (!dev_list)
686 		errx(1, "no devices specified");
687 
688 	dt = (dev_t *)malloc(BIOC_CRMAXLEN);
689 	if (!dt)
690 		err(1, "not enough memory for dev_t list");
691 	memset(dt, 0, BIOC_CRMAXLEN);
692 
693 	no_dev = bio_parse_devlist(dev_list, dt);
694 
695 	switch (level) {
696 	case 0:
697 		min_disks = 2;
698 		break;
699 	case 1:
700 		min_disks = 2;
701 		break;
702 	case 'C':
703 		min_disks = 1;
704 		break;
705 	case 'c':
706 		min_disks = 1;
707 		break;
708 	default:
709 		errx(1, "unsupported raid level");
710 	}
711 
712 	if (no_dev < min_disks)
713 		errx(1, "not enough disks");
714 
715 	/* for crypto raid we only allow one single chunk */
716 	if (level == 'C' && no_dev != min_disks)
717 		errx(1, "not exactly one disks");
718 
719 
720 	memset(&create, 0, sizeof(create));
721 	create.bc_cookie = bl.bl_cookie;
722 	create.bc_level = level;
723 	create.bc_dev_list_len = no_dev * sizeof(dev_t);
724 	create.bc_dev_list = dt;
725 	create.bc_flags = BIOC_SCDEVT | cflags;
726 
727 	if (level == 'C') {
728 		memset(&kdfinfo, 0, sizeof(kdfinfo));
729 		memset(&kdfhint, 0, sizeof(kdfhint));
730 
731 		create.bc_opaque = &kdfhint;
732 		create.bc_opaque_size = sizeof(kdfhint);
733 		create.bc_opaque_flags = BIOC_SOOUT;
734 
735 		/* try to get KDF hint */
736 		if (ioctl(devh, BIOCCREATERAID, &create) == -1)
737 			err(1, "ioctl");
738 
739 		if (create.bc_opaque_status == BIOC_SOINOUT_OK) {
740 			bio_kdf_derive(&kdfinfo, &kdfhint);
741 			memset(&kdfhint, 0, sizeof(kdfhint));
742 		} else  {
743 			bio_kdf_generate(&kdfinfo);
744 			/* no auto assembling */
745 			create.bc_flags |= BIOC_SCNOAUTOASSEMBLE;
746 		}
747 
748 		create.bc_opaque = &kdfinfo;
749 		create.bc_opaque_size = sizeof(kdfinfo);
750 		create.bc_opaque_flags = BIOC_SOIN;
751 	}
752 
753 	rv = ioctl(devh, BIOCCREATERAID, &create);
754 	memset(&kdfinfo, 0, sizeof(kdfinfo));
755 	memset(&create, 0, sizeof(create));
756 	if (rv == -1) {
757 		if (errno == EPERM)
758 			errx(1, "Incorrect passphrase");
759 		err(1, "BIOCCREATERAID");
760 	}
761 
762 	free(dt);
763 }
764 
765 void
766 bio_kdf_derive(struct sr_crypto_kdfinfo *kdfinfo, struct sr_crypto_kdf_pbkdf2
767     *kdfhint)
768 {
769 	if (!kdfinfo)
770 		errx(1, "invalid KDF info");
771 	if (!kdfhint)
772 		errx(1, "invalid KDF hint");
773 
774 	if (kdfhint->len != sizeof(*kdfhint))
775 		errx(1, "KDF hint has invalid size");
776 	if (kdfhint->type != SR_CRYPTOKDFT_PBKDF2)
777 		errx(1, "unknown KDF type %d", kdfhint->type);
778 	if (kdfhint->rounds < 1000)
779 		errx(1, "number of KDF rounds too low: %d", kdfhint->rounds);
780 
781 	kdfinfo->flags = SR_CRYPTOKDF_KEY;
782 	kdfinfo->len = sizeof(*kdfinfo);
783 
784 	derive_key_pkcs(kdfhint->rounds,
785 	    kdfinfo->maskkey, sizeof(kdfinfo->maskkey),
786 	    kdfhint->salt, sizeof(kdfhint->salt), 0);
787 }
788 
789 void
790 bio_kdf_generate(struct sr_crypto_kdfinfo *kdfinfo)
791 {
792 	if (!kdfinfo)
793 		errx(1, "invalid KDF info");
794 
795 	kdfinfo->pbkdf2.len = sizeof(kdfinfo->pbkdf2);
796 	kdfinfo->pbkdf2.type = SR_CRYPTOKDFT_PBKDF2;
797 	kdfinfo->pbkdf2.rounds = rflag;
798 	kdfinfo->len = sizeof(*kdfinfo);
799 	kdfinfo->flags = (SR_CRYPTOKDF_KEY | SR_CRYPTOKDF_HINT);
800 
801 	/* generate salt */
802 	arc4random_buf(kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt));
803 
804 	derive_key_pkcs(kdfinfo->pbkdf2.rounds,
805 	    kdfinfo->maskkey, sizeof(kdfinfo->maskkey),
806 	    kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt), 1);
807 }
808 
809 int
810 bio_parse_devlist(char *lst, dev_t *dt)
811 {
812 	char			*s, *e;
813 	u_int32_t		sz = 0;
814 	int			no_dev = 0, i, x;
815 	struct stat		sb;
816 	char			dev[MAXPATHLEN];
817 
818 	if (!lst)
819 		errx(1, "invalid device list");
820 
821 	s = e = lst;
822 	/* make sure we have a valid device list like /dev/sdNa,/dev/sdNNa */
823 	while (*e != '\0') {
824 		if (*e == ',')
825 			s = e + 1;
826 		else if (*(e + 1) == '\0' || *(e + 1) == ',') {
827 			/* got one */
828 			sz = e - s + 1;
829 			strlcpy(dev, s, sz + 1);
830 			if (stat(dev, &sb) == -1)
831 				err(1, "could not stat %s", dev);
832 			dt[no_dev] = sb.st_rdev;
833 			no_dev++;
834 			if (no_dev > (int)(BIOC_CRMAXLEN / sizeof(dev_t)))
835 				errx(1, "too many devices on device list");
836 		}
837 		e++;
838 	}
839 
840 	for (i = 0; i < no_dev; i++)
841 		for (x = 0; x < no_dev; x++)
842 			if (dt[i] == dt[x] && x != i)
843 				errx(1, "duplicate device in list");
844 
845 	return (no_dev);
846 }
847 
848 u_int32_t
849 bio_createflags(char *lst)
850 {
851 	char			*s, *e, fs[32];
852 	u_int32_t		sz = 0;
853 	u_int32_t		flags = 0;
854 
855 	if (!lst)
856 		errx(1, "invalid flags list");
857 
858 	s = e = lst;
859 	/* make sure we have a valid flags list like force,noassemeble */
860 	while (*e != '\0') {
861 		if (*e == ',')
862 			s = e + 1;
863 		else if (*(e + 1) == '\0' || *(e + 1) == ',') {
864 			/* got one */
865 			sz = e - s + 1;
866 			switch (s[0]) {
867 			case 'f':
868 				flags |= BIOC_SCFORCE;
869 				break;
870 			case 'n':
871 				flags |= BIOC_SCNOAUTOASSEMBLE;
872 				break;
873 			default:
874 				strlcpy(fs, s, sz + 1);
875 				errx(1, "invalid flag %s", fs);
876 			}
877 		}
878 		e++;
879 	}
880 
881 	return (flags);
882 }
883 
884 void
885 bio_deleteraid(char *dev)
886 {
887 	struct bioc_deleteraid	bd;
888 	memset(&bd, 0, sizeof(bd));
889 
890 	bd.bd_cookie = bd.bd_cookie;
891 	/* XXX make this a dev_t instead of a string */
892 	strlcpy(bd.bd_dev, dev, sizeof bd.bd_dev);
893 	if (ioctl(devh, BIOCDELETERAID, &bd))
894 		errx(1, "delete volume %s failed", dev);
895 }
896 
897 #define BIOCTL_VIS_NBUF		4
898 #define BIOCTL_VIS_BUFLEN	80
899 
900 char *
901 bio_vis(char *s)
902 {
903 	static char	 rbuf[BIOCTL_VIS_NBUF][BIOCTL_VIS_BUFLEN];
904 	static uint	 idx = 0;
905 	char		*buf;
906 
907 	buf = rbuf[idx++];
908 	if (idx == BIOCTL_VIS_NBUF)
909 		idx = 0;
910 
911 	strnvis(buf, s, BIOCTL_VIS_BUFLEN, VIS_NL|VIS_CSTYLE);
912 	return (buf);
913 }
914 
915 void
916 bio_diskinq(char *sd_dev)
917 {
918 	struct dk_inquiry	di;
919 
920 	if (ioctl(devh, DIOCINQ, &di) == -1)
921 		err(1, "DIOCINQ");
922 
923 	printf("%s: <%s, %s, %s>, serial %s\n", sd_dev, bio_vis(di.vendor),
924 	    bio_vis(di.product), bio_vis(di.revision), bio_vis(di.serial));
925 }
926 
927 void
928 derive_key_pkcs(int rounds, u_int8_t *key, size_t keysz, u_int8_t *salt,
929     size_t saltsz, int verify)
930 {
931 	char		 passphrase[1024], verifybuf[1024];
932 
933 	if (!key)
934 		errx(1, "Invalid key");
935 	if (!salt)
936 		errx(1, "Invalid salt");
937 	if (rounds < 1000)
938 		errx(1, "Too less rounds: %d", rounds);
939 
940 	/* get passphrase */
941 	if (readpassphrase("Passphrase: ", passphrase, sizeof(passphrase),
942 	    RPP_REQUIRE_TTY) == NULL)
943 		errx(1, "unable to read passphrase");
944 
945 	if (verify) {
946 		/* request user to re-type it */
947 		if (readpassphrase("Re-type passphrase: ", verifybuf,
948 		    sizeof(verifybuf), RPP_REQUIRE_TTY) == NULL) {
949 			memset(passphrase, 0, sizeof(passphrase));
950 			errx(1, "unable to read passphrase");
951 		}
952 		if ((strlen(passphrase) != strlen(verifybuf)) ||
953 		    (strcmp(passphrase, verifybuf) != 0)) {
954 			memset(passphrase, 0, sizeof(passphrase));
955 			memset(verifybuf, 0, sizeof(verifybuf));
956 			errx(1, "Passphrases did not match");
957 		}
958 		/* forget the re-typed one */
959 		memset(verifybuf, 0, strlen(verifybuf));
960 	}
961 
962 	/* derive key from passphrase */
963 	if (pkcs5_pbkdf2(passphrase, strlen(passphrase), salt, saltsz,
964 	    key, keysz, rounds) != 0)
965 		errx(1, "pbkdf2 failed");
966 
967 	/* forget passphrase */
968 	memset(passphrase, 0, sizeof(passphrase));
969 
970 	return;
971 }
972