1*ea8dc4b6Seschrock /* 2*ea8dc4b6Seschrock * CDDL HEADER START 3*ea8dc4b6Seschrock * 4*ea8dc4b6Seschrock * The contents of this file are subject to the terms of the 5*ea8dc4b6Seschrock * Common Development and Distribution License (the "License"). 6*ea8dc4b6Seschrock * You may not use this file except in compliance with the License. 7*ea8dc4b6Seschrock * 8*ea8dc4b6Seschrock * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*ea8dc4b6Seschrock * or http://www.opensolaris.org/os/licensing. 10*ea8dc4b6Seschrock * See the License for the specific language governing permissions 11*ea8dc4b6Seschrock * and limitations under the License. 12*ea8dc4b6Seschrock * 13*ea8dc4b6Seschrock * When distributing Covered Code, include this CDDL HEADER in each 14*ea8dc4b6Seschrock * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*ea8dc4b6Seschrock * If applicable, add the following below this CDDL HEADER, with the 16*ea8dc4b6Seschrock * fields enclosed by brackets "[]" replaced with your own identifying 17*ea8dc4b6Seschrock * information: Portions Copyright [yyyy] [name of copyright owner] 18*ea8dc4b6Seschrock * 19*ea8dc4b6Seschrock * CDDL HEADER END 20*ea8dc4b6Seschrock */ 21*ea8dc4b6Seschrock /* 22*ea8dc4b6Seschrock * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23*ea8dc4b6Seschrock * Use is subject to license terms. 24*ea8dc4b6Seschrock */ 25*ea8dc4b6Seschrock 26*ea8dc4b6Seschrock #pragma ident "%Z%%M% %I% %E% SMI" 27*ea8dc4b6Seschrock 28*ea8dc4b6Seschrock #include <libzfs.h> 29*ea8dc4b6Seschrock 30*ea8dc4b6Seschrock #undef verify /* both libzfs.h and zfs_context.h want to define this */ 31*ea8dc4b6Seschrock 32*ea8dc4b6Seschrock #include <sys/zfs_context.h> 33*ea8dc4b6Seschrock 34*ea8dc4b6Seschrock #include <errno.h> 35*ea8dc4b6Seschrock #include <fcntl.h> 36*ea8dc4b6Seschrock #include <stdarg.h> 37*ea8dc4b6Seschrock #include <stddef.h> 38*ea8dc4b6Seschrock #include <stdio.h> 39*ea8dc4b6Seschrock #include <stdlib.h> 40*ea8dc4b6Seschrock #include <strings.h> 41*ea8dc4b6Seschrock #include <sys/file.h> 42*ea8dc4b6Seschrock #include <sys/mntent.h> 43*ea8dc4b6Seschrock #include <sys/mnttab.h> 44*ea8dc4b6Seschrock #include <sys/param.h> 45*ea8dc4b6Seschrock #include <sys/stat.h> 46*ea8dc4b6Seschrock 47*ea8dc4b6Seschrock #include <sys/dmu.h> 48*ea8dc4b6Seschrock #include <sys/dmu_objset.h> 49*ea8dc4b6Seschrock #include <sys/dnode.h> 50*ea8dc4b6Seschrock 51*ea8dc4b6Seschrock #include <sys/mkdev.h> 52*ea8dc4b6Seschrock 53*ea8dc4b6Seschrock #include "zinject.h" 54*ea8dc4b6Seschrock 55*ea8dc4b6Seschrock extern void kernel_init(int); 56*ea8dc4b6Seschrock extern void kernel_fini(void); 57*ea8dc4b6Seschrock 58*ea8dc4b6Seschrock static int debug; 59*ea8dc4b6Seschrock 60*ea8dc4b6Seschrock static void 61*ea8dc4b6Seschrock ziprintf(const char *fmt, ...) 62*ea8dc4b6Seschrock { 63*ea8dc4b6Seschrock va_list ap; 64*ea8dc4b6Seschrock 65*ea8dc4b6Seschrock if (!debug) 66*ea8dc4b6Seschrock return; 67*ea8dc4b6Seschrock 68*ea8dc4b6Seschrock va_start(ap, fmt); 69*ea8dc4b6Seschrock (void) vprintf(fmt, ap); 70*ea8dc4b6Seschrock va_end(ap); 71*ea8dc4b6Seschrock } 72*ea8dc4b6Seschrock 73*ea8dc4b6Seschrock /* 74*ea8dc4b6Seschrock * Given a full path to a file, translate into a dataset name and a relative 75*ea8dc4b6Seschrock * path within the dataset. 'dataset' must be at least MAXNAMELEN characters, 76*ea8dc4b6Seschrock * and 'relpath' must be at least MAXPATHLEN characters. We also pass a stat64 77*ea8dc4b6Seschrock * buffer, which we need later to get the object ID. 78*ea8dc4b6Seschrock */ 79*ea8dc4b6Seschrock static int 80*ea8dc4b6Seschrock parse_pathname(const char *fullpath, char *dataset, char *relpath, 81*ea8dc4b6Seschrock struct stat64 *statbuf) 82*ea8dc4b6Seschrock { 83*ea8dc4b6Seschrock struct extmnttab mp; 84*ea8dc4b6Seschrock FILE *fp; 85*ea8dc4b6Seschrock int match; 86*ea8dc4b6Seschrock const char *rel; 87*ea8dc4b6Seschrock 88*ea8dc4b6Seschrock if (fullpath[0] != '/') { 89*ea8dc4b6Seschrock (void) fprintf(stderr, "invalid object '%s': must be full " 90*ea8dc4b6Seschrock "path\n", fullpath); 91*ea8dc4b6Seschrock usage(); 92*ea8dc4b6Seschrock return (-1); 93*ea8dc4b6Seschrock } 94*ea8dc4b6Seschrock 95*ea8dc4b6Seschrock if (strlen(fullpath) >= MAXPATHLEN) { 96*ea8dc4b6Seschrock (void) fprintf(stderr, "invalid object; pathname too long\n"); 97*ea8dc4b6Seschrock return (-1); 98*ea8dc4b6Seschrock } 99*ea8dc4b6Seschrock 100*ea8dc4b6Seschrock if (stat64(fullpath, statbuf) != 0) { 101*ea8dc4b6Seschrock (void) fprintf(stderr, "cannot open '%s': %s\n", 102*ea8dc4b6Seschrock fullpath, strerror(errno)); 103*ea8dc4b6Seschrock return (-1); 104*ea8dc4b6Seschrock } 105*ea8dc4b6Seschrock 106*ea8dc4b6Seschrock if ((fp = fopen(MNTTAB, "r")) == NULL) { 107*ea8dc4b6Seschrock (void) fprintf(stderr, "cannot open /etc/mnttab\n"); 108*ea8dc4b6Seschrock return (-1); 109*ea8dc4b6Seschrock } 110*ea8dc4b6Seschrock 111*ea8dc4b6Seschrock match = 0; 112*ea8dc4b6Seschrock while (getextmntent(fp, &mp, sizeof (mp)) == 0) { 113*ea8dc4b6Seschrock if (makedev(mp.mnt_major, mp.mnt_minor) == statbuf->st_dev) { 114*ea8dc4b6Seschrock match = 1; 115*ea8dc4b6Seschrock break; 116*ea8dc4b6Seschrock } 117*ea8dc4b6Seschrock } 118*ea8dc4b6Seschrock 119*ea8dc4b6Seschrock if (!match) { 120*ea8dc4b6Seschrock (void) fprintf(stderr, "cannot find mountpoint for '%s'\n", 121*ea8dc4b6Seschrock fullpath); 122*ea8dc4b6Seschrock return (-1); 123*ea8dc4b6Seschrock } 124*ea8dc4b6Seschrock 125*ea8dc4b6Seschrock if (strcmp(mp.mnt_fstype, MNTTYPE_ZFS) != 0) { 126*ea8dc4b6Seschrock (void) fprintf(stderr, "invalid path '%s': not a ZFS " 127*ea8dc4b6Seschrock "filesystem\n", fullpath); 128*ea8dc4b6Seschrock return (-1); 129*ea8dc4b6Seschrock } 130*ea8dc4b6Seschrock 131*ea8dc4b6Seschrock if (strncmp(fullpath, mp.mnt_mountp, strlen(mp.mnt_mountp)) != 0) { 132*ea8dc4b6Seschrock (void) fprintf(stderr, "invalid path '%s': mountpoint " 133*ea8dc4b6Seschrock "doesn't match path\n", fullpath); 134*ea8dc4b6Seschrock return (-1); 135*ea8dc4b6Seschrock } 136*ea8dc4b6Seschrock 137*ea8dc4b6Seschrock (void) strcpy(dataset, mp.mnt_special); 138*ea8dc4b6Seschrock 139*ea8dc4b6Seschrock rel = fullpath + strlen(mp.mnt_mountp); 140*ea8dc4b6Seschrock if (rel[0] == '/') 141*ea8dc4b6Seschrock rel++; 142*ea8dc4b6Seschrock (void) strcpy(relpath, rel); 143*ea8dc4b6Seschrock 144*ea8dc4b6Seschrock return (0); 145*ea8dc4b6Seschrock } 146*ea8dc4b6Seschrock 147*ea8dc4b6Seschrock /* 148*ea8dc4b6Seschrock * Convert from a (dataset, path) pair into a (objset, object) pair. Note that 149*ea8dc4b6Seschrock * we grab the object number from the inode number, since looking this up via 150*ea8dc4b6Seschrock * libzpool is a real pain. 151*ea8dc4b6Seschrock */ 152*ea8dc4b6Seschrock /* ARGSUSED */ 153*ea8dc4b6Seschrock static int 154*ea8dc4b6Seschrock object_from_path(const char *dataset, const char *path, struct stat64 *statbuf, 155*ea8dc4b6Seschrock zinject_record_t *record) 156*ea8dc4b6Seschrock { 157*ea8dc4b6Seschrock objset_t *os; 158*ea8dc4b6Seschrock int err; 159*ea8dc4b6Seschrock 160*ea8dc4b6Seschrock /* 161*ea8dc4b6Seschrock * Before doing any libzpool operations, call sync() to ensure that the 162*ea8dc4b6Seschrock * on-disk state is consistent with the in-core state. 163*ea8dc4b6Seschrock */ 164*ea8dc4b6Seschrock sync(); 165*ea8dc4b6Seschrock 166*ea8dc4b6Seschrock if ((err = dmu_objset_open(dataset, DMU_OST_ZFS, 167*ea8dc4b6Seschrock DS_MODE_STANDARD | DS_MODE_READONLY, &os)) != 0) { 168*ea8dc4b6Seschrock (void) fprintf(stderr, "cannot open dataset '%s': %s\n", 169*ea8dc4b6Seschrock dataset, strerror(err)); 170*ea8dc4b6Seschrock return (-1); 171*ea8dc4b6Seschrock } 172*ea8dc4b6Seschrock 173*ea8dc4b6Seschrock record->zi_objset = dmu_objset_id(os); 174*ea8dc4b6Seschrock record->zi_object = statbuf->st_ino; 175*ea8dc4b6Seschrock 176*ea8dc4b6Seschrock dmu_objset_close(os); 177*ea8dc4b6Seschrock 178*ea8dc4b6Seschrock return (0); 179*ea8dc4b6Seschrock } 180*ea8dc4b6Seschrock 181*ea8dc4b6Seschrock /* 182*ea8dc4b6Seschrock * Calculate the real range based on the type, level, and range given. 183*ea8dc4b6Seschrock */ 184*ea8dc4b6Seschrock static int 185*ea8dc4b6Seschrock calculate_range(const char *dataset, err_type_t type, int level, char *range, 186*ea8dc4b6Seschrock zinject_record_t *record) 187*ea8dc4b6Seschrock { 188*ea8dc4b6Seschrock objset_t *os = NULL; 189*ea8dc4b6Seschrock dnode_t *dn = NULL; 190*ea8dc4b6Seschrock int err; 191*ea8dc4b6Seschrock int ret = -1; 192*ea8dc4b6Seschrock 193*ea8dc4b6Seschrock /* 194*ea8dc4b6Seschrock * Determine the numeric range from the string. 195*ea8dc4b6Seschrock */ 196*ea8dc4b6Seschrock if (range == NULL) { 197*ea8dc4b6Seschrock /* 198*ea8dc4b6Seschrock * If range is unspecified, set the range to [0,-1], which 199*ea8dc4b6Seschrock * indicates that the whole object should be treated as an 200*ea8dc4b6Seschrock * error. 201*ea8dc4b6Seschrock */ 202*ea8dc4b6Seschrock record->zi_start = 0; 203*ea8dc4b6Seschrock record->zi_end = -1ULL; 204*ea8dc4b6Seschrock } else { 205*ea8dc4b6Seschrock char *end; 206*ea8dc4b6Seschrock 207*ea8dc4b6Seschrock /* XXX add support for suffixes */ 208*ea8dc4b6Seschrock record->zi_start = strtoull(range, &end, 10); 209*ea8dc4b6Seschrock 210*ea8dc4b6Seschrock 211*ea8dc4b6Seschrock if (*end == '\0') 212*ea8dc4b6Seschrock record->zi_end = record->zi_start + 1; 213*ea8dc4b6Seschrock else if (*end == ',') 214*ea8dc4b6Seschrock record->zi_end = strtoull(end + 1, &end, 10); 215*ea8dc4b6Seschrock 216*ea8dc4b6Seschrock if (*end != '\0') { 217*ea8dc4b6Seschrock (void) fprintf(stderr, "invalid range '%s': must be " 218*ea8dc4b6Seschrock "a numeric range of the form 'start[,end]'\n", 219*ea8dc4b6Seschrock range); 220*ea8dc4b6Seschrock goto out; 221*ea8dc4b6Seschrock } 222*ea8dc4b6Seschrock } 223*ea8dc4b6Seschrock 224*ea8dc4b6Seschrock switch (type) { 225*ea8dc4b6Seschrock case TYPE_DATA: 226*ea8dc4b6Seschrock break; 227*ea8dc4b6Seschrock 228*ea8dc4b6Seschrock case TYPE_DNODE: 229*ea8dc4b6Seschrock /* 230*ea8dc4b6Seschrock * If this is a request to inject faults into the dnode, then we 231*ea8dc4b6Seschrock * must translate the current (objset,object) pair into an 232*ea8dc4b6Seschrock * offset within the metadnode for the objset. Specifying any 233*ea8dc4b6Seschrock * kind of range with type 'dnode' is illegal. 234*ea8dc4b6Seschrock */ 235*ea8dc4b6Seschrock if (range != NULL) { 236*ea8dc4b6Seschrock (void) fprintf(stderr, "range cannot be specified when " 237*ea8dc4b6Seschrock "type is 'dnode'\n"); 238*ea8dc4b6Seschrock goto out; 239*ea8dc4b6Seschrock } 240*ea8dc4b6Seschrock 241*ea8dc4b6Seschrock record->zi_start = record->zi_object * sizeof (dnode_phys_t); 242*ea8dc4b6Seschrock record->zi_end = record->zi_start + sizeof (dnode_phys_t); 243*ea8dc4b6Seschrock record->zi_object = 0; 244*ea8dc4b6Seschrock break; 245*ea8dc4b6Seschrock } 246*ea8dc4b6Seschrock 247*ea8dc4b6Seschrock /* 248*ea8dc4b6Seschrock * Get the dnode associated with object, so we can calculate the block 249*ea8dc4b6Seschrock * size. 250*ea8dc4b6Seschrock */ 251*ea8dc4b6Seschrock if ((err = dmu_objset_open(dataset, DMU_OST_ANY, 252*ea8dc4b6Seschrock DS_MODE_STANDARD | DS_MODE_READONLY, &os)) != 0) { 253*ea8dc4b6Seschrock (void) fprintf(stderr, "cannot open dataset '%s': %s\n", 254*ea8dc4b6Seschrock dataset, strerror(err)); 255*ea8dc4b6Seschrock goto out; 256*ea8dc4b6Seschrock } 257*ea8dc4b6Seschrock 258*ea8dc4b6Seschrock if (record->zi_object == 0) { 259*ea8dc4b6Seschrock dn = os->os->os_meta_dnode; 260*ea8dc4b6Seschrock } else { 261*ea8dc4b6Seschrock err = dnode_hold(os->os, record->zi_object, FTAG, &dn); 262*ea8dc4b6Seschrock if (err != 0) { 263*ea8dc4b6Seschrock (void) fprintf(stderr, "failed to hold dnode " 264*ea8dc4b6Seschrock "for object %llu\n", 265*ea8dc4b6Seschrock (u_longlong_t)record->zi_object); 266*ea8dc4b6Seschrock goto out; 267*ea8dc4b6Seschrock } 268*ea8dc4b6Seschrock } 269*ea8dc4b6Seschrock 270*ea8dc4b6Seschrock 271*ea8dc4b6Seschrock ziprintf("data shift: %d\n", (int)dn->dn_datablkshift); 272*ea8dc4b6Seschrock ziprintf(" ind shift: %d\n", (int)dn->dn_indblkshift); 273*ea8dc4b6Seschrock 274*ea8dc4b6Seschrock /* 275*ea8dc4b6Seschrock * Translate range into block IDs. 276*ea8dc4b6Seschrock */ 277*ea8dc4b6Seschrock if (record->zi_start != 0 || record->zi_end != -1ULL) { 278*ea8dc4b6Seschrock record->zi_start >>= dn->dn_datablkshift; 279*ea8dc4b6Seschrock record->zi_end >>= dn->dn_datablkshift; 280*ea8dc4b6Seschrock } 281*ea8dc4b6Seschrock 282*ea8dc4b6Seschrock /* 283*ea8dc4b6Seschrock * Check level, and then translate level 0 blkids into ranges 284*ea8dc4b6Seschrock * appropriate for level of indirection. 285*ea8dc4b6Seschrock */ 286*ea8dc4b6Seschrock record->zi_level = level; 287*ea8dc4b6Seschrock if (level > 0) { 288*ea8dc4b6Seschrock ziprintf("level 0 blkid range: [%llu, %llu]\n", 289*ea8dc4b6Seschrock record->zi_start, record->zi_end); 290*ea8dc4b6Seschrock 291*ea8dc4b6Seschrock if (level >= dn->dn_nlevels) { 292*ea8dc4b6Seschrock (void) fprintf(stderr, "level %d exceeds max level " 293*ea8dc4b6Seschrock "of object (%d)\n", level, dn->dn_nlevels - 1); 294*ea8dc4b6Seschrock goto out; 295*ea8dc4b6Seschrock } 296*ea8dc4b6Seschrock 297*ea8dc4b6Seschrock if (record->zi_start != 0 || record->zi_end != 0) { 298*ea8dc4b6Seschrock int shift = dn->dn_indblkshift - SPA_BLKPTRSHIFT; 299*ea8dc4b6Seschrock 300*ea8dc4b6Seschrock for (; level > 0; level--) { 301*ea8dc4b6Seschrock record->zi_start >>= shift; 302*ea8dc4b6Seschrock record->zi_end >>= shift; 303*ea8dc4b6Seschrock } 304*ea8dc4b6Seschrock } 305*ea8dc4b6Seschrock } 306*ea8dc4b6Seschrock 307*ea8dc4b6Seschrock ret = 0; 308*ea8dc4b6Seschrock out: 309*ea8dc4b6Seschrock if (dn) { 310*ea8dc4b6Seschrock if (dn != os->os->os_meta_dnode) 311*ea8dc4b6Seschrock dnode_rele(dn, FTAG); 312*ea8dc4b6Seschrock } 313*ea8dc4b6Seschrock if (os) 314*ea8dc4b6Seschrock dmu_objset_close(os); 315*ea8dc4b6Seschrock 316*ea8dc4b6Seschrock return (ret); 317*ea8dc4b6Seschrock } 318*ea8dc4b6Seschrock 319*ea8dc4b6Seschrock int 320*ea8dc4b6Seschrock translate_record(err_type_t type, const char *object, const char *range, 321*ea8dc4b6Seschrock int level, zinject_record_t *record, char *poolname, char *dataset) 322*ea8dc4b6Seschrock { 323*ea8dc4b6Seschrock char path[MAXPATHLEN]; 324*ea8dc4b6Seschrock char *slash; 325*ea8dc4b6Seschrock struct stat64 statbuf; 326*ea8dc4b6Seschrock int ret = -1; 327*ea8dc4b6Seschrock 328*ea8dc4b6Seschrock kernel_init(FREAD); 329*ea8dc4b6Seschrock 330*ea8dc4b6Seschrock debug = (getenv("ZINJECT_DEBUG") != NULL); 331*ea8dc4b6Seschrock 332*ea8dc4b6Seschrock ziprintf("translating: %s\n", object); 333*ea8dc4b6Seschrock 334*ea8dc4b6Seschrock if (MOS_TYPE(type)) { 335*ea8dc4b6Seschrock /* 336*ea8dc4b6Seschrock * MOS objects are treated specially. 337*ea8dc4b6Seschrock */ 338*ea8dc4b6Seschrock switch (type) { 339*ea8dc4b6Seschrock case TYPE_MOS: 340*ea8dc4b6Seschrock record->zi_type = 0; 341*ea8dc4b6Seschrock break; 342*ea8dc4b6Seschrock case TYPE_MOSDIR: 343*ea8dc4b6Seschrock record->zi_type = DMU_OT_OBJECT_DIRECTORY; 344*ea8dc4b6Seschrock break; 345*ea8dc4b6Seschrock case TYPE_METASLAB: 346*ea8dc4b6Seschrock record->zi_type = DMU_OT_OBJECT_ARRAY; 347*ea8dc4b6Seschrock break; 348*ea8dc4b6Seschrock case TYPE_CONFIG: 349*ea8dc4b6Seschrock record->zi_type = DMU_OT_PACKED_NVLIST; 350*ea8dc4b6Seschrock break; 351*ea8dc4b6Seschrock case TYPE_BPLIST: 352*ea8dc4b6Seschrock record->zi_type = DMU_OT_BPLIST; 353*ea8dc4b6Seschrock break; 354*ea8dc4b6Seschrock case TYPE_SPACEMAP: 355*ea8dc4b6Seschrock record->zi_type = DMU_OT_SPACE_MAP; 356*ea8dc4b6Seschrock break; 357*ea8dc4b6Seschrock case TYPE_ERRLOG: 358*ea8dc4b6Seschrock record->zi_type = DMU_OT_ERROR_LOG; 359*ea8dc4b6Seschrock break; 360*ea8dc4b6Seschrock } 361*ea8dc4b6Seschrock 362*ea8dc4b6Seschrock dataset[0] = '\0'; 363*ea8dc4b6Seschrock (void) strcpy(poolname, object); 364*ea8dc4b6Seschrock return (0); 365*ea8dc4b6Seschrock } 366*ea8dc4b6Seschrock 367*ea8dc4b6Seschrock /* 368*ea8dc4b6Seschrock * Convert a full path into a (dataset, file) pair. 369*ea8dc4b6Seschrock */ 370*ea8dc4b6Seschrock if (parse_pathname(object, dataset, path, &statbuf) != 0) 371*ea8dc4b6Seschrock goto err; 372*ea8dc4b6Seschrock 373*ea8dc4b6Seschrock ziprintf(" dataset: %s\n", dataset); 374*ea8dc4b6Seschrock ziprintf(" path: %s\n", path); 375*ea8dc4b6Seschrock 376*ea8dc4b6Seschrock /* 377*ea8dc4b6Seschrock * Convert (dataset, file) into (objset, object) 378*ea8dc4b6Seschrock */ 379*ea8dc4b6Seschrock if (object_from_path(dataset, path, &statbuf, record) != 0) 380*ea8dc4b6Seschrock goto err; 381*ea8dc4b6Seschrock 382*ea8dc4b6Seschrock ziprintf("raw objset: %llu\n", record->zi_objset); 383*ea8dc4b6Seschrock ziprintf("raw object: %llu\n", record->zi_object); 384*ea8dc4b6Seschrock 385*ea8dc4b6Seschrock /* 386*ea8dc4b6Seschrock * For the given object, calculate the real (type, level, range) 387*ea8dc4b6Seschrock */ 388*ea8dc4b6Seschrock if (calculate_range(dataset, type, level, (char *)range, record) != 0) 389*ea8dc4b6Seschrock goto err; 390*ea8dc4b6Seschrock 391*ea8dc4b6Seschrock ziprintf(" objset: %llu\n", record->zi_objset); 392*ea8dc4b6Seschrock ziprintf(" object: %llu\n", record->zi_object); 393*ea8dc4b6Seschrock if (record->zi_start == 0 && 394*ea8dc4b6Seschrock record->zi_end == -1ULL) 395*ea8dc4b6Seschrock ziprintf(" range: all\n"); 396*ea8dc4b6Seschrock else 397*ea8dc4b6Seschrock ziprintf(" range: [%llu, %llu]\n", record->zi_start, 398*ea8dc4b6Seschrock record->zi_end); 399*ea8dc4b6Seschrock 400*ea8dc4b6Seschrock /* 401*ea8dc4b6Seschrock * Copy the pool name 402*ea8dc4b6Seschrock */ 403*ea8dc4b6Seschrock (void) strcpy(poolname, dataset); 404*ea8dc4b6Seschrock if ((slash = strchr(poolname, '/')) != NULL) 405*ea8dc4b6Seschrock *slash = '\0'; 406*ea8dc4b6Seschrock 407*ea8dc4b6Seschrock ret = 0; 408*ea8dc4b6Seschrock 409*ea8dc4b6Seschrock err: 410*ea8dc4b6Seschrock kernel_fini(); 411*ea8dc4b6Seschrock return (ret); 412*ea8dc4b6Seschrock } 413*ea8dc4b6Seschrock 414*ea8dc4b6Seschrock int 415*ea8dc4b6Seschrock translate_raw(const char *str, zinject_record_t *record) 416*ea8dc4b6Seschrock { 417*ea8dc4b6Seschrock /* 418*ea8dc4b6Seschrock * A raw bookmark of the form objset:object:level:blkid, where each 419*ea8dc4b6Seschrock * number is a hexidecimal value. 420*ea8dc4b6Seschrock */ 421*ea8dc4b6Seschrock if (sscanf(str, "%llx:%llx:%x:%llx", (u_longlong_t *)&record->zi_objset, 422*ea8dc4b6Seschrock (u_longlong_t *)&record->zi_object, &record->zi_level, 423*ea8dc4b6Seschrock (u_longlong_t *)&record->zi_start) != 4) { 424*ea8dc4b6Seschrock (void) fprintf(stderr, "bad raw spec '%s': must be of the form " 425*ea8dc4b6Seschrock "'objset:object:level:blkid'\n", str); 426*ea8dc4b6Seschrock return (-1); 427*ea8dc4b6Seschrock } 428*ea8dc4b6Seschrock 429*ea8dc4b6Seschrock record->zi_end = record->zi_start; 430*ea8dc4b6Seschrock 431*ea8dc4b6Seschrock return (0); 432*ea8dc4b6Seschrock } 433*ea8dc4b6Seschrock 434*ea8dc4b6Seschrock int 435*ea8dc4b6Seschrock translate_device(const char *pool, const char *device, zinject_record_t *record) 436*ea8dc4b6Seschrock { 437*ea8dc4b6Seschrock char *end; 438*ea8dc4b6Seschrock zpool_handle_t *zhp; 439*ea8dc4b6Seschrock 440*ea8dc4b6Seschrock /* 441*ea8dc4b6Seschrock * Given a device name or GUID, create an appropriate injection record 442*ea8dc4b6Seschrock * with zi_guid set. 443*ea8dc4b6Seschrock */ 444*ea8dc4b6Seschrock if ((zhp = zpool_open(pool)) == NULL) 445*ea8dc4b6Seschrock return (-1); 446*ea8dc4b6Seschrock 447*ea8dc4b6Seschrock record->zi_guid = strtoull(device, &end, 16); 448*ea8dc4b6Seschrock if (record->zi_guid == 0 || *end != '\0') 449*ea8dc4b6Seschrock record->zi_guid = zpool_vdev_to_guid(zhp, device); 450*ea8dc4b6Seschrock 451*ea8dc4b6Seschrock if (record->zi_guid == 0) { 452*ea8dc4b6Seschrock (void) fprintf(stderr, "cannot find device '%s' in pool '%s'\n", 453*ea8dc4b6Seschrock device, pool); 454*ea8dc4b6Seschrock return (-1); 455*ea8dc4b6Seschrock } 456*ea8dc4b6Seschrock 457*ea8dc4b6Seschrock return (0); 458*ea8dc4b6Seschrock } 459