1*ffb4dd05Sguenther /* $OpenBSD: bioctl.c,v 1.121 2014/07/20 01:38:40 guenther 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 30e7d4f752Sderaadt #include <sys/param.h> 31c2126c9aSmarco #include <sys/ioctl.h> 3291f4f7d8Sdlg #include <sys/dkio.h> 3346bc198bSmarco #include <sys/stat.h> 34aef7fe28Shshoexer #include <dev/softraidvar.h> 35e7d4f752Sderaadt #include <dev/biovar.h> 363af9de98Smarco 37db2730c1Smarco #include <errno.h> 38db2730c1Smarco #include <err.h> 39db2730c1Smarco #include <fcntl.h> 408ccdd032Sderaadt #include <util.h> 41934f30d8Sderaadt #include <ctype.h> 42db2730c1Smarco #include <stdio.h> 43db2730c1Smarco #include <stdlib.h> 44db2730c1Smarco #include <string.h> 45db2730c1Smarco #include <unistd.h> 4603b2dfbfShenning #include <vis.h> 479e8c6f5bShshoexer #include <readpassphrase.h> 48db2730c1Smarco 49e7d4f752Sderaadt #ifdef AOE 50e7d4f752Sderaadt #include <net/if.h> 51e7d4f752Sderaadt #include <netinet/in.h> 52e7d4f752Sderaadt #include <netinet/if_ether.h> 53e7d4f752Sderaadt 54e7d4f752Sderaadt struct sr_aoe_config *create_aoe(u_int16_t, char *); 55e7d4f752Sderaadt #endif /* AOE */ 56e7d4f752Sderaadt 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 *); 65d313c28bSjsing void bio_status(struct bio_status *); 6646bc198bSmarco int bio_parse_devlist(char *, dev_t *); 67aef7fe28Shshoexer void bio_kdf_derive(struct sr_crypto_kdfinfo *, 68c6446370Sjsing 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 *, 71c6446370Sjsing 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); 790054cd36Sjsing void bio_createraid(u_int16_t, char *, char *); 80c7c3e8aaSmarco void bio_deleteraid(char *); 81c6446370Sjsing 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 93545c4d7fSjsing void *bio_cookie; 94545c4d7fSjsing 95b96c6ce2Sckuethe int rpp_flag = RPP_REQUIRE_TTY; 963af9de98Smarco 973af9de98Smarco int 983af9de98Smarco main(int argc, char *argv[]) 993af9de98Smarco { 100545c4d7fSjsing struct bio_locate bl; 1013af9de98Smarco extern char *optarg; 102db2730c1Smarco u_int64_t func = 0; 103e63d8b1dSdtucker char *devicename = NULL; 104cf6503d7Sderaadt char *realname = NULL, *al_arg = NULL; 1057195049bSmarco char *bl_arg = NULL, *dev_list = NULL; 1060054cd36Sjsing char *key_disk = NULL; 107aedd4f07Sdjm const char *errstr; 108d313c28bSjsing int ch, blink = 0, changepass = 0, diskinq = 0; 109c6446370Sjsing int ss_func = 0; 1109ecba717Sderaadt u_int16_t cr_level = 0; 111e37c64dbSjsing int biodev = 0; 1123af9de98Smarco 1133af9de98Smarco if (argc < 2) 1143af9de98Smarco usage(); 1153af9de98Smarco 11650e55a42Sjsing while ((ch = getopt(argc, argv, "a:b:C:c:dH:hik:l:O:Pp:qr:R:svu:")) != 117c6446370Sjsing -1) { 1183af9de98Smarco switch (ch) { 119edfd9792Smarco case 'a': /* alarm */ 120edfd9792Smarco func |= BIOC_ALARM; 121edfd9792Smarco al_arg = optarg; 122edfd9792Smarco break; 123c55617f1Sdlg case 'b': /* blink */ 124c55617f1Sdlg func |= BIOC_BLINK; 125a928c459Sderaadt blink = BIOC_SBBLINK; 126a928c459Sderaadt bl_arg = optarg; 127a928c459Sderaadt break; 128e8a57fdeSmarco case 'C': /* creation flags */ 129e8a57fdeSmarco cflags = bio_createflags(optarg); 130e8a57fdeSmarco break; 1317195049bSmarco case 'c': /* create */ 1327195049bSmarco func |= BIOC_CREATERAID; 133025f5691Sderaadt if (isdigit((unsigned char)*optarg)) { 13492d21b5cStedu cr_level = strtonum(optarg, 0, 10, &errstr); 13592d21b5cStedu if (errstr != NULL) 13692d21b5cStedu errx(1, "Invalid RAID level"); 13792d21b5cStedu } else 13898b750e4Stedu cr_level = *optarg; 1397195049bSmarco break; 140c7c3e8aaSmarco case 'd': 141c7c3e8aaSmarco /* delete volume */ 142c7c3e8aaSmarco func |= BIOC_DELETERAID; 143c7c3e8aaSmarco break; 144a928c459Sderaadt case 'u': /* unblink */ 145a928c459Sderaadt func |= BIOC_BLINK; 146a928c459Sderaadt blink = BIOC_SBUNBLINK; 147c55617f1Sdlg bl_arg = optarg; 148c55617f1Sdlg break; 1496de960dcSmarco case 'H': /* set hotspare */ 1506de960dcSmarco func |= BIOC_SETSTATE; 151a15048bbSmarco ss_func = BIOC_SSHOTSPARE; 1526de960dcSmarco al_arg = optarg; 1536de960dcSmarco break; 1548ccdd032Sderaadt case 'h': 1558ccdd032Sderaadt human = 1; 1568ccdd032Sderaadt break; 157db2730c1Smarco case 'i': /* inquiry */ 158db2730c1Smarco func |= BIOC_INQ; 1593af9de98Smarco break; 1600054cd36Sjsing case 'k': /* Key disk. */ 1610054cd36Sjsing key_disk = optarg; 1620054cd36Sjsing break; 1637195049bSmarco case 'l': /* device list */ 1647195049bSmarco func |= BIOC_DEVLIST; 1657195049bSmarco dev_list = optarg; 1667195049bSmarco break; 167c6446370Sjsing case 'P': 168c6446370Sjsing /* Change passphrase. */ 169c6446370Sjsing changepass = 1; 170c6446370Sjsing break; 17186735da2Smarco case 'p': 17286735da2Smarco password = optarg; 17386735da2Smarco break; 174aedd4f07Sdjm case 'r': 175aedd4f07Sdjm rflag = strtonum(optarg, 1000, 1<<30, &errstr); 176aedd4f07Sdjm if (errstr != NULL) 177aedd4f07Sdjm errx(1, "Number of rounds is %s: %s", 178aedd4f07Sdjm errstr, optarg); 179aedd4f07Sdjm break; 18050e55a42Sjsing case 'O': 18150e55a42Sjsing /* set a chunk to offline */ 18250e55a42Sjsing func |= BIOC_SETSTATE; 18350e55a42Sjsing ss_func = BIOC_SSOFFLINE; 18450e55a42Sjsing al_arg = optarg; 18550e55a42Sjsing break; 186a15048bbSmarco case 'R': 187a15048bbSmarco /* rebuild to provided chunk/CTL */ 188a15048bbSmarco func |= BIOC_SETSTATE; 189a15048bbSmarco ss_func = BIOC_SSREBUILD; 190a15048bbSmarco al_arg = optarg; 191a15048bbSmarco break; 192b96c6ce2Sckuethe case 's': 193b96c6ce2Sckuethe rpp_flag = RPP_STDIN; 194b96c6ce2Sckuethe break; 195abe9d68eSderaadt case 'v': 196abe9d68eSderaadt verbose = 1; 197abe9d68eSderaadt break; 19803b2dfbfShenning case 'q': 19903b2dfbfShenning diskinq = 1; 20003b2dfbfShenning break; 2013af9de98Smarco default: 2023af9de98Smarco usage(); 2033af9de98Smarco /* NOTREACHED */ 2043af9de98Smarco } 2053af9de98Smarco } 206cf6503d7Sderaadt argc -= optind; 207cf6503d7Sderaadt argv += optind; 2083af9de98Smarco 209c6446370Sjsing if (argc != 1 || (changepass && func != 0)) 210cf6503d7Sderaadt usage(); 211cf6503d7Sderaadt 212dcbaf4c8Sderaadt if (func == 0) 213dcbaf4c8Sderaadt func |= BIOC_INQ; 214dcbaf4c8Sderaadt 215e63d8b1dSdtucker devicename = argv[0]; 216e63d8b1dSdtucker if (devicename == NULL) 217e37c64dbSjsing errx(1, "need device"); 21810b411a7Smarco 219e63d8b1dSdtucker devh = opendev(devicename, O_RDWR, OPENDEV_PART, &realname); 220e37c64dbSjsing if (devh == -1) { 22141eccc89Sderaadt devh = open("/dev/bio", O_RDWR); 2223af9de98Smarco if (devh == -1) 22341eccc89Sderaadt err(1, "Can't open %s", "/dev/bio"); 2243af9de98Smarco 225e63d8b1dSdtucker bl.bl_name = devicename; 226d313c28bSjsing if (ioctl(devh, BIOCLOCATE, &bl)) 22710b411a7Smarco errx(1, "Can't locate %s device via %s", 22841eccc89Sderaadt bl.bl_name, "/dev/bio"); 229d313c28bSjsing 230d313c28bSjsing bio_status(&bl.bl_bio.bio_status); 231d313c28bSjsing 232545c4d7fSjsing bio_cookie = bl.bl_bio.bio_cookie; 233e37c64dbSjsing biodev = 1; 234e63d8b1dSdtucker devicename = NULL; 235e37c64dbSjsing } 2363af9de98Smarco 23703b2dfbfShenning if (diskinq) { 238e63d8b1dSdtucker bio_diskinq(devicename); 239e37c64dbSjsing } else if (changepass && !biodev) { 240e63d8b1dSdtucker bio_changepass(devicename); 24103b2dfbfShenning } else if (func & BIOC_INQ) { 242e63d8b1dSdtucker bio_inq(devicename); 243edfd9792Smarco } else if (func == BIOC_ALARM) { 244edfd9792Smarco bio_alarm(al_arg); 245c55617f1Sdlg } else if (func == BIOC_BLINK) { 246e63d8b1dSdtucker bio_setblink(devicename, bl_arg, blink); 2476de960dcSmarco } else if (func == BIOC_SETSTATE) { 248a15048bbSmarco bio_setstate(al_arg, ss_func, argv[0]); 249e37c64dbSjsing } else if (func == BIOC_DELETERAID && !biodev) { 250e63d8b1dSdtucker bio_deleteraid(devicename); 2517195049bSmarco } else if (func & BIOC_CREATERAID || func & BIOC_DEVLIST) { 2527195049bSmarco if (!(func & BIOC_CREATERAID)) 2537195049bSmarco errx(1, "need -c parameter"); 2547195049bSmarco if (!(func & BIOC_DEVLIST)) 2557195049bSmarco errx(1, "need -l parameter"); 256e37c64dbSjsing if (!biodev) 257e37c64dbSjsing errx(1, "must use bio device"); 2580054cd36Sjsing bio_createraid(cr_level, dev_list, key_disk); 2593af9de98Smarco } 2603af9de98Smarco 2613af9de98Smarco return (0); 2623af9de98Smarco } 2633af9de98Smarco 2643af9de98Smarco void 2653af9de98Smarco usage(void) 2663af9de98Smarco { 2673af9de98Smarco extern char *__progname; 2683af9de98Smarco 269d90b5d8bSjmc fprintf(stderr, 270d0b772c8Sjmc "usage: %s [-hiqv] [-a alarm-function] " 271d90b5d8bSjmc "[-b channel:target[.lun]]\n" 272d0b772c8Sjmc "\t[-H channel:target[.lun]] " 273af56bbe7Smatthieu "[-R device | channel:target[.lun]]\n" 274d0b772c8Sjmc "\t[-u channel:target[.lun]] " 275d0b772c8Sjmc "device\n" 276b96c6ce2Sckuethe " %s [-dhiPqsv] " 277b90fdff5Sjmc "[-C flag[,flag,...]] [-c raidlevel] [-k keydisk]\n" 27850e55a42Sjsing "\t[-l special[,special,...]] " 27950e55a42Sjsing "[-O device | channel:target[.lun]]\n" 28050e55a42Sjsing "\t[-p passfile] [-R device | channel:target[.lun]]\n" 28150e55a42Sjsing "\t[-r rounds] " 282d0b772c8Sjmc "device\n", __progname, __progname); 283d90b5d8bSjmc 2843af9de98Smarco exit(1); 2853af9de98Smarco } 2863af9de98Smarco 28741eccc89Sderaadt const char * 2886de960dcSmarco str2locator(const char *string, struct locator *location) 2896de960dcSmarco { 29050d3c4dcSdlg const char *errstr; 29141eccc89Sderaadt char parse[80], *targ, *lun; 2926de960dcSmarco 29341eccc89Sderaadt strlcpy(parse, string, sizeof parse); 29441eccc89Sderaadt targ = strchr(parse, ':'); 2956de960dcSmarco if (targ == NULL) 29641eccc89Sderaadt return ("target not specified"); 2976de960dcSmarco *targ++ = '\0'; 2986de960dcSmarco 29950d3c4dcSdlg lun = strchr(targ, '.'); 3006de960dcSmarco if (lun != NULL) { 3016de960dcSmarco *lun++ = '\0'; 30250d3c4dcSdlg location->lun = strtonum(lun, 0, 256, &errstr); 30350d3c4dcSdlg if (errstr) 30441eccc89Sderaadt return (errstr); 3056de960dcSmarco } else 3066de960dcSmarco location->lun = 0; 3076de960dcSmarco 30850d3c4dcSdlg location->target = strtonum(targ, 0, 256, &errstr); 30950d3c4dcSdlg if (errstr) 31041eccc89Sderaadt return (errstr); 31141eccc89Sderaadt location->channel = strtonum(parse, 0, 256, &errstr); 31250d3c4dcSdlg if (errstr) 31341eccc89Sderaadt return (errstr); 31441eccc89Sderaadt return (NULL); 3156de960dcSmarco } 3166de960dcSmarco 3173af9de98Smarco void 318d313c28bSjsing bio_status(struct bio_status *bs) 319d313c28bSjsing { 3200a69bfccSjsing extern char *__progname; 3210a69bfccSjsing char *prefix; 322d313c28bSjsing int i; 323d313c28bSjsing 324d313c28bSjsing if (strlen(bs->bs_controller)) 3250a69bfccSjsing prefix = bs->bs_controller; 3260a69bfccSjsing else 3270a69bfccSjsing prefix = __progname; 328d313c28bSjsing 3290a69bfccSjsing for (i = 0; i < bs->bs_msg_count; i++) 3300a69bfccSjsing printf("%s: %s\n", prefix, bs->bs_msgs[i].bm_msg); 3310a69bfccSjsing 3320a69bfccSjsing if (bs->bs_status == BIO_STATUS_ERROR) { 3330a69bfccSjsing if (bs->bs_msg_count == 0) 3340a69bfccSjsing errx(1, "unknown error"); 3350a69bfccSjsing else 336d313c28bSjsing exit(1); 337d313c28bSjsing } 3380a69bfccSjsing } 339d313c28bSjsing 340d313c28bSjsing void 3418ccdd032Sderaadt bio_inq(char *name) 342d4546a56Sdlg { 343cc711184Skettenis char *status, *cache; 344cc711184Skettenis char size[64], scsiname[16], volname[32]; 345a4d3c4a2Sderaadt char percent[10], seconds[20]; 346d313c28bSjsing int i, d, volheader, hotspare, unused; 347aa65acf1Sderaadt char encname[16], serial[32]; 3488ccdd032Sderaadt struct bioc_inq bi; 3498ccdd032Sderaadt struct bioc_vol bv; 350c2b1f828Sderaadt struct bioc_disk bd; 351db2730c1Smarco 352db2730c1Smarco memset(&bi, 0, sizeof(bi)); 3533af9de98Smarco 354545c4d7fSjsing bi.bi_bio.bio_cookie = bio_cookie; 3553af9de98Smarco 356d313c28bSjsing if (ioctl(devh, BIOCINQ, &bi)) { 35703b2dfbfShenning if (errno == ENOTTY) 35803b2dfbfShenning bio_diskinq(name); 35903b2dfbfShenning else 360da3b0664Shenning err(1, "BIOCINQ"); 3613af9de98Smarco return; 3623af9de98Smarco } 3633af9de98Smarco 364d313c28bSjsing bio_status(&bi.bi_bio.bio_status); 365d313c28bSjsing 3668ccdd032Sderaadt volheader = 0; 3678ccdd032Sderaadt for (i = 0; i < bi.bi_novol; i++) { 368db2730c1Smarco memset(&bv, 0, sizeof(bv)); 369545c4d7fSjsing bv.bv_bio.bio_cookie = bio_cookie; 3708ccdd032Sderaadt bv.bv_volid = i; 3710a92ff65Sderaadt bv.bv_percent = -1; 3729017fb97Sderaadt bv.bv_seconds = 0; 37370a2ae7bSmarco 374d313c28bSjsing if (ioctl(devh, BIOCVOL, &bv)) 375da3b0664Shenning err(1, "BIOCVOL"); 3763af9de98Smarco 377d313c28bSjsing bio_status(&bv.bv_bio.bio_status); 378d313c28bSjsing 3798ccdd032Sderaadt if (name && strcmp(name, bv.bv_dev) != 0) 3808ccdd032Sderaadt continue; 3818ccdd032Sderaadt 3828ccdd032Sderaadt if (!volheader) { 3838ccdd032Sderaadt volheader = 1; 384150c22bbSjcs printf("%-11s %-10s %14s %-8s\n", 3858ccdd032Sderaadt "Volume", "Status", "Size", "Device"); 3868ccdd032Sderaadt } 3878ccdd032Sderaadt 3880a92ff65Sderaadt percent[0] = '\0'; 3899017fb97Sderaadt seconds[0] = '\0'; 3900a92ff65Sderaadt if (bv.bv_percent != -1) 3910a92ff65Sderaadt snprintf(percent, sizeof percent, 3920a92ff65Sderaadt " %d%% done", bv.bv_percent); 3939017fb97Sderaadt if (bv.bv_seconds) 3949017fb97Sderaadt snprintf(seconds, sizeof seconds, 3959017fb97Sderaadt " %u seconds", bv.bv_seconds); 3968ccdd032Sderaadt switch (bv.bv_status) { 397db2730c1Smarco case BIOC_SVONLINE: 3988ccdd032Sderaadt status = BIOC_SVONLINE_S; 399db2730c1Smarco break; 400db2730c1Smarco case BIOC_SVOFFLINE: 4018ccdd032Sderaadt status = BIOC_SVOFFLINE_S; 402db2730c1Smarco break; 403db2730c1Smarco case BIOC_SVDEGRADED: 4048ccdd032Sderaadt status = BIOC_SVDEGRADED_S; 405db2730c1Smarco break; 4060a92ff65Sderaadt case BIOC_SVBUILDING: 4070a92ff65Sderaadt status = BIOC_SVBUILDING_S; 4080a92ff65Sderaadt break; 4090a92ff65Sderaadt case BIOC_SVREBUILD: 4100a92ff65Sderaadt status = BIOC_SVREBUILD_S; 4110a92ff65Sderaadt break; 4120a92ff65Sderaadt case BIOC_SVSCRUB: 4130a92ff65Sderaadt status = BIOC_SVSCRUB_S; 4140a92ff65Sderaadt break; 415db2730c1Smarco case BIOC_SVINVALID: 416db2730c1Smarco default: 4178ccdd032Sderaadt status = BIOC_SVINVALID_S; 418d4546a56Sdlg } 419cc711184Skettenis switch (bv.bv_cache) { 420cc711184Skettenis case BIOC_CVWRITEBACK: 421cc711184Skettenis cache = BIOC_CVWRITEBACK_S; 422cc711184Skettenis break; 423cc711184Skettenis case BIOC_CVWRITETHROUGH: 424cc711184Skettenis cache = BIOC_CVWRITETHROUGH_S; 425cc711184Skettenis break; 426cc711184Skettenis case BIOC_CVUNKNOWN: 427cc711184Skettenis default: 428cc711184Skettenis cache = BIOC_CVUNKNOWN_S; 429cc711184Skettenis } 4303af9de98Smarco 431aa65acf1Sderaadt snprintf(volname, sizeof volname, "%s %u", 4328ccdd032Sderaadt bi.bi_dev, bv.bv_volid); 433b9950701Smarco 4349ecba717Sderaadt unused = 0; 4359ecba717Sderaadt hotspare = 0; 436aa65acf1Sderaadt if (bv.bv_level == -1 && bv.bv_nodisk == 1) 437aa65acf1Sderaadt hotspare = 1; 438b9950701Smarco else if (bv.bv_level == -2 && bv.bv_nodisk == 1) 439b9950701Smarco unused = 1; 440aa65acf1Sderaadt else { 4418ccdd032Sderaadt if (human) 4428ccdd032Sderaadt fmt_scaled(bv.bv_size, size); 4438ccdd032Sderaadt else 4448ccdd032Sderaadt snprintf(size, sizeof size, "%14llu", 4458ccdd032Sderaadt bv.bv_size); 446da935596Stodd switch (bv.bv_level) { 447da935596Stodd case 'C': 448150c22bbSjcs printf("%11s %-10s %14s %-7s CRYPTO%s%s\n", 449da935596Stodd volname, status, size, bv.bv_dev, 450da935596Stodd percent, seconds); 451da935596Stodd break; 4522b5fc845Sjsing case 'c': 4532b5fc845Sjsing printf("%11s %-10s %14s %-7s CONCAT%s%s\n", 4542b5fc845Sjsing volname, status, size, bv.bv_dev, 4552b5fc845Sjsing percent, seconds); 4562b5fc845Sjsing break; 457da935596Stodd default: 458cc711184Skettenis printf("%11s %-10s %14s %-7s RAID%u%s%s %s\n", 4590a92ff65Sderaadt volname, status, size, bv.bv_dev, 460cc711184Skettenis bv.bv_level, percent, seconds, cache); 461da935596Stodd break; 462da935596Stodd } 463da935596Stodd 464aa65acf1Sderaadt } 4658ccdd032Sderaadt 4668ccdd032Sderaadt for (d = 0; d < bv.bv_nodisk; d++) { 467db2730c1Smarco memset(&bd, 0, sizeof(bd)); 468545c4d7fSjsing bd.bd_bio.bio_cookie = bio_cookie; 4698ccdd032Sderaadt bd.bd_diskid = d; 4708ccdd032Sderaadt bd.bd_volid = i; 4713af9de98Smarco 472d313c28bSjsing if (ioctl(devh, BIOCDISK, &bd)) 473da3b0664Shenning err(1, "BIOCDISK"); 4743af9de98Smarco 475d313c28bSjsing bio_status(&bd.bd_bio.bio_status); 476d313c28bSjsing 4778ccdd032Sderaadt switch (bd.bd_status) { 478db2730c1Smarco case BIOC_SDONLINE: 4798ccdd032Sderaadt status = BIOC_SDONLINE_S; 480d4546a56Sdlg break; 481db2730c1Smarco case BIOC_SDOFFLINE: 4828ccdd032Sderaadt status = BIOC_SDOFFLINE_S; 483d4546a56Sdlg break; 484db2730c1Smarco case BIOC_SDFAILED: 4858ccdd032Sderaadt status = BIOC_SDFAILED_S; 486db2730c1Smarco break; 487db2730c1Smarco case BIOC_SDREBUILD: 4888ccdd032Sderaadt status = BIOC_SDREBUILD_S; 489db2730c1Smarco break; 490db2730c1Smarco case BIOC_SDHOTSPARE: 4918ccdd032Sderaadt status = BIOC_SDHOTSPARE_S; 492db2730c1Smarco break; 493db2730c1Smarco case BIOC_SDUNUSED: 4948ccdd032Sderaadt status = BIOC_SDUNUSED_S; 495db2730c1Smarco break; 496e1dfb373Sderaadt case BIOC_SDSCRUB: 497e1dfb373Sderaadt status = BIOC_SDSCRUB_S; 498e1dfb373Sderaadt break; 499db2730c1Smarco case BIOC_SDINVALID: 500d4546a56Sdlg default: 5018ccdd032Sderaadt status = BIOC_SDINVALID_S; 502d4546a56Sdlg } 503aa65acf1Sderaadt 504b9950701Smarco if (hotspare || unused) 505aa65acf1Sderaadt ; /* use volname from parent volume */ 506aa65acf1Sderaadt else 507aa65acf1Sderaadt snprintf(volname, sizeof volname, " %3u", 508aa65acf1Sderaadt bd.bd_diskid); 509aa65acf1Sderaadt 5100054cd36Sjsing if (bv.bv_level == 'C' && bd.bd_size == 0) 5110054cd36Sjsing snprintf(size, sizeof size, "%14s", "key disk"); 5120054cd36Sjsing else if (human) 5138ccdd032Sderaadt fmt_scaled(bd.bd_size, size); 5148ccdd032Sderaadt else 5158ccdd032Sderaadt snprintf(size, sizeof size, "%14llu", 5168ccdd032Sderaadt bd.bd_size); 5178ccdd032Sderaadt snprintf(scsiname, sizeof scsiname, 51843d61178Sderaadt "%u:%u.%u", 51943d61178Sderaadt bd.bd_channel, bd.bd_target, bd.bd_lun); 5205978b28dSderaadt if (bd.bd_procdev[0]) 521abe9d68eSderaadt strlcpy(encname, bd.bd_procdev, sizeof encname); 5225978b28dSderaadt else 523abe9d68eSderaadt strlcpy(encname, "noencl", sizeof encname); 524abe9d68eSderaadt if (bd.bd_serial[0]) 525abe9d68eSderaadt strlcpy(serial, bd.bd_serial, sizeof serial); 526abe9d68eSderaadt else 527abe9d68eSderaadt strlcpy(serial, "unknown serial", sizeof serial); 5288ccdd032Sderaadt 529150c22bbSjcs printf("%11s %-10s %14s %-7s %-6s <%s>\n", 530aa65acf1Sderaadt volname, status, size, scsiname, encname, 5318ccdd032Sderaadt bd.bd_vendor); 532abe9d68eSderaadt if (verbose) 533959b5194Skettenis printf("%11s %-10s %14s %-7s %-6s '%s'\n", 534abe9d68eSderaadt "", "", "", "", "", serial); 535d4546a56Sdlg } 536d4546a56Sdlg } 537d4546a56Sdlg } 538edfd9792Smarco 539edfd9792Smarco void 540edfd9792Smarco bio_alarm(char *arg) 541edfd9792Smarco { 5428ccdd032Sderaadt struct bioc_alarm ba; 543edfd9792Smarco 544c2b1f828Sderaadt memset(&ba, 0, sizeof(ba)); 545545c4d7fSjsing ba.ba_bio.bio_cookie = bio_cookie; 546edfd9792Smarco 547edfd9792Smarco switch (arg[0]) { 548edfd9792Smarco case 'q': /* silence alarm */ 549edfd9792Smarco /* FALLTHROUGH */ 550edfd9792Smarco case 's': 5518ccdd032Sderaadt ba.ba_opcode = BIOC_SASILENCE; 552edfd9792Smarco break; 553edfd9792Smarco 554edfd9792Smarco case 'e': /* enable alarm */ 5558ccdd032Sderaadt ba.ba_opcode = BIOC_SAENABLE; 556edfd9792Smarco break; 557edfd9792Smarco 558edfd9792Smarco case 'd': /* disable alarm */ 5598ccdd032Sderaadt ba.ba_opcode = BIOC_SADISABLE; 560edfd9792Smarco break; 561edfd9792Smarco 562edfd9792Smarco case 't': /* test alarm */ 5638ccdd032Sderaadt ba.ba_opcode = BIOC_SATEST; 564edfd9792Smarco break; 565edfd9792Smarco 566edfd9792Smarco case 'g': /* get alarm state */ 5678ccdd032Sderaadt ba.ba_opcode = BIOC_GASTATUS; 568edfd9792Smarco break; 569edfd9792Smarco 570edfd9792Smarco default: 571da3b0664Shenning errx(1, "invalid alarm function: %s", arg); 572edfd9792Smarco } 573edfd9792Smarco 574d313c28bSjsing if (ioctl(devh, BIOCALARM, &ba)) 575da3b0664Shenning err(1, "BIOCALARM"); 576edfd9792Smarco 577d313c28bSjsing bio_status(&ba.ba_bio.bio_status); 578d313c28bSjsing 579d313c28bSjsing if (arg[0] == 'g') 580edfd9792Smarco printf("alarm is currently %s\n", 5818ccdd032Sderaadt ba.ba_status ? "enabled" : "disabled"); 582edfd9792Smarco } 5836de960dcSmarco 584a15048bbSmarco int 585a15048bbSmarco bio_getvolbyname(char *name) 586a15048bbSmarco { 587d313c28bSjsing int id = -1, i; 588a15048bbSmarco struct bioc_inq bi; 589a15048bbSmarco struct bioc_vol bv; 590a15048bbSmarco 591a15048bbSmarco memset(&bi, 0, sizeof(bi)); 592545c4d7fSjsing bi.bi_bio.bio_cookie = bio_cookie; 593d313c28bSjsing if (ioctl(devh, BIOCINQ, &bi)) 594a15048bbSmarco err(1, "BIOCINQ"); 595a15048bbSmarco 596d313c28bSjsing bio_status(&bi.bi_bio.bio_status); 597d313c28bSjsing 598a15048bbSmarco for (i = 0; i < bi.bi_novol; i++) { 599a15048bbSmarco memset(&bv, 0, sizeof(bv)); 600545c4d7fSjsing bv.bv_bio.bio_cookie = bio_cookie; 601a15048bbSmarco bv.bv_volid = i; 602d313c28bSjsing if (ioctl(devh, BIOCVOL, &bv)) 603a15048bbSmarco err(1, "BIOCVOL"); 604a15048bbSmarco 605d313c28bSjsing bio_status(&bv.bv_bio.bio_status); 606d313c28bSjsing 607a15048bbSmarco if (name && strcmp(name, bv.bv_dev) != 0) 608a15048bbSmarco continue; 609a15048bbSmarco id = i; 610a15048bbSmarco break; 611a15048bbSmarco } 612a15048bbSmarco 613a15048bbSmarco return (id); 614a15048bbSmarco } 615a15048bbSmarco 616ebaf584eSderaadt void 6178d8693a2Sdtucker bio_setstate(char *arg, int status, char *devicename) 6186de960dcSmarco { 6196de960dcSmarco struct bioc_setstate bs; 6206de960dcSmarco struct locator location; 621a15048bbSmarco struct stat sb; 62241eccc89Sderaadt const char *errstr; 6236de960dcSmarco 624a15048bbSmarco memset(&bs, 0, sizeof(bs)); 625a15048bbSmarco if (stat(arg, &sb) == -1) { 626a15048bbSmarco /* use CTL */ 62741eccc89Sderaadt errstr = str2locator(arg, &location); 62841eccc89Sderaadt if (errstr) 62941eccc89Sderaadt errx(1, "Target %s: %s", arg, errstr); 6306de960dcSmarco bs.bs_channel = location.channel; 6316de960dcSmarco bs.bs_target = location.target; 6326de960dcSmarco bs.bs_lun = location.lun; 633a15048bbSmarco } else { 634a15048bbSmarco /* use other id */ 635a15048bbSmarco bs.bs_other_id = sb.st_rdev; 636a15048bbSmarco bs.bs_other_id_type = BIOC_SSOTHER_DEVT; 637a15048bbSmarco } 638a15048bbSmarco 639545c4d7fSjsing bs.bs_bio.bio_cookie = bio_cookie; 640a15048bbSmarco bs.bs_status = status; 641a15048bbSmarco 642d2647ac1Sjsing if (status != BIOC_SSHOTSPARE) { 643a15048bbSmarco /* make sure user supplied a sd device */ 6448d8693a2Sdtucker bs.bs_volid = bio_getvolbyname(devicename); 645a15048bbSmarco if (bs.bs_volid == -1) 6468d8693a2Sdtucker errx(1, "invalid device %s", devicename); 647d2647ac1Sjsing } 6486de960dcSmarco 649d313c28bSjsing if (ioctl(devh, BIOCSETSTATE, &bs)) 650da3b0664Shenning err(1, "BIOCSETSTATE"); 651d313c28bSjsing 652d313c28bSjsing bio_status(&bs.bs_bio.bio_status); 6536de960dcSmarco } 654c55617f1Sdlg 655c55617f1Sdlg void 656a928c459Sderaadt bio_setblink(char *name, char *arg, int blink) 657c55617f1Sdlg { 65850d3c4dcSdlg struct locator location; 659c2b1f828Sderaadt struct bioc_blink bb; 66050d3c4dcSdlg struct bioc_inq bi; 66150d3c4dcSdlg struct bioc_vol bv; 66250d3c4dcSdlg struct bioc_disk bd; 66341eccc89Sderaadt const char *errstr; 66450d3c4dcSdlg int v, d, rv; 665c55617f1Sdlg 66641eccc89Sderaadt errstr = str2locator(arg, &location); 66741eccc89Sderaadt if (errstr) 66841eccc89Sderaadt errx(1, "Target %s: %s", arg, errstr); 66950d3c4dcSdlg 6700505205bSdlg /* try setting blink on the device directly */ 6710505205bSdlg memset(&bb, 0, sizeof(bb)); 672545c4d7fSjsing bb.bb_bio.bio_cookie = bio_cookie; 6730505205bSdlg bb.bb_status = blink; 6740505205bSdlg bb.bb_target = location.target; 675649724a4Smarco bb.bb_channel = location.channel; 6760505205bSdlg rv = ioctl(devh, BIOCBLINK, &bb); 677d313c28bSjsing 678d313c28bSjsing if (rv == 0 && bb.bb_bio.bio_status.bs_status == BIO_STATUS_UNKNOWN) 6790505205bSdlg return; 6800505205bSdlg 681d313c28bSjsing if (rv == 0 && bb.bb_bio.bio_status.bs_status == BIO_STATUS_SUCCESS) { 682d313c28bSjsing bio_status(&bb.bb_bio.bio_status); 683d313c28bSjsing return; 684d313c28bSjsing } 685d313c28bSjsing 686855d4e83Ssobrado /* if the blink didn't work, try to find something that will */ 6870505205bSdlg 68850d3c4dcSdlg memset(&bi, 0, sizeof(bi)); 689545c4d7fSjsing bi.bi_bio.bio_cookie = bio_cookie; 690d313c28bSjsing if (ioctl(devh, BIOCINQ, &bi)) 691da3b0664Shenning err(1, "BIOCINQ"); 69250d3c4dcSdlg 693d313c28bSjsing bio_status(&bi.bi_bio.bio_status); 694d313c28bSjsing 69550d3c4dcSdlg for (v = 0; v < bi.bi_novol; v++) { 69650d3c4dcSdlg memset(&bv, 0, sizeof(bv)); 697545c4d7fSjsing bv.bv_bio.bio_cookie = bio_cookie; 69850d3c4dcSdlg bv.bv_volid = v; 699d313c28bSjsing if (ioctl(devh, BIOCVOL, &bv)) 700da3b0664Shenning err(1, "BIOCVOL"); 70150d3c4dcSdlg 702d313c28bSjsing bio_status(&bv.bv_bio.bio_status); 703d313c28bSjsing 70450d3c4dcSdlg if (name && strcmp(name, bv.bv_dev) != 0) 70550d3c4dcSdlg continue; 70650d3c4dcSdlg 70750d3c4dcSdlg for (d = 0; d < bv.bv_nodisk; d++) { 70850d3c4dcSdlg memset(&bd, 0, sizeof(bd)); 709545c4d7fSjsing bd.bd_bio.bio_cookie = bio_cookie; 71050d3c4dcSdlg bd.bd_volid = v; 71150d3c4dcSdlg bd.bd_diskid = d; 71250d3c4dcSdlg 713d313c28bSjsing if (ioctl(devh, BIOCDISK, &bd)) 714da3b0664Shenning err(1, "BIOCDISK"); 71550d3c4dcSdlg 716d313c28bSjsing bio_status(&bd.bd_bio.bio_status); 717d313c28bSjsing 71850d3c4dcSdlg if (bd.bd_channel == location.channel && 71950d3c4dcSdlg bd.bd_target == location.target && 72050d3c4dcSdlg bd.bd_lun == location.lun) { 721d313c28bSjsing if (bd.bd_procdev[0] != '\0') 72250d3c4dcSdlg bio_blink(bd.bd_procdev, 723a928c459Sderaadt location.target, blink); 724d313c28bSjsing else 725d313c28bSjsing warnx("Disk %s is not in an enclosure", 726d313c28bSjsing arg); 72750d3c4dcSdlg return; 72850d3c4dcSdlg } 72950d3c4dcSdlg } 73050d3c4dcSdlg } 73150d3c4dcSdlg 73241eccc89Sderaadt warnx("Disk %s does not exist", arg); 733d313c28bSjsing 73450d3c4dcSdlg return; 73550d3c4dcSdlg } 73650d3c4dcSdlg 73750d3c4dcSdlg void 738a928c459Sderaadt bio_blink(char *enclosure, int target, int blinktype) 73950d3c4dcSdlg { 74050d3c4dcSdlg int bioh; 741d313c28bSjsing struct bio_locate bl; 74250d3c4dcSdlg struct bioc_blink blink; 74350d3c4dcSdlg 74441eccc89Sderaadt bioh = open("/dev/bio", O_RDWR); 74550d3c4dcSdlg if (bioh == -1) 74641eccc89Sderaadt err(1, "Can't open %s", "/dev/bio"); 74750d3c4dcSdlg 748c2b1f828Sderaadt memset(&bl, 0, sizeof(bl)); 749d313c28bSjsing bl.bl_name = enclosure; 750d313c28bSjsing if (ioctl(bioh, BIOCLOCATE, &bl)) 75141eccc89Sderaadt errx(1, "Can't locate %s device via %s", enclosure, "/dev/bio"); 752c55617f1Sdlg 753d313c28bSjsing bio_status(&bl.bl_bio.bio_status); 754d313c28bSjsing 755c55617f1Sdlg memset(&blink, 0, sizeof(blink)); 756545c4d7fSjsing blink.bb_bio.bio_cookie = bio_cookie; 757a928c459Sderaadt blink.bb_status = blinktype; 758c55617f1Sdlg blink.bb_target = target; 759c55617f1Sdlg 760d313c28bSjsing if (ioctl(bioh, BIOCBLINK, &blink)) 761da3b0664Shenning err(1, "BIOCBLINK"); 76250d3c4dcSdlg 763d313c28bSjsing bio_status(&blink.bb_bio.bio_status); 764d313c28bSjsing 76550d3c4dcSdlg close(bioh); 766c55617f1Sdlg } 7677195049bSmarco 768e7d4f752Sderaadt #ifdef AOE 769a2fc2d65Stedu struct sr_aoe_config * 770a2fc2d65Stedu create_aoe(u_int16_t level, char *dev_list) 771a2fc2d65Stedu { 772a2fc2d65Stedu static struct sr_aoe_config sac; 773a2fc2d65Stedu char *nic; 774a2fc2d65Stedu char *dsteaddr; 775a2fc2d65Stedu char *shelf; 776a2fc2d65Stedu char *slot; 777a2fc2d65Stedu struct ether_addr *eaddr; 778a2fc2d65Stedu const char *errstr; 779a2fc2d65Stedu 780a2fc2d65Stedu nic = dsteaddr = slot = shelf = 0; 781a2fc2d65Stedu 782a2fc2d65Stedu memset(&sac, 0, sizeof(sac)); 783a2fc2d65Stedu nic = dev_list; 784a2fc2d65Stedu dsteaddr = strchr(nic, ','); 785a2fc2d65Stedu if (!dsteaddr) 786a2fc2d65Stedu goto invalid; 787a2fc2d65Stedu *dsteaddr++ = '\0'; 788a2fc2d65Stedu shelf = strchr(dsteaddr, ','); 789a2fc2d65Stedu if (!shelf) 790a2fc2d65Stedu goto invalid; 791a2fc2d65Stedu *shelf++ = '\0'; 792a2fc2d65Stedu slot = strchr(shelf, ','); 793a2fc2d65Stedu if (!slot) 794a2fc2d65Stedu goto invalid; 795a2fc2d65Stedu *slot++ = '\0'; 796a2fc2d65Stedu strlcpy(sac.nic, nic, sizeof(sac.nic)); 797a2fc2d65Stedu eaddr = ether_aton(dsteaddr); 798a2fc2d65Stedu if (!eaddr) 799a2fc2d65Stedu goto invalid; 800a2fc2d65Stedu sac.dsteaddr = *eaddr; 801a2fc2d65Stedu sac.shelf = htons(strtonum(shelf, 0, 0xfffe, &errstr)); 802a2fc2d65Stedu if (errstr) 803a2fc2d65Stedu goto invalid; 804a2fc2d65Stedu sac.slot = strtonum(slot, 0, 0xfe, &errstr); 805a2fc2d65Stedu if (errstr) 806a2fc2d65Stedu goto invalid; 807a2fc2d65Stedu 808a2fc2d65Stedu return &sac; 809a2fc2d65Stedu invalid: 810a2fc2d65Stedu errx(1, "invalid AOE dev list: use nic,dsteaddr,shelf,slot"); 811a2fc2d65Stedu } 812e7d4f752Sderaadt #endif /* AOE */ 813a2fc2d65Stedu 8147195049bSmarco void 8150054cd36Sjsing bio_createraid(u_int16_t level, char *dev_list, char *key_disk) 8167195049bSmarco { 8177195049bSmarco struct bioc_createraid create; 818aef7fe28Shshoexer struct sr_crypto_kdfinfo kdfinfo; 819aef7fe28Shshoexer struct sr_crypto_kdf_pbkdf2 kdfhint; 820934f30d8Sderaadt #ifdef AOE 821a2fc2d65Stedu struct sr_aoe_config *sac; 822934f30d8Sderaadt #endif /* AOE */ 8230054cd36Sjsing struct stat sb; 8248b0d0f28Sjsing int rv, no_dev, fd; 8257f8eae2bSnicm dev_t *dt; 8267195049bSmarco u_int16_t min_disks = 0; 8277195049bSmarco 8287195049bSmarco if (!dev_list) 8297195049bSmarco errx(1, "no devices specified"); 8307195049bSmarco 831e7d4f752Sderaadt #ifdef AOE 832a2fc2d65Stedu if (level == 'a') { 833a2fc2d65Stedu sac = create_aoe(level, dev_list); 834a2fc2d65Stedu no_dev = 0; 835a2fc2d65Stedu dt = NULL; 836e7d4f752Sderaadt } else 837e7d4f752Sderaadt #endif /* AOE */ 838e7d4f752Sderaadt { 839f9b0dfcfStedu dt = calloc(1, BIOC_CRMAXLEN); 84046bc198bSmarco if (!dt) 84146bc198bSmarco err(1, "not enough memory for dev_t list"); 84246bc198bSmarco 84346bc198bSmarco no_dev = bio_parse_devlist(dev_list, dt); 844a2fc2d65Stedu } 84546bc198bSmarco 8467195049bSmarco switch (level) { 8477195049bSmarco case 0: 84884e48fabSmarco min_disks = 2; 8497195049bSmarco break; 8507195049bSmarco case 1: 8517195049bSmarco min_disks = 2; 8527195049bSmarco break; 853c231d813Sjsing #ifdef RAID5 854e717853eSmarco case 5: 855e717853eSmarco min_disks = 3; 856e717853eSmarco break; 857c231d813Sjsing #endif /* RAID5 */ 85884e48fabSmarco case 'C': 859aef7fe28Shshoexer min_disks = 1; 86084e48fabSmarco break; 86198b750e4Stedu case 'c': 8628fe6c343Sjsing min_disks = 2; 86398b750e4Stedu break; 864c231d813Sjsing #ifdef AOE 865a2fc2d65Stedu case 'a': 866a2fc2d65Stedu break; 867c231d813Sjsing #endif /* AOE */ 8687195049bSmarco default: 86923afedbfSgrunk errx(1, "unsupported raid level"); 8707195049bSmarco } 8717195049bSmarco 87284e48fabSmarco if (no_dev < min_disks) 87384e48fabSmarco errx(1, "not enough disks"); 87484e48fabSmarco 875aef7fe28Shshoexer /* for crypto raid we only allow one single chunk */ 876aef7fe28Shshoexer if (level == 'C' && no_dev != min_disks) 877818b0595Shalex errx(1, "not exactly one partition"); 878aef7fe28Shshoexer 8797195049bSmarco memset(&create, 0, sizeof(create)); 880545c4d7fSjsing create.bc_bio.bio_cookie = bio_cookie; 8817195049bSmarco create.bc_level = level; 88246bc198bSmarco create.bc_dev_list_len = no_dev * sizeof(dev_t); 88346bc198bSmarco create.bc_dev_list = dt; 884e8a57fdeSmarco create.bc_flags = BIOC_SCDEVT | cflags; 8850054cd36Sjsing create.bc_key_disk = NODEV; 8867195049bSmarco 887e7d4f752Sderaadt #ifdef AOE 888a2fc2d65Stedu if (level == 'a') { 889a2fc2d65Stedu create.bc_opaque = sac; 890a2fc2d65Stedu create.bc_opaque_size = sizeof(*sac); 891a2fc2d65Stedu create.bc_opaque_flags = BIOC_SOIN; 892e7d4f752Sderaadt } else 893e7d4f752Sderaadt #endif /* AOE */ 894e7d4f752Sderaadt if (level == 'C' && key_disk == NULL) { 8950054cd36Sjsing 896aef7fe28Shshoexer memset(&kdfinfo, 0, sizeof(kdfinfo)); 897aef7fe28Shshoexer memset(&kdfhint, 0, sizeof(kdfhint)); 898aef7fe28Shshoexer 8990054cd36Sjsing create.bc_flags |= BIOC_SCNOAUTOASSEMBLE; 9000054cd36Sjsing 901aef7fe28Shshoexer create.bc_opaque = &kdfhint; 902aef7fe28Shshoexer create.bc_opaque_size = sizeof(kdfhint); 903aef7fe28Shshoexer create.bc_opaque_flags = BIOC_SOOUT; 904aef7fe28Shshoexer 905aef7fe28Shshoexer /* try to get KDF hint */ 906d313c28bSjsing if (ioctl(devh, BIOCCREATERAID, &create)) 90783e979edShshoexer err(1, "ioctl"); 90883e979edShshoexer 909d313c28bSjsing bio_status(&create.bc_bio.bio_status); 910d313c28bSjsing 91183e979edShshoexer if (create.bc_opaque_status == BIOC_SOINOUT_OK) { 912c6446370Sjsing bio_kdf_derive(&kdfinfo, &kdfhint, "Passphrase: ", 0); 913aef7fe28Shshoexer memset(&kdfhint, 0, sizeof(kdfhint)); 914aef7fe28Shshoexer } else { 915aef7fe28Shshoexer bio_kdf_generate(&kdfinfo); 916aef7fe28Shshoexer } 917aef7fe28Shshoexer 918aef7fe28Shshoexer create.bc_opaque = &kdfinfo; 919aef7fe28Shshoexer create.bc_opaque_size = sizeof(kdfinfo); 920aef7fe28Shshoexer create.bc_opaque_flags = BIOC_SOIN; 9210054cd36Sjsing 9220054cd36Sjsing } else if (level == 'C' && key_disk != NULL) { 9230054cd36Sjsing 9248b0d0f28Sjsing /* Get device number for key disk. */ 9258b0d0f28Sjsing fd = opendev(key_disk, O_RDONLY, OPENDEV_BLCK, NULL); 9268b0d0f28Sjsing if (fd == -1) 9278b0d0f28Sjsing err(1, "could not open %s", key_disk); 9288b0d0f28Sjsing if (fstat(fd, &sb) == -1) { 929*ffb4dd05Sguenther int saved_errno = errno; 9308b0d0f28Sjsing close(fd); 931*ffb4dd05Sguenther errc(1, saved_errno, "could not stat %s", key_disk); 9328b0d0f28Sjsing } 9338b0d0f28Sjsing close(fd); 9340054cd36Sjsing create.bc_key_disk = sb.st_rdev; 9350054cd36Sjsing 9360054cd36Sjsing memset(&kdfinfo, 0, sizeof(kdfinfo)); 9370054cd36Sjsing 9380054cd36Sjsing kdfinfo.genkdf.len = sizeof(kdfinfo.genkdf); 9390054cd36Sjsing kdfinfo.genkdf.type = SR_CRYPTOKDFT_KEYDISK; 9400054cd36Sjsing kdfinfo.len = sizeof(kdfinfo); 9410054cd36Sjsing kdfinfo.flags = SR_CRYPTOKDF_HINT; 9420054cd36Sjsing 9430054cd36Sjsing create.bc_opaque = &kdfinfo; 9440054cd36Sjsing create.bc_opaque_size = sizeof(kdfinfo); 9450054cd36Sjsing create.bc_opaque_flags = BIOC_SOIN; 9460054cd36Sjsing 947aef7fe28Shshoexer } 948aef7fe28Shshoexer 9497195049bSmarco rv = ioctl(devh, BIOCCREATERAID, &create); 950aef7fe28Shshoexer memset(&kdfinfo, 0, sizeof(kdfinfo)); 951d313c28bSjsing if (rv == -1) 952da3b0664Shenning err(1, "BIOCCREATERAID"); 953d313c28bSjsing 954d313c28bSjsing bio_status(&create.bc_bio.bio_status); 95546bc198bSmarco 95646bc198bSmarco free(dt); 95746bc198bSmarco } 95846bc198bSmarco 959aef7fe28Shshoexer void 960aef7fe28Shshoexer bio_kdf_derive(struct sr_crypto_kdfinfo *kdfinfo, struct sr_crypto_kdf_pbkdf2 961c6446370Sjsing *kdfhint, char* prompt, int verify) 962aef7fe28Shshoexer { 963aef7fe28Shshoexer if (!kdfinfo) 964aef7fe28Shshoexer errx(1, "invalid KDF info"); 965aef7fe28Shshoexer if (!kdfhint) 966aef7fe28Shshoexer errx(1, "invalid KDF hint"); 967aef7fe28Shshoexer 968aef7fe28Shshoexer if (kdfhint->len != sizeof(*kdfhint)) 969aef7fe28Shshoexer errx(1, "KDF hint has invalid size"); 970aef7fe28Shshoexer if (kdfhint->type != SR_CRYPTOKDFT_PBKDF2) 971aef7fe28Shshoexer errx(1, "unknown KDF type %d", kdfhint->type); 972aef7fe28Shshoexer if (kdfhint->rounds < 1000) 973aef7fe28Shshoexer errx(1, "number of KDF rounds too low: %d", kdfhint->rounds); 974aef7fe28Shshoexer 975aef7fe28Shshoexer kdfinfo->flags = SR_CRYPTOKDF_KEY; 976aef7fe28Shshoexer kdfinfo->len = sizeof(*kdfinfo); 977aef7fe28Shshoexer 9789e8c6f5bShshoexer derive_key_pkcs(kdfhint->rounds, 979aef7fe28Shshoexer kdfinfo->maskkey, sizeof(kdfinfo->maskkey), 980c6446370Sjsing kdfhint->salt, sizeof(kdfhint->salt), prompt, verify); 981aef7fe28Shshoexer } 982aef7fe28Shshoexer 983aef7fe28Shshoexer void 984aef7fe28Shshoexer bio_kdf_generate(struct sr_crypto_kdfinfo *kdfinfo) 985aef7fe28Shshoexer { 986aef7fe28Shshoexer if (!kdfinfo) 987aef7fe28Shshoexer errx(1, "invalid KDF info"); 988aef7fe28Shshoexer 989aef7fe28Shshoexer kdfinfo->pbkdf2.len = sizeof(kdfinfo->pbkdf2); 990aef7fe28Shshoexer kdfinfo->pbkdf2.type = SR_CRYPTOKDFT_PBKDF2; 991aedd4f07Sdjm kdfinfo->pbkdf2.rounds = rflag; 992aef7fe28Shshoexer kdfinfo->len = sizeof(*kdfinfo); 9930054cd36Sjsing kdfinfo->flags = SR_CRYPTOKDF_KEY | SR_CRYPTOKDF_HINT; 994aef7fe28Shshoexer 995aef7fe28Shshoexer /* generate salt */ 996aef7fe28Shshoexer arc4random_buf(kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt)); 997aef7fe28Shshoexer 9989e8c6f5bShshoexer derive_key_pkcs(kdfinfo->pbkdf2.rounds, 999aef7fe28Shshoexer kdfinfo->maskkey, sizeof(kdfinfo->maskkey), 1000c6446370Sjsing kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt), 1001c6446370Sjsing "New passphrase: ", 1); 1002aef7fe28Shshoexer } 1003aef7fe28Shshoexer 100446bc198bSmarco int 100546bc198bSmarco bio_parse_devlist(char *lst, dev_t *dt) 100646bc198bSmarco { 100746bc198bSmarco char *s, *e; 100846bc198bSmarco u_int32_t sz = 0; 100946bc198bSmarco int no_dev = 0, i, x; 101046bc198bSmarco struct stat sb; 10115c1f8f6bSdjm char dev[MAXPATHLEN]; 1012e37c64dbSjsing int fd; 101346bc198bSmarco 101446bc198bSmarco if (!lst) 101546bc198bSmarco errx(1, "invalid device list"); 101646bc198bSmarco 101746bc198bSmarco s = e = lst; 101846bc198bSmarco /* make sure we have a valid device list like /dev/sdNa,/dev/sdNNa */ 101946bc198bSmarco while (*e != '\0') { 102046bc198bSmarco if (*e == ',') 102146bc198bSmarco s = e + 1; 102246bc198bSmarco else if (*(e + 1) == '\0' || *(e + 1) == ',') { 102346bc198bSmarco /* got one */ 102446bc198bSmarco sz = e - s + 1; 10255c1f8f6bSdjm strlcpy(dev, s, sz + 1); 1026e37c64dbSjsing fd = opendev(dev, O_RDONLY, OPENDEV_BLCK, NULL); 1027e37c64dbSjsing if (fd == -1) 1028e37c64dbSjsing err(1, "could not open %s", dev); 1029e37c64dbSjsing if (fstat(fd, &sb) == -1) { 1030*ffb4dd05Sguenther int saved_errno = errno; 1031e37c64dbSjsing close(fd); 1032*ffb4dd05Sguenther errc(1, saved_errno, "could not stat %s", dev); 1033e37c64dbSjsing } 1034e37c64dbSjsing close(fd); 103546bc198bSmarco dt[no_dev] = sb.st_rdev; 103646bc198bSmarco no_dev++; 10375c1f8f6bSdjm if (no_dev > (int)(BIOC_CRMAXLEN / sizeof(dev_t))) 103846bc198bSmarco errx(1, "too many devices on device list"); 103946bc198bSmarco } 104046bc198bSmarco e++; 104146bc198bSmarco } 104246bc198bSmarco 104346bc198bSmarco for (i = 0; i < no_dev; i++) 104446bc198bSmarco for (x = 0; x < no_dev; x++) 104546bc198bSmarco if (dt[i] == dt[x] && x != i) 104646bc198bSmarco errx(1, "duplicate device in list"); 104746bc198bSmarco 104846bc198bSmarco return (no_dev); 10497195049bSmarco } 1050e8a57fdeSmarco 1051e8a57fdeSmarco u_int32_t 1052e8a57fdeSmarco bio_createflags(char *lst) 1053e8a57fdeSmarco { 1054e8a57fdeSmarco char *s, *e, fs[32]; 1055e8a57fdeSmarco u_int32_t sz = 0; 1056e8a57fdeSmarco u_int32_t flags = 0; 1057e8a57fdeSmarco 1058e8a57fdeSmarco if (!lst) 1059e8a57fdeSmarco errx(1, "invalid flags list"); 1060e8a57fdeSmarco 1061e8a57fdeSmarco s = e = lst; 1062e8a57fdeSmarco /* make sure we have a valid flags list like force,noassemeble */ 1063e8a57fdeSmarco while (*e != '\0') { 1064e8a57fdeSmarco if (*e == ',') 1065e8a57fdeSmarco s = e + 1; 1066e8a57fdeSmarco else if (*(e + 1) == '\0' || *(e + 1) == ',') { 1067e8a57fdeSmarco /* got one */ 1068e8a57fdeSmarco sz = e - s + 1; 1069e8a57fdeSmarco switch (s[0]) { 1070e8a57fdeSmarco case 'f': 1071e8a57fdeSmarco flags |= BIOC_SCFORCE; 1072e8a57fdeSmarco break; 1073e8a57fdeSmarco case 'n': 1074e8a57fdeSmarco flags |= BIOC_SCNOAUTOASSEMBLE; 1075e8a57fdeSmarco break; 1076e8a57fdeSmarco default: 1077e8a57fdeSmarco strlcpy(fs, s, sz + 1); 1078e8a57fdeSmarco errx(1, "invalid flag %s", fs); 1079e8a57fdeSmarco } 1080e8a57fdeSmarco } 1081e8a57fdeSmarco e++; 1082e8a57fdeSmarco } 1083e8a57fdeSmarco 1084e8a57fdeSmarco return (flags); 1085e8a57fdeSmarco } 108603b2dfbfShenning 1087c7c3e8aaSmarco void 1088c7c3e8aaSmarco bio_deleteraid(char *dev) 1089c7c3e8aaSmarco { 1090c7c3e8aaSmarco struct bioc_deleteraid bd; 1091c7c3e8aaSmarco memset(&bd, 0, sizeof(bd)); 1092c7c3e8aaSmarco 1093545c4d7fSjsing bd.bd_bio.bio_cookie = bio_cookie; 1094a15048bbSmarco /* XXX make this a dev_t instead of a string */ 1095c7c3e8aaSmarco strlcpy(bd.bd_dev, dev, sizeof bd.bd_dev); 1096c7c3e8aaSmarco if (ioctl(devh, BIOCDELETERAID, &bd)) 1097d313c28bSjsing err(1, "BIOCDELETERAID"); 1098d313c28bSjsing 1099d313c28bSjsing bio_status(&bd.bd_bio.bio_status); 1100c7c3e8aaSmarco } 1101c7c3e8aaSmarco 1102c6446370Sjsing void 1103c6446370Sjsing bio_changepass(char *dev) 1104c6446370Sjsing { 1105c6446370Sjsing struct bioc_discipline bd; 1106c6446370Sjsing struct sr_crypto_kdfpair kdfpair; 1107c6446370Sjsing struct sr_crypto_kdfinfo kdfinfo1, kdfinfo2; 1108c6446370Sjsing struct sr_crypto_kdf_pbkdf2 kdfhint; 1109c6446370Sjsing int rv; 1110c6446370Sjsing 1111c6446370Sjsing memset(&bd, 0, sizeof(bd)); 1112c6446370Sjsing memset(&kdfhint, 0, sizeof(kdfhint)); 1113c6446370Sjsing memset(&kdfinfo1, 0, sizeof(kdfinfo1)); 1114c6446370Sjsing memset(&kdfinfo2, 0, sizeof(kdfinfo2)); 1115c6446370Sjsing 1116c6446370Sjsing /* XXX use dev_t instead of string. */ 1117c6446370Sjsing strlcpy(bd.bd_dev, dev, sizeof(bd.bd_dev)); 1118c6446370Sjsing bd.bd_cmd = SR_IOCTL_GET_KDFHINT; 1119c6446370Sjsing bd.bd_size = sizeof(kdfhint); 1120c6446370Sjsing bd.bd_data = &kdfhint; 1121c6446370Sjsing 1122c6446370Sjsing if (ioctl(devh, BIOCDISCIPLINE, &bd)) 1123d313c28bSjsing err(1, "BIOCDISCIPLINE"); 1124d313c28bSjsing 1125d313c28bSjsing bio_status(&bd.bd_bio.bio_status); 1126c6446370Sjsing 1127c6446370Sjsing /* Current passphrase. */ 1128c6446370Sjsing bio_kdf_derive(&kdfinfo1, &kdfhint, "Old passphrase: ", 0); 1129c6446370Sjsing 1130c6446370Sjsing /* New passphrase. */ 1131c6446370Sjsing bio_kdf_derive(&kdfinfo2, &kdfhint, "New passphrase: ", 1); 1132c6446370Sjsing 1133c6446370Sjsing kdfpair.kdfinfo1 = &kdfinfo1; 1134c6446370Sjsing kdfpair.kdfsize1 = sizeof(kdfinfo1); 1135c6446370Sjsing kdfpair.kdfinfo2 = &kdfinfo2; 1136c6446370Sjsing kdfpair.kdfsize2 = sizeof(kdfinfo2); 1137c6446370Sjsing 1138c6446370Sjsing bd.bd_cmd = SR_IOCTL_CHANGE_PASSPHRASE; 1139c6446370Sjsing bd.bd_size = sizeof(kdfpair); 1140c6446370Sjsing bd.bd_data = &kdfpair; 1141c6446370Sjsing 1142c6446370Sjsing rv = ioctl(devh, BIOCDISCIPLINE, &bd); 1143c6446370Sjsing 1144c6446370Sjsing memset(&kdfhint, 0, sizeof(kdfhint)); 1145c6446370Sjsing memset(&kdfinfo1, 0, sizeof(kdfinfo1)); 1146c6446370Sjsing memset(&kdfinfo2, 0, sizeof(kdfinfo2)); 1147c6446370Sjsing 1148d313c28bSjsing if (rv) 1149d313c28bSjsing err(1, "BIOCDISCIPLINE"); 1150d313c28bSjsing 1151d313c28bSjsing bio_status(&bd.bd_bio.bio_status); 1152c6446370Sjsing } 1153c6446370Sjsing 115403b2dfbfShenning #define BIOCTL_VIS_NBUF 4 115503b2dfbfShenning #define BIOCTL_VIS_BUFLEN 80 115603b2dfbfShenning 115703b2dfbfShenning char * 115803b2dfbfShenning bio_vis(char *s) 115903b2dfbfShenning { 116003b2dfbfShenning static char rbuf[BIOCTL_VIS_NBUF][BIOCTL_VIS_BUFLEN]; 116103b2dfbfShenning static uint idx = 0; 116203b2dfbfShenning char *buf; 116303b2dfbfShenning 116403b2dfbfShenning buf = rbuf[idx++]; 116503b2dfbfShenning if (idx == BIOCTL_VIS_NBUF) 116603b2dfbfShenning idx = 0; 116703b2dfbfShenning 116803b2dfbfShenning strnvis(buf, s, BIOCTL_VIS_BUFLEN, VIS_NL|VIS_CSTYLE); 116903b2dfbfShenning return (buf); 117003b2dfbfShenning } 117103b2dfbfShenning 117203b2dfbfShenning void 117303b2dfbfShenning bio_diskinq(char *sd_dev) 117403b2dfbfShenning { 117503b2dfbfShenning struct dk_inquiry di; 117603b2dfbfShenning 1177da3b0664Shenning if (ioctl(devh, DIOCINQ, &di) == -1) 1178da3b0664Shenning err(1, "DIOCINQ"); 117903b2dfbfShenning 118003b2dfbfShenning printf("%s: <%s, %s, %s>, serial %s\n", sd_dev, bio_vis(di.vendor), 118103b2dfbfShenning bio_vis(di.product), bio_vis(di.revision), bio_vis(di.serial)); 118203b2dfbfShenning } 1183aef7fe28Shshoexer 1184aef7fe28Shshoexer void 11859e8c6f5bShshoexer derive_key_pkcs(int rounds, u_int8_t *key, size_t keysz, u_int8_t *salt, 1186c6446370Sjsing size_t saltsz, char *prompt, int verify) 1187aef7fe28Shshoexer { 118886735da2Smarco FILE *f; 118986735da2Smarco size_t pl; 119086735da2Smarco struct stat sb; 11919e8c6f5bShshoexer char passphrase[1024], verifybuf[1024]; 1192aef7fe28Shshoexer 1193aef7fe28Shshoexer if (!key) 1194aef7fe28Shshoexer errx(1, "Invalid key"); 1195aef7fe28Shshoexer if (!salt) 1196aef7fe28Shshoexer errx(1, "Invalid salt"); 1197aef7fe28Shshoexer if (rounds < 1000) 1198b4604b5cShalex errx(1, "Too few rounds: %d", rounds); 1199aef7fe28Shshoexer 1200aef7fe28Shshoexer /* get passphrase */ 1201ba3d8661Smarco if (password && verify) 1202ba3d8661Smarco errx(1, "can't specify passphrase file during initial " 1203ba3d8661Smarco "creation of crypto volume"); 1204ba3d8661Smarco if (password) { 120586735da2Smarco if ((f = fopen(password, "r")) == NULL) 120686735da2Smarco err(1, "invalid passphrase file"); 120786735da2Smarco 120886735da2Smarco if (fstat(fileno(f), &sb) == -1) 120986735da2Smarco err(1, "can't stat passphrase file"); 121086735da2Smarco if (sb.st_uid != 0) 121186735da2Smarco errx(1, "passphrase file must be owned by root"); 121286735da2Smarco if ((sb.st_mode & ~S_IFMT) != (S_IRUSR | S_IWUSR)) 121386735da2Smarco errx(1, "passphrase file has the wrong permissions"); 121486735da2Smarco 121586735da2Smarco if (fgets(passphrase, sizeof(passphrase), f) == NULL) 121686735da2Smarco err(1, "can't read passphrase file"); 121786735da2Smarco pl = strlen(passphrase); 121886735da2Smarco if (pl > 0 && passphrase[pl - 1] == '\n') 121986735da2Smarco passphrase[pl - 1] = '\0'; 122086735da2Smarco else 122186735da2Smarco errx(1, "invalid passphrase length"); 122286735da2Smarco 122386735da2Smarco fclose(f); 1224ba3d8661Smarco } else { 1225c6446370Sjsing if (readpassphrase(prompt, passphrase, sizeof(passphrase), 1226b96c6ce2Sckuethe rpp_flag) == NULL) 12279e8c6f5bShshoexer errx(1, "unable to read passphrase"); 1228ba3d8661Smarco } 12299e8c6f5bShshoexer 12309e8c6f5bShshoexer if (verify) { 12319e8c6f5bShshoexer /* request user to re-type it */ 12329e8c6f5bShshoexer if (readpassphrase("Re-type passphrase: ", verifybuf, 1233b96c6ce2Sckuethe sizeof(verifybuf), rpp_flag) == NULL) { 12349e8c6f5bShshoexer memset(passphrase, 0, sizeof(passphrase)); 12359e8c6f5bShshoexer errx(1, "unable to read passphrase"); 12369e8c6f5bShshoexer } 12379e8c6f5bShshoexer if ((strlen(passphrase) != strlen(verifybuf)) || 12389e8c6f5bShshoexer (strcmp(passphrase, verifybuf) != 0)) { 12399e8c6f5bShshoexer memset(passphrase, 0, sizeof(passphrase)); 12409e8c6f5bShshoexer memset(verifybuf, 0, sizeof(verifybuf)); 12419e8c6f5bShshoexer errx(1, "Passphrases did not match"); 12429e8c6f5bShshoexer } 12439e8c6f5bShshoexer /* forget the re-typed one */ 12449e8c6f5bShshoexer memset(verifybuf, 0, strlen(verifybuf)); 12459e8c6f5bShshoexer } 1246aef7fe28Shshoexer 1247aef7fe28Shshoexer /* derive key from passphrase */ 12485c1f8f6bSdjm if (pkcs5_pbkdf2(passphrase, strlen(passphrase), salt, saltsz, 12495c1f8f6bSdjm key, keysz, rounds) != 0) 12505c1f8f6bSdjm errx(1, "pbkdf2 failed"); 1251aef7fe28Shshoexer 1252aef7fe28Shshoexer /* forget passphrase */ 12539e8c6f5bShshoexer memset(passphrase, 0, sizeof(passphrase)); 1254aef7fe28Shshoexer 1255aef7fe28Shshoexer return; 1256aef7fe28Shshoexer } 1257