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