xref: /openbsd-src/sbin/bioctl/bioctl.c (revision 4c1e55dc91edd6e69ccc60ce855900fbc12cf34f)
1 /* $OpenBSD: bioctl.c,v 1.110 2012/04/19 19:13:51 deraadt 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/dkio.h>
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <dev/biovar.h>
36 #include <dev/softraidvar.h>
37 
38 #include <errno.h>
39 #include <err.h>
40 #include <fcntl.h>
41 #include <util.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include <ctype.h>
47 #include <vis.h>
48 #include <readpassphrase.h>
49 
50 #include "pbkdf2.h"
51 
52 struct locator {
53 	int		channel;
54 	int		target;
55 	int		lun;
56 };
57 
58 void			usage(void);
59 const char 		*str2locator(const char *, struct locator *);
60 void			bio_status(struct bio_status *);
61 int			bio_parse_devlist(char *, dev_t *);
62 void			bio_kdf_derive(struct sr_crypto_kdfinfo *,
63 			    struct sr_crypto_kdf_pbkdf2 *, char *, int);
64 void			bio_kdf_generate(struct sr_crypto_kdfinfo *);
65 void			derive_key_pkcs(int, u_int8_t *, size_t, u_int8_t *,
66 			    size_t, char *, int);
67 
68 void			bio_inq(char *);
69 void			bio_alarm(char *);
70 int			bio_getvolbyname(char *);
71 void			bio_setstate(char *, int, char *);
72 void			bio_setblink(char *, char *, int);
73 void			bio_blink(char *, int, int);
74 struct sr_aoe_config 	*create_aoe(u_int16_t, char *);
75 void			bio_createraid(u_int16_t, char *, char *);
76 void			bio_deleteraid(char *);
77 void			bio_changepass(char *);
78 u_int32_t		bio_createflags(char *);
79 char			*bio_vis(char *);
80 void			bio_diskinq(char *);
81 
82 int			devh = -1;
83 int			human;
84 int			verbose;
85 u_int32_t		cflags = 0;
86 int			rflag = 8192;
87 char			*password;
88 
89 struct bio_locate	bl;
90 int rpp_flag = RPP_REQUIRE_TTY;
91 
92 int
93 main(int argc, char *argv[])
94 {
95 	extern char		*optarg;
96 	u_int64_t		func = 0;
97 	char			*devicename = NULL;
98 	char			*realname = NULL, *al_arg = NULL;
99 	char			*bl_arg = NULL, *dev_list = NULL;
100 	char			*key_disk = NULL;
101 	const char		*errstr;
102 	int			ch, blink = 0, changepass = 0, diskinq = 0;
103 	int			ss_func = 0;
104 	u_int16_t		cr_level = 0;
105 	int			biodev = 0;
106 
107 	if (argc < 2)
108 		usage();
109 
110 	while ((ch = getopt(argc, argv, "a:b:C:c:dH:hik:l:O:Pp:qr:R:svu:")) !=
111 	    -1) {
112 		switch (ch) {
113 		case 'a': /* alarm */
114 			func |= BIOC_ALARM;
115 			al_arg = optarg;
116 			break;
117 		case 'b': /* blink */
118 			func |= BIOC_BLINK;
119 			blink = BIOC_SBBLINK;
120 			bl_arg = optarg;
121 			break;
122 		case 'C': /* creation flags */
123 			cflags = bio_createflags(optarg);
124 			break;
125 		case 'c': /* create */
126 			func |= BIOC_CREATERAID;
127 			if (isdigit(*optarg)) {
128 				cr_level = strtonum(optarg, 0, 10, &errstr);
129 				if (errstr != NULL)
130 					errx(1, "Invalid RAID level");
131 			} else
132 				cr_level = *optarg;
133 			break;
134 		case 'd':
135 			/* delete volume */
136 			func |= BIOC_DELETERAID;
137 			break;
138 		case 'u': /* unblink */
139 			func |= BIOC_BLINK;
140 			blink = BIOC_SBUNBLINK;
141 			bl_arg = optarg;
142 			break;
143 		case 'H': /* set hotspare */
144 			func |= BIOC_SETSTATE;
145 			ss_func = BIOC_SSHOTSPARE;
146 			al_arg = optarg;
147 			break;
148 		case 'h':
149 			human = 1;
150 			break;
151 		case 'i': /* inquiry */
152 			func |= BIOC_INQ;
153 			break;
154 		case 'k': /* Key disk. */
155 			key_disk = optarg;
156 			break;
157 		case 'l': /* device list */
158 			func |= BIOC_DEVLIST;
159 			dev_list = optarg;
160 			break;
161 		case 'P':
162 			/* Change passphrase. */
163 			changepass = 1;
164 			break;
165 		case 'p':
166 			password = optarg;
167 			break;
168 		case 'r':
169 			rflag = strtonum(optarg, 1000, 1<<30, &errstr);
170 			if (errstr != NULL)
171 				errx(1, "Number of rounds is %s: %s",
172 				    errstr, optarg);
173 			break;
174 		case 'O':
175 			/* set a chunk to offline */
176 			func |= BIOC_SETSTATE;
177 			ss_func = BIOC_SSOFFLINE;
178 			al_arg = optarg;
179 			break;
180 		case 'R':
181 			/* rebuild to provided chunk/CTL */
182 			func |= BIOC_SETSTATE;
183 			ss_func = BIOC_SSREBUILD;
184 			al_arg = optarg;
185 			break;
186 		case 's':
187 			rpp_flag = RPP_STDIN;
188 			break;
189 		case 'v':
190 			verbose = 1;
191 			break;
192 		case 'q':
193 			diskinq = 1;
194 			break;
195 		default:
196 			usage();
197 			/* NOTREACHED */
198 		}
199 	}
200 	argc -= optind;
201 	argv += optind;
202 
203 	if (argc != 1 || (changepass && func != 0))
204 		usage();
205 
206 	if (func == 0)
207 		func |= BIOC_INQ;
208 
209 	devicename = argv[0];
210 	if (devicename == NULL)
211 		errx(1, "need device");
212 
213 	devh = opendev(devicename, O_RDWR, OPENDEV_PART, &realname);
214 	if (devh == -1) {
215 		devh = open("/dev/bio", O_RDWR);
216 		if (devh == -1)
217 			err(1, "Can't open %s", "/dev/bio");
218 
219 		bl.bl_name = devicename;
220 		if (ioctl(devh, BIOCLOCATE, &bl))
221 			errx(1, "Can't locate %s device via %s",
222 			    bl.bl_name, "/dev/bio");
223 
224 		bio_status(&bl.bl_bio.bio_status);
225 
226 		biodev = 1;
227 		devicename = NULL;
228 	}
229 
230 	if (diskinq) {
231 		bio_diskinq(devicename);
232 	} else if (changepass && !biodev) {
233 		bio_changepass(devicename);
234 	} else if (func & BIOC_INQ) {
235 		bio_inq(devicename);
236 	} else if (func == BIOC_ALARM) {
237 		bio_alarm(al_arg);
238 	} else if (func == BIOC_BLINK) {
239 		bio_setblink(devicename, bl_arg, blink);
240 	} else if (func == BIOC_SETSTATE) {
241 		bio_setstate(al_arg, ss_func, argv[0]);
242 	} else if (func == BIOC_DELETERAID && !biodev) {
243 		bio_deleteraid(devicename);
244 	} else if (func & BIOC_CREATERAID || func & BIOC_DEVLIST) {
245 		if (!(func & BIOC_CREATERAID))
246 			errx(1, "need -c parameter");
247 		if (!(func & BIOC_DEVLIST))
248 			errx(1, "need -l parameter");
249 		if (!biodev)
250 			errx(1, "must use bio device");
251 		bio_createraid(cr_level, dev_list, key_disk);
252 	}
253 
254 	return (0);
255 }
256 
257 void
258 usage(void)
259 {
260 	extern char		*__progname;
261 
262 	fprintf(stderr,
263 		"usage: %s [-hiqv] [-a alarm-function] "
264 		"[-b channel:target[.lun]]\n"
265 		"\t[-H channel:target[.lun]] "
266 		"[-R device | channel:target[.lun]]\n"
267 		"\t[-u channel:target[.lun]] "
268 		"device\n"
269 		"       %s [-dhiPqsv] "
270 		"[-C flag[,flag,...]] [-c raidlevel] [-k keydisk]\n"
271 		"\t[-l special[,special,...]] "
272 		"[-O device | channel:target[.lun]]\n"
273 		"\t[-p passfile] [-R device | channel:target[.lun]]\n"
274 		"\t[-r rounds] "
275 		"device\n", __progname, __progname);
276 
277 	exit(1);
278 }
279 
280 const char *
281 str2locator(const char *string, struct locator *location)
282 {
283 	const char		*errstr;
284 	char			parse[80], *targ, *lun;
285 
286 	strlcpy(parse, string, sizeof parse);
287 	targ = strchr(parse, ':');
288 	if (targ == NULL)
289 		return ("target not specified");
290 	*targ++ = '\0';
291 
292 	lun = strchr(targ, '.');
293 	if (lun != NULL) {
294 		*lun++ = '\0';
295 		location->lun = strtonum(lun, 0, 256, &errstr);
296 		if (errstr)
297 			return (errstr);
298 	} else
299 		location->lun = 0;
300 
301 	location->target = strtonum(targ, 0, 256, &errstr);
302 	if (errstr)
303 		return (errstr);
304 	location->channel = strtonum(parse, 0, 256, &errstr);
305 	if (errstr)
306 		return (errstr);
307 	return (NULL);
308 }
309 
310 void
311 bio_status(struct bio_status *bs)
312 {
313 	extern char		*__progname;
314 	char			*prefix;
315 	int			i;
316 
317 	if (strlen(bs->bs_controller))
318 		prefix = bs->bs_controller;
319 	else
320 		prefix = __progname;
321 
322 	for (i = 0; i < bs->bs_msg_count; i++)
323 		printf("%s: %s\n", prefix, bs->bs_msgs[i].bm_msg);
324 
325 	if (bs->bs_status == BIO_STATUS_ERROR) {
326 		if (bs->bs_msg_count == 0)
327 			errx(1, "unknown error");
328 		else
329 			exit(1);
330 	}
331 }
332 
333 void
334 bio_inq(char *name)
335 {
336 	char 			*status, size[64], scsiname[16], volname[32];
337 	char			percent[10], seconds[20];
338 	int			i, d, volheader, hotspare, unused;
339 	char			encname[16], serial[32];
340 	struct bioc_inq		bi;
341 	struct bioc_vol		bv;
342 	struct bioc_disk	bd;
343 
344 	memset(&bi, 0, sizeof(bi));
345 
346 	bi.bi_bio.bio_cookie = bl.bl_bio.bio_cookie;
347 
348 	if (ioctl(devh, BIOCINQ, &bi)) {
349 		if (errno == ENOTTY)
350 			bio_diskinq(name);
351 		else
352 			err(1, "BIOCINQ");
353 		return;
354 	}
355 
356 	bio_status(&bi.bi_bio.bio_status);
357 
358 	volheader = 0;
359 	for (i = 0; i < bi.bi_novol; i++) {
360 		memset(&bv, 0, sizeof(bv));
361 		bv.bv_bio.bio_cookie = bl.bl_bio.bio_cookie;
362 		bv.bv_volid = i;
363 		bv.bv_percent = -1;
364 		bv.bv_seconds = 0;
365 
366 		if (ioctl(devh, BIOCVOL, &bv))
367 			err(1, "BIOCVOL");
368 
369 		bio_status(&bv.bv_bio.bio_status);
370 
371 		if (name && strcmp(name, bv.bv_dev) != 0)
372 			continue;
373 
374 		if (!volheader) {
375 			volheader = 1;
376 			printf("%-11s %-10s %14s %-8s\n",
377 			    "Volume", "Status", "Size", "Device");
378 		}
379 
380 		percent[0] = '\0';
381 		seconds[0] = '\0';
382 		if (bv.bv_percent != -1)
383 			snprintf(percent, sizeof percent,
384 			    " %d%% done", bv.bv_percent);
385 		if (bv.bv_seconds)
386 			snprintf(seconds, sizeof seconds,
387 			    " %u seconds", bv.bv_seconds);
388 		switch (bv.bv_status) {
389 		case BIOC_SVONLINE:
390 			status = BIOC_SVONLINE_S;
391 			break;
392 		case BIOC_SVOFFLINE:
393 			status = BIOC_SVOFFLINE_S;
394 			break;
395 		case BIOC_SVDEGRADED:
396 			status = BIOC_SVDEGRADED_S;
397 			break;
398 		case BIOC_SVBUILDING:
399 			status = BIOC_SVBUILDING_S;
400 			break;
401 		case BIOC_SVREBUILD:
402 			status = BIOC_SVREBUILD_S;
403 			break;
404 		case BIOC_SVSCRUB:
405 			status = BIOC_SVSCRUB_S;
406 			break;
407 		case BIOC_SVINVALID:
408 		default:
409 			status = BIOC_SVINVALID_S;
410 		}
411 
412 		snprintf(volname, sizeof volname, "%s %u",
413 		    bi.bi_dev, bv.bv_volid);
414 
415 		unused = 0;
416 		hotspare = 0;
417 		if (bv.bv_level == -1 && bv.bv_nodisk == 1)
418 			hotspare = 1;
419 		else if (bv.bv_level == -2 && bv.bv_nodisk == 1)
420 			unused = 1;
421 		else {
422 			if (human)
423 				fmt_scaled(bv.bv_size, size);
424 			else
425 				snprintf(size, sizeof size, "%14llu",
426 				    bv.bv_size);
427 			switch (bv.bv_level) {
428 			case 'C':
429 				printf("%11s %-10s %14s %-7s CRYPTO%s%s\n",
430 				    volname, status, size, bv.bv_dev,
431 				    percent, seconds);
432 				break;
433 			case 'c':
434 				printf("%11s %-10s %14s %-7s CONCAT%s%s\n",
435 				    volname, status, size, bv.bv_dev,
436 				    percent, seconds);
437 				break;
438 			default:
439 				printf("%11s %-10s %14s %-7s RAID%u%s%s\n",
440 				    volname, status, size, bv.bv_dev,
441 				    bv.bv_level, percent, seconds);
442 				break;
443 			}
444 
445 		}
446 
447 		for (d = 0; d < bv.bv_nodisk; d++) {
448 			memset(&bd, 0, sizeof(bd));
449 			bd.bd_bio.bio_cookie = bl.bl_bio.bio_cookie;
450 			bd.bd_diskid = d;
451 			bd.bd_volid = i;
452 
453 			if (ioctl(devh, BIOCDISK, &bd))
454 				err(1, "BIOCDISK");
455 
456 			bio_status(&bd.bd_bio.bio_status);
457 
458 			switch (bd.bd_status) {
459 			case BIOC_SDONLINE:
460 				status = BIOC_SDONLINE_S;
461 				break;
462 			case BIOC_SDOFFLINE:
463 				status = BIOC_SDOFFLINE_S;
464 				break;
465 			case BIOC_SDFAILED:
466 				status = BIOC_SDFAILED_S;
467 				break;
468 			case BIOC_SDREBUILD:
469 				status = BIOC_SDREBUILD_S;
470 				break;
471 			case BIOC_SDHOTSPARE:
472 				status = BIOC_SDHOTSPARE_S;
473 				break;
474 			case BIOC_SDUNUSED:
475 				status = BIOC_SDUNUSED_S;
476 				break;
477 			case BIOC_SDSCRUB:
478 				status = BIOC_SDSCRUB_S;
479 				break;
480 			case BIOC_SDINVALID:
481 			default:
482 				status = BIOC_SDINVALID_S;
483 			}
484 
485 			if (hotspare || unused)
486 				;	/* use volname from parent volume */
487 			else
488 				snprintf(volname, sizeof volname, "    %3u",
489 				    bd.bd_diskid);
490 
491 			if (bv.bv_level == 'C' && bd.bd_size == 0)
492 				snprintf(size, sizeof size, "%14s", "key disk");
493 			else if (human)
494 				fmt_scaled(bd.bd_size, size);
495 			else
496 				snprintf(size, sizeof size, "%14llu",
497 				    bd.bd_size);
498 			snprintf(scsiname, sizeof scsiname,
499 			    "%u:%u.%u",
500 			    bd.bd_channel, bd.bd_target, bd.bd_lun);
501 			if (bd.bd_procdev[0])
502 				strlcpy(encname, bd.bd_procdev, sizeof encname);
503 			else
504 				strlcpy(encname, "noencl", sizeof encname);
505 			if (bd.bd_serial[0])
506 				strlcpy(serial, bd.bd_serial, sizeof serial);
507 			else
508 				strlcpy(serial, "unknown serial", sizeof serial);
509 
510 			printf("%11s %-10s %14s %-7s %-6s <%s>\n",
511 			    volname, status, size, scsiname, encname,
512 			    bd.bd_vendor);
513 			if (verbose)
514 				printf("%7s %-10s %14s %-7s %-6s '%s'\n",
515 				    "", "", "", "", "", serial);
516 		}
517 	}
518 }
519 
520 void
521 bio_alarm(char *arg)
522 {
523 	struct bioc_alarm	ba;
524 
525 	memset(&ba, 0, sizeof(ba));
526 	ba.ba_bio.bio_cookie = bl.bl_bio.bio_cookie;
527 
528 	switch (arg[0]) {
529 	case 'q': /* silence alarm */
530 		/* FALLTHROUGH */
531 	case 's':
532 		ba.ba_opcode = BIOC_SASILENCE;
533 		break;
534 
535 	case 'e': /* enable alarm */
536 		ba.ba_opcode = BIOC_SAENABLE;
537 		break;
538 
539 	case 'd': /* disable alarm */
540 		ba.ba_opcode = BIOC_SADISABLE;
541 		break;
542 
543 	case 't': /* test alarm */
544 		ba.ba_opcode = BIOC_SATEST;
545 		break;
546 
547 	case 'g': /* get alarm state */
548 		ba.ba_opcode = BIOC_GASTATUS;
549 		break;
550 
551 	default:
552 		errx(1, "invalid alarm function: %s", arg);
553 	}
554 
555 	if (ioctl(devh, BIOCALARM, &ba))
556 		err(1, "BIOCALARM");
557 
558 	bio_status(&ba.ba_bio.bio_status);
559 
560 	if (arg[0] == 'g')
561 		printf("alarm is currently %s\n",
562 		    ba.ba_status ? "enabled" : "disabled");
563 }
564 
565 int
566 bio_getvolbyname(char *name)
567 {
568 	int			id = -1, i;
569 	struct bioc_inq		bi;
570 	struct bioc_vol		bv;
571 
572 	memset(&bi, 0, sizeof(bi));
573 	bi.bi_bio.bio_cookie = bl.bl_bio.bio_cookie;
574 	if (ioctl(devh, BIOCINQ, &bi))
575 		err(1, "BIOCINQ");
576 
577 	bio_status(&bi.bi_bio.bio_status);
578 
579 	for (i = 0; i < bi.bi_novol; i++) {
580 		memset(&bv, 0, sizeof(bv));
581 		bv.bv_bio.bio_cookie = bl.bl_bio.bio_cookie;
582 		bv.bv_volid = i;
583 		if (ioctl(devh, BIOCVOL, &bv))
584 			err(1, "BIOCVOL");
585 
586 		bio_status(&bv.bv_bio.bio_status);
587 
588 		if (name && strcmp(name, bv.bv_dev) != 0)
589 			continue;
590 		id = i;
591 		break;
592 	}
593 
594 	return (id);
595 }
596 
597 void
598 bio_setstate(char *arg, int status, char *devicename)
599 {
600 	struct bioc_setstate	bs;
601 	struct locator		location;
602 	struct stat		sb;
603 	const char		*errstr;
604 
605 	memset(&bs, 0, sizeof(bs));
606 	if (stat(arg, &sb) == -1) {
607 		/* use CTL */
608 		errstr = str2locator(arg, &location);
609 		if (errstr)
610 			errx(1, "Target %s: %s", arg, errstr);
611 		bs.bs_channel = location.channel;
612 		bs.bs_target = location.target;
613 		bs.bs_lun = location.lun;
614 	} else {
615 		/* use other id */
616 		bs.bs_other_id = sb.st_rdev;
617 		bs.bs_other_id_type = BIOC_SSOTHER_DEVT;
618 	}
619 
620 	bs.bs_bio.bio_cookie = bl.bl_bio.bio_cookie;
621 	bs.bs_status = status;
622 
623 	if (status != BIOC_SSHOTSPARE) {
624 		/* make sure user supplied a sd device */
625 		bs.bs_volid = bio_getvolbyname(devicename);
626 		if (bs.bs_volid == -1)
627 			errx(1, "invalid device %s", devicename);
628 	}
629 
630 	if (ioctl(devh, BIOCSETSTATE, &bs))
631 		err(1, "BIOCSETSTATE");
632 
633 	bio_status(&bs.bs_bio.bio_status);
634 }
635 
636 void
637 bio_setblink(char *name, char *arg, int blink)
638 {
639 	struct locator		location;
640 	struct bioc_blink	bb;
641 	struct bioc_inq		bi;
642 	struct bioc_vol		bv;
643 	struct bioc_disk	bd;
644 	const char		*errstr;
645 	int			v, d, rv;
646 
647 	errstr = str2locator(arg, &location);
648 	if (errstr)
649 		errx(1, "Target %s: %s", arg, errstr);
650 
651 	/* try setting blink on the device directly */
652 	memset(&bb, 0, sizeof(bb));
653 	bb.bb_bio.bio_cookie = bl.bl_bio.bio_cookie;
654 	bb.bb_status = blink;
655 	bb.bb_target = location.target;
656 	bb.bb_channel = location.channel;
657 	rv = ioctl(devh, BIOCBLINK, &bb);
658 
659 	if (rv == 0 && bb.bb_bio.bio_status.bs_status == BIO_STATUS_UNKNOWN)
660 		return;
661 
662 	if (rv == 0 && bb.bb_bio.bio_status.bs_status == BIO_STATUS_SUCCESS) {
663 		bio_status(&bb.bb_bio.bio_status);
664 		return;
665 	}
666 
667 	/* if the blink didn't work, try to find something that will */
668 
669 	memset(&bi, 0, sizeof(bi));
670 	bi.bi_bio.bio_cookie = bl.bl_bio.bio_cookie;
671 	if (ioctl(devh, BIOCINQ, &bi))
672 		err(1, "BIOCINQ");
673 
674 	bio_status(&bi.bi_bio.bio_status);
675 
676 	for (v = 0; v < bi.bi_novol; v++) {
677 		memset(&bv, 0, sizeof(bv));
678 		bv.bv_bio.bio_cookie = bl.bl_bio.bio_cookie;
679 		bv.bv_volid = v;
680 		if (ioctl(devh, BIOCVOL, &bv))
681 			err(1, "BIOCVOL");
682 
683 		bio_status(&bv.bv_bio.bio_status);
684 
685 		if (name && strcmp(name, bv.bv_dev) != 0)
686 			continue;
687 
688 		for (d = 0; d < bv.bv_nodisk; d++) {
689 			memset(&bd, 0, sizeof(bd));
690 			bd.bd_bio.bio_cookie = bl.bl_bio.bio_cookie;
691 			bd.bd_volid = v;
692 			bd.bd_diskid = d;
693 
694 			if (ioctl(devh, BIOCDISK, &bd))
695 				err(1, "BIOCDISK");
696 
697 			bio_status(&bd.bd_bio.bio_status);
698 
699 			if (bd.bd_channel == location.channel &&
700 			    bd.bd_target == location.target &&
701 			    bd.bd_lun == location.lun) {
702 				if (bd.bd_procdev[0] != '\0')
703 					bio_blink(bd.bd_procdev,
704 					    location.target, blink);
705 				else
706 					warnx("Disk %s is not in an enclosure",
707 					    arg);
708 				return;
709 			}
710 		}
711 	}
712 
713 	warnx("Disk %s does not exist", arg);
714 
715 	return;
716 }
717 
718 void
719 bio_blink(char *enclosure, int target, int blinktype)
720 {
721 	int			bioh;
722 	struct bio_locate	bl;
723 	struct bioc_blink	blink;
724 
725 	bioh = open("/dev/bio", O_RDWR);
726 	if (bioh == -1)
727 		err(1, "Can't open %s", "/dev/bio");
728 
729 	memset(&bl, 0, sizeof(bl));
730 	bl.bl_name = enclosure;
731 	if (ioctl(bioh, BIOCLOCATE, &bl))
732 		errx(1, "Can't locate %s device via %s", enclosure, "/dev/bio");
733 
734 	bio_status(&bl.bl_bio.bio_status);
735 
736 	memset(&blink, 0, sizeof(blink));
737 	blink.bb_bio.bio_cookie = bl.bl_bio.bio_cookie;
738 	blink.bb_status = blinktype;
739 	blink.bb_target = target;
740 
741 	if (ioctl(bioh, BIOCBLINK, &blink))
742 		err(1, "BIOCBLINK");
743 
744 	bio_status(&blink.bb_bio.bio_status);
745 
746 	close(bioh);
747 }
748 
749 struct sr_aoe_config *
750 create_aoe(u_int16_t level, char *dev_list)
751 {
752 	static struct sr_aoe_config sac;
753 	char *nic;
754 	char *dsteaddr;
755 	char *shelf;
756 	char *slot;
757 	struct ether_addr *eaddr;
758 	const char *errstr;
759 
760 	nic = dsteaddr = slot = shelf = 0;
761 
762 	memset(&sac, 0, sizeof(sac));
763 	nic = dev_list;
764 	dsteaddr = strchr(nic, ',');
765 	if (!dsteaddr)
766 		goto invalid;
767 	*dsteaddr++ = '\0';
768 	shelf = strchr(dsteaddr, ',');
769 	if (!shelf)
770 		goto invalid;
771 	*shelf++ = '\0';
772 	slot = strchr(shelf, ',');
773 	if (!slot)
774 		goto invalid;
775 	*slot++ = '\0';
776 	strlcpy(sac.nic, nic, sizeof(sac.nic));
777 	eaddr = ether_aton(dsteaddr);
778 	if (!eaddr)
779 		goto invalid;
780 	sac.dsteaddr = *eaddr;
781 	sac.shelf = htons(strtonum(shelf, 0, 0xfffe, &errstr));
782 	if (errstr)
783 		goto invalid;
784 	sac.slot = strtonum(slot, 0, 0xfe, &errstr);
785 	if (errstr)
786 		goto invalid;
787 
788 	return &sac;
789 invalid:
790 	errx(1, "invalid AOE dev list: use nic,dsteaddr,shelf,slot");
791 }
792 
793 void
794 bio_createraid(u_int16_t level, char *dev_list, char *key_disk)
795 {
796 	struct bioc_createraid	create;
797 	struct sr_crypto_kdfinfo kdfinfo;
798 	struct sr_crypto_kdf_pbkdf2 kdfhint;
799 	struct sr_aoe_config	*sac;
800 	struct stat		sb;
801 	int			rv, no_dev, fd;
802 	dev_t			*dt;
803 	u_int16_t		min_disks = 0;
804 
805 	if (!dev_list)
806 		errx(1, "no devices specified");
807 
808 	if (level == 'a') {
809 		sac = create_aoe(level, dev_list);
810 		no_dev = 0;
811 		dt = NULL;
812 	} else  {
813 		dt = (dev_t *)malloc(BIOC_CRMAXLEN);
814 		if (!dt)
815 			err(1, "not enough memory for dev_t list");
816 		memset(dt, 0, BIOC_CRMAXLEN);
817 
818 		no_dev = bio_parse_devlist(dev_list, dt);
819 	}
820 
821 	switch (level) {
822 	case 0:
823 		min_disks = 2;
824 		break;
825 	case 1:
826 		min_disks = 2;
827 		break;
828 	case 4:
829 	case 5:
830 		min_disks = 3;
831 		break;
832 	case 'C':
833 		min_disks = 1;
834 		break;
835 	case 'c':
836 		min_disks = 2;
837 		break;
838 	case 'a':
839 		break;
840 	default:
841 		errx(1, "unsupported raid level");
842 	}
843 
844 	if (no_dev < min_disks)
845 		errx(1, "not enough disks");
846 
847 	/* for crypto raid we only allow one single chunk */
848 	if (level == 'C' && no_dev != min_disks)
849 		errx(1, "not exactly one partition");
850 
851 	memset(&create, 0, sizeof(create));
852 	create.bc_bio.bio_cookie = bl.bl_bio.bio_cookie;
853 	create.bc_level = level;
854 	create.bc_dev_list_len = no_dev * sizeof(dev_t);
855 	create.bc_dev_list = dt;
856 	create.bc_flags = BIOC_SCDEVT | cflags;
857 	create.bc_key_disk = NODEV;
858 
859 	if (level == 'a') {
860 		create.bc_opaque = sac;
861 		create.bc_opaque_size = sizeof(*sac);
862 		create.bc_opaque_flags = BIOC_SOIN;
863 	} else if (level == 'C' && key_disk == NULL) {
864 
865 		memset(&kdfinfo, 0, sizeof(kdfinfo));
866 		memset(&kdfhint, 0, sizeof(kdfhint));
867 
868 		create.bc_flags |= BIOC_SCNOAUTOASSEMBLE;
869 
870 		create.bc_opaque = &kdfhint;
871 		create.bc_opaque_size = sizeof(kdfhint);
872 		create.bc_opaque_flags = BIOC_SOOUT;
873 
874 		/* try to get KDF hint */
875 		if (ioctl(devh, BIOCCREATERAID, &create))
876 			err(1, "ioctl");
877 
878 		bio_status(&create.bc_bio.bio_status);
879 
880 		if (create.bc_opaque_status == BIOC_SOINOUT_OK) {
881 			bio_kdf_derive(&kdfinfo, &kdfhint, "Passphrase: ", 0);
882 			memset(&kdfhint, 0, sizeof(kdfhint));
883 		} else {
884 			bio_kdf_generate(&kdfinfo);
885 		}
886 
887 		create.bc_opaque = &kdfinfo;
888 		create.bc_opaque_size = sizeof(kdfinfo);
889 		create.bc_opaque_flags = BIOC_SOIN;
890 
891 	} else if (level == 'C' && key_disk != NULL) {
892 
893 		/* Get device number for key disk. */
894 		fd = opendev(key_disk, O_RDONLY, OPENDEV_BLCK, NULL);
895 		if (fd == -1)
896 			err(1, "could not open %s", key_disk);
897 		if (fstat(fd, &sb) == -1) {
898 			close(fd);
899 			err(1, "could not stat %s", key_disk);
900 		}
901 		close(fd);
902 		create.bc_key_disk = sb.st_rdev;
903 
904 		memset(&kdfinfo, 0, sizeof(kdfinfo));
905 
906 		kdfinfo.genkdf.len = sizeof(kdfinfo.genkdf);
907 		kdfinfo.genkdf.type = SR_CRYPTOKDFT_KEYDISK;
908 		kdfinfo.len = sizeof(kdfinfo);
909 		kdfinfo.flags = SR_CRYPTOKDF_HINT;
910 
911 		create.bc_opaque = &kdfinfo;
912 		create.bc_opaque_size = sizeof(kdfinfo);
913 		create.bc_opaque_flags = BIOC_SOIN;
914 
915 	}
916 
917 	rv = ioctl(devh, BIOCCREATERAID, &create);
918 	memset(&kdfinfo, 0, sizeof(kdfinfo));
919 	if (rv == -1)
920 		err(1, "BIOCCREATERAID");
921 
922 	bio_status(&create.bc_bio.bio_status);
923 
924 	free(dt);
925 }
926 
927 void
928 bio_kdf_derive(struct sr_crypto_kdfinfo *kdfinfo, struct sr_crypto_kdf_pbkdf2
929     *kdfhint, char* prompt, int verify)
930 {
931 	if (!kdfinfo)
932 		errx(1, "invalid KDF info");
933 	if (!kdfhint)
934 		errx(1, "invalid KDF hint");
935 
936 	if (kdfhint->len != sizeof(*kdfhint))
937 		errx(1, "KDF hint has invalid size");
938 	if (kdfhint->type != SR_CRYPTOKDFT_PBKDF2)
939 		errx(1, "unknown KDF type %d", kdfhint->type);
940 	if (kdfhint->rounds < 1000)
941 		errx(1, "number of KDF rounds too low: %d", kdfhint->rounds);
942 
943 	kdfinfo->flags = SR_CRYPTOKDF_KEY;
944 	kdfinfo->len = sizeof(*kdfinfo);
945 
946 	derive_key_pkcs(kdfhint->rounds,
947 	    kdfinfo->maskkey, sizeof(kdfinfo->maskkey),
948 	    kdfhint->salt, sizeof(kdfhint->salt), prompt, verify);
949 }
950 
951 void
952 bio_kdf_generate(struct sr_crypto_kdfinfo *kdfinfo)
953 {
954 	if (!kdfinfo)
955 		errx(1, "invalid KDF info");
956 
957 	kdfinfo->pbkdf2.len = sizeof(kdfinfo->pbkdf2);
958 	kdfinfo->pbkdf2.type = SR_CRYPTOKDFT_PBKDF2;
959 	kdfinfo->pbkdf2.rounds = rflag;
960 	kdfinfo->len = sizeof(*kdfinfo);
961 	kdfinfo->flags = SR_CRYPTOKDF_KEY | SR_CRYPTOKDF_HINT;
962 
963 	/* generate salt */
964 	arc4random_buf(kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt));
965 
966 	derive_key_pkcs(kdfinfo->pbkdf2.rounds,
967 	    kdfinfo->maskkey, sizeof(kdfinfo->maskkey),
968 	    kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt),
969 	    "New passphrase: ", 1);
970 }
971 
972 int
973 bio_parse_devlist(char *lst, dev_t *dt)
974 {
975 	char			*s, *e;
976 	u_int32_t		sz = 0;
977 	int			no_dev = 0, i, x;
978 	struct stat		sb;
979 	char			dev[MAXPATHLEN];
980 	int			fd;
981 
982 	if (!lst)
983 		errx(1, "invalid device list");
984 
985 	s = e = lst;
986 	/* make sure we have a valid device list like /dev/sdNa,/dev/sdNNa */
987 	while (*e != '\0') {
988 		if (*e == ',')
989 			s = e + 1;
990 		else if (*(e + 1) == '\0' || *(e + 1) == ',') {
991 			/* got one */
992 			sz = e - s + 1;
993 			strlcpy(dev, s, sz + 1);
994 			fd = opendev(dev, O_RDONLY, OPENDEV_BLCK, NULL);
995 			if (fd == -1)
996 				err(1, "could not open %s", dev);
997 			if (fstat(fd, &sb) == -1) {
998 				close(fd);
999 				err(1, "could not stat %s", dev);
1000 			}
1001 			close(fd);
1002 			dt[no_dev] = sb.st_rdev;
1003 			no_dev++;
1004 			if (no_dev > (int)(BIOC_CRMAXLEN / sizeof(dev_t)))
1005 				errx(1, "too many devices on device list");
1006 		}
1007 		e++;
1008 	}
1009 
1010 	for (i = 0; i < no_dev; i++)
1011 		for (x = 0; x < no_dev; x++)
1012 			if (dt[i] == dt[x] && x != i)
1013 				errx(1, "duplicate device in list");
1014 
1015 	return (no_dev);
1016 }
1017 
1018 u_int32_t
1019 bio_createflags(char *lst)
1020 {
1021 	char			*s, *e, fs[32];
1022 	u_int32_t		sz = 0;
1023 	u_int32_t		flags = 0;
1024 
1025 	if (!lst)
1026 		errx(1, "invalid flags list");
1027 
1028 	s = e = lst;
1029 	/* make sure we have a valid flags list like force,noassemeble */
1030 	while (*e != '\0') {
1031 		if (*e == ',')
1032 			s = e + 1;
1033 		else if (*(e + 1) == '\0' || *(e + 1) == ',') {
1034 			/* got one */
1035 			sz = e - s + 1;
1036 			switch (s[0]) {
1037 			case 'f':
1038 				flags |= BIOC_SCFORCE;
1039 				break;
1040 			case 'n':
1041 				flags |= BIOC_SCNOAUTOASSEMBLE;
1042 				break;
1043 			default:
1044 				strlcpy(fs, s, sz + 1);
1045 				errx(1, "invalid flag %s", fs);
1046 			}
1047 		}
1048 		e++;
1049 	}
1050 
1051 	return (flags);
1052 }
1053 
1054 void
1055 bio_deleteraid(char *dev)
1056 {
1057 	struct bioc_deleteraid	bd;
1058 	memset(&bd, 0, sizeof(bd));
1059 
1060 	bd.bd_bio.bio_cookie = bd.bd_bio.bio_cookie;
1061 	/* XXX make this a dev_t instead of a string */
1062 	strlcpy(bd.bd_dev, dev, sizeof bd.bd_dev);
1063 	if (ioctl(devh, BIOCDELETERAID, &bd))
1064 		err(1, "BIOCDELETERAID");
1065 
1066 	bio_status(&bd.bd_bio.bio_status);
1067 }
1068 
1069 void
1070 bio_changepass(char *dev)
1071 {
1072 	struct bioc_discipline bd;
1073 	struct sr_crypto_kdfpair kdfpair;
1074 	struct sr_crypto_kdfinfo kdfinfo1, kdfinfo2;
1075 	struct sr_crypto_kdf_pbkdf2 kdfhint;
1076 	int rv;
1077 
1078 	memset(&bd, 0, sizeof(bd));
1079 	memset(&kdfhint, 0, sizeof(kdfhint));
1080 	memset(&kdfinfo1, 0, sizeof(kdfinfo1));
1081 	memset(&kdfinfo2, 0, sizeof(kdfinfo2));
1082 
1083 	/* XXX use dev_t instead of string. */
1084 	strlcpy(bd.bd_dev, dev, sizeof(bd.bd_dev));
1085 	bd.bd_cmd = SR_IOCTL_GET_KDFHINT;
1086 	bd.bd_size = sizeof(kdfhint);
1087 	bd.bd_data = &kdfhint;
1088 
1089 	if (ioctl(devh, BIOCDISCIPLINE, &bd))
1090 		err(1, "BIOCDISCIPLINE");
1091 
1092 	bio_status(&bd.bd_bio.bio_status);
1093 
1094 	/* Current passphrase. */
1095 	bio_kdf_derive(&kdfinfo1, &kdfhint, "Old passphrase: ", 0);
1096 
1097 	/* New passphrase. */
1098 	bio_kdf_derive(&kdfinfo2, &kdfhint, "New passphrase: ", 1);
1099 
1100 	kdfpair.kdfinfo1 = &kdfinfo1;
1101 	kdfpair.kdfsize1 = sizeof(kdfinfo1);
1102 	kdfpair.kdfinfo2 = &kdfinfo2;
1103 	kdfpair.kdfsize2 = sizeof(kdfinfo2);
1104 
1105 	bd.bd_cmd = SR_IOCTL_CHANGE_PASSPHRASE;
1106 	bd.bd_size = sizeof(kdfpair);
1107 	bd.bd_data = &kdfpair;
1108 
1109 	rv = ioctl(devh, BIOCDISCIPLINE, &bd);
1110 
1111 	memset(&kdfhint, 0, sizeof(kdfhint));
1112 	memset(&kdfinfo1, 0, sizeof(kdfinfo1));
1113 	memset(&kdfinfo2, 0, sizeof(kdfinfo2));
1114 
1115 	if (rv)
1116 		err(1, "BIOCDISCIPLINE");
1117 
1118 	bio_status(&bd.bd_bio.bio_status);
1119 }
1120 
1121 #define BIOCTL_VIS_NBUF		4
1122 #define BIOCTL_VIS_BUFLEN	80
1123 
1124 char *
1125 bio_vis(char *s)
1126 {
1127 	static char	 rbuf[BIOCTL_VIS_NBUF][BIOCTL_VIS_BUFLEN];
1128 	static uint	 idx = 0;
1129 	char		*buf;
1130 
1131 	buf = rbuf[idx++];
1132 	if (idx == BIOCTL_VIS_NBUF)
1133 		idx = 0;
1134 
1135 	strnvis(buf, s, BIOCTL_VIS_BUFLEN, VIS_NL|VIS_CSTYLE);
1136 	return (buf);
1137 }
1138 
1139 void
1140 bio_diskinq(char *sd_dev)
1141 {
1142 	struct dk_inquiry	di;
1143 
1144 	if (ioctl(devh, DIOCINQ, &di) == -1)
1145 		err(1, "DIOCINQ");
1146 
1147 	printf("%s: <%s, %s, %s>, serial %s\n", sd_dev, bio_vis(di.vendor),
1148 	    bio_vis(di.product), bio_vis(di.revision), bio_vis(di.serial));
1149 }
1150 
1151 void
1152 derive_key_pkcs(int rounds, u_int8_t *key, size_t keysz, u_int8_t *salt,
1153     size_t saltsz, char *prompt, int verify)
1154 {
1155 	FILE		*f;
1156 	size_t		pl;
1157 	struct stat	sb;
1158 	char		passphrase[1024], verifybuf[1024];
1159 
1160 	if (!key)
1161 		errx(1, "Invalid key");
1162 	if (!salt)
1163 		errx(1, "Invalid salt");
1164 	if (rounds < 1000)
1165 		errx(1, "Too few rounds: %d", rounds);
1166 
1167 	/* get passphrase */
1168 	if (password && verify)
1169 		errx(1, "can't specify passphrase file during initial "
1170 		    "creation of crypto volume");
1171 	if (password) {
1172 		if ((f = fopen(password, "r")) == NULL)
1173 			err(1, "invalid passphrase file");
1174 
1175 		if (fstat(fileno(f), &sb) == -1)
1176 			err(1, "can't stat passphrase file");
1177 		if (sb.st_uid != 0)
1178 			errx(1, "passphrase file must be owned by root");
1179 		if ((sb.st_mode & ~S_IFMT) != (S_IRUSR | S_IWUSR))
1180 			errx(1, "passphrase file has the wrong permissions");
1181 
1182 		if (fgets(passphrase, sizeof(passphrase), f) == NULL)
1183 			err(1, "can't read passphrase file");
1184 		pl = strlen(passphrase);
1185 		if (pl > 0 && passphrase[pl - 1] == '\n')
1186 			passphrase[pl - 1] = '\0';
1187 		else
1188 			errx(1, "invalid passphrase length");
1189 
1190 		fclose(f);
1191 	} else {
1192 		if (readpassphrase(prompt, passphrase, sizeof(passphrase),
1193 		    rpp_flag) == NULL)
1194 			errx(1, "unable to read passphrase");
1195 	}
1196 
1197 	if (verify) {
1198 		/* request user to re-type it */
1199 		if (readpassphrase("Re-type passphrase: ", verifybuf,
1200 		    sizeof(verifybuf), rpp_flag) == NULL) {
1201 			memset(passphrase, 0, sizeof(passphrase));
1202 			errx(1, "unable to read passphrase");
1203 		}
1204 		if ((strlen(passphrase) != strlen(verifybuf)) ||
1205 		    (strcmp(passphrase, verifybuf) != 0)) {
1206 			memset(passphrase, 0, sizeof(passphrase));
1207 			memset(verifybuf, 0, sizeof(verifybuf));
1208 			errx(1, "Passphrases did not match");
1209 		}
1210 		/* forget the re-typed one */
1211 		memset(verifybuf, 0, strlen(verifybuf));
1212 	}
1213 
1214 	/* derive key from passphrase */
1215 	if (pkcs5_pbkdf2(passphrase, strlen(passphrase), salt, saltsz,
1216 	    key, keysz, rounds) != 0)
1217 		errx(1, "pbkdf2 failed");
1218 
1219 	/* forget passphrase */
1220 	memset(passphrase, 0, sizeof(passphrase));
1221 
1222 	return;
1223 }
1224