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