GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/bioctl/bioctl.c Lines: 0 659 0.0 %
Date: 2016-12-06 Branches: 0 382 0.0 %

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