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