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