1*c6446370Sjsing /* $OpenBSD: bioctl.c,v 1.85 2009/11/24 02:19:35 jsing Exp $ */ 2cf6503d7Sderaadt 33af9de98Smarco /* 42f39728eSdlg * Copyright (c) 2004, 2005 Marco Peereboom 53af9de98Smarco * All rights reserved. 63af9de98Smarco * 73af9de98Smarco * Redistribution and use in source and binary forms, with or without 83af9de98Smarco * modification, are permitted provided that the following conditions 93af9de98Smarco * are met: 103af9de98Smarco * 1. Redistributions of source code must retain the above copyright 113af9de98Smarco * notice, this list of conditions and the following disclaimer. 123af9de98Smarco * 2. Redistributions in binary form must reproduce the above copyright 133af9de98Smarco * notice, this list of conditions and the following disclaimer in the 143af9de98Smarco * documentation and/or other materials provided with the distribution. 153af9de98Smarco * 163af9de98Smarco * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 173af9de98Smarco * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 183af9de98Smarco * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 193af9de98Smarco * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR 203af9de98Smarco * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 213af9de98Smarco * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 223af9de98Smarco * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 233af9de98Smarco * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 243af9de98Smarco * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 253af9de98Smarco * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 263af9de98Smarco * SUCH DAMAGE. 273af9de98Smarco * 283af9de98Smarco */ 293af9de98Smarco 30c2126c9aSmarco #include <sys/ioctl.h> 31c2126c9aSmarco #include <sys/param.h> 32c2126c9aSmarco #include <sys/queue.h> 3346bc198bSmarco #include <sys/types.h> 3446bc198bSmarco #include <sys/stat.h> 35c2126c9aSmarco #include <scsi/scsi_disk.h> 362b69df39Smarco #include <scsi/scsi_all.h> 373af9de98Smarco #include <dev/biovar.h> 38aef7fe28Shshoexer #include <dev/softraidvar.h> 3986735da2Smarco #include <sys/types.h> 4086735da2Smarco #include <sys/stat.h> 413af9de98Smarco 42db2730c1Smarco #include <errno.h> 43db2730c1Smarco #include <err.h> 44db2730c1Smarco #include <fcntl.h> 458ccdd032Sderaadt #include <util.h> 46db2730c1Smarco #include <stdio.h> 47db2730c1Smarco #include <stdlib.h> 48db2730c1Smarco #include <string.h> 49db2730c1Smarco #include <unistd.h> 50e4e14ad7Sderaadt #include <ctype.h> 51db2730c1Smarco #include <util.h> 5203b2dfbfShenning #include <vis.h> 539e8c6f5bShshoexer #include <readpassphrase.h> 54db2730c1Smarco 555c1f8f6bSdjm #include "pbkdf2.h" 56aef7fe28Shshoexer 576de960dcSmarco struct locator { 586de960dcSmarco int channel; 596de960dcSmarco int target; 606de960dcSmarco int lun; 616de960dcSmarco }; 626de960dcSmarco 638ccdd032Sderaadt void usage(void); 6441eccc89Sderaadt const char *str2locator(const char *, struct locator *); 658ccdd032Sderaadt void cleanup(void); 6646bc198bSmarco int bio_parse_devlist(char *, dev_t *); 67aef7fe28Shshoexer void bio_kdf_derive(struct sr_crypto_kdfinfo *, 68*c6446370Sjsing struct sr_crypto_kdf_pbkdf2 *, char *, int); 69aef7fe28Shshoexer void bio_kdf_generate(struct sr_crypto_kdfinfo *); 709e8c6f5bShshoexer void derive_key_pkcs(int, u_int8_t *, size_t, u_int8_t *, 71*c6446370Sjsing size_t, char *, int); 728ccdd032Sderaadt 738ccdd032Sderaadt void bio_inq(char *); 748ccdd032Sderaadt void bio_alarm(char *); 75a15048bbSmarco int bio_getvolbyname(char *); 76a15048bbSmarco void bio_setstate(char *, int, char *); 77a928c459Sderaadt void bio_setblink(char *, char *, int); 78a928c459Sderaadt void bio_blink(char *, int, int); 797195049bSmarco void bio_createraid(u_int16_t, char *); 80c7c3e8aaSmarco void bio_deleteraid(char *); 81*c6446370Sjsing void bio_changepass(char *); 82e8a57fdeSmarco u_int32_t bio_createflags(char *); 8303b2dfbfShenning char *bio_vis(char *); 8403b2dfbfShenning void bio_diskinq(char *); 853af9de98Smarco 863af9de98Smarco int devh = -1; 87abe9d68eSderaadt int human; 88abe9d68eSderaadt int verbose; 89e8a57fdeSmarco u_int32_t cflags = 0; 90aedd4f07Sdjm int rflag = 8192; 9186735da2Smarco char *password; 923af9de98Smarco 933af9de98Smarco struct bio_locate bl; 943af9de98Smarco 953af9de98Smarco int 963af9de98Smarco main(int argc, char *argv[]) 973af9de98Smarco { 983af9de98Smarco extern char *optarg; 99db2730c1Smarco u_int64_t func = 0; 100db2730c1Smarco /* u_int64_t subfunc = 0; */ 101cf6503d7Sderaadt char *bioc_dev = NULL, *sd_dev = NULL; 102cf6503d7Sderaadt char *realname = NULL, *al_arg = NULL; 1037195049bSmarco char *bl_arg = NULL, *dev_list = NULL; 104aedd4f07Sdjm const char *errstr; 105*c6446370Sjsing int ch, rv, blink = 0, changepass = 0, diskinq = 0; 106*c6446370Sjsing int ss_func = 0; 1079ecba717Sderaadt u_int16_t cr_level = 0; 1083af9de98Smarco 1093af9de98Smarco if (argc < 2) 1103af9de98Smarco usage(); 1113af9de98Smarco 112*c6446370Sjsing while ((ch = getopt(argc, argv, "a:b:C:c:dH:hil:Pp:qr:R:vu:")) != 113*c6446370Sjsing -1) { 1143af9de98Smarco switch (ch) { 115edfd9792Smarco case 'a': /* alarm */ 116edfd9792Smarco func |= BIOC_ALARM; 117edfd9792Smarco al_arg = optarg; 118edfd9792Smarco break; 119c55617f1Sdlg case 'b': /* blink */ 120c55617f1Sdlg func |= BIOC_BLINK; 121a928c459Sderaadt blink = BIOC_SBBLINK; 122a928c459Sderaadt bl_arg = optarg; 123a928c459Sderaadt break; 124e8a57fdeSmarco case 'C': /* creation flags */ 125e8a57fdeSmarco cflags = bio_createflags(optarg); 126e8a57fdeSmarco break; 1277195049bSmarco case 'c': /* create */ 1287195049bSmarco func |= BIOC_CREATERAID; 12998b750e4Stedu if (isdigit(*optarg)) 1307195049bSmarco cr_level = atoi(optarg); 13198b750e4Stedu else 13298b750e4Stedu cr_level = *optarg; 1337195049bSmarco break; 134c7c3e8aaSmarco case 'd': 135c7c3e8aaSmarco /* delete volume */ 136c7c3e8aaSmarco func |= BIOC_DELETERAID; 137c7c3e8aaSmarco break; 138a928c459Sderaadt case 'u': /* unblink */ 139a928c459Sderaadt func |= BIOC_BLINK; 140a928c459Sderaadt blink = BIOC_SBUNBLINK; 141c55617f1Sdlg bl_arg = optarg; 142c55617f1Sdlg break; 1436de960dcSmarco case 'H': /* set hotspare */ 1446de960dcSmarco func |= BIOC_SETSTATE; 145a15048bbSmarco ss_func = BIOC_SSHOTSPARE; 1466de960dcSmarco al_arg = optarg; 1476de960dcSmarco break; 1488ccdd032Sderaadt case 'h': 1498ccdd032Sderaadt human = 1; 1508ccdd032Sderaadt break; 151db2730c1Smarco case 'i': /* inquiry */ 152db2730c1Smarco func |= BIOC_INQ; 1533af9de98Smarco break; 1547195049bSmarco case 'l': /* device list */ 1557195049bSmarco func |= BIOC_DEVLIST; 1567195049bSmarco dev_list = optarg; 1577195049bSmarco break; 158*c6446370Sjsing case 'P': 159*c6446370Sjsing /* Change passphrase. */ 160*c6446370Sjsing changepass = 1; 161*c6446370Sjsing break; 16286735da2Smarco case 'p': 16386735da2Smarco password = optarg; 16486735da2Smarco break; 165aedd4f07Sdjm case 'r': 166aedd4f07Sdjm rflag = strtonum(optarg, 1000, 1<<30, &errstr); 167aedd4f07Sdjm if (errstr != NULL) 168aedd4f07Sdjm errx(1, "Number of rounds is %s: %s", 169aedd4f07Sdjm errstr, optarg); 170aedd4f07Sdjm break; 171a15048bbSmarco case 'R': 172a15048bbSmarco /* rebuild to provided chunk/CTL */ 173a15048bbSmarco func |= BIOC_SETSTATE; 174a15048bbSmarco ss_func = BIOC_SSREBUILD; 175a15048bbSmarco al_arg = optarg; 176a15048bbSmarco break; 177abe9d68eSderaadt case 'v': 178abe9d68eSderaadt verbose = 1; 179abe9d68eSderaadt break; 18003b2dfbfShenning case 'q': 18103b2dfbfShenning diskinq = 1; 18203b2dfbfShenning break; 1833af9de98Smarco default: 1843af9de98Smarco usage(); 1853af9de98Smarco /* NOTREACHED */ 1863af9de98Smarco } 1873af9de98Smarco } 188cf6503d7Sderaadt argc -= optind; 189cf6503d7Sderaadt argv += optind; 1903af9de98Smarco 191*c6446370Sjsing if (argc != 1 || (changepass && func != 0)) 192cf6503d7Sderaadt usage(); 193cf6503d7Sderaadt 194dcbaf4c8Sderaadt if (func == 0) 195dcbaf4c8Sderaadt func |= BIOC_INQ; 196dcbaf4c8Sderaadt 197e4e14ad7Sderaadt /* if at least glob sd[0-9]*, it is a drive identifier */ 198e4e14ad7Sderaadt if (strncmp(argv[0], "sd", 2) == 0 && strlen(argv[0]) > 2 && 199e4e14ad7Sderaadt isdigit(argv[0][2])) 200cf6503d7Sderaadt sd_dev = argv[0]; 201cf6503d7Sderaadt else 202cf6503d7Sderaadt bioc_dev = argv[0]; 20310b411a7Smarco 20410b411a7Smarco if (bioc_dev) { 20541eccc89Sderaadt devh = open("/dev/bio", O_RDWR); 2063af9de98Smarco if (devh == -1) 20741eccc89Sderaadt err(1, "Can't open %s", "/dev/bio"); 2083af9de98Smarco 2098ccdd032Sderaadt bl.bl_name = bioc_dev; 2103af9de98Smarco rv = ioctl(devh, BIOCLOCATE, &bl); 2113af9de98Smarco if (rv == -1) 21210b411a7Smarco errx(1, "Can't locate %s device via %s", 21341eccc89Sderaadt bl.bl_name, "/dev/bio"); 214db2730c1Smarco } else if (sd_dev) { 21510b411a7Smarco devh = opendev(sd_dev, O_RDWR, OPENDEV_PART, &realname); 21610b411a7Smarco if (devh == -1) 21710b411a7Smarco err(1, "Can't open %s", sd_dev); 218db2730c1Smarco } else 21986735da2Smarco errx(1, "need device"); 2203af9de98Smarco 22103b2dfbfShenning if (diskinq) { 22203b2dfbfShenning bio_diskinq(sd_dev); 223*c6446370Sjsing } else if (changepass && sd_dev != NULL) { 224*c6446370Sjsing bio_changepass(sd_dev); 22503b2dfbfShenning } else if (func & BIOC_INQ) { 2268ccdd032Sderaadt bio_inq(sd_dev); 227edfd9792Smarco } else if (func == BIOC_ALARM) { 228edfd9792Smarco bio_alarm(al_arg); 229c55617f1Sdlg } else if (func == BIOC_BLINK) { 230a928c459Sderaadt bio_setblink(sd_dev, bl_arg, blink); 2316de960dcSmarco } else if (func == BIOC_SETSTATE) { 232a15048bbSmarco bio_setstate(al_arg, ss_func, argv[0]); 233c7c3e8aaSmarco } else if (func == BIOC_DELETERAID && sd_dev != NULL) { 234c7c3e8aaSmarco bio_deleteraid(sd_dev); 2357195049bSmarco } else if (func & BIOC_CREATERAID || func & BIOC_DEVLIST) { 2367195049bSmarco if (!(func & BIOC_CREATERAID)) 2377195049bSmarco errx(1, "need -c parameter"); 2387195049bSmarco if (!(func & BIOC_DEVLIST)) 2397195049bSmarco errx(1, "need -l parameter"); 2407195049bSmarco if (sd_dev) 2417195049bSmarco errx(1, "can't use sd device"); 2427195049bSmarco bio_createraid(cr_level, dev_list); 2433af9de98Smarco } 2443af9de98Smarco 2453af9de98Smarco return (0); 2463af9de98Smarco } 2473af9de98Smarco 2483af9de98Smarco void 2493af9de98Smarco usage(void) 2503af9de98Smarco { 2513af9de98Smarco extern char *__progname; 2523af9de98Smarco 253d90b5d8bSjmc fprintf(stderr, 254d0b772c8Sjmc "usage: %s [-hiqv] [-a alarm-function] " 255d90b5d8bSjmc "[-b channel:target[.lun]]\n" 256d0b772c8Sjmc "\t[-H channel:target[.lun]] " 257d0b772c8Sjmc "[-R device | channel:target[.lun]\n" 258d0b772c8Sjmc "\t[-u channel:target[.lun]] " 259d0b772c8Sjmc "device\n" 260*c6446370Sjsing " %s [-Pdhiqv] " 261d0b772c8Sjmc "[-C flag[,flag,...]] [-c raidlevel]\n" 26278702060Sjmc "\t[-l special[,special,...]] [-p passfile]\n" 26378702060Sjmc "\t[-R device | channel:target[.lun] [-r rounds] " 264d0b772c8Sjmc "device\n", __progname, __progname); 265d90b5d8bSjmc 2663af9de98Smarco exit(1); 2673af9de98Smarco } 2683af9de98Smarco 26941eccc89Sderaadt const char * 2706de960dcSmarco str2locator(const char *string, struct locator *location) 2716de960dcSmarco { 27250d3c4dcSdlg const char *errstr; 27341eccc89Sderaadt char parse[80], *targ, *lun; 2746de960dcSmarco 27541eccc89Sderaadt strlcpy(parse, string, sizeof parse); 27641eccc89Sderaadt targ = strchr(parse, ':'); 2776de960dcSmarco if (targ == NULL) 27841eccc89Sderaadt return ("target not specified"); 2796de960dcSmarco *targ++ = '\0'; 2806de960dcSmarco 28150d3c4dcSdlg lun = strchr(targ, '.'); 2826de960dcSmarco if (lun != NULL) { 2836de960dcSmarco *lun++ = '\0'; 28450d3c4dcSdlg location->lun = strtonum(lun, 0, 256, &errstr); 28550d3c4dcSdlg if (errstr) 28641eccc89Sderaadt return (errstr); 2876de960dcSmarco } else 2886de960dcSmarco location->lun = 0; 2896de960dcSmarco 29050d3c4dcSdlg location->target = strtonum(targ, 0, 256, &errstr); 29150d3c4dcSdlg if (errstr) 29241eccc89Sderaadt return (errstr); 29341eccc89Sderaadt location->channel = strtonum(parse, 0, 256, &errstr); 29450d3c4dcSdlg if (errstr) 29541eccc89Sderaadt return (errstr); 29641eccc89Sderaadt return (NULL); 2976de960dcSmarco } 2986de960dcSmarco 2993af9de98Smarco void 3008ccdd032Sderaadt bio_inq(char *name) 301d4546a56Sdlg { 3029017fb97Sderaadt char *status, size[64], scsiname[16], volname[32]; 303a4d3c4a2Sderaadt char percent[10], seconds[20]; 304b9950701Smarco int rv, i, d, volheader, hotspare, unused; 305aa65acf1Sderaadt char encname[16], serial[32]; 3068ccdd032Sderaadt struct bioc_disk bd; 3078ccdd032Sderaadt struct bioc_inq bi; 3088ccdd032Sderaadt struct bioc_vol bv; 309db2730c1Smarco 310db2730c1Smarco memset(&bi, 0, sizeof(bi)); 3113af9de98Smarco 3128ccdd032Sderaadt bi.bi_cookie = bl.bl_cookie; 3133af9de98Smarco 314db2730c1Smarco rv = ioctl(devh, BIOCINQ, &bi); 3153af9de98Smarco if (rv == -1) { 31603b2dfbfShenning if (errno == ENOTTY) 31703b2dfbfShenning bio_diskinq(name); 31803b2dfbfShenning else 319da3b0664Shenning err(1, "BIOCINQ"); 3203af9de98Smarco return; 3213af9de98Smarco } 3223af9de98Smarco 3238ccdd032Sderaadt volheader = 0; 3248ccdd032Sderaadt for (i = 0; i < bi.bi_novol; i++) { 325db2730c1Smarco memset(&bv, 0, sizeof(bv)); 3268ccdd032Sderaadt bv.bv_cookie = bl.bl_cookie; 3278ccdd032Sderaadt bv.bv_volid = i; 3280a92ff65Sderaadt bv.bv_percent = -1; 3299017fb97Sderaadt bv.bv_seconds = 0; 33070a2ae7bSmarco 331db2730c1Smarco rv = ioctl(devh, BIOCVOL, &bv); 332da3b0664Shenning if (rv == -1) 333da3b0664Shenning err(1, "BIOCVOL"); 3343af9de98Smarco 3358ccdd032Sderaadt if (name && strcmp(name, bv.bv_dev) != 0) 3368ccdd032Sderaadt continue; 3378ccdd032Sderaadt 3388ccdd032Sderaadt if (!volheader) { 3398ccdd032Sderaadt volheader = 1; 340c9377e3bSmickey printf("%-7s %-10s %14s %-8s\n", 3418ccdd032Sderaadt "Volume", "Status", "Size", "Device"); 3428ccdd032Sderaadt } 3438ccdd032Sderaadt 3440a92ff65Sderaadt percent[0] = '\0'; 3459017fb97Sderaadt seconds[0] = '\0'; 3460a92ff65Sderaadt if (bv.bv_percent != -1) 3470a92ff65Sderaadt snprintf(percent, sizeof percent, 3480a92ff65Sderaadt " %d%% done", bv.bv_percent); 3499017fb97Sderaadt if (bv.bv_seconds) 3509017fb97Sderaadt snprintf(seconds, sizeof seconds, 3519017fb97Sderaadt " %u seconds", bv.bv_seconds); 3528ccdd032Sderaadt switch (bv.bv_status) { 353db2730c1Smarco case BIOC_SVONLINE: 3548ccdd032Sderaadt status = BIOC_SVONLINE_S; 355db2730c1Smarco break; 356db2730c1Smarco case BIOC_SVOFFLINE: 3578ccdd032Sderaadt status = BIOC_SVOFFLINE_S; 358db2730c1Smarco break; 359db2730c1Smarco case BIOC_SVDEGRADED: 3608ccdd032Sderaadt status = BIOC_SVDEGRADED_S; 361db2730c1Smarco break; 3620a92ff65Sderaadt case BIOC_SVBUILDING: 3630a92ff65Sderaadt status = BIOC_SVBUILDING_S; 3640a92ff65Sderaadt break; 3650a92ff65Sderaadt case BIOC_SVREBUILD: 3660a92ff65Sderaadt status = BIOC_SVREBUILD_S; 3670a92ff65Sderaadt break; 3680a92ff65Sderaadt case BIOC_SVSCRUB: 3690a92ff65Sderaadt status = BIOC_SVSCRUB_S; 3700a92ff65Sderaadt break; 371db2730c1Smarco case BIOC_SVINVALID: 372db2730c1Smarco default: 3738ccdd032Sderaadt status = BIOC_SVINVALID_S; 374d4546a56Sdlg } 3753af9de98Smarco 376aa65acf1Sderaadt snprintf(volname, sizeof volname, "%s %u", 3778ccdd032Sderaadt bi.bi_dev, bv.bv_volid); 378b9950701Smarco 3799ecba717Sderaadt unused = 0; 3809ecba717Sderaadt hotspare = 0; 381aa65acf1Sderaadt if (bv.bv_level == -1 && bv.bv_nodisk == 1) 382aa65acf1Sderaadt hotspare = 1; 383b9950701Smarco else if (bv.bv_level == -2 && bv.bv_nodisk == 1) 384b9950701Smarco unused = 1; 385aa65acf1Sderaadt else { 3868ccdd032Sderaadt if (human) 3878ccdd032Sderaadt fmt_scaled(bv.bv_size, size); 3888ccdd032Sderaadt else 3898ccdd032Sderaadt snprintf(size, sizeof size, "%14llu", 3908ccdd032Sderaadt bv.bv_size); 391da935596Stodd switch (bv.bv_level) { 392da935596Stodd case 'C': 393da935596Stodd printf("%7s %-10s %14s %-7s CRYPTO%s%s\n", 394da935596Stodd volname, status, size, bv.bv_dev, 395da935596Stodd percent, seconds); 396da935596Stodd break; 397da935596Stodd default: 3989017fb97Sderaadt printf("%7s %-10s %14s %-7s RAID%u%s%s\n", 3990a92ff65Sderaadt volname, status, size, bv.bv_dev, 4009017fb97Sderaadt bv.bv_level, percent, seconds); 401da935596Stodd break; 402da935596Stodd } 403da935596Stodd 404aa65acf1Sderaadt } 4058ccdd032Sderaadt 4068ccdd032Sderaadt for (d = 0; d < bv.bv_nodisk; d++) { 407db2730c1Smarco memset(&bd, 0, sizeof(bd)); 4088ccdd032Sderaadt bd.bd_cookie = bl.bl_cookie; 4098ccdd032Sderaadt bd.bd_diskid = d; 4108ccdd032Sderaadt bd.bd_volid = i; 4113af9de98Smarco 412db2730c1Smarco rv = ioctl(devh, BIOCDISK, &bd); 413da3b0664Shenning if (rv == -1) 414da3b0664Shenning err(1, "BIOCDISK"); 4153af9de98Smarco 4168ccdd032Sderaadt switch (bd.bd_status) { 417db2730c1Smarco case BIOC_SDONLINE: 4188ccdd032Sderaadt status = BIOC_SDONLINE_S; 419d4546a56Sdlg break; 420db2730c1Smarco case BIOC_SDOFFLINE: 4218ccdd032Sderaadt status = BIOC_SDOFFLINE_S; 422d4546a56Sdlg break; 423db2730c1Smarco case BIOC_SDFAILED: 4248ccdd032Sderaadt status = BIOC_SDFAILED_S; 425db2730c1Smarco break; 426db2730c1Smarco case BIOC_SDREBUILD: 4278ccdd032Sderaadt status = BIOC_SDREBUILD_S; 428db2730c1Smarco break; 429db2730c1Smarco case BIOC_SDHOTSPARE: 4308ccdd032Sderaadt status = BIOC_SDHOTSPARE_S; 431db2730c1Smarco break; 432db2730c1Smarco case BIOC_SDUNUSED: 4338ccdd032Sderaadt status = BIOC_SDUNUSED_S; 434db2730c1Smarco break; 435e1dfb373Sderaadt case BIOC_SDSCRUB: 436e1dfb373Sderaadt status = BIOC_SDSCRUB_S; 437e1dfb373Sderaadt break; 438db2730c1Smarco case BIOC_SDINVALID: 439d4546a56Sdlg default: 4408ccdd032Sderaadt status = BIOC_SDINVALID_S; 441d4546a56Sdlg } 442aa65acf1Sderaadt 443b9950701Smarco if (hotspare || unused) 444aa65acf1Sderaadt ; /* use volname from parent volume */ 445aa65acf1Sderaadt else 446aa65acf1Sderaadt snprintf(volname, sizeof volname, " %3u", 447aa65acf1Sderaadt bd.bd_diskid); 448aa65acf1Sderaadt 4498ccdd032Sderaadt if (human) 4508ccdd032Sderaadt fmt_scaled(bd.bd_size, size); 4518ccdd032Sderaadt else 4528ccdd032Sderaadt snprintf(size, sizeof size, "%14llu", 4538ccdd032Sderaadt bd.bd_size); 4548ccdd032Sderaadt snprintf(scsiname, sizeof scsiname, 45543d61178Sderaadt "%u:%u.%u", 45643d61178Sderaadt bd.bd_channel, bd.bd_target, bd.bd_lun); 4575978b28dSderaadt if (bd.bd_procdev[0]) 458abe9d68eSderaadt strlcpy(encname, bd.bd_procdev, sizeof encname); 4595978b28dSderaadt else 460abe9d68eSderaadt strlcpy(encname, "noencl", sizeof encname); 461abe9d68eSderaadt if (bd.bd_serial[0]) 462abe9d68eSderaadt strlcpy(serial, bd.bd_serial, sizeof serial); 463abe9d68eSderaadt else 464abe9d68eSderaadt strlcpy(serial, "unknown serial", sizeof serial); 4658ccdd032Sderaadt 466aa65acf1Sderaadt printf("%7s %-10s %14s %-7s %-6s <%s>\n", 467aa65acf1Sderaadt volname, status, size, scsiname, encname, 4688ccdd032Sderaadt bd.bd_vendor); 469abe9d68eSderaadt if (verbose) 470aa65acf1Sderaadt printf("%7s %-10s %14s %-7s %-6s '%s'\n", 471abe9d68eSderaadt "", "", "", "", "", serial); 472d4546a56Sdlg } 473d4546a56Sdlg } 474d4546a56Sdlg } 475edfd9792Smarco 476edfd9792Smarco void 477edfd9792Smarco bio_alarm(char *arg) 478edfd9792Smarco { 479edfd9792Smarco int rv; 4808ccdd032Sderaadt struct bioc_alarm ba; 481edfd9792Smarco 4828ccdd032Sderaadt ba.ba_cookie = bl.bl_cookie; 483edfd9792Smarco 484edfd9792Smarco switch (arg[0]) { 485edfd9792Smarco case 'q': /* silence alarm */ 486edfd9792Smarco /* FALLTHROUGH */ 487edfd9792Smarco case 's': 4888ccdd032Sderaadt ba.ba_opcode = BIOC_SASILENCE; 489edfd9792Smarco break; 490edfd9792Smarco 491edfd9792Smarco case 'e': /* enable alarm */ 4928ccdd032Sderaadt ba.ba_opcode = BIOC_SAENABLE; 493edfd9792Smarco break; 494edfd9792Smarco 495edfd9792Smarco case 'd': /* disable alarm */ 4968ccdd032Sderaadt ba.ba_opcode = BIOC_SADISABLE; 497edfd9792Smarco break; 498edfd9792Smarco 499edfd9792Smarco case 't': /* test alarm */ 5008ccdd032Sderaadt ba.ba_opcode = BIOC_SATEST; 501edfd9792Smarco break; 502edfd9792Smarco 503edfd9792Smarco case 'g': /* get alarm state */ 5048ccdd032Sderaadt ba.ba_opcode = BIOC_GASTATUS; 505edfd9792Smarco break; 506edfd9792Smarco 507edfd9792Smarco default: 508da3b0664Shenning errx(1, "invalid alarm function: %s", arg); 509edfd9792Smarco } 510edfd9792Smarco 511edfd9792Smarco rv = ioctl(devh, BIOCALARM, &ba); 512da3b0664Shenning if (rv == -1) 513da3b0664Shenning err(1, "BIOCALARM"); 514edfd9792Smarco 515edfd9792Smarco if (arg[0] == 'g') { 516edfd9792Smarco printf("alarm is currently %s\n", 5178ccdd032Sderaadt ba.ba_status ? "enabled" : "disabled"); 5188ccdd032Sderaadt 519edfd9792Smarco } 520edfd9792Smarco } 5216de960dcSmarco 522a15048bbSmarco int 523a15048bbSmarco bio_getvolbyname(char *name) 524a15048bbSmarco { 525a15048bbSmarco int id = -1, i, rv; 526a15048bbSmarco struct bioc_inq bi; 527a15048bbSmarco struct bioc_vol bv; 528a15048bbSmarco 529a15048bbSmarco memset(&bi, 0, sizeof(bi)); 530a15048bbSmarco bi.bi_cookie = bl.bl_cookie; 531a15048bbSmarco rv = ioctl(devh, BIOCINQ, &bi); 532a15048bbSmarco if (rv == -1) 533a15048bbSmarco err(1, "BIOCINQ"); 534a15048bbSmarco 535a15048bbSmarco for (i = 0; i < bi.bi_novol; i++) { 536a15048bbSmarco memset(&bv, 0, sizeof(bv)); 537a15048bbSmarco bv.bv_cookie = bl.bl_cookie; 538a15048bbSmarco bv.bv_volid = i; 539a15048bbSmarco rv = ioctl(devh, BIOCVOL, &bv); 540a15048bbSmarco if (rv == -1) 541a15048bbSmarco err(1, "BIOCVOL"); 542a15048bbSmarco 543a15048bbSmarco if (name && strcmp(name, bv.bv_dev) != 0) 544a15048bbSmarco continue; 545a15048bbSmarco id = i; 546a15048bbSmarco break; 547a15048bbSmarco } 548a15048bbSmarco 549a15048bbSmarco return (id); 550a15048bbSmarco } 551a15048bbSmarco 552ebaf584eSderaadt void 5538d8693a2Sdtucker bio_setstate(char *arg, int status, char *devicename) 5546de960dcSmarco { 5556de960dcSmarco struct bioc_setstate bs; 5566de960dcSmarco struct locator location; 557a15048bbSmarco struct stat sb; 55841eccc89Sderaadt const char *errstr; 559ebaf584eSderaadt int rv; 5606de960dcSmarco 561a15048bbSmarco memset(&bs, 0, sizeof(bs)); 562a15048bbSmarco if (stat(arg, &sb) == -1) { 563a15048bbSmarco /* use CTL */ 56441eccc89Sderaadt errstr = str2locator(arg, &location); 56541eccc89Sderaadt if (errstr) 56641eccc89Sderaadt errx(1, "Target %s: %s", arg, errstr); 5676de960dcSmarco bs.bs_channel = location.channel; 5686de960dcSmarco bs.bs_target = location.target; 5696de960dcSmarco bs.bs_lun = location.lun; 570a15048bbSmarco } else { 571a15048bbSmarco /* use other id */ 572a15048bbSmarco bs.bs_other_id = sb.st_rdev; 573a15048bbSmarco bs.bs_other_id_type = BIOC_SSOTHER_DEVT; 574a15048bbSmarco } 575a15048bbSmarco 576a15048bbSmarco bs.bs_cookie = bl.bl_cookie; 577a15048bbSmarco bs.bs_status = status; 578a15048bbSmarco 579d2647ac1Sjsing if (status != BIOC_SSHOTSPARE) { 580a15048bbSmarco /* make sure user supplied a sd device */ 5818d8693a2Sdtucker bs.bs_volid = bio_getvolbyname(devicename); 582a15048bbSmarco if (bs.bs_volid == -1) 5838d8693a2Sdtucker errx(1, "invalid device %s", devicename); 584d2647ac1Sjsing } 5856de960dcSmarco 5866de960dcSmarco rv = ioctl(devh, BIOCSETSTATE, &bs); 587da3b0664Shenning if (rv == -1) 588da3b0664Shenning err(1, "BIOCSETSTATE"); 5896de960dcSmarco } 590c55617f1Sdlg 591c55617f1Sdlg void 592a928c459Sderaadt bio_setblink(char *name, char *arg, int blink) 593c55617f1Sdlg { 59450d3c4dcSdlg struct locator location; 59550d3c4dcSdlg struct bioc_inq bi; 59650d3c4dcSdlg struct bioc_vol bv; 59750d3c4dcSdlg struct bioc_disk bd; 5980505205bSdlg struct bioc_blink bb; 59941eccc89Sderaadt const char *errstr; 60050d3c4dcSdlg int v, d, rv; 601c55617f1Sdlg 60241eccc89Sderaadt errstr = str2locator(arg, &location); 60341eccc89Sderaadt if (errstr) 60441eccc89Sderaadt errx(1, "Target %s: %s", arg, errstr); 60550d3c4dcSdlg 6060505205bSdlg /* try setting blink on the device directly */ 6070505205bSdlg memset(&bb, 0, sizeof(bb)); 6080505205bSdlg bb.bb_cookie = bl.bl_cookie; 6090505205bSdlg bb.bb_status = blink; 6100505205bSdlg bb.bb_target = location.target; 611649724a4Smarco bb.bb_channel = location.channel; 6120505205bSdlg rv = ioctl(devh, BIOCBLINK, &bb); 6130505205bSdlg if (rv == 0) 6140505205bSdlg return; 6150505205bSdlg 6160505205bSdlg /* if the blink didnt work, try to find something that will */ 6170505205bSdlg 61850d3c4dcSdlg memset(&bi, 0, sizeof(bi)); 61950d3c4dcSdlg bi.bi_cookie = bl.bl_cookie; 62050d3c4dcSdlg rv = ioctl(devh, BIOCINQ, &bi); 621da3b0664Shenning if (rv == -1) 622da3b0664Shenning err(1, "BIOCINQ"); 62350d3c4dcSdlg 62450d3c4dcSdlg for (v = 0; v < bi.bi_novol; v++) { 62550d3c4dcSdlg memset(&bv, 0, sizeof(bv)); 62650d3c4dcSdlg bv.bv_cookie = bl.bl_cookie; 62750d3c4dcSdlg bv.bv_volid = v; 62850d3c4dcSdlg rv = ioctl(devh, BIOCVOL, &bv); 629da3b0664Shenning if (rv == -1) 630da3b0664Shenning err(1, "BIOCVOL"); 63150d3c4dcSdlg 63250d3c4dcSdlg if (name && strcmp(name, bv.bv_dev) != 0) 63350d3c4dcSdlg continue; 63450d3c4dcSdlg 63550d3c4dcSdlg for (d = 0; d < bv.bv_nodisk; d++) { 63650d3c4dcSdlg memset(&bd, 0, sizeof(bd)); 63750d3c4dcSdlg bd.bd_cookie = bl.bl_cookie; 63850d3c4dcSdlg bd.bd_volid = v; 63950d3c4dcSdlg bd.bd_diskid = d; 64050d3c4dcSdlg 64150d3c4dcSdlg rv = ioctl(devh, BIOCDISK, &bd); 642da3b0664Shenning if (rv == -1) 643da3b0664Shenning err(1, "BIOCDISK"); 64450d3c4dcSdlg 64550d3c4dcSdlg if (bd.bd_channel == location.channel && 64650d3c4dcSdlg bd.bd_target == location.target && 64750d3c4dcSdlg bd.bd_lun == location.lun) { 64850d3c4dcSdlg if (bd.bd_procdev[0] != '\0') { 64950d3c4dcSdlg bio_blink(bd.bd_procdev, 650a928c459Sderaadt location.target, blink); 65150d3c4dcSdlg } else 65241eccc89Sderaadt warnx("Disk %s is not in an enclosure", arg); 65350d3c4dcSdlg return; 65450d3c4dcSdlg } 65550d3c4dcSdlg } 65650d3c4dcSdlg } 65750d3c4dcSdlg 65841eccc89Sderaadt warnx("Disk %s does not exist", arg); 65950d3c4dcSdlg return; 66050d3c4dcSdlg } 66150d3c4dcSdlg 66250d3c4dcSdlg void 663a928c459Sderaadt bio_blink(char *enclosure, int target, int blinktype) 66450d3c4dcSdlg { 66550d3c4dcSdlg int bioh; 66650d3c4dcSdlg struct bio_locate bio; 66750d3c4dcSdlg struct bioc_blink blink; 66850d3c4dcSdlg int rv; 66950d3c4dcSdlg 67041eccc89Sderaadt bioh = open("/dev/bio", O_RDWR); 67150d3c4dcSdlg if (bioh == -1) 67241eccc89Sderaadt err(1, "Can't open %s", "/dev/bio"); 67350d3c4dcSdlg 67450d3c4dcSdlg bio.bl_name = enclosure; 67550d3c4dcSdlg rv = ioctl(bioh, BIOCLOCATE, &bio); 67650d3c4dcSdlg if (rv == -1) 67741eccc89Sderaadt errx(1, "Can't locate %s device via %s", enclosure, "/dev/bio"); 678c55617f1Sdlg 679c55617f1Sdlg memset(&blink, 0, sizeof(blink)); 68050d3c4dcSdlg blink.bb_cookie = bio.bl_cookie; 681a928c459Sderaadt blink.bb_status = blinktype; 682c55617f1Sdlg blink.bb_target = target; 683c55617f1Sdlg 68450d3c4dcSdlg rv = ioctl(bioh, BIOCBLINK, &blink); 685c55617f1Sdlg if (rv == -1) 686da3b0664Shenning err(1, "BIOCBLINK"); 68750d3c4dcSdlg 68850d3c4dcSdlg close(bioh); 689c55617f1Sdlg } 6907195049bSmarco 6917195049bSmarco void 6927195049bSmarco bio_createraid(u_int16_t level, char *dev_list) 6937195049bSmarco { 6947195049bSmarco struct bioc_createraid create; 695aef7fe28Shshoexer struct sr_crypto_kdfinfo kdfinfo; 696aef7fe28Shshoexer struct sr_crypto_kdf_pbkdf2 kdfhint; 69746bc198bSmarco int rv, no_dev; 69846bc198bSmarco dev_t *dt; 6997195049bSmarco u_int16_t min_disks = 0; 7007195049bSmarco 7017195049bSmarco if (!dev_list) 7027195049bSmarco errx(1, "no devices specified"); 7037195049bSmarco 70446bc198bSmarco dt = (dev_t *)malloc(BIOC_CRMAXLEN); 70546bc198bSmarco if (!dt) 70646bc198bSmarco err(1, "not enough memory for dev_t list"); 70746bc198bSmarco memset(dt, 0, BIOC_CRMAXLEN); 70846bc198bSmarco 70946bc198bSmarco no_dev = bio_parse_devlist(dev_list, dt); 71046bc198bSmarco 7117195049bSmarco switch (level) { 7127195049bSmarco case 0: 71384e48fabSmarco min_disks = 2; 7147195049bSmarco break; 7157195049bSmarco case 1: 7167195049bSmarco min_disks = 2; 7177195049bSmarco break; 718e717853eSmarco case 4: 719e717853eSmarco case 5: 720e717853eSmarco min_disks = 3; 721e717853eSmarco break; 72284e48fabSmarco case 'C': 723aef7fe28Shshoexer min_disks = 1; 72484e48fabSmarco break; 72598b750e4Stedu case 'c': 72698b750e4Stedu min_disks = 1; 72798b750e4Stedu break; 7287195049bSmarco default: 72923afedbfSgrunk errx(1, "unsupported raid level"); 7307195049bSmarco } 7317195049bSmarco 73284e48fabSmarco if (no_dev < min_disks) 73384e48fabSmarco errx(1, "not enough disks"); 73484e48fabSmarco 735aef7fe28Shshoexer /* for crypto raid we only allow one single chunk */ 736aef7fe28Shshoexer if (level == 'C' && no_dev != min_disks) 737818b0595Shalex errx(1, "not exactly one partition"); 738aef7fe28Shshoexer 7397195049bSmarco memset(&create, 0, sizeof(create)); 7407195049bSmarco create.bc_cookie = bl.bl_cookie; 7417195049bSmarco create.bc_level = level; 74246bc198bSmarco create.bc_dev_list_len = no_dev * sizeof(dev_t); 74346bc198bSmarco create.bc_dev_list = dt; 744e8a57fdeSmarco create.bc_flags = BIOC_SCDEVT | cflags; 7457195049bSmarco 746aef7fe28Shshoexer if (level == 'C') { 747aef7fe28Shshoexer memset(&kdfinfo, 0, sizeof(kdfinfo)); 748aef7fe28Shshoexer memset(&kdfhint, 0, sizeof(kdfhint)); 749aef7fe28Shshoexer 750aef7fe28Shshoexer create.bc_opaque = &kdfhint; 751aef7fe28Shshoexer create.bc_opaque_size = sizeof(kdfhint); 752aef7fe28Shshoexer create.bc_opaque_flags = BIOC_SOOUT; 753aef7fe28Shshoexer 754aef7fe28Shshoexer /* try to get KDF hint */ 75583e979edShshoexer if (ioctl(devh, BIOCCREATERAID, &create) == -1) 75683e979edShshoexer err(1, "ioctl"); 75783e979edShshoexer 75883e979edShshoexer if (create.bc_opaque_status == BIOC_SOINOUT_OK) { 759*c6446370Sjsing bio_kdf_derive(&kdfinfo, &kdfhint, "Passphrase: ", 0); 760aef7fe28Shshoexer memset(&kdfhint, 0, sizeof(kdfhint)); 761aef7fe28Shshoexer } else { 762aef7fe28Shshoexer bio_kdf_generate(&kdfinfo); 763aef7fe28Shshoexer /* no auto assembling */ 764aef7fe28Shshoexer create.bc_flags |= BIOC_SCNOAUTOASSEMBLE; 765aef7fe28Shshoexer } 766aef7fe28Shshoexer 767aef7fe28Shshoexer create.bc_opaque = &kdfinfo; 768aef7fe28Shshoexer create.bc_opaque_size = sizeof(kdfinfo); 769aef7fe28Shshoexer create.bc_opaque_flags = BIOC_SOIN; 770aef7fe28Shshoexer } 771aef7fe28Shshoexer 7727195049bSmarco rv = ioctl(devh, BIOCCREATERAID, &create); 773aef7fe28Shshoexer memset(&kdfinfo, 0, sizeof(kdfinfo)); 77483e979edShshoexer memset(&create, 0, sizeof(create)); 775a83e4577Sdjm if (rv == -1) { 776a83e4577Sdjm if (errno == EPERM) 777a83e4577Sdjm errx(1, "Incorrect passphrase"); 778da3b0664Shenning err(1, "BIOCCREATERAID"); 779a83e4577Sdjm } 78046bc198bSmarco 78146bc198bSmarco free(dt); 78246bc198bSmarco } 78346bc198bSmarco 784aef7fe28Shshoexer void 785aef7fe28Shshoexer bio_kdf_derive(struct sr_crypto_kdfinfo *kdfinfo, struct sr_crypto_kdf_pbkdf2 786*c6446370Sjsing *kdfhint, char* prompt, int verify) 787aef7fe28Shshoexer { 788aef7fe28Shshoexer if (!kdfinfo) 789aef7fe28Shshoexer errx(1, "invalid KDF info"); 790aef7fe28Shshoexer if (!kdfhint) 791aef7fe28Shshoexer errx(1, "invalid KDF hint"); 792aef7fe28Shshoexer 793aef7fe28Shshoexer if (kdfhint->len != sizeof(*kdfhint)) 794aef7fe28Shshoexer errx(1, "KDF hint has invalid size"); 795aef7fe28Shshoexer if (kdfhint->type != SR_CRYPTOKDFT_PBKDF2) 796aef7fe28Shshoexer errx(1, "unknown KDF type %d", kdfhint->type); 797aef7fe28Shshoexer if (kdfhint->rounds < 1000) 798aef7fe28Shshoexer errx(1, "number of KDF rounds too low: %d", kdfhint->rounds); 799aef7fe28Shshoexer 800aef7fe28Shshoexer kdfinfo->flags = SR_CRYPTOKDF_KEY; 801aef7fe28Shshoexer kdfinfo->len = sizeof(*kdfinfo); 802aef7fe28Shshoexer 8039e8c6f5bShshoexer derive_key_pkcs(kdfhint->rounds, 804aef7fe28Shshoexer kdfinfo->maskkey, sizeof(kdfinfo->maskkey), 805*c6446370Sjsing kdfhint->salt, sizeof(kdfhint->salt), prompt, verify); 806aef7fe28Shshoexer } 807aef7fe28Shshoexer 808aef7fe28Shshoexer void 809aef7fe28Shshoexer bio_kdf_generate(struct sr_crypto_kdfinfo *kdfinfo) 810aef7fe28Shshoexer { 811aef7fe28Shshoexer if (!kdfinfo) 812aef7fe28Shshoexer errx(1, "invalid KDF info"); 813aef7fe28Shshoexer 814aef7fe28Shshoexer kdfinfo->pbkdf2.len = sizeof(kdfinfo->pbkdf2); 815aef7fe28Shshoexer kdfinfo->pbkdf2.type = SR_CRYPTOKDFT_PBKDF2; 816aedd4f07Sdjm kdfinfo->pbkdf2.rounds = rflag; 817aef7fe28Shshoexer kdfinfo->len = sizeof(*kdfinfo); 818aef7fe28Shshoexer kdfinfo->flags = (SR_CRYPTOKDF_KEY | SR_CRYPTOKDF_HINT); 819aef7fe28Shshoexer 820aef7fe28Shshoexer /* generate salt */ 821aef7fe28Shshoexer arc4random_buf(kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt)); 822aef7fe28Shshoexer 8239e8c6f5bShshoexer derive_key_pkcs(kdfinfo->pbkdf2.rounds, 824aef7fe28Shshoexer kdfinfo->maskkey, sizeof(kdfinfo->maskkey), 825*c6446370Sjsing kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt), 826*c6446370Sjsing "New passphrase: ", 1); 827aef7fe28Shshoexer } 828aef7fe28Shshoexer 82946bc198bSmarco int 83046bc198bSmarco bio_parse_devlist(char *lst, dev_t *dt) 83146bc198bSmarco { 83246bc198bSmarco char *s, *e; 83346bc198bSmarco u_int32_t sz = 0; 83446bc198bSmarco int no_dev = 0, i, x; 83546bc198bSmarco struct stat sb; 8365c1f8f6bSdjm char dev[MAXPATHLEN]; 83746bc198bSmarco 83846bc198bSmarco if (!lst) 83946bc198bSmarco errx(1, "invalid device list"); 84046bc198bSmarco 84146bc198bSmarco s = e = lst; 84246bc198bSmarco /* make sure we have a valid device list like /dev/sdNa,/dev/sdNNa */ 84346bc198bSmarco while (*e != '\0') { 84446bc198bSmarco if (*e == ',') 84546bc198bSmarco s = e + 1; 84646bc198bSmarco else if (*(e + 1) == '\0' || *(e + 1) == ',') { 84746bc198bSmarco /* got one */ 84846bc198bSmarco sz = e - s + 1; 8495c1f8f6bSdjm strlcpy(dev, s, sz + 1); 8505c1f8f6bSdjm if (stat(dev, &sb) == -1) 8515c1f8f6bSdjm err(1, "could not stat %s", dev); 85246bc198bSmarco dt[no_dev] = sb.st_rdev; 85346bc198bSmarco no_dev++; 8545c1f8f6bSdjm if (no_dev > (int)(BIOC_CRMAXLEN / sizeof(dev_t))) 85546bc198bSmarco errx(1, "too many devices on device list"); 85646bc198bSmarco } 85746bc198bSmarco e++; 85846bc198bSmarco } 85946bc198bSmarco 86046bc198bSmarco for (i = 0; i < no_dev; i++) 86146bc198bSmarco for (x = 0; x < no_dev; x++) 86246bc198bSmarco if (dt[i] == dt[x] && x != i) 86346bc198bSmarco errx(1, "duplicate device in list"); 86446bc198bSmarco 86546bc198bSmarco return (no_dev); 8667195049bSmarco } 867e8a57fdeSmarco 868e8a57fdeSmarco u_int32_t 869e8a57fdeSmarco bio_createflags(char *lst) 870e8a57fdeSmarco { 871e8a57fdeSmarco char *s, *e, fs[32]; 872e8a57fdeSmarco u_int32_t sz = 0; 873e8a57fdeSmarco u_int32_t flags = 0; 874e8a57fdeSmarco 875e8a57fdeSmarco if (!lst) 876e8a57fdeSmarco errx(1, "invalid flags list"); 877e8a57fdeSmarco 878e8a57fdeSmarco s = e = lst; 879e8a57fdeSmarco /* make sure we have a valid flags list like force,noassemeble */ 880e8a57fdeSmarco while (*e != '\0') { 881e8a57fdeSmarco if (*e == ',') 882e8a57fdeSmarco s = e + 1; 883e8a57fdeSmarco else if (*(e + 1) == '\0' || *(e + 1) == ',') { 884e8a57fdeSmarco /* got one */ 885e8a57fdeSmarco sz = e - s + 1; 886e8a57fdeSmarco switch (s[0]) { 887e8a57fdeSmarco case 'f': 888e8a57fdeSmarco flags |= BIOC_SCFORCE; 889e8a57fdeSmarco break; 890e8a57fdeSmarco case 'n': 891e8a57fdeSmarco flags |= BIOC_SCNOAUTOASSEMBLE; 892e8a57fdeSmarco break; 893e8a57fdeSmarco default: 894e8a57fdeSmarco strlcpy(fs, s, sz + 1); 895e8a57fdeSmarco errx(1, "invalid flag %s", fs); 896e8a57fdeSmarco } 897e8a57fdeSmarco } 898e8a57fdeSmarco e++; 899e8a57fdeSmarco } 900e8a57fdeSmarco 901e8a57fdeSmarco return (flags); 902e8a57fdeSmarco } 90303b2dfbfShenning 904c7c3e8aaSmarco void 905c7c3e8aaSmarco bio_deleteraid(char *dev) 906c7c3e8aaSmarco { 907c7c3e8aaSmarco struct bioc_deleteraid bd; 908c7c3e8aaSmarco memset(&bd, 0, sizeof(bd)); 909c7c3e8aaSmarco 910c7c3e8aaSmarco bd.bd_cookie = bd.bd_cookie; 911a15048bbSmarco /* XXX make this a dev_t instead of a string */ 912c7c3e8aaSmarco strlcpy(bd.bd_dev, dev, sizeof bd.bd_dev); 913c7c3e8aaSmarco if (ioctl(devh, BIOCDELETERAID, &bd)) 914c7c3e8aaSmarco errx(1, "delete volume %s failed", dev); 915c7c3e8aaSmarco } 916c7c3e8aaSmarco 917*c6446370Sjsing void 918*c6446370Sjsing bio_changepass(char *dev) 919*c6446370Sjsing { 920*c6446370Sjsing struct bioc_discipline bd; 921*c6446370Sjsing struct sr_crypto_kdfpair kdfpair; 922*c6446370Sjsing struct sr_crypto_kdfinfo kdfinfo1, kdfinfo2; 923*c6446370Sjsing struct sr_crypto_kdf_pbkdf2 kdfhint; 924*c6446370Sjsing int rv; 925*c6446370Sjsing 926*c6446370Sjsing memset(&bd, 0, sizeof(bd)); 927*c6446370Sjsing memset(&kdfhint, 0, sizeof(kdfhint)); 928*c6446370Sjsing memset(&kdfinfo1, 0, sizeof(kdfinfo1)); 929*c6446370Sjsing memset(&kdfinfo2, 0, sizeof(kdfinfo2)); 930*c6446370Sjsing 931*c6446370Sjsing /* XXX use dev_t instead of string. */ 932*c6446370Sjsing strlcpy(bd.bd_dev, dev, sizeof(bd.bd_dev)); 933*c6446370Sjsing bd.bd_cmd = SR_IOCTL_GET_KDFHINT; 934*c6446370Sjsing bd.bd_size = sizeof(kdfhint); 935*c6446370Sjsing bd.bd_data = &kdfhint; 936*c6446370Sjsing 937*c6446370Sjsing if (ioctl(devh, BIOCDISCIPLINE, &bd)) 938*c6446370Sjsing errx(1, "%s: failed to get KDF hint", dev); 939*c6446370Sjsing 940*c6446370Sjsing /* Current passphrase. */ 941*c6446370Sjsing bio_kdf_derive(&kdfinfo1, &kdfhint, "Old passphrase: ", 0); 942*c6446370Sjsing 943*c6446370Sjsing /* New passphrase. */ 944*c6446370Sjsing bio_kdf_derive(&kdfinfo2, &kdfhint, "New passphrase: ", 1); 945*c6446370Sjsing 946*c6446370Sjsing kdfpair.kdfinfo1 = &kdfinfo1; 947*c6446370Sjsing kdfpair.kdfsize1 = sizeof(kdfinfo1); 948*c6446370Sjsing kdfpair.kdfinfo2 = &kdfinfo2; 949*c6446370Sjsing kdfpair.kdfsize2 = sizeof(kdfinfo2); 950*c6446370Sjsing 951*c6446370Sjsing bd.bd_cmd = SR_IOCTL_CHANGE_PASSPHRASE; 952*c6446370Sjsing bd.bd_size = sizeof(kdfpair); 953*c6446370Sjsing bd.bd_data = &kdfpair; 954*c6446370Sjsing 955*c6446370Sjsing rv = ioctl(devh, BIOCDISCIPLINE, &bd); 956*c6446370Sjsing 957*c6446370Sjsing memset(&kdfhint, 0, sizeof(kdfhint)); 958*c6446370Sjsing memset(&kdfinfo1, 0, sizeof(kdfinfo1)); 959*c6446370Sjsing memset(&kdfinfo2, 0, sizeof(kdfinfo2)); 960*c6446370Sjsing 961*c6446370Sjsing if (rv) { 962*c6446370Sjsing if (errno == EPERM) 963*c6446370Sjsing errx(1, "%s: incorrect passphrase", dev); 964*c6446370Sjsing else 965*c6446370Sjsing errx(1, "%s: failed to change passphrase", dev); 966*c6446370Sjsing } 967*c6446370Sjsing } 968*c6446370Sjsing 96903b2dfbfShenning #define BIOCTL_VIS_NBUF 4 97003b2dfbfShenning #define BIOCTL_VIS_BUFLEN 80 97103b2dfbfShenning 97203b2dfbfShenning char * 97303b2dfbfShenning bio_vis(char *s) 97403b2dfbfShenning { 97503b2dfbfShenning static char rbuf[BIOCTL_VIS_NBUF][BIOCTL_VIS_BUFLEN]; 97603b2dfbfShenning static uint idx = 0; 97703b2dfbfShenning char *buf; 97803b2dfbfShenning 97903b2dfbfShenning buf = rbuf[idx++]; 98003b2dfbfShenning if (idx == BIOCTL_VIS_NBUF) 98103b2dfbfShenning idx = 0; 98203b2dfbfShenning 98303b2dfbfShenning strnvis(buf, s, BIOCTL_VIS_BUFLEN, VIS_NL|VIS_CSTYLE); 98403b2dfbfShenning return (buf); 98503b2dfbfShenning } 98603b2dfbfShenning 98703b2dfbfShenning void 98803b2dfbfShenning bio_diskinq(char *sd_dev) 98903b2dfbfShenning { 99003b2dfbfShenning struct dk_inquiry di; 99103b2dfbfShenning 992da3b0664Shenning if (ioctl(devh, DIOCINQ, &di) == -1) 993da3b0664Shenning err(1, "DIOCINQ"); 99403b2dfbfShenning 99503b2dfbfShenning printf("%s: <%s, %s, %s>, serial %s\n", sd_dev, bio_vis(di.vendor), 99603b2dfbfShenning bio_vis(di.product), bio_vis(di.revision), bio_vis(di.serial)); 99703b2dfbfShenning } 998aef7fe28Shshoexer 999aef7fe28Shshoexer void 10009e8c6f5bShshoexer derive_key_pkcs(int rounds, u_int8_t *key, size_t keysz, u_int8_t *salt, 1001*c6446370Sjsing size_t saltsz, char *prompt, int verify) 1002aef7fe28Shshoexer { 100386735da2Smarco FILE *f; 100486735da2Smarco size_t pl; 100586735da2Smarco struct stat sb; 10069e8c6f5bShshoexer char passphrase[1024], verifybuf[1024]; 1007aef7fe28Shshoexer 1008aef7fe28Shshoexer if (!key) 1009aef7fe28Shshoexer errx(1, "Invalid key"); 1010aef7fe28Shshoexer if (!salt) 1011aef7fe28Shshoexer errx(1, "Invalid salt"); 1012aef7fe28Shshoexer if (rounds < 1000) 1013aef7fe28Shshoexer errx(1, "Too less rounds: %d", rounds); 1014aef7fe28Shshoexer 1015aef7fe28Shshoexer /* get passphrase */ 1016ba3d8661Smarco if (password && verify) 1017ba3d8661Smarco errx(1, "can't specify passphrase file during initial " 1018ba3d8661Smarco "creation of crypto volume"); 1019ba3d8661Smarco if (password) { 102086735da2Smarco if ((f = fopen(password, "r")) == NULL) 102186735da2Smarco err(1, "invalid passphrase file"); 102286735da2Smarco 102386735da2Smarco if (fstat(fileno(f), &sb) == -1) 102486735da2Smarco err(1, "can't stat passphrase file"); 102586735da2Smarco if (sb.st_uid != 0) 102686735da2Smarco errx(1, "passphrase file must be owned by root"); 102786735da2Smarco if ((sb.st_mode & ~S_IFMT) != (S_IRUSR | S_IWUSR)) 102886735da2Smarco errx(1, "passphrase file has the wrong permissions"); 102986735da2Smarco 103086735da2Smarco if (fgets(passphrase, sizeof(passphrase), f) == NULL) 103186735da2Smarco err(1, "can't read passphrase file"); 103286735da2Smarco pl = strlen(passphrase); 103386735da2Smarco if (pl > 0 && passphrase[pl - 1] == '\n') 103486735da2Smarco passphrase[pl - 1] = '\0'; 103586735da2Smarco else 103686735da2Smarco errx(1, "invalid passphrase length"); 103786735da2Smarco 103886735da2Smarco fclose(f); 1039ba3d8661Smarco } else { 1040*c6446370Sjsing if (readpassphrase(prompt, passphrase, sizeof(passphrase), 1041*c6446370Sjsing RPP_REQUIRE_TTY) == NULL) 10429e8c6f5bShshoexer errx(1, "unable to read passphrase"); 1043ba3d8661Smarco } 10449e8c6f5bShshoexer 10459e8c6f5bShshoexer if (verify) { 10469e8c6f5bShshoexer /* request user to re-type it */ 10479e8c6f5bShshoexer if (readpassphrase("Re-type passphrase: ", verifybuf, 10489e8c6f5bShshoexer sizeof(verifybuf), RPP_REQUIRE_TTY) == NULL) { 10499e8c6f5bShshoexer memset(passphrase, 0, sizeof(passphrase)); 10509e8c6f5bShshoexer errx(1, "unable to read passphrase"); 10519e8c6f5bShshoexer } 10529e8c6f5bShshoexer if ((strlen(passphrase) != strlen(verifybuf)) || 10539e8c6f5bShshoexer (strcmp(passphrase, verifybuf) != 0)) { 10549e8c6f5bShshoexer memset(passphrase, 0, sizeof(passphrase)); 10559e8c6f5bShshoexer memset(verifybuf, 0, sizeof(verifybuf)); 10569e8c6f5bShshoexer errx(1, "Passphrases did not match"); 10579e8c6f5bShshoexer } 10589e8c6f5bShshoexer /* forget the re-typed one */ 10599e8c6f5bShshoexer memset(verifybuf, 0, strlen(verifybuf)); 10609e8c6f5bShshoexer } 1061aef7fe28Shshoexer 1062aef7fe28Shshoexer /* derive key from passphrase */ 10635c1f8f6bSdjm if (pkcs5_pbkdf2(passphrase, strlen(passphrase), salt, saltsz, 10645c1f8f6bSdjm key, keysz, rounds) != 0) 10655c1f8f6bSdjm errx(1, "pbkdf2 failed"); 1066aef7fe28Shshoexer 1067aef7fe28Shshoexer /* forget passphrase */ 10689e8c6f5bShshoexer memset(passphrase, 0, sizeof(passphrase)); 1069aef7fe28Shshoexer 1070aef7fe28Shshoexer return; 1071aef7fe28Shshoexer } 1072