The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/openzfs/cmd/zhack.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * CDDL HEADER START
    3  *
    4  * The contents of this file are subject to the terms of the
    5  * Common Development and Distribution License (the "License").
    6  * You may not use this file except in compliance with the License.
    7  *
    8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
    9  * or https://opensource.org/licenses/CDDL-1.0.
   10  * See the License for the specific language governing permissions
   11  * and limitations under the License.
   12  *
   13  * When distributing Covered Code, include this CDDL HEADER in each
   14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
   15  * If applicable, add the following below this CDDL HEADER, with the
   16  * fields enclosed by brackets "[]" replaced with your own identifying
   17  * information: Portions Copyright [yyyy] [name of copyright owner]
   18  *
   19  * CDDL HEADER END
   20  */
   21 
   22 /*
   23  * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
   24  * Copyright (c) 2013 Steven Hartland. All rights reserved.
   25  */
   26 
   27 /*
   28  * zhack is a debugging tool that can write changes to ZFS pool using libzpool
   29  * for testing purposes. Altering pools with zhack is unsupported and may
   30  * result in corrupted pools.
   31  */
   32 
   33 #include <zfs_prop.h>
   34 #include <stdio.h>
   35 #include <stdlib.h>
   36 #include <ctype.h>
   37 #include <sys/stat.h>
   38 #include <sys/zfs_context.h>
   39 #include <sys/spa.h>
   40 #include <sys/spa_impl.h>
   41 #include <sys/dmu.h>
   42 #include <sys/zap.h>
   43 #include <sys/zfs_znode.h>
   44 #include <sys/dsl_synctask.h>
   45 #include <sys/vdev.h>
   46 #include <sys/vdev_impl.h>
   47 #include <sys/fs/zfs.h>
   48 #include <sys/dmu_objset.h>
   49 #include <sys/dsl_pool.h>
   50 #include <sys/zio_checksum.h>
   51 #include <sys/zio_compress.h>
   52 #include <sys/zfeature.h>
   53 #include <sys/dmu_tx.h>
   54 #include <zfeature_common.h>
   55 #include <libzutil.h>
   56 
   57 static importargs_t g_importargs;
   58 static char *g_pool;
   59 static boolean_t g_readonly;
   60 
   61 static __attribute__((noreturn)) void
   62 usage(void)
   63 {
   64         (void) fprintf(stderr,
   65             "Usage: zhack [-c cachefile] [-d dir] <subcommand> <args> ...\n"
   66             "where <subcommand> <args> is one of the following:\n"
   67             "\n");
   68 
   69         (void) fprintf(stderr,
   70             "    feature stat <pool>\n"
   71             "        print information about enabled features\n"
   72             "    feature enable [-r] [-d desc] <pool> <feature>\n"
   73             "        add a new enabled feature to the pool\n"
   74             "        -d <desc> sets the feature's description\n"
   75             "        -r set read-only compatible flag for feature\n"
   76             "    feature ref [-md] <pool> <feature>\n"
   77             "        change the refcount on the given feature\n"
   78             "        -d decrease instead of increase the refcount\n"
   79             "        -m add the feature to the label if increasing refcount\n"
   80             "\n"
   81             "    <feature> : should be a feature guid\n"
   82             "\n"
   83             "    label repair <device>\n"
   84             "        repair corrupted label checksums\n"
   85             "\n"
   86             "    <device> : path to vdev\n");
   87         exit(1);
   88 }
   89 
   90 
   91 static __attribute__((format(printf, 3, 4))) __attribute__((noreturn)) void
   92 fatal(spa_t *spa, const void *tag, const char *fmt, ...)
   93 {
   94         va_list ap;
   95 
   96         if (spa != NULL) {
   97                 spa_close(spa, tag);
   98                 (void) spa_export(g_pool, NULL, B_TRUE, B_FALSE);
   99         }
  100 
  101         va_start(ap, fmt);
  102         (void) fputs("zhack: ", stderr);
  103         (void) vfprintf(stderr, fmt, ap);
  104         va_end(ap);
  105         (void) fputc('\n', stderr);
  106 
  107         exit(1);
  108 }
  109 
  110 static int
  111 space_delta_cb(dmu_object_type_t bonustype, const void *data,
  112     zfs_file_info_t *zoi)
  113 {
  114         (void) data, (void) zoi;
  115 
  116         /*
  117          * Is it a valid type of object to track?
  118          */
  119         if (bonustype != DMU_OT_ZNODE && bonustype != DMU_OT_SA)
  120                 return (ENOENT);
  121         (void) fprintf(stderr, "modifying object that needs user accounting");
  122         abort();
  123 }
  124 
  125 /*
  126  * Target is the dataset whose pool we want to open.
  127  */
  128 static void
  129 zhack_import(char *target, boolean_t readonly)
  130 {
  131         nvlist_t *config;
  132         nvlist_t *props;
  133         int error;
  134 
  135         kernel_init(readonly ? SPA_MODE_READ :
  136             (SPA_MODE_READ | SPA_MODE_WRITE));
  137 
  138         dmu_objset_register_type(DMU_OST_ZFS, space_delta_cb);
  139 
  140         g_readonly = readonly;
  141         g_importargs.can_be_active = readonly;
  142         g_pool = strdup(target);
  143 
  144         libpc_handle_t lpch = {
  145                 .lpc_lib_handle = NULL,
  146                 .lpc_ops = &libzpool_config_ops,
  147                 .lpc_printerr = B_TRUE
  148         };
  149         error = zpool_find_config(&lpch, target, &config, &g_importargs);
  150         if (error)
  151                 fatal(NULL, FTAG, "cannot import '%s'", target);
  152 
  153         props = NULL;
  154         if (readonly) {
  155                 VERIFY(nvlist_alloc(&props, NV_UNIQUE_NAME, 0) == 0);
  156                 VERIFY(nvlist_add_uint64(props,
  157                     zpool_prop_to_name(ZPOOL_PROP_READONLY), 1) == 0);
  158         }
  159 
  160         zfeature_checks_disable = B_TRUE;
  161         error = spa_import(target, config, props,
  162             (readonly ?  ZFS_IMPORT_SKIP_MMP : ZFS_IMPORT_NORMAL));
  163         fnvlist_free(config);
  164         zfeature_checks_disable = B_FALSE;
  165         if (error == EEXIST)
  166                 error = 0;
  167 
  168         if (error)
  169                 fatal(NULL, FTAG, "can't import '%s': %s", target,
  170                     strerror(error));
  171 }
  172 
  173 static void
  174 zhack_spa_open(char *target, boolean_t readonly, const void *tag, spa_t **spa)
  175 {
  176         int err;
  177 
  178         zhack_import(target, readonly);
  179 
  180         zfeature_checks_disable = B_TRUE;
  181         err = spa_open(target, spa, tag);
  182         zfeature_checks_disable = B_FALSE;
  183 
  184         if (err != 0)
  185                 fatal(*spa, FTAG, "cannot open '%s': %s", target,
  186                     strerror(err));
  187         if (spa_version(*spa) < SPA_VERSION_FEATURES) {
  188                 fatal(*spa, FTAG, "'%s' has version %d, features not enabled",
  189                     target, (int)spa_version(*spa));
  190         }
  191 }
  192 
  193 static void
  194 dump_obj(objset_t *os, uint64_t obj, const char *name)
  195 {
  196         zap_cursor_t zc;
  197         zap_attribute_t za;
  198 
  199         (void) printf("%s_obj:\n", name);
  200 
  201         for (zap_cursor_init(&zc, os, obj);
  202             zap_cursor_retrieve(&zc, &za) == 0;
  203             zap_cursor_advance(&zc)) {
  204                 if (za.za_integer_length == 8) {
  205                         ASSERT(za.za_num_integers == 1);
  206                         (void) printf("\t%s = %llu\n",
  207                             za.za_name, (u_longlong_t)za.za_first_integer);
  208                 } else {
  209                         ASSERT(za.za_integer_length == 1);
  210                         char val[1024];
  211                         VERIFY(zap_lookup(os, obj, za.za_name,
  212                             1, sizeof (val), val) == 0);
  213                         (void) printf("\t%s = %s\n", za.za_name, val);
  214                 }
  215         }
  216         zap_cursor_fini(&zc);
  217 }
  218 
  219 static void
  220 dump_mos(spa_t *spa)
  221 {
  222         nvlist_t *nv = spa->spa_label_features;
  223         nvpair_t *pair;
  224 
  225         (void) printf("label config:\n");
  226         for (pair = nvlist_next_nvpair(nv, NULL);
  227             pair != NULL;
  228             pair = nvlist_next_nvpair(nv, pair)) {
  229                 (void) printf("\t%s\n", nvpair_name(pair));
  230         }
  231 }
  232 
  233 static void
  234 zhack_do_feature_stat(int argc, char **argv)
  235 {
  236         spa_t *spa;
  237         objset_t *os;
  238         char *target;
  239 
  240         argc--;
  241         argv++;
  242 
  243         if (argc < 1) {
  244                 (void) fprintf(stderr, "error: missing pool name\n");
  245                 usage();
  246         }
  247         target = argv[0];
  248 
  249         zhack_spa_open(target, B_TRUE, FTAG, &spa);
  250         os = spa->spa_meta_objset;
  251 
  252         dump_obj(os, spa->spa_feat_for_read_obj, "for_read");
  253         dump_obj(os, spa->spa_feat_for_write_obj, "for_write");
  254         dump_obj(os, spa->spa_feat_desc_obj, "descriptions");
  255         if (spa_feature_is_active(spa, SPA_FEATURE_ENABLED_TXG)) {
  256                 dump_obj(os, spa->spa_feat_enabled_txg_obj, "enabled_txg");
  257         }
  258         dump_mos(spa);
  259 
  260         spa_close(spa, FTAG);
  261 }
  262 
  263 static void
  264 zhack_feature_enable_sync(void *arg, dmu_tx_t *tx)
  265 {
  266         spa_t *spa = dmu_tx_pool(tx)->dp_spa;
  267         zfeature_info_t *feature = arg;
  268 
  269         feature_enable_sync(spa, feature, tx);
  270 
  271         spa_history_log_internal(spa, "zhack enable feature", tx,
  272             "name=%s flags=%u",
  273             feature->fi_guid, feature->fi_flags);
  274 }
  275 
  276 static void
  277 zhack_do_feature_enable(int argc, char **argv)
  278 {
  279         int c;
  280         char *desc, *target;
  281         spa_t *spa;
  282         objset_t *mos;
  283         zfeature_info_t feature;
  284         const spa_feature_t nodeps[] = { SPA_FEATURE_NONE };
  285 
  286         /*
  287          * Features are not added to the pool's label until their refcounts
  288          * are incremented, so fi_mos can just be left as false for now.
  289          */
  290         desc = NULL;
  291         feature.fi_uname = "zhack";
  292         feature.fi_flags = 0;
  293         feature.fi_depends = nodeps;
  294         feature.fi_feature = SPA_FEATURE_NONE;
  295 
  296         optind = 1;
  297         while ((c = getopt(argc, argv, "+rd:")) != -1) {
  298                 switch (c) {
  299                 case 'r':
  300                         feature.fi_flags |= ZFEATURE_FLAG_READONLY_COMPAT;
  301                         break;
  302                 case 'd':
  303                         if (desc != NULL)
  304                                 free(desc);
  305                         desc = strdup(optarg);
  306                         break;
  307                 default:
  308                         usage();
  309                         break;
  310                 }
  311         }
  312 
  313         if (desc == NULL)
  314                 desc = strdup("zhack injected");
  315         feature.fi_desc = desc;
  316 
  317         argc -= optind;
  318         argv += optind;
  319 
  320         if (argc < 2) {
  321                 (void) fprintf(stderr, "error: missing feature or pool name\n");
  322                 usage();
  323         }
  324         target = argv[0];
  325         feature.fi_guid = argv[1];
  326 
  327         if (!zfeature_is_valid_guid(feature.fi_guid))
  328                 fatal(NULL, FTAG, "invalid feature guid: %s", feature.fi_guid);
  329 
  330         zhack_spa_open(target, B_FALSE, FTAG, &spa);
  331         mos = spa->spa_meta_objset;
  332 
  333         if (zfeature_is_supported(feature.fi_guid))
  334                 fatal(spa, FTAG, "'%s' is a real feature, will not enable",
  335                     feature.fi_guid);
  336         if (0 == zap_contains(mos, spa->spa_feat_desc_obj, feature.fi_guid))
  337                 fatal(spa, FTAG, "feature already enabled: %s",
  338                     feature.fi_guid);
  339 
  340         VERIFY0(dsl_sync_task(spa_name(spa), NULL,
  341             zhack_feature_enable_sync, &feature, 5, ZFS_SPACE_CHECK_NORMAL));
  342 
  343         spa_close(spa, FTAG);
  344 
  345         free(desc);
  346 }
  347 
  348 static void
  349 feature_incr_sync(void *arg, dmu_tx_t *tx)
  350 {
  351         spa_t *spa = dmu_tx_pool(tx)->dp_spa;
  352         zfeature_info_t *feature = arg;
  353         uint64_t refcount;
  354 
  355         VERIFY0(feature_get_refcount_from_disk(spa, feature, &refcount));
  356         feature_sync(spa, feature, refcount + 1, tx);
  357         spa_history_log_internal(spa, "zhack feature incr", tx,
  358             "name=%s", feature->fi_guid);
  359 }
  360 
  361 static void
  362 feature_decr_sync(void *arg, dmu_tx_t *tx)
  363 {
  364         spa_t *spa = dmu_tx_pool(tx)->dp_spa;
  365         zfeature_info_t *feature = arg;
  366         uint64_t refcount;
  367 
  368         VERIFY0(feature_get_refcount_from_disk(spa, feature, &refcount));
  369         feature_sync(spa, feature, refcount - 1, tx);
  370         spa_history_log_internal(spa, "zhack feature decr", tx,
  371             "name=%s", feature->fi_guid);
  372 }
  373 
  374 static void
  375 zhack_do_feature_ref(int argc, char **argv)
  376 {
  377         int c;
  378         char *target;
  379         boolean_t decr = B_FALSE;
  380         spa_t *spa;
  381         objset_t *mos;
  382         zfeature_info_t feature;
  383         const spa_feature_t nodeps[] = { SPA_FEATURE_NONE };
  384 
  385         /*
  386          * fi_desc does not matter here because it was written to disk
  387          * when the feature was enabled, but we need to properly set the
  388          * feature for read or write based on the information we read off
  389          * disk later.
  390          */
  391         feature.fi_uname = "zhack";
  392         feature.fi_flags = 0;
  393         feature.fi_desc = NULL;
  394         feature.fi_depends = nodeps;
  395         feature.fi_feature = SPA_FEATURE_NONE;
  396 
  397         optind = 1;
  398         while ((c = getopt(argc, argv, "+md")) != -1) {
  399                 switch (c) {
  400                 case 'm':
  401                         feature.fi_flags |= ZFEATURE_FLAG_MOS;
  402                         break;
  403                 case 'd':
  404                         decr = B_TRUE;
  405                         break;
  406                 default:
  407                         usage();
  408                         break;
  409                 }
  410         }
  411         argc -= optind;
  412         argv += optind;
  413 
  414         if (argc < 2) {
  415                 (void) fprintf(stderr, "error: missing feature or pool name\n");
  416                 usage();
  417         }
  418         target = argv[0];
  419         feature.fi_guid = argv[1];
  420 
  421         if (!zfeature_is_valid_guid(feature.fi_guid))
  422                 fatal(NULL, FTAG, "invalid feature guid: %s", feature.fi_guid);
  423 
  424         zhack_spa_open(target, B_FALSE, FTAG, &spa);
  425         mos = spa->spa_meta_objset;
  426 
  427         if (zfeature_is_supported(feature.fi_guid)) {
  428                 fatal(spa, FTAG,
  429                     "'%s' is a real feature, will not change refcount",
  430                     feature.fi_guid);
  431         }
  432 
  433         if (0 == zap_contains(mos, spa->spa_feat_for_read_obj,
  434             feature.fi_guid)) {
  435                 feature.fi_flags &= ~ZFEATURE_FLAG_READONLY_COMPAT;
  436         } else if (0 == zap_contains(mos, spa->spa_feat_for_write_obj,
  437             feature.fi_guid)) {
  438                 feature.fi_flags |= ZFEATURE_FLAG_READONLY_COMPAT;
  439         } else {
  440                 fatal(spa, FTAG, "feature is not enabled: %s", feature.fi_guid);
  441         }
  442 
  443         if (decr) {
  444                 uint64_t count;
  445                 if (feature_get_refcount_from_disk(spa, &feature,
  446                     &count) == 0 && count == 0) {
  447                         fatal(spa, FTAG, "feature refcount already 0: %s",
  448                             feature.fi_guid);
  449                 }
  450         }
  451 
  452         VERIFY0(dsl_sync_task(spa_name(spa), NULL,
  453             decr ? feature_decr_sync : feature_incr_sync, &feature,
  454             5, ZFS_SPACE_CHECK_NORMAL));
  455 
  456         spa_close(spa, FTAG);
  457 }
  458 
  459 static int
  460 zhack_do_feature(int argc, char **argv)
  461 {
  462         char *subcommand;
  463 
  464         argc--;
  465         argv++;
  466         if (argc == 0) {
  467                 (void) fprintf(stderr,
  468                     "error: no feature operation specified\n");
  469                 usage();
  470         }
  471 
  472         subcommand = argv[0];
  473         if (strcmp(subcommand, "stat") == 0) {
  474                 zhack_do_feature_stat(argc, argv);
  475         } else if (strcmp(subcommand, "enable") == 0) {
  476                 zhack_do_feature_enable(argc, argv);
  477         } else if (strcmp(subcommand, "ref") == 0) {
  478                 zhack_do_feature_ref(argc, argv);
  479         } else {
  480                 (void) fprintf(stderr, "error: unknown subcommand: %s\n",
  481                     subcommand);
  482                 usage();
  483         }
  484 
  485         return (0);
  486 }
  487 
  488 static int
  489 zhack_repair_label_cksum(int argc, char **argv)
  490 {
  491         zio_checksum_info_t *ci = &zio_checksum_table[ZIO_CHECKSUM_LABEL];
  492         const char *cfg_keys[] = { ZPOOL_CONFIG_VERSION,
  493             ZPOOL_CONFIG_POOL_STATE, ZPOOL_CONFIG_GUID };
  494         boolean_t labels_repaired[VDEV_LABELS] = {0};
  495         boolean_t repaired = B_FALSE;
  496         vdev_label_t labels[VDEV_LABELS] = {{{0}}};
  497         struct stat st;
  498         int fd;
  499 
  500         abd_init();
  501 
  502         argc -= 1;
  503         argv += 1;
  504 
  505         if (argc < 1) {
  506                 (void) fprintf(stderr, "error: missing device\n");
  507                 usage();
  508         }
  509 
  510         if ((fd = open(argv[0], O_RDWR)) == -1)
  511                 fatal(NULL, FTAG, "cannot open '%s': %s", argv[0],
  512                     strerror(errno));
  513 
  514         if (stat(argv[0], &st) != 0)
  515                 fatal(NULL, FTAG, "cannot stat '%s': %s", argv[0],
  516                     strerror(errno));
  517 
  518         for (int l = 0; l < VDEV_LABELS; l++) {
  519                 uint64_t label_offset, offset;
  520                 zio_cksum_t expected_cksum;
  521                 zio_cksum_t actual_cksum;
  522                 zio_cksum_t verifier;
  523                 zio_eck_t *eck;
  524                 nvlist_t *cfg;
  525                 int byteswap;
  526                 uint64_t val;
  527                 ssize_t err;
  528 
  529                 vdev_label_t *vl = &labels[l];
  530 
  531                 label_offset = vdev_label_offset(st.st_size, l, 0);
  532                 err = pread64(fd, vl, sizeof (vdev_label_t), label_offset);
  533                 if (err == -1) {
  534                         (void) fprintf(stderr, "error: cannot read "
  535                             "label %d: %s\n", l, strerror(errno));
  536                         continue;
  537                 } else if (err != sizeof (vdev_label_t)) {
  538                         (void) fprintf(stderr, "error: bad label %d read size "
  539                             "\n", l);
  540                         continue;
  541                 }
  542 
  543                 err = nvlist_unpack(vl->vl_vdev_phys.vp_nvlist,
  544                     VDEV_PHYS_SIZE - sizeof (zio_eck_t), &cfg, 0);
  545                 if (err) {
  546                         (void) fprintf(stderr, "error: cannot unpack nvlist "
  547                             "label %d\n", l);
  548                         continue;
  549                 }
  550 
  551                 for (int i = 0; i < ARRAY_SIZE(cfg_keys); i++) {
  552                         err = nvlist_lookup_uint64(cfg, cfg_keys[i], &val);
  553                         if (err) {
  554                                 (void) fprintf(stderr, "error: label %d: "
  555                                     "cannot find nvlist key %s\n",
  556                                     l, cfg_keys[i]);
  557                                 continue;
  558                         }
  559                 }
  560 
  561                 void *data = (char *)vl + offsetof(vdev_label_t, vl_vdev_phys);
  562                 eck = (zio_eck_t *)((char *)(data) + VDEV_PHYS_SIZE) - 1;
  563 
  564                 offset = label_offset + offsetof(vdev_label_t, vl_vdev_phys);
  565                 ZIO_SET_CHECKSUM(&verifier, offset, 0, 0, 0);
  566 
  567                 byteswap = (eck->zec_magic == BSWAP_64(ZEC_MAGIC));
  568                 if (byteswap)
  569                         byteswap_uint64_array(&verifier, sizeof (zio_cksum_t));
  570 
  571                 expected_cksum = eck->zec_cksum;
  572                 eck->zec_cksum = verifier;
  573 
  574                 abd_t *abd = abd_get_from_buf(data, VDEV_PHYS_SIZE);
  575                 ci->ci_func[byteswap](abd, VDEV_PHYS_SIZE, NULL, &actual_cksum);
  576                 abd_free(abd);
  577 
  578                 if (byteswap)
  579                         byteswap_uint64_array(&expected_cksum,
  580                             sizeof (zio_cksum_t));
  581 
  582                 if (ZIO_CHECKSUM_EQUAL(actual_cksum, expected_cksum))
  583                         continue;
  584 
  585                 eck->zec_cksum = actual_cksum;
  586 
  587                 err = pwrite64(fd, data, VDEV_PHYS_SIZE, offset);
  588                 if (err == -1) {
  589                         (void) fprintf(stderr, "error: cannot write "
  590                             "label %d: %s\n", l, strerror(errno));
  591                         continue;
  592                 } else if (err != VDEV_PHYS_SIZE) {
  593                         (void) fprintf(stderr, "error: bad write size "
  594                             "label %d\n", l);
  595                         continue;
  596                 }
  597 
  598                 fsync(fd);
  599 
  600                 labels_repaired[l] = B_TRUE;
  601         }
  602 
  603         close(fd);
  604 
  605         abd_fini();
  606 
  607         for (int l = 0; l < VDEV_LABELS; l++) {
  608                 (void) printf("label %d: %s\n", l,
  609                     labels_repaired[l] ? "repaired" : "skipped");
  610                 repaired |= labels_repaired[l];
  611         }
  612 
  613         if (repaired)
  614                 return (0);
  615 
  616         return (1);
  617 }
  618 
  619 static int
  620 zhack_do_label(int argc, char **argv)
  621 {
  622         char *subcommand;
  623         int err;
  624 
  625         argc--;
  626         argv++;
  627         if (argc == 0) {
  628                 (void) fprintf(stderr,
  629                     "error: no label operation specified\n");
  630                 usage();
  631         }
  632 
  633         subcommand = argv[0];
  634         if (strcmp(subcommand, "repair") == 0) {
  635                 err = zhack_repair_label_cksum(argc, argv);
  636         } else {
  637                 (void) fprintf(stderr, "error: unknown subcommand: %s\n",
  638                     subcommand);
  639                 usage();
  640         }
  641 
  642         return (err);
  643 }
  644 
  645 #define MAX_NUM_PATHS 1024
  646 
  647 int
  648 main(int argc, char **argv)
  649 {
  650         char *path[MAX_NUM_PATHS];
  651         const char *subcommand;
  652         int rv = 0;
  653         int c;
  654 
  655         g_importargs.path = path;
  656 
  657         dprintf_setup(&argc, argv);
  658         zfs_prop_init();
  659 
  660         while ((c = getopt(argc, argv, "+c:d:")) != -1) {
  661                 switch (c) {
  662                 case 'c':
  663                         g_importargs.cachefile = optarg;
  664                         break;
  665                 case 'd':
  666                         assert(g_importargs.paths < MAX_NUM_PATHS);
  667                         g_importargs.path[g_importargs.paths++] = optarg;
  668                         break;
  669                 default:
  670                         usage();
  671                         break;
  672                 }
  673         }
  674 
  675         argc -= optind;
  676         argv += optind;
  677         optind = 1;
  678 
  679         if (argc == 0) {
  680                 (void) fprintf(stderr, "error: no command specified\n");
  681                 usage();
  682         }
  683 
  684         subcommand = argv[0];
  685 
  686         if (strcmp(subcommand, "feature") == 0) {
  687                 rv = zhack_do_feature(argc, argv);
  688         } else if (strcmp(subcommand, "label") == 0) {
  689                 return (zhack_do_label(argc, argv));
  690         } else {
  691                 (void) fprintf(stderr, "error: unknown subcommand: %s\n",
  692                     subcommand);
  693                 usage();
  694         }
  695 
  696         if (!g_readonly && spa_export(g_pool, NULL, B_TRUE, B_FALSE) != 0) {
  697                 fatal(NULL, FTAG, "pool export failed; "
  698                     "changes may not be committed to disk\n");
  699         }
  700 
  701         kernel_fini();
  702 
  703         return (rv);
  704 }

Cache object: e76dde2f61689a706e2090da86319143


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.