"Fossies" - the Fresh Open Source Software Archive

Member "cryptsetup-2.4.3/src/veritysetup.c" (13 Jan 2022, 20745 Bytes) of package /linux/misc/cryptsetup-2.4.3.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "veritysetup.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2.3.6_vs_2.4.0.

    1 /*
    2  * veritysetup - setup cryptographic volumes for dm-verity
    3  *
    4  * Copyright (C) 2012-2021 Red Hat, Inc. All rights reserved.
    5  * Copyright (C) 2012-2021 Milan Broz
    6  *
    7  * This program is free software; you can redistribute it and/or
    8  * modify it under the terms of the GNU General Public License
    9  * as published by the Free Software Foundation; either version 2
   10  * of the License, or (at your option) any later version.
   11  *
   12  * This program is distributed in the hope that it will be useful,
   13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15  * GNU General Public License for more details.
   16  *
   17  * You should have received a copy of the GNU General Public License
   18  * along with this program; if not, write to the Free Software
   19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   20  */
   21 
   22 #include "cryptsetup.h"
   23 #include "veritysetup_args.h"
   24 
   25 #define PACKAGE_VERITY "veritysetup"
   26 
   27 static const char **action_argv;
   28 static int action_argc;
   29 static struct tools_log_params log_parms;
   30 
   31 void tools_cleanup(void)
   32 {
   33     tools_args_free(tool_core_args, ARRAY_SIZE(tool_core_args));
   34 }
   35 
   36 static int _prepare_format(struct crypt_params_verity *params,
   37                const char *data_device,
   38                uint32_t flags)
   39 {
   40     char *salt = NULL;
   41     int len;
   42 
   43     params->hash_name = ARG_STR(OPT_HASH_ID);
   44     params->data_device = data_device;
   45     params->fec_device = ARG_STR(OPT_FEC_DEVICE_ID);
   46     params->fec_roots = ARG_UINT32(OPT_FEC_ROOTS_ID);
   47 
   48     if (ARG_STR(OPT_SALT_ID) && !strcmp(ARG_STR(OPT_SALT_ID), "-")) {
   49         params->salt_size = 0;
   50         params->salt = NULL;
   51     } else if (ARG_SET(OPT_SALT_ID)) {
   52         len = crypt_hex_to_bytes(ARG_STR(OPT_SALT_ID), &salt, 0);
   53         if (len < 0) {
   54             log_err(_("Invalid salt string specified."));
   55             return -EINVAL;
   56         }
   57         params->salt_size = len;
   58         params->salt = salt;
   59     } else {
   60         params->salt_size = DEFAULT_VERITY_SALT_SIZE;
   61         params->salt = NULL;
   62     }
   63 
   64     params->data_block_size = ARG_UINT32(OPT_DATA_BLOCK_SIZE_ID);
   65     params->hash_block_size = ARG_UINT32(OPT_HASH_BLOCK_SIZE_ID);
   66     params->data_size = ARG_UINT64(OPT_DATA_BLOCKS_ID);
   67     params->hash_area_offset = ARG_UINT64(OPT_HASH_OFFSET_ID);
   68     params->fec_area_offset = ARG_UINT64(OPT_FEC_OFFSET_ID);
   69     params->hash_type = ARG_UINT32(OPT_FORMAT_ID);
   70     params->flags = flags;
   71 
   72     return 0;
   73 }
   74 
   75 static int action_format(void)
   76 {
   77     struct crypt_device *cd = NULL;
   78     struct crypt_params_verity params = {};
   79     uint32_t flags = CRYPT_VERITY_CREATE_HASH;
   80     char *root_hash_bytes = NULL;
   81     size_t root_hash_size;
   82     int root_hash_fd = -1, i, r;
   83 
   84     /* Try to create hash image if doesn't exist */
   85     r = open(action_argv[1], O_WRONLY | O_EXCL | O_CREAT, S_IRUSR | S_IWUSR);
   86     if (r < 0 && errno != EEXIST) {
   87         log_err(_("Cannot create hash image %s for writing."), action_argv[1]);
   88         return -EINVAL;
   89     } else if (r >= 0) {
   90         log_dbg("Created hash image %s.", action_argv[1]);
   91         close(r);
   92     }
   93     /* Try to create FEC image if doesn't exist */
   94     if (ARG_SET(OPT_FEC_DEVICE_ID)) {
   95         r = open(ARG_STR(OPT_FEC_DEVICE_ID), O_WRONLY | O_EXCL | O_CREAT, S_IRUSR | S_IWUSR);
   96         if (r < 0 && errno != EEXIST) {
   97             log_err(_("Cannot create FEC image %s for writing."), ARG_STR(OPT_FEC_DEVICE_ID));
   98             return -EINVAL;
   99         } else if (r >= 0) {
  100             log_dbg("Created FEC image %s.", ARG_STR(OPT_FEC_DEVICE_ID));
  101             close(r);
  102         }
  103     }
  104 
  105     if ((r = crypt_init(&cd, action_argv[1])))
  106         goto out;
  107 
  108     if (ARG_SET(OPT_NO_SUPERBLOCK_ID))
  109         flags |= CRYPT_VERITY_NO_HEADER;
  110 
  111     r = _prepare_format(&params, action_argv[0], flags);
  112     if (r < 0)
  113         goto out;
  114 
  115     r = crypt_format(cd, CRYPT_VERITY, NULL, NULL, ARG_STR(OPT_UUID_ID), NULL, 0, &params);
  116     if (r < 0)
  117         goto out;
  118 
  119     crypt_dump(cd);
  120 
  121     /* Create or overwrite the root hash file */
  122     if (ARG_SET(OPT_ROOT_HASH_FILE_ID)) {
  123         root_hash_size = crypt_get_volume_key_size(cd);
  124         root_hash_bytes = malloc(root_hash_size);
  125         if (!root_hash_bytes) {
  126             r = -ENOMEM;
  127             goto out;
  128         }
  129 
  130         r = crypt_volume_key_get(cd, CRYPT_ANY_SLOT, root_hash_bytes, &root_hash_size, NULL, 0);
  131         if (r < 0)
  132             goto out;
  133 
  134         root_hash_fd = open(ARG_STR(OPT_ROOT_HASH_FILE_ID), O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
  135         if (root_hash_fd == -1) {
  136             log_err(_("Cannot create root hash file %s for writing."), ARG_STR(OPT_ROOT_HASH_FILE_ID));
  137             r = -EINVAL;
  138             goto out;
  139         }
  140 
  141         for (i = 0; i < (int)root_hash_size; i++)
  142             if (dprintf(root_hash_fd, "%02hhx", root_hash_bytes[i]) != 2) {
  143                 log_err(_("Cannot write to root hash file %s."), ARG_STR(OPT_ROOT_HASH_FILE_ID));
  144                 r = -EIO;
  145                 goto out;
  146             }
  147 
  148         log_dbg("Created root hash file %s.", ARG_STR(OPT_ROOT_HASH_FILE_ID));
  149     }
  150 out:
  151     crypt_free(cd);
  152     free(CONST_CAST(char*)params.salt);
  153     free(root_hash_bytes);
  154     if (root_hash_fd != -1)
  155         close(root_hash_fd);
  156     return r;
  157 }
  158 
  159 static int _activate(const char *dm_device,
  160               const char *data_device,
  161               const char *hash_device,
  162               const char *root_hash,
  163               uint32_t flags)
  164 {
  165     struct crypt_device *cd = NULL;
  166     struct crypt_params_verity params = {};
  167     uint32_t activate_flags = CRYPT_ACTIVATE_READONLY;
  168     char *root_hash_bytes = NULL, *root_hash_from_file = NULL;
  169     ssize_t hash_size, hash_size_hex;
  170     struct stat st;
  171     char *signature = NULL;
  172     int signature_size = 0, root_hash_fd = -1, r;
  173 
  174     if ((r = crypt_init_data_device(&cd, hash_device, data_device)))
  175         goto out;
  176 
  177     if (ARG_SET(OPT_IGNORE_CORRUPTION_ID))
  178         activate_flags |= CRYPT_ACTIVATE_IGNORE_CORRUPTION;
  179     if (ARG_SET(OPT_RESTART_ON_CORRUPTION_ID))
  180         activate_flags |= CRYPT_ACTIVATE_RESTART_ON_CORRUPTION;
  181     if (ARG_SET(OPT_PANIC_ON_CORRUPTION_ID))
  182         activate_flags |= CRYPT_ACTIVATE_PANIC_ON_CORRUPTION;
  183     if (ARG_SET(OPT_IGNORE_ZERO_BLOCKS_ID))
  184         activate_flags |= CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS;
  185     if (ARG_SET(OPT_CHECK_AT_MOST_ONCE_ID))
  186         activate_flags |= CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE;
  187 
  188     if (!ARG_SET(OPT_NO_SUPERBLOCK_ID)) {
  189         params.flags = flags;
  190         params.hash_area_offset = ARG_UINT64(OPT_HASH_OFFSET_ID);
  191         params.fec_area_offset = ARG_UINT64(OPT_FEC_OFFSET_ID);
  192         params.fec_device = ARG_STR(OPT_FEC_DEVICE_ID);
  193         params.fec_roots = ARG_UINT32(OPT_FEC_ROOTS_ID);
  194         r = crypt_load(cd, CRYPT_VERITY, &params);
  195     } else {
  196         r = _prepare_format(&params, data_device, flags | CRYPT_VERITY_NO_HEADER);
  197         if (r < 0)
  198             goto out;
  199         r = crypt_format(cd, CRYPT_VERITY, NULL, NULL, NULL, NULL, 0, &params);
  200     }
  201     if (r < 0)
  202         goto out;
  203 
  204     hash_size = crypt_get_volume_key_size(cd);
  205     hash_size_hex = 2 * hash_size;
  206 
  207     if (!root_hash) {
  208         root_hash_fd = open(ARG_STR(OPT_ROOT_HASH_FILE_ID), O_RDONLY);
  209         if (root_hash_fd == -1) {
  210             log_err(_("Cannot read root hash file %s."), ARG_STR(OPT_ROOT_HASH_FILE_ID));
  211             goto out;
  212         }
  213 
  214         if (fstat(root_hash_fd, &st) || !S_ISREG(st.st_mode) || st.st_size < hash_size_hex) {
  215             log_err(_("Invalid root hash file %s."), ARG_STR(OPT_ROOT_HASH_FILE_ID));
  216             r = -EINVAL;
  217             goto out;
  218         }
  219 
  220         root_hash_from_file = malloc(hash_size_hex + 1);
  221         if (!root_hash_from_file) {
  222             r = -ENOMEM;
  223             goto out;
  224         }
  225 
  226         if (read_buffer(root_hash_fd, root_hash_from_file, hash_size_hex) != hash_size_hex) {
  227             log_err(_("Cannot read root hash file %s."), root_hash_from_file);
  228             goto out;
  229         }
  230 
  231         root_hash_from_file[hash_size_hex] = '\0';
  232         root_hash = root_hash_from_file;
  233     }
  234 
  235     if (crypt_hex_to_bytes(root_hash, &root_hash_bytes, 0) != hash_size) {
  236         log_err(_("Invalid root hash string specified."));
  237         r = -EINVAL;
  238         goto out;
  239     }
  240 
  241     if (ARG_SET(OPT_ROOT_HASH_SIGNATURE_ID)) {
  242         // FIXME: check max file size
  243         if (stat(ARG_STR(OPT_ROOT_HASH_SIGNATURE_ID), &st) || !S_ISREG(st.st_mode) || !st.st_size) {
  244             log_err(_("Invalid signature file %s."), ARG_STR(OPT_ROOT_HASH_SIGNATURE_ID));
  245             r = -EINVAL;
  246             goto out;
  247         }
  248         signature_size = st.st_size;
  249         r = tools_read_mk(ARG_STR(OPT_ROOT_HASH_SIGNATURE_ID), &signature, signature_size);
  250         if (r < 0) {
  251             log_err(_("Cannot read signature file %s."), ARG_STR(OPT_ROOT_HASH_SIGNATURE_ID));
  252             goto out;
  253         }
  254     }
  255     r = crypt_activate_by_signed_key(cd, dm_device,
  256                      root_hash_bytes,
  257                      hash_size,
  258                      signature, signature_size,
  259                      activate_flags);
  260 out:
  261     crypt_safe_free(signature);
  262     crypt_free(cd);
  263     free(root_hash_from_file);
  264     free(root_hash_bytes);
  265     free(CONST_CAST(char*)params.salt);
  266     if (root_hash_fd != -1)
  267         close(root_hash_fd);
  268     return r;
  269 }
  270 
  271 static int action_open(void)
  272 {
  273     if (action_argc < 4 && !ARG_SET(OPT_ROOT_HASH_FILE_ID)) {
  274         log_err(_("Command requires <root_hash> or --root-hash-file option as argument."));
  275         return -EINVAL;
  276     }
  277 
  278     return _activate(action_argv[1],
  279              action_argv[0],
  280              action_argv[2],
  281              ARG_SET(OPT_ROOT_HASH_FILE_ID) ? NULL : action_argv[3],
  282              ARG_SET(OPT_ROOT_HASH_SIGNATURE_ID) ? CRYPT_VERITY_ROOT_HASH_SIGNATURE : 0);
  283 }
  284 
  285 static int action_verify(void)
  286 {
  287     if (action_argc < 3 && !ARG_SET(OPT_ROOT_HASH_FILE_ID)) {
  288         log_err(_("Command requires <root_hash> or --root-hash-file option as argument."));
  289         return -EINVAL;
  290     }
  291 
  292     return _activate(NULL,
  293              action_argv[0],
  294              action_argv[1],
  295              ARG_SET(OPT_ROOT_HASH_FILE_ID) ? NULL : action_argv[2],
  296              CRYPT_VERITY_CHECK_HASH);
  297 }
  298 
  299 static int action_close(void)
  300 {
  301     struct crypt_device *cd = NULL;
  302     crypt_status_info ci;
  303     uint32_t flags = 0;
  304     int r;
  305 
  306     if (ARG_SET(OPT_DEFERRED_ID))
  307         flags |= CRYPT_DEACTIVATE_DEFERRED;
  308     if (ARG_SET(OPT_CANCEL_DEFERRED_ID))
  309         flags |= CRYPT_DEACTIVATE_DEFERRED_CANCEL;
  310 
  311     r = crypt_init_by_name(&cd, action_argv[0]);
  312     if (r == 0)
  313         r = crypt_deactivate_by_name(cd, action_argv[0], flags);
  314 
  315     if (!r && ARG_SET(OPT_DEFERRED_ID)) {
  316         ci = crypt_status(cd, action_argv[0]);
  317         if (ci == CRYPT_ACTIVE || ci == CRYPT_BUSY)
  318             log_std(_("Device %s is still active and scheduled for deferred removal.\n"),
  319                   action_argv[0]);
  320     }
  321 
  322     crypt_free(cd);
  323     return r;
  324 }
  325 
  326 static int action_status(void)
  327 {
  328     crypt_status_info ci;
  329     struct crypt_active_device cad;
  330     struct crypt_params_verity vp = {};
  331     struct crypt_device *cd = NULL;
  332     struct stat st;
  333     char *backing_file, *root_hash;
  334     size_t root_hash_size;
  335     unsigned i, path = 0;
  336     int r = 0;
  337 
  338     /* perhaps a path, not a dm device name */
  339     if (strchr(action_argv[0], '/') && !stat(action_argv[0], &st))
  340         path = 1;
  341 
  342     ci = crypt_status(NULL, action_argv[0]);
  343     switch (ci) {
  344     case CRYPT_INVALID:
  345         r = -EINVAL;
  346         break;
  347     case CRYPT_INACTIVE:
  348         if (path)
  349             log_std("%s is inactive.\n", action_argv[0]);
  350         else
  351             log_std("%s/%s is inactive.\n", crypt_get_dir(), action_argv[0]);
  352         r = -ENODEV;
  353         break;
  354     case CRYPT_ACTIVE:
  355     case CRYPT_BUSY:
  356         if (path)
  357             log_std("%s is active%s.\n", action_argv[0],
  358                 ci == CRYPT_BUSY ? " and is in use" : "");
  359         else
  360             log_std("%s/%s is active%s.\n", crypt_get_dir(), action_argv[0],
  361                 ci == CRYPT_BUSY ? " and is in use" : "");
  362 
  363         r = crypt_init_by_name_and_header(&cd, action_argv[0], NULL);
  364         if (r < 0)
  365             goto out;
  366 
  367         log_std("  type:        %s\n", crypt_get_type(cd) ?: "n/a");
  368 
  369         r = crypt_get_active_device(cd, action_argv[0], &cad);
  370         if (r < 0)
  371             goto out;
  372 
  373         /* Print only VERITY type devices */
  374         r = crypt_get_verity_info(cd, &vp);
  375         if (r < 0)
  376             goto out;
  377 
  378         log_std("  status:      %s%s\n",
  379             cad.flags & CRYPT_ACTIVATE_CORRUPTED ? "corrupted" : "verified",
  380             vp.flags & CRYPT_VERITY_ROOT_HASH_SIGNATURE ? " (with signature)" : "");
  381 
  382         log_std("  hash type:   %u\n", vp.hash_type);
  383         log_std("  data block:  %u\n", vp.data_block_size);
  384         log_std("  hash block:  %u\n", vp.hash_block_size);
  385         log_std("  hash name:   %s\n", vp.hash_name);
  386         log_std("  salt:        ");
  387         if (vp.salt_size)
  388             for(i = 0; i < vp.salt_size; i++)
  389                 log_std("%02hhx", (const char)vp.salt[i]);
  390         else
  391             log_std("-");
  392         log_std("\n");
  393 
  394         log_std("  data device: %s\n", vp.data_device);
  395         if ((backing_file = crypt_loop_backing_file(vp.data_device))) {
  396             log_std("  data loop:   %s\n", backing_file);
  397             free(backing_file);
  398         }
  399         log_std("  size:        %" PRIu64 " sectors\n", cad.size);
  400         log_std("  mode:        %s\n", cad.flags & CRYPT_ACTIVATE_READONLY ?
  401                        "readonly" : "read/write");
  402 
  403         log_std("  hash device: %s\n", vp.hash_device);
  404         if ((backing_file = crypt_loop_backing_file(vp.hash_device))) {
  405             log_std("  hash loop:   %s\n", backing_file);
  406             free(backing_file);
  407         }
  408         log_std("  hash offset: %" PRIu64 " sectors\n",
  409             vp.hash_area_offset * vp.hash_block_size / 512);
  410 
  411         if (vp.fec_device) {
  412             log_std("  FEC device:  %s\n", vp.fec_device);
  413             if ((backing_file = crypt_loop_backing_file(ARG_STR(OPT_FEC_DEVICE_ID)))) {
  414                 log_std("  FEC loop:    %s\n", backing_file);
  415                 free(backing_file);
  416             }
  417             log_std("  FEC offset:  %" PRIu64 " sectors\n",
  418                 vp.fec_area_offset * vp.hash_block_size / 512);
  419             log_std("  FEC roots:   %u\n", vp.fec_roots);
  420         }
  421 
  422         root_hash_size = crypt_get_volume_key_size(cd);
  423         if (root_hash_size > 0 && (root_hash = malloc(root_hash_size))) {
  424             r = crypt_volume_key_get(cd, CRYPT_ANY_SLOT, root_hash, &root_hash_size, NULL, 0);
  425             if (!r) {
  426                 log_std("  root hash:   ");
  427                 for (i = 0; i < root_hash_size; i++)
  428                     log_std("%02hhx", (const char)root_hash[i]);
  429                 log_std("\n");
  430             }
  431             free(root_hash);
  432         }
  433 
  434         if (cad.flags & (CRYPT_ACTIVATE_IGNORE_CORRUPTION|
  435                  CRYPT_ACTIVATE_RESTART_ON_CORRUPTION|
  436                  CRYPT_ACTIVATE_PANIC_ON_CORRUPTION|
  437                  CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS|
  438                  CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE))
  439             log_std("  flags:       %s%s%s%s%s\n",
  440                 (cad.flags & CRYPT_ACTIVATE_IGNORE_CORRUPTION) ? "ignore_corruption " : "",
  441                 (cad.flags & CRYPT_ACTIVATE_RESTART_ON_CORRUPTION) ? "restart_on_corruption " : "",
  442                 (cad.flags & CRYPT_ACTIVATE_PANIC_ON_CORRUPTION) ? "panic_on_corruption " : "",
  443                 (cad.flags & CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS) ? "ignore_zero_blocks " : "",
  444                 (cad.flags & CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE) ? "check_at_most_once" : "");
  445     }
  446 out:
  447     crypt_free(cd);
  448     if (r == -ENOTSUP)
  449         r = 0;
  450     return r;
  451 }
  452 
  453 static int action_dump(void)
  454 {
  455     struct crypt_device *cd = NULL;
  456     struct crypt_params_verity params = {};
  457     int r;
  458 
  459     if ((r = crypt_init(&cd, action_argv[0])))
  460         return r;
  461 
  462     params.hash_area_offset = ARG_UINT64(OPT_HASH_OFFSET_ID);
  463     params.fec_area_offset = ARG_UINT64(OPT_FEC_OFFSET_ID);
  464     r = crypt_load(cd, CRYPT_VERITY, &params);
  465     if (!r)
  466         crypt_dump(cd);
  467     crypt_free(cd);
  468     return r;
  469 }
  470 
  471 static struct action_type {
  472     const char *type;
  473     int (*handler)(void);
  474     int required_action_argc;
  475     const char *arg_desc;
  476     const char *desc;
  477 } action_types[] = {
  478     { "format", action_format, 2, N_("<data_device> <hash_device>"),N_("format device") },
  479     { "verify", action_verify, 2, N_("<data_device> <hash_device> [<root_hash>]"),N_("verify device") },
  480     { "open",   action_open,   3, N_("<data_device> <name> <hash_device> [<root_hash>]"),N_("open device as <name>") },
  481     { "close",  action_close,  1, N_("<name>"),N_("close device (remove mapping)") },
  482     { "status", action_status, 1, N_("<name>"),N_("show active device status") },
  483     { "dump",   action_dump,   1, N_("<hash_device>"),N_("show on-disk information") },
  484     { NULL, NULL, 0, NULL, NULL }
  485 };
  486 
  487 static void help(poptContext popt_context,
  488          enum poptCallbackReason reason __attribute__((unused)),
  489          struct poptOption *key,
  490          const char *arg __attribute__((unused)),
  491          void *data __attribute__((unused)))
  492 {
  493     struct action_type *action;
  494 
  495     if (key->shortName == '?') {
  496         log_std("%s %s\n", PACKAGE_VERITY, PACKAGE_VERSION);
  497         poptPrintHelp(popt_context, stdout, 0);
  498         log_std(_("\n"
  499              "<action> is one of:\n"));
  500         for(action = action_types; action->type; action++)
  501             log_std("\t%s %s - %s\n", action->type, _(action->arg_desc), _(action->desc));
  502         log_std(_("\n"
  503              "<name> is the device to create under %s\n"
  504              "<data_device> is the data device\n"
  505              "<hash_device> is the device containing verification data\n"
  506              "<root_hash> hash of the root node on <hash_device>\n"),
  507             crypt_get_dir());
  508 
  509         log_std(_("\nDefault compiled-in dm-verity parameters:\n"
  510              "\tHash: %s, Data block (bytes): %u, "
  511              "Hash block (bytes): %u, Salt size: %u, Hash format: %u\n"),
  512             DEFAULT_VERITY_HASH, DEFAULT_VERITY_DATA_BLOCK,
  513             DEFAULT_VERITY_HASH_BLOCK, DEFAULT_VERITY_SALT_SIZE,
  514             1);
  515         tools_cleanup();
  516         poptFreeContext(popt_context);
  517         exit(EXIT_SUCCESS);
  518     } else if (key->shortName == 'V') {
  519         log_std("%s %s\n", PACKAGE_VERITY, PACKAGE_VERSION);
  520         tools_cleanup();
  521         poptFreeContext(popt_context);
  522         exit(EXIT_SUCCESS);
  523     } else
  524         usage(popt_context, EXIT_SUCCESS, NULL, NULL);
  525 }
  526 
  527 static int run_action(struct action_type *action)
  528 {
  529     int r;
  530 
  531     log_dbg("Running command %s.", action->type);
  532 
  533     r = action->handler();
  534 
  535     show_status(r);
  536     return translate_errno(r);
  537 }
  538 
  539 static void basic_options_cb(poptContext popt_context,
  540          enum poptCallbackReason reason __attribute__((unused)),
  541          struct poptOption *key,
  542          const char *arg,
  543          void *data __attribute__((unused)))
  544 {
  545     tools_parse_arg_value(popt_context, tool_core_args[key->val].type, tool_core_args + key->val, arg, key->val, NULL);
  546 
  547     switch (key->val) {
  548     case OPT_DEBUG_ID:
  549         log_parms.debug = true;
  550         /* fall through */
  551     case OPT_VERBOSE_ID:
  552         log_parms.verbose = true;
  553     }
  554 }
  555 
  556 int main(int argc, const char **argv)
  557 {
  558     static const char *null_action_argv[] = {NULL};
  559     static struct poptOption popt_help_options[] = {
  560         { NULL,    '\0', POPT_ARG_CALLBACK, help, 0, NULL,                         NULL },
  561         { "help",  '?',  POPT_ARG_NONE,     NULL, 0, N_("Show this help message"), NULL },
  562         { "usage", '\0', POPT_ARG_NONE,     NULL, 0, N_("Display brief usage"),    NULL },
  563         { "version",'V', POPT_ARG_NONE,     NULL, 0, N_("Print package version"),  NULL },
  564         POPT_TABLEEND
  565     };
  566     static struct poptOption popt_basic_options[] = {
  567         { NULL,    '\0', POPT_ARG_CALLBACK, basic_options_cb, 0, NULL, NULL },
  568 #define ARG(A, B, C, D, E, F, G, H) { A, B, C, NULL, A ## _ID, D, E },
  569 #include "veritysetup_arg_list.h"
  570 #undef arg
  571         POPT_TABLEEND
  572     };
  573     static struct poptOption popt_options[] = {
  574         { NULL,              '\0', POPT_ARG_INCLUDE_TABLE, popt_help_options, 0, N_("Help options:"), NULL },
  575         { NULL,              '\0', POPT_ARG_INCLUDE_TABLE, popt_basic_options, 0, NULL, NULL },
  576         POPT_TABLEEND
  577     };
  578 
  579     poptContext popt_context;
  580     struct action_type *action;
  581     const char *aname;
  582     int r;
  583 
  584     crypt_set_log_callback(NULL, tool_log, &log_parms);
  585 
  586     setlocale(LC_ALL, "");
  587     bindtextdomain(PACKAGE, LOCALEDIR);
  588     textdomain(PACKAGE);
  589 
  590     popt_context = poptGetContext("verity", argc, argv, popt_options, 0);
  591     poptSetOtherOptionHelp(popt_context,
  592                            _("[OPTION...] <action> <action-specific>"));
  593 
  594     while((r = poptGetNextOpt(popt_context)) > 0) {}
  595 
  596     if (r < -1)
  597         usage(popt_context, EXIT_FAILURE, poptStrerror(r),
  598               poptBadOption(popt_context, POPT_BADOPTION_NOALIAS));
  599 
  600     if (!(aname = poptGetArg(popt_context)))
  601         usage(popt_context, EXIT_FAILURE, _("Argument <action> missing."),
  602               poptGetInvocationName(popt_context));
  603 
  604     action_argc = 0;
  605     action_argv = poptGetArgs(popt_context);
  606     /* Make return values of poptGetArgs more consistent in case of remaining argc = 0 */
  607     if(!action_argv)
  608         action_argv = null_action_argv;
  609 
  610     /* Count args, somewhat unnice, change? */
  611     while(action_argv[action_argc] != NULL)
  612         action_argc++;
  613 
  614     /* Handle aliases */
  615     if (!strcmp(aname, "create") && action_argc > 1) {
  616         /* create command had historically switched arguments */
  617         if (action_argv[0] && action_argv[1]) {
  618             const char *tmp = action_argv[0];
  619             action_argv[0] = action_argv[1];
  620             action_argv[1] = tmp;
  621         }
  622         aname = "open";
  623     } else if (!strcmp(aname, "remove")) {
  624         aname = "close";
  625     }
  626 
  627     for (action = action_types; action->type; action++)
  628         if (strcmp(action->type, aname) == 0)
  629             break;
  630 
  631     if (!action->type)
  632         usage(popt_context, EXIT_FAILURE, _("Unknown action."),
  633               poptGetInvocationName(popt_context));
  634 
  635     if (action_argc < action->required_action_argc) {
  636         char buf[128];
  637         snprintf(buf, 128,_("%s: requires %s as arguments"), action->type, action->arg_desc);
  638         usage(popt_context, EXIT_FAILURE, buf,
  639               poptGetInvocationName(popt_context));
  640     }
  641 
  642     tools_check_args(action->type, tool_core_args, ARRAY_SIZE(tool_core_args), popt_context);
  643 
  644     if (ARG_SET(OPT_IGNORE_CORRUPTION_ID) && ARG_SET(OPT_RESTART_ON_CORRUPTION_ID))
  645         usage(popt_context, EXIT_FAILURE,
  646         _("Option --ignore-corruption and --restart-on-corruption cannot be used together."),
  647         poptGetInvocationName(popt_context));
  648 
  649     if (ARG_SET(OPT_PANIC_ON_CORRUPTION_ID) && ARG_SET(OPT_RESTART_ON_CORRUPTION_ID))
  650         usage(popt_context, EXIT_FAILURE,
  651         _("Option --panic-on-corruption and --restart-on-corruption cannot be used together."),
  652         poptGetInvocationName(popt_context));
  653 
  654     if (ARG_SET(OPT_CANCEL_DEFERRED_ID) && ARG_SET(OPT_DEFERRED_ID))
  655         usage(popt_context, EXIT_FAILURE,
  656               _("Options --cancel-deferred and --deferred cannot be used at the same time."),
  657               poptGetInvocationName(popt_context));
  658 
  659     if (ARG_SET(OPT_DEBUG_ID)) {
  660         crypt_set_debug_level(CRYPT_DEBUG_ALL);
  661         dbg_version_and_cmd(argc, argv);
  662     }
  663 
  664     r = run_action(action);
  665     tools_cleanup();
  666     poptFreeContext(popt_context);
  667     return r;
  668 }