"Fossies" - the Fresh Open Source Software Archive

Member "cryptsetup-2.4.3/src/integritysetup.c" (13 Jan 2022, 22644 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 "integritysetup.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  * integritysetup - setup integrity protected volumes for dm-integrity
    3  *
    4  * Copyright (C) 2017-2021 Red Hat, Inc. All rights reserved.
    5  * Copyright (C) 2017-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 <uuid/uuid.h>
   23 
   24 #define DEFAULT_ALG_NAME "crc32c"
   25 
   26 #include "cryptsetup.h"
   27 #include "integritysetup_args.h"
   28 
   29 #define PACKAGE_INTEGRITY "integritysetup"
   30 
   31 static const char **action_argv;
   32 static int action_argc;
   33 static struct tools_log_params log_parms;
   34 
   35 void tools_cleanup(void)
   36 {
   37     tools_args_free(tool_core_args, ARRAY_SIZE(tool_core_args));
   38 }
   39 
   40 static int _read_keys(char **integrity_key, struct crypt_params_integrity *params)
   41 {
   42     char *int_key = NULL, *journal_integrity_key = NULL, *journal_crypt_key = NULL;
   43     int r;
   44 
   45     if (integrity_key && ARG_SET(OPT_INTEGRITY_KEY_FILE_ID)) {
   46         r = tools_read_mk(ARG_STR(OPT_INTEGRITY_KEY_FILE_ID), &int_key, ARG_UINT32(OPT_INTEGRITY_KEY_SIZE_ID));
   47         if (r < 0)
   48             return r;
   49         params->integrity_key_size = ARG_UINT32(OPT_INTEGRITY_KEY_SIZE_ID);
   50     }
   51 
   52     if (ARG_SET(OPT_JOURNAL_INTEGRITY_KEY_FILE_ID)) {
   53         r = tools_read_mk(ARG_STR(OPT_JOURNAL_INTEGRITY_KEY_FILE_ID), &journal_integrity_key, ARG_UINT32(OPT_JOURNAL_INTEGRITY_KEY_SIZE_ID));
   54         if (r < 0) {
   55             crypt_safe_free(int_key);
   56             return r;
   57         }
   58         params->journal_integrity_key = journal_integrity_key;
   59         params->journal_integrity_key_size = ARG_UINT32(OPT_JOURNAL_INTEGRITY_KEY_SIZE_ID);
   60     }
   61 
   62     if (ARG_SET(OPT_JOURNAL_CRYPT_KEY_FILE_ID)) {
   63         r = tools_read_mk(ARG_STR(OPT_JOURNAL_CRYPT_KEY_FILE_ID), &journal_crypt_key, ARG_UINT32(OPT_JOURNAL_CRYPT_KEY_SIZE_ID));
   64         if (r < 0) {
   65             crypt_safe_free(int_key);
   66             crypt_safe_free(journal_integrity_key);
   67             return r;
   68         }
   69         params->journal_crypt_key = journal_crypt_key;
   70         params->journal_crypt_key_size = ARG_UINT32(OPT_JOURNAL_CRYPT_KEY_SIZE_ID);
   71     }
   72 
   73     if (integrity_key)
   74         *integrity_key = int_key;
   75 
   76     return 0;
   77 }
   78 
   79 static int _wipe_data_device(struct crypt_device *cd, const char *integrity_key)
   80 {
   81     char tmp_name[64], tmp_path[128], tmp_uuid[40];
   82     uuid_t tmp_uuid_bin;
   83     int r;
   84     struct tools_progress_params prog_parms = {
   85         .frequency = ARG_UINT32(OPT_PROGRESS_FREQUENCY_ID),
   86         .batch_mode = ARG_SET(OPT_BATCH_MODE_ID)
   87     };
   88 
   89     if (!ARG_SET(OPT_BATCH_MODE_ID))
   90         log_std(_("Wiping device to initialize integrity checksum.\n"
   91             "You can interrupt this by pressing CTRL+c "
   92             "(rest of not wiped device will contain invalid checksum).\n"));
   93 
   94     /* Activate the device a temporary one */
   95     uuid_generate(tmp_uuid_bin);
   96     uuid_unparse(tmp_uuid_bin, tmp_uuid);
   97     if (snprintf(tmp_name, sizeof(tmp_name), "temporary-cryptsetup-%s", tmp_uuid) < 0)
   98         return -EINVAL;
   99     if (snprintf(tmp_path, sizeof(tmp_path), "%s/%s", crypt_get_dir(), tmp_name) < 0)
  100         return -EINVAL;
  101 
  102     r = crypt_activate_by_volume_key(cd, tmp_name, integrity_key,
  103         ARG_UINT32(OPT_INTEGRITY_KEY_SIZE_ID), CRYPT_ACTIVATE_PRIVATE | CRYPT_ACTIVATE_NO_JOURNAL);
  104     if (r < 0)
  105         return r;
  106 
  107     /* Wipe the device */
  108     set_int_handler(0);
  109     r = crypt_wipe(cd, tmp_path, CRYPT_WIPE_ZERO, 0, 0, DEFAULT_WIPE_BLOCK,
  110                0, &tools_wipe_progress, &prog_parms);
  111     if (crypt_deactivate(cd, tmp_name))
  112         log_err(_("Cannot deactivate temporary device %s."), tmp_path);
  113     set_int_block(0);
  114 
  115     return r;
  116 }
  117 
  118 static int action_format(void)
  119 {
  120     struct crypt_device *cd = NULL;
  121     struct crypt_params_integrity params = {
  122         .journal_size = ARG_UINT64(OPT_JOURNAL_SIZE_ID),
  123         .interleave_sectors = ARG_UINT32(OPT_INTERLEAVE_SECTORS_ID),
  124         /* in bitmap mode we have to overload these values... */
  125         .journal_watermark = ARG_SET(OPT_INTEGRITY_BITMAP_MODE_ID) ? ARG_UINT32(OPT_BITMAP_SECTORS_PER_BIT_ID) : ARG_UINT32(OPT_JOURNAL_WATERMARK_ID),
  126         .journal_commit_time = ARG_SET(OPT_INTEGRITY_BITMAP_MODE_ID) ? ARG_UINT32(OPT_BITMAP_FLUSH_TIME_ID) : ARG_UINT32(OPT_JOURNAL_COMMIT_TIME_ID),
  127         .buffer_sectors = ARG_UINT32(OPT_BUFFER_SECTORS_ID),
  128         .tag_size = ARG_UINT32(OPT_TAG_SIZE_ID),
  129         .sector_size = ARG_UINT32(OPT_SECTOR_SIZE_ID),
  130     }, params2;
  131     char integrity[MAX_CIPHER_LEN], journal_integrity[MAX_CIPHER_LEN], journal_crypt[MAX_CIPHER_LEN];
  132     char *integrity_key = NULL, *msg = NULL;
  133     int r;
  134     size_t signatures;
  135 
  136     r = crypt_parse_hash_integrity_mode(ARG_STR(OPT_INTEGRITY_ID), integrity);
  137     if (r < 0) {
  138         log_err(_("No known integrity specification pattern detected."));
  139         return r;
  140     }
  141     params.integrity = integrity;
  142 
  143     if (ARG_SET(OPT_JOURNAL_INTEGRITY_ID)) {
  144         r = crypt_parse_hash_integrity_mode(ARG_STR(OPT_JOURNAL_INTEGRITY_ID), journal_integrity);
  145         if (r < 0) {
  146             log_err(_("No known integrity specification pattern detected."));
  147             return r;
  148         }
  149         params.journal_integrity = journal_integrity;
  150     }
  151 
  152     if (ARG_SET(OPT_JOURNAL_CRYPT_ID)) {
  153         r = crypt_parse_hash_integrity_mode(ARG_STR(OPT_JOURNAL_CRYPT_ID), journal_crypt);
  154         if (r < 0) {
  155             log_err(_("No known integrity specification pattern detected."));
  156             return r;
  157         }
  158         params.journal_crypt = journal_crypt;
  159     }
  160 
  161     r = _read_keys(&integrity_key, &params);
  162     if (r)
  163         goto out;
  164 
  165     r = crypt_init_data_device(&cd, action_argv[0], ARG_STR(OPT_DATA_DEVICE_ID));
  166     if (r < 0)
  167         goto out;
  168 
  169     if (!ARG_SET(OPT_BATCH_MODE_ID)) {
  170         r = asprintf(&msg, _("This will overwrite data on %s irrevocably."), action_argv[0]);
  171         if (r == -1) {
  172             r = -ENOMEM;
  173             goto out;
  174         }
  175 
  176         r = yesDialog(msg, _("Operation aborted.\n")) ? 0 : -EINVAL;
  177         free(msg);
  178         if (r < 0)
  179             goto out;
  180     }
  181 
  182     r = tools_detect_signatures(action_argv[0], 0, &signatures, ARG_SET(OPT_BATCH_MODE_ID));
  183     if (r < 0)
  184         goto out;
  185 
  186     /* Signature candidates found */
  187     if (signatures && ((r = tools_wipe_all_signatures(action_argv[0])) < 0))
  188         goto out;
  189 
  190     if (ARG_SET(OPT_INTEGRITY_LEGACY_PADDING_ID))
  191         crypt_set_compatibility(cd, CRYPT_COMPAT_LEGACY_INTEGRITY_PADDING);
  192 
  193     if (ARG_SET(OPT_INTEGRITY_LEGACY_HMAC_ID))
  194         crypt_set_compatibility(cd, CRYPT_COMPAT_LEGACY_INTEGRITY_HMAC);
  195 
  196     r = crypt_format(cd, CRYPT_INTEGRITY, NULL, NULL, NULL, NULL, 0, &params);
  197     if (r < 0) /* FIXME: call wipe signatures again */
  198         goto out;
  199 
  200     if (!ARG_SET(OPT_BATCH_MODE_ID) && !crypt_get_integrity_info(cd, &params2))
  201         log_std(_("Formatted with tag size %u, internal integrity %s.\n"),
  202             params2.tag_size, params2.integrity);
  203 
  204     if (!ARG_SET(OPT_NO_WIPE_ID))
  205         r = _wipe_data_device(cd, integrity_key);
  206 out:
  207     crypt_safe_free(integrity_key);
  208     crypt_safe_free(CONST_CAST(void*)params.journal_integrity_key);
  209     crypt_safe_free(CONST_CAST(void*)params.journal_crypt_key);
  210     crypt_free(cd);
  211     return r;
  212 }
  213 
  214 static int action_open(void)
  215 {
  216     struct crypt_device *cd = NULL;
  217     struct crypt_params_integrity params = {
  218         /* in bitmap mode we have to overload these values... */
  219         .journal_watermark = ARG_SET(OPT_INTEGRITY_BITMAP_MODE_ID) ? ARG_UINT32(OPT_BITMAP_SECTORS_PER_BIT_ID) : ARG_UINT32(OPT_JOURNAL_WATERMARK_ID),
  220         .journal_commit_time = ARG_SET(OPT_INTEGRITY_BITMAP_MODE_ID) ? ARG_UINT32(OPT_BITMAP_FLUSH_TIME_ID) : ARG_UINT32(OPT_JOURNAL_COMMIT_TIME_ID),
  221         .buffer_sectors = ARG_UINT32(OPT_BUFFER_SECTORS_ID),
  222     };
  223     uint32_t activate_flags = 0;
  224     char integrity[MAX_CIPHER_LEN], journal_integrity[MAX_CIPHER_LEN], journal_crypt[MAX_CIPHER_LEN];
  225     char *integrity_key = NULL;
  226     int r;
  227 
  228     r = crypt_parse_hash_integrity_mode(ARG_STR(OPT_INTEGRITY_ID), integrity);
  229     if (r < 0) {
  230         log_err(_("No known integrity specification pattern detected."));
  231         return r;
  232     }
  233     params.integrity = integrity;
  234 
  235     if (ARG_SET(OPT_JOURNAL_INTEGRITY_ID)) {
  236         r = crypt_parse_hash_integrity_mode(ARG_STR(OPT_JOURNAL_INTEGRITY_ID), journal_integrity);
  237         if (r < 0) {
  238             log_err(_("No known integrity specification pattern detected."));
  239             return r;
  240 
  241         }
  242         params.journal_integrity = journal_integrity;
  243     }
  244 
  245     if (ARG_SET(OPT_JOURNAL_CRYPT_ID)) {
  246         r = crypt_parse_hash_integrity_mode(ARG_STR(OPT_JOURNAL_CRYPT_ID), journal_crypt);
  247         if (r < 0) {
  248             log_err(_("No known integrity specification pattern detected."));
  249             return r;
  250         }
  251         params.journal_crypt = journal_crypt;
  252     }
  253 
  254     if (ARG_SET(OPT_INTEGRITY_NO_JOURNAL_ID) || ARG_SET(OPT_INTEGRITY_BITMAP_MODE_ID))
  255         activate_flags |= CRYPT_ACTIVATE_NO_JOURNAL;
  256     if (ARG_SET(OPT_INTEGRITY_RECOVERY_MODE_ID))
  257         activate_flags |= CRYPT_ACTIVATE_RECOVERY;
  258     if (ARG_SET(OPT_INTEGRITY_BITMAP_MODE_ID))
  259         activate_flags |= CRYPT_ACTIVATE_NO_JOURNAL_BITMAP;
  260 
  261     if (ARG_SET(OPT_INTEGRITY_RECALCULATE_ID) || ARG_SET(OPT_INTEGRITY_LEGACY_RECALC_ID))
  262         activate_flags |= CRYPT_ACTIVATE_RECALCULATE;
  263 
  264     if (ARG_SET(OPT_INTEGRITY_RECALCULATE_RESET_ID))
  265         activate_flags |= CRYPT_ACTIVATE_RECALCULATE_RESET;
  266 
  267     if (ARG_SET(OPT_ALLOW_DISCARDS_ID))
  268         activate_flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
  269 
  270     r = _read_keys(&integrity_key, &params);
  271     if (r)
  272         goto out;
  273 
  274     if ((r = crypt_init_data_device(&cd, action_argv[0], ARG_STR(OPT_DATA_DEVICE_ID))))
  275         goto out;
  276 
  277     r = crypt_load(cd, CRYPT_INTEGRITY, &params);
  278     if (r)
  279         goto out;
  280 
  281     if (ARG_SET(OPT_INTEGRITY_LEGACY_RECALC_ID))
  282         crypt_set_compatibility(cd, CRYPT_COMPAT_LEGACY_INTEGRITY_RECALC);
  283 
  284     r = crypt_activate_by_volume_key(cd, action_argv[1], integrity_key,
  285                      ARG_UINT32(OPT_INTEGRITY_KEY_SIZE_ID), activate_flags);
  286 out:
  287     crypt_safe_free(integrity_key);
  288     crypt_safe_free(CONST_CAST(void*)params.journal_integrity_key);
  289     crypt_safe_free(CONST_CAST(void*)params.journal_crypt_key);
  290     crypt_free(cd);
  291     return r;
  292 }
  293 
  294 static int action_close(void)
  295 {
  296     struct crypt_device *cd = NULL;
  297     crypt_status_info ci;
  298     uint32_t flags = 0;
  299     int r;
  300 
  301     if (ARG_SET(OPT_DEFERRED_ID))
  302         flags |= CRYPT_DEACTIVATE_DEFERRED;
  303     if (ARG_SET(OPT_CANCEL_DEFERRED_ID))
  304         flags |= CRYPT_DEACTIVATE_DEFERRED_CANCEL;
  305 
  306     r = crypt_init_by_name(&cd, action_argv[0]);
  307     if (r == 0)
  308         r = crypt_deactivate_by_name(cd, action_argv[0], flags);
  309 
  310     if (!r && ARG_SET(OPT_DEFERRED_ID)) {
  311         ci = crypt_status(cd, action_argv[0]);
  312         if (ci == CRYPT_ACTIVE || ci == CRYPT_BUSY)
  313             log_std(_("Device %s is still active and scheduled for deferred removal.\n"),
  314                   action_argv[0]);
  315     }
  316 
  317     crypt_free(cd);
  318     return r;
  319 }
  320 
  321 static int action_status(void)
  322 {
  323     crypt_status_info ci;
  324     struct crypt_active_device cad;
  325     struct crypt_params_integrity ip = {};
  326     struct crypt_device *cd = NULL;
  327     char *backing_file;
  328     const char *device, *metadata_device;
  329     int path = 0, r = 0;
  330 
  331     /* perhaps a path, not a dm device name */
  332     if (strchr(action_argv[0], '/'))
  333         path = 1;
  334 
  335     ci = crypt_status(NULL, action_argv[0]);
  336     switch (ci) {
  337     case CRYPT_INVALID:
  338         r = -EINVAL;
  339         break;
  340     case CRYPT_INACTIVE:
  341         if (path)
  342             log_std("%s is inactive.\n", action_argv[0]);
  343         else
  344             log_std("%s/%s is inactive.\n", crypt_get_dir(), action_argv[0]);
  345         r = -ENODEV;
  346         break;
  347     case CRYPT_ACTIVE:
  348     case CRYPT_BUSY:
  349         if (path)
  350             log_std("%s is active%s.\n", action_argv[0],
  351                 ci == CRYPT_BUSY ? " and is in use" : "");
  352         else
  353             log_std("%s/%s is active%s.\n", crypt_get_dir(), action_argv[0],
  354                 ci == CRYPT_BUSY ? " and is in use" : "");
  355 
  356         r = crypt_init_by_name_and_header(&cd, action_argv[0], NULL);
  357         if (r < 0)
  358             goto out;
  359 
  360         log_std("  type:    %s\n", crypt_get_type(cd) ?: "n/a");
  361 
  362         r = crypt_get_active_device(cd, action_argv[0], &cad);
  363         if (r < 0)
  364             goto out;
  365 
  366         /* Print only INTEGRITY (and LUKS2 with integrity) info */
  367         r = crypt_get_integrity_info(cd, &ip);
  368         if (r < 0)
  369             goto out;
  370 
  371         log_std("  tag size: %u\n", ip.tag_size);
  372         log_std("  integrity: %s\n", ip.integrity ?: "(none)");
  373         device = crypt_get_device_name(cd);
  374         metadata_device = crypt_get_metadata_device_name(cd);
  375         log_std("  device:  %s%s\n", device, metadata_device ? " (detached)" : "");
  376         if ((backing_file = crypt_loop_backing_file(device))) {
  377             log_std("  loop:    %s\n", backing_file);
  378             free(backing_file);
  379         }
  380         if (metadata_device) {
  381             log_std("  metadata device:  %s\n", metadata_device);
  382             if ((backing_file = crypt_loop_backing_file(metadata_device))) {
  383                 log_std("  loop:    %s\n", backing_file);
  384                 free(backing_file);
  385             }
  386         }
  387         log_std("  sector size:  %u bytes\n", crypt_get_sector_size(cd));
  388         log_std("  interleave sectors: %u\n", ip.interleave_sectors);
  389         log_std("  size:    %" PRIu64 " sectors\n", cad.size);
  390         log_std("  mode:    %s%s\n",
  391             cad.flags & CRYPT_ACTIVATE_READONLY ? "readonly" : "read/write",
  392             cad.flags & CRYPT_ACTIVATE_RECOVERY ? " recovery" : "");
  393         log_std("  failures: %" PRIu64 "\n",
  394             crypt_get_active_integrity_failures(cd, action_argv[0]));
  395         if (cad.flags & CRYPT_ACTIVATE_NO_JOURNAL_BITMAP) {
  396             log_std("  bitmap 512-byte sectors per bit: %u\n", ip.journal_watermark);
  397             log_std("  bitmap flush interval: %u ms\n", ip.journal_commit_time);
  398         } if (cad.flags & CRYPT_ACTIVATE_NO_JOURNAL) {
  399             log_std("  journal: not active\n");
  400         } else {
  401             log_std("  journal size: %" PRIu64 " bytes\n", ip.journal_size);
  402             log_std("  journal watermark: %u%%\n", ip.journal_watermark);
  403             log_std("  journal commit time: %u ms\n", ip.journal_commit_time);
  404             if (ip.journal_integrity)
  405                 log_std("  journal integrity MAC: %s\n", ip.journal_integrity);
  406             if (ip.journal_crypt)
  407                 log_std("  journal encryption: %s\n", ip.journal_crypt);
  408         }
  409         if (cad.flags & (CRYPT_ACTIVATE_ALLOW_DISCARDS))
  410             log_std("  flags: %s\n",
  411                 (cad.flags & CRYPT_ACTIVATE_ALLOW_DISCARDS) ? "discards " : "");
  412     }
  413 out:
  414     crypt_free(cd);
  415     if (r == -ENOTSUP)
  416         r = 0;
  417     return r;
  418     return -EINVAL;
  419 }
  420 
  421 static int action_dump(void)
  422 {
  423     struct crypt_device *cd = NULL;
  424     struct crypt_params_integrity params = {};
  425     int r;
  426 
  427     if ((r = crypt_init(&cd, action_argv[0])))
  428         return r;
  429 
  430     r = crypt_load(cd, CRYPT_INTEGRITY, &params);
  431     if (!r)
  432         crypt_dump(cd);
  433 
  434     crypt_free(cd);
  435     return r;
  436 }
  437 
  438 static struct action_type {
  439     const char *type;
  440     int (*handler)(void);
  441     int required_action_argc;
  442     const char *arg_desc;
  443     const char *desc;
  444 } action_types[] = {
  445     { FORMAT_ACTION,action_format, 1, N_("<integrity_device>"),N_("format device") },
  446     { OPEN_ACTION,  action_open,   2, N_("<integrity_device> <name>"),N_("open device as <name>") },
  447     { CLOSE_ACTION, action_close,  1, N_("<name>"),N_("close device (remove mapping)") },
  448     { STATUS_ACTION,action_status, 1, N_("<name>"),N_("show active device status") },
  449     { DUMP_ACTION,  action_dump,   1, N_("<integrity_device>"),N_("show on-disk information") },
  450     {}
  451 };
  452 
  453 static void help(poptContext popt_context,
  454          enum poptCallbackReason reason __attribute__((unused)),
  455          struct poptOption *key,
  456          const char *arg __attribute__((unused)),
  457          void *data __attribute__((unused)))
  458 {
  459     struct action_type *action;
  460 
  461     if (key->shortName == '?') {
  462         log_std("%s %s\n", PACKAGE_INTEGRITY, PACKAGE_VERSION);
  463         poptPrintHelp(popt_context, stdout, 0);
  464         log_std(_("\n"
  465              "<action> is one of:\n"));
  466         for(action = action_types; action->type; action++)
  467             log_std("\t%s %s - %s\n", action->type, _(action->arg_desc), _(action->desc));
  468         log_std(_("\n"
  469              "<name> is the device to create under %s\n"
  470              "<integrity_device> is the device containing data with integrity tags\n"),
  471             crypt_get_dir());
  472 
  473         log_std(_("\nDefault compiled-in dm-integrity parameters:\n"
  474               "\tChecksum algorithm: %s\n"
  475               "\tMaximum keyfile size: %dkB\n"),
  476               DEFAULT_ALG_NAME, DEFAULT_INTEGRITY_KEYFILE_SIZE_MAXKB);
  477         tools_cleanup();
  478         poptFreeContext(popt_context);
  479         exit(EXIT_SUCCESS);
  480     } else if (key->shortName == 'V') {
  481         log_std("%s %s\n", PACKAGE_INTEGRITY, PACKAGE_VERSION);
  482         tools_cleanup();
  483         poptFreeContext(popt_context);
  484         exit(EXIT_SUCCESS);
  485     } else
  486         usage(popt_context, EXIT_SUCCESS, NULL, NULL);
  487 }
  488 
  489 static int run_action(struct action_type *action)
  490 {
  491     int r;
  492 
  493     log_dbg("Running command %s.", action->type);
  494 
  495     r = action->handler();
  496 
  497     show_status(r);
  498     return translate_errno(r);
  499 }
  500 
  501 static bool needs_size_conversion(unsigned int arg_id)
  502 {
  503     return arg_id == OPT_JOURNAL_SIZE_ID;
  504 }
  505 
  506 static void basic_options_cb(poptContext popt_context,
  507          enum poptCallbackReason reason __attribute__((unused)),
  508          struct poptOption *key,
  509          const char *arg,
  510          void *data __attribute__((unused)))
  511 {
  512     char msg[256];
  513 
  514     tools_parse_arg_value(popt_context, tool_core_args[key->val].type, tool_core_args + key->val, arg, key->val, needs_size_conversion);
  515 
  516     /* special cases additional handling */
  517     switch (key->val) {
  518     case OPT_DEBUG_ID:
  519         log_parms.debug = true;
  520         /* fall through */
  521     case OPT_VERBOSE_ID:
  522         log_parms.verbose = true;
  523         break;
  524     case OPT_INTEGRITY_KEY_SIZE_ID:
  525         /* fall through */
  526     case OPT_JOURNAL_INTEGRITY_KEY_SIZE_ID:
  527         /* fall through */
  528     case OPT_JOURNAL_CRYPT_KEY_SIZE_ID:
  529         if (ARG_UINT32(key->val) > (DEFAULT_INTEGRITY_KEYFILE_SIZE_MAXKB * 1024)) {
  530             snprintf(msg, sizeof(msg), _("Invalid --%s size. Maximum is %u bytes."),
  531                  key->longName, DEFAULT_INTEGRITY_KEYFILE_SIZE_MAXKB * 1024);
  532             usage(popt_context, EXIT_FAILURE, msg,
  533                   poptGetInvocationName(popt_context));
  534         }
  535     }
  536 }
  537 
  538 int main(int argc, const char **argv)
  539 {
  540     static const char *null_action_argv[] = {NULL};
  541     static struct poptOption popt_help_options[] = {
  542         { NULL,    '\0', POPT_ARG_CALLBACK, help, 0, NULL,                         NULL },
  543         { "help",  '?',  POPT_ARG_NONE,     NULL, 0, N_("Show this help message"), NULL },
  544         { "usage", '\0', POPT_ARG_NONE,     NULL, 0, N_("Display brief usage"),    NULL },
  545         { "version",'V', POPT_ARG_NONE,     NULL, 0, N_("Print package version"),  NULL },
  546         POPT_TABLEEND
  547     };
  548     static struct poptOption popt_basic_options[] = {
  549         { NULL,    '\0', POPT_ARG_CALLBACK, basic_options_cb, 0, NULL, NULL },
  550 #define ARG(A, B, C, D, E, F, G, H) { A, B, C, NULL, A ## _ID, D, E },
  551 #include "integritysetup_arg_list.h"
  552 #undef arg
  553         POPT_TABLEEND
  554     };
  555     static struct poptOption popt_options[] = {
  556         { NULL, '\0', POPT_ARG_INCLUDE_TABLE, popt_help_options, 0, N_("Help options:"), NULL },
  557         { NULL, '\0', POPT_ARG_INCLUDE_TABLE, popt_basic_options, 0, NULL, NULL },
  558         POPT_TABLEEND
  559     };
  560     poptContext popt_context;
  561     struct action_type *action;
  562     const char *aname;
  563     int r;
  564 
  565     crypt_set_log_callback(NULL, tool_log, &log_parms);
  566 
  567     setlocale(LC_ALL, "");
  568     bindtextdomain(PACKAGE, LOCALEDIR);
  569     textdomain(PACKAGE);
  570 
  571     popt_context = poptGetContext("integrity", argc, argv, popt_options, 0);
  572     poptSetOtherOptionHelp(popt_context,
  573                            _("[OPTION...] <action> <action-specific>"));
  574 
  575 
  576     while ((r = poptGetNextOpt(popt_context)) >= 0) {
  577     }
  578 
  579     if (r < -1)
  580         usage(popt_context, EXIT_FAILURE, poptStrerror(r),
  581               poptBadOption(popt_context, POPT_BADOPTION_NOALIAS));
  582 
  583     if (!(aname = poptGetArg(popt_context)))
  584         usage(popt_context, EXIT_FAILURE, _("Argument <action> missing."),
  585               poptGetInvocationName(popt_context));
  586 
  587     action_argc = 0;
  588     action_argv = poptGetArgs(popt_context);
  589     /* Make return values of poptGetArgs more consistent in case of remaining argc = 0 */
  590     if (!action_argv)
  591         action_argv = null_action_argv;
  592 
  593     /* Count args, somewhat unnice, change? */
  594     while (action_argv[action_argc] != NULL)
  595         action_argc++;
  596 
  597     /* Handle aliases */
  598     if (!strcmp(aname, "create") && action_argc > 1) {
  599         /* create command had historically switched arguments */
  600         if (action_argv[0] && action_argv[1]) {
  601             const char *tmp = action_argv[0];
  602             action_argv[0] = action_argv[1];
  603             action_argv[1] = tmp;
  604         }
  605         aname = "open";
  606     } else if (!strcmp(aname, "remove")) {
  607         aname = "close";
  608     }
  609 
  610     for (action = action_types; action->type; action++)
  611         if (strcmp(action->type, aname) == 0)
  612             break;
  613 
  614     if (!action->type)
  615         usage(popt_context, EXIT_FAILURE, _("Unknown action."),
  616               poptGetInvocationName(popt_context));
  617 
  618     if (action_argc < action->required_action_argc) {
  619         char buf[128];
  620         snprintf(buf, 128,_("%s: requires %s as arguments"), action->type, action->arg_desc);
  621         usage(popt_context, EXIT_FAILURE, buf,
  622               poptGetInvocationName(popt_context));
  623     }
  624 
  625     tools_check_args(action->type, tool_core_args, ARRAY_SIZE(tool_core_args), popt_context);
  626 
  627     if (ARG_SET(OPT_INTEGRITY_KEY_FILE_ID) != ARG_SET(OPT_INTEGRITY_KEY_SIZE_ID))
  628         usage(popt_context, EXIT_FAILURE, _("Both key file and key size options must be specified."),
  629               poptGetInvocationName(popt_context));
  630 
  631     if (ARG_SET(OPT_JOURNAL_INTEGRITY_KEY_FILE_ID) != ARG_SET(OPT_JOURNAL_INTEGRITY_KEY_SIZE_ID))
  632         usage(popt_context, EXIT_FAILURE, _("Both journal integrity key file and key size options must be specified."),
  633               poptGetInvocationName(popt_context));
  634     if (!ARG_SET(OPT_JOURNAL_INTEGRITY_ID) && ARG_SET(OPT_JOURNAL_INTEGRITY_KEY_FILE_ID))
  635         usage(popt_context, EXIT_FAILURE, _("Journal integrity algorithm must be specified if journal integrity key is used."),
  636               poptGetInvocationName(popt_context));
  637 
  638     if (ARG_SET(OPT_JOURNAL_CRYPT_KEY_FILE_ID) != ARG_SET(OPT_JOURNAL_CRYPT_KEY_SIZE_ID))
  639         usage(popt_context, EXIT_FAILURE, _("Both journal encryption key file and key size options must be specified."),
  640               poptGetInvocationName(popt_context));
  641     if (!ARG_SET(OPT_JOURNAL_CRYPT_ID) && ARG_SET(OPT_JOURNAL_CRYPT_KEY_FILE_ID))
  642         usage(popt_context, EXIT_FAILURE, _("Journal encryption algorithm must be specified if journal encryption key is used."),
  643               poptGetInvocationName(popt_context));
  644 
  645     if (ARG_SET(OPT_INTEGRITY_RECOVERY_MODE_ID) && ARG_SET(OPT_INTEGRITY_BITMAP_MODE_ID))
  646         usage(popt_context, EXIT_FAILURE, _("Recovery and bitmap mode options are mutually exclusive."),
  647               poptGetInvocationName(popt_context));
  648 
  649     if (ARG_SET(OPT_INTEGRITY_BITMAP_MODE_ID) &&
  650         (ARG_SET(OPT_JOURNAL_INTEGRITY_KEY_FILE_ID) ||
  651          ARG_SET(OPT_JOURNAL_CRYPT_ID) || ARG_SET(OPT_JOURNAL_WATERMARK_ID) ||
  652          ARG_SET(OPT_JOURNAL_COMMIT_TIME_ID)))
  653         usage(popt_context, EXIT_FAILURE, _("Journal options cannot be used in bitmap mode."),
  654               poptGetInvocationName(popt_context));
  655 
  656     if (!ARG_SET(OPT_INTEGRITY_BITMAP_MODE_ID) &&
  657         (ARG_SET(OPT_BITMAP_FLUSH_TIME_ID) || ARG_SET(OPT_BITMAP_SECTORS_PER_BIT_ID)))
  658         usage(popt_context, EXIT_FAILURE, _("Bitmap options can be used only in bitmap mode."),
  659               poptGetInvocationName(popt_context));
  660 
  661     if (ARG_SET(OPT_CANCEL_DEFERRED_ID) && ARG_SET(OPT_DEFERRED_ID))
  662         usage(popt_context, EXIT_FAILURE,
  663               _("Options --cancel-deferred and --deferred cannot be used at the same time."),
  664               poptGetInvocationName(popt_context));
  665 
  666     if (ARG_SET(OPT_DEBUG_ID)) {
  667         crypt_set_debug_level(CRYPT_DEBUG_ALL);
  668         dbg_version_and_cmd(argc, argv);
  669     }
  670 
  671     r = run_action(action);
  672     tools_cleanup();
  673     poptFreeContext(popt_context);
  674     return r;
  675 }