Add master key dump option for tcryptDump.
[platform/upstream/cryptsetup.git] / src / cryptsetup.c
index dde6aec..779c1b4 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <stdarg.h>
-#include <inttypes.h>
-#include <errno.h>
-#include <unistd.h>
-#include <ctype.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <assert.h>
-#include <limits.h>
-#include <popt.h>
-
 #include "cryptsetup.h"
 
 #include "cryptsetup.h"
 
-static int opt_verbose = 0;
-static int opt_debug = 0;
 static const char *opt_cipher = NULL;
 static const char *opt_hash = NULL;
 static int opt_verify_passphrase = 0;
 static const char *opt_cipher = NULL;
 static const char *opt_hash = NULL;
 static int opt_verify_passphrase = 0;
+
 static const char *opt_key_file = NULL;
 static const char *opt_key_file = NULL;
+static int opt_keyfiles_count = 0;
+static const char *opt_keyfiles[MAX_KEYFILES];
+
 static const char *opt_master_key_file = NULL;
 static const char *opt_header_backup_file = NULL;
 static const char *opt_uuid = NULL;
 static const char *opt_header_device = NULL;
 static const char *opt_master_key_file = NULL;
 static const char *opt_header_backup_file = NULL;
 static const char *opt_uuid = NULL;
 static const char *opt_header_device = NULL;
+static const char *opt_type = "luks";
 static int opt_key_size = 0;
 static long opt_keyfile_size = 0;
 static long opt_new_keyfile_size = 0;
 static int opt_key_size = 0;
 static long opt_keyfile_size = 0;
 static long opt_new_keyfile_size = 0;
@@ -57,8 +45,7 @@ static uint64_t opt_offset = 0;
 static uint64_t opt_skip = 0;
 static int opt_skip_valid = 0;
 static int opt_readonly = 0;
 static uint64_t opt_skip = 0;
 static int opt_skip_valid = 0;
 static int opt_readonly = 0;
-static int opt_iteration_time = 1000;
-static int opt_batch_mode = 0;
+static int opt_iteration_time = DEFAULT_LUKS1_ITER_TIME;
 static int opt_version_mode = 0;
 static int opt_timeout = 0;
 static int opt_tries = 3;
 static int opt_version_mode = 0;
 static int opt_timeout = 0;
 static int opt_tries = 3;
@@ -68,140 +55,12 @@ static int opt_urandom = 0;
 static int opt_dump_master_key = 0;
 static int opt_shared = 0;
 static int opt_allow_discards = 0;
 static int opt_dump_master_key = 0;
 static int opt_shared = 0;
 static int opt_allow_discards = 0;
+static int opt_test_passphrase = 0;
+static int opt_hidden = 0;
 
 static const char **action_argv;
 static int action_argc;
 
 static const char **action_argv;
 static int action_argc;
-
-static int action_create(int arg);
-static int action_remove(int arg);
-static int action_resize(int arg);
-static int action_status(int arg);
-static int action_luksFormat(int arg);
-static int action_luksOpen(int arg);
-static int action_luksAddKey(int arg);
-static int action_luksKillSlot(int arg);
-static int action_luksRemoveKey(int arg);
-static int action_luksChangeKey(int arg);
-static int action_isLuks(int arg);
-static int action_luksUUID(int arg);
-static int action_luksDump(int arg);
-static int action_luksSuspend(int arg);
-static int action_luksResume(int arg);
-static int action_luksBackup(int arg);
-static int action_luksRestore(int arg);
-static int action_loopaesOpen(int arg);
-static int action_luksRepair(int arg);
-
-static struct action_type {
-       const char *type;
-       int (*handler)(int);
-       int arg;
-       int required_action_argc;
-       int required_memlock;
-       const char *arg_desc;
-       const char *desc;
-} action_types[] = {
-       { "create",     action_create,          0, 2, 1, N_("<name> <device>"),N_("create device") },
-       { "remove",     action_remove,          0, 1, 1, N_("<name>"), N_("remove device") },
-       { "resize",     action_resize,          0, 1, 1, N_("<name>"), N_("resize active device") },
-       { "status",     action_status,          0, 1, 0, N_("<name>"), N_("show device status") },
-       { "repair",     action_luksRepair,      0, 1, 1, N_("<device>"), N_("try to repair on-disk metadata") },
-       { "luksFormat", action_luksFormat,      0, 1, 1, N_("<device> [<new key file>]"), N_("formats a LUKS device") },
-       { "luksOpen",   action_luksOpen,        0, 2, 1, N_("<device> <name> "), N_("open LUKS device as mapping <name>") },
-       { "luksAddKey", action_luksAddKey,      0, 1, 1, N_("<device> [<new key file>]"), N_("add key to LUKS device") },
-       { "luksRemoveKey",action_luksRemoveKey, 0, 1, 1, N_("<device> [<key file>]"), N_("removes supplied key or key file from LUKS device") },
-       { "luksChangeKey",action_luksChangeKey, 0, 1, 1, N_("<device> [<key file>]"), N_("changes supplied key or key file of LUKS device") },
-       { "luksKillSlot",  action_luksKillSlot, 0, 2, 1, N_("<device> <key slot>"), N_("wipes key with number <key slot> from LUKS device") },
-       { "luksUUID",   action_luksUUID,        0, 1, 0, N_("<device>"), N_("print UUID of LUKS device") },
-       { "isLuks",     action_isLuks,          0, 1, 0, N_("<device>"), N_("tests <device> for LUKS partition header") },
-       { "luksClose",  action_remove,          0, 1, 1, N_("<name>"), N_("remove LUKS mapping") },
-       { "luksDump",   action_luksDump,        0, 1, 1, N_("<device>"), N_("dump LUKS partition information") },
-       { "luksSuspend",action_luksSuspend,     0, 1, 1, N_("<device>"), N_("Suspend LUKS device and wipe key (all IOs are frozen).") },
-       { "luksResume", action_luksResume,      0, 1, 1, N_("<device>"), N_("Resume suspended LUKS device.") },
-       { "luksHeaderBackup",action_luksBackup, 0, 1, 1, N_("<device>"), N_("Backup LUKS device header and keyslots") },
-       { "luksHeaderRestore",action_luksRestore,0,1, 1, N_("<device>"), N_("Restore LUKS device header and keyslots") },
-       { "loopaesOpen",action_loopaesOpen,     0, 2, 1, N_("<device> <name> "), N_("open loop-AES device as mapping <name>") },
-       { "loopaesClose",action_remove,         0, 1, 1, N_("<name>"), N_("remove loop-AES mapping") },
-       { NULL, NULL, 0, 0, 0, NULL, NULL }
-};
-
-__attribute__((format(printf, 5, 6)))
-static void clogger(struct crypt_device *cd, int level, const char *file,
-                  int line, const char *format, ...)
-{
-       va_list argp;
-       char *target = NULL;
-
-       va_start(argp, format);
-
-       if (vasprintf(&target, format, argp) > 0) {
-               if (level >= 0) {
-                       crypt_log(cd, level, target);
-#ifdef CRYPT_DEBUG
-               } else if (opt_debug)
-                       printf("# %s:%d %s\n", file ?: "?", line, target);
-#else
-               } else if (opt_debug)
-                       printf("# %s\n", target);
-#endif
-       }
-
-       va_end(argp);
-       free(target);
-}
-
-static int _yesDialog(const char *msg, void *usrptr __attribute__((unused)))
-{
-       char *answer = NULL;
-       size_t size = 0;
-       int r = 1;
-
-       if(isatty(STDIN_FILENO) && !opt_batch_mode) {
-               log_std("\nWARNING!\n========\n");
-               log_std("%s\n\nAre you sure? (Type uppercase yes): ", msg);
-               if(getline(&answer, &size, stdin) == -1) {
-                       perror("getline");
-                       free(answer);
-                       return 0;
-               }
-               if(strcmp(answer, "YES\n"))
-                       r = 0;
-               free(answer);
-       }
-
-       return r;
-}
-
-static void _log(int level, const char *msg, void *usrptr __attribute__((unused)))
-{
-       switch(level) {
-
-       case CRYPT_LOG_NORMAL:
-               fputs(msg, stdout);
-               break;
-       case CRYPT_LOG_VERBOSE:
-               if (opt_verbose)
-                       fputs(msg, stdout);
-               break;
-       case CRYPT_LOG_ERROR:
-               fputs(msg, stderr);
-               break;
-       case CRYPT_LOG_DEBUG:
-               if (opt_debug)
-                       printf("# %s\n", msg);
-               break;
-       default:
-               fprintf(stderr, "Internal error on logging class for msg: %s", msg);
-               break;
-       }
-}
-
-static void _quiet_log(int level, const char *msg, void *usrptr)
-{
-       if (!opt_verbose && (level == CRYPT_LOG_ERROR || level == CRYPT_LOG_NORMAL))
-               level = CRYPT_LOG_VERBOSE;
-       _log(level, msg, usrptr);
-}
+static const char *null_action_argv[] = {NULL, NULL};
 
 static int _verify_passphrase(int def)
 {
 
 static int _verify_passphrase(int def)
 {
@@ -221,61 +80,7 @@ static int _verify_passphrase(int def)
        return def;
 }
 
        return def;
 }
 
-static void show_status(int errcode)
-{
-       char error[256], *error_;
-
-       if(!opt_verbose)
-               return;
-
-       if(!errcode) {
-               log_std(_("Command successful.\n"));
-               return;
-       }
-
-       crypt_get_error(error, sizeof(error));
-
-       if (!error[0]) {
-               error_ = strerror_r(-errcode, error, sizeof(error));
-               if (error_ != error) {
-                       strncpy(error, error_, sizeof(error));
-                       error[sizeof(error) - 1] = '\0';
-               }
-       }
-
-       log_err(_("Command failed with code %i"), -errcode);
-       if (*error)
-               log_err(": %s\n", error);
-       else
-               log_err(".\n");
-}
-
-static const char *uuid_or_device(const char *spec)
-{
-       static char device[PATH_MAX];
-       char s, *ptr;
-       int i = 0, uuid_len = 5;
-
-       /* Check if it is correct UUID=<LUKS_UUID> format */
-       if (spec && !strncmp(spec, "UUID=", uuid_len)) {
-               strcpy(device, "/dev/disk/by-uuid/");
-               ptr = &device[strlen(device)];
-               i = uuid_len;
-               while ((s = spec[i++]) && i < PATH_MAX) {
-                       if (!isxdigit(s) && s != '-')
-                               return spec; /* Bail it out */
-                       if (isalpha(s))
-                               s = tolower(s);
-                       *ptr++ = s;
-               }
-               *ptr = '\0';
-               return device;
-       }
-
-       return spec;
-}
-
-static int action_create(int arg __attribute__((unused)))
+static int action_open_plain(void)
 {
        struct crypt_device *cd = NULL;
        char cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
 {
        struct crypt_device *cd = NULL;
        char cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
@@ -309,7 +114,7 @@ static int action_create(int arg __attribute__((unused)))
                goto out;
        }
 
                goto out;
        }
 
-       if ((r = crypt_init(&cd, action_argv[1])))
+       if ((r = crypt_init(&cd, action_argv[0])))
                goto out;
 
        crypt_set_timeout(cd, opt_timeout);
                goto out;
 
        crypt_set_timeout(cd, opt_timeout);
@@ -334,7 +139,7 @@ static int action_create(int arg __attribute__((unused)))
 
        if (opt_key_file)
                /* With hashing, read the whole keyfile */
 
        if (opt_key_file)
                /* With hashing, read the whole keyfile */
-               r = crypt_activate_by_keyfile_offset(cd, action_argv[0],
+               r = crypt_activate_by_keyfile_offset(cd, action_argv[1],
                        CRYPT_ANY_SLOT, opt_key_file,
                        params.hash ? 0 : key_size, 0,
                        activate_flags);
                        CRYPT_ANY_SLOT, opt_key_file,
                        params.hash ? 0 : key_size, 0,
                        activate_flags);
@@ -348,7 +153,7 @@ static int action_create(int arg __attribute__((unused)))
                if (r < 0)
                        goto out;
 
                if (r < 0)
                        goto out;
 
-               r = crypt_activate_by_passphrase(cd, action_argv[0],
+               r = crypt_activate_by_passphrase(cd, action_argv[1],
                        CRYPT_ANY_SLOT, password, passwordLen, activate_flags);
        }
 out:
                        CRYPT_ANY_SLOT, password, passwordLen, activate_flags);
        }
 out:
@@ -358,7 +163,7 @@ out:
        return r;
 }
 
        return r;
 }
 
-static int action_loopaesOpen(int arg __attribute__((unused)))
+static int action_open_loopaes(void)
 {
        struct crypt_device *cd = NULL;
        struct crypt_params_loopaes params = {
 {
        struct crypt_device *cd = NULL;
        struct crypt_params_loopaes params = {
@@ -398,7 +203,130 @@ out:
        return r;
 }
 
        return r;
 }
 
-static int action_remove(int arg __attribute__((unused)))
+static int action_open_tcrypt(void)
+{
+       struct crypt_device *cd = NULL;
+       struct crypt_params_tcrypt params = {
+               .keyfiles = opt_keyfiles,
+               .keyfiles_count = opt_keyfiles_count,
+               .flags = CRYPT_TCRYPT_LEGACY_MODES,
+       };
+       const char *activated_name;
+       uint32_t flags = 0;
+       int r;
+
+       activated_name = opt_test_passphrase ? NULL : action_argv[1];
+
+       if ((r = crypt_init(&cd, action_argv[0])))
+               goto out;
+
+       /* TCRYPT header is encrypted, get passphrase now */
+       r = crypt_get_key(_("Enter passphrase: "),
+                         CONST_CAST(char**)&params.passphrase,
+                         &params.passphrase_size, 0, 0, NULL, opt_timeout,
+                         _verify_passphrase(0), cd);
+       if (r < 0)
+               goto out;
+
+       if (opt_hidden)
+               params.flags |= CRYPT_TCRYPT_HIDDEN_HEADER;
+
+       r = crypt_load(cd, CRYPT_TCRYPT, &params);
+       if (r < 0)
+               goto out;
+
+       if (opt_readonly)
+               flags |= CRYPT_ACTIVATE_READONLY;
+
+       if (activated_name)
+               r = crypt_activate_by_volume_key(cd, activated_name, NULL, 0, flags);
+out:
+       crypt_free(cd);
+       crypt_safe_free(CONST_CAST(char*)params.passphrase);
+       return r;
+}
+
+static int tcryptDump_with_volume_key(struct crypt_device *cd)
+{
+       char *vk = NULL;
+       size_t vk_size;
+       unsigned i;
+       int r;
+
+       crypt_set_confirm_callback(cd, yesDialog, NULL);
+       if (!yesDialog(
+           _("Header dump with volume key is sensitive information\n"
+             "which allows access to encrypted partition without passphrase.\n"
+             "This dump should be always stored encrypted on safe place."),
+             NULL))
+               return -EPERM;
+
+       vk_size = crypt_get_volume_key_size(cd);
+       vk = crypt_safe_alloc(vk_size);
+       if (!vk)
+               return -ENOMEM;
+
+       r = crypt_volume_key_get(cd, CRYPT_ANY_SLOT, vk, &vk_size, NULL, 0);
+       if (r < 0)
+               goto out;
+
+       log_std("TCRYPT header information for %s\n", crypt_get_device_name(cd));
+       log_std("Cipher chain:  \t%s\n", crypt_get_cipher(cd));
+       log_std("Cipher mode:   \t%s\n", crypt_get_cipher_mode(cd));
+       log_std("Payload offset:\t%d\n", (int)crypt_get_data_offset(cd));
+       log_std("MK bits:       \t%d\n", (int)vk_size * 8);
+       log_std("MK dump:\t");
+
+       for(i = 0; i < vk_size; i++) {
+               if (i && !(i % 16))
+                       log_std("\n\t\t");
+               log_std("%02hhx ", (char)vk[i]);
+       }
+       log_std("\n");
+out:
+       crypt_safe_free(vk);
+       return r;
+}
+
+static int action_tcryptDump(void)
+{
+       struct crypt_device *cd = NULL;
+       struct crypt_params_tcrypt params = {
+               .keyfiles = opt_keyfiles,
+               .keyfiles_count = opt_keyfiles_count,
+               .flags = CRYPT_TCRYPT_LEGACY_MODES,
+       };
+       int r;
+
+       if ((r = crypt_init(&cd, action_argv[0])))
+               goto out;
+
+       /* TCRYPT header is encrypted, get passphrase now */
+       r = crypt_get_key(_("Enter passphrase: "),
+                         CONST_CAST(char**)&params.passphrase,
+                         &params.passphrase_size, 0, 0, NULL, opt_timeout,
+                         _verify_passphrase(0), cd);
+       if (r < 0)
+               goto out;
+
+       if (opt_hidden)
+               params.flags |= CRYPT_TCRYPT_HIDDEN_HEADER;
+
+       r = crypt_load(cd, CRYPT_TCRYPT, &params);
+       if (r < 0)
+               goto out;
+
+       if (opt_dump_master_key)
+               r = tcryptDump_with_volume_key(cd);
+       else
+               r = crypt_dump(cd);
+out:
+       crypt_free(cd);
+       crypt_safe_free(CONST_CAST(char*)params.passphrase);
+       return r;
+}
+
+static int action_close(void)
 {
        struct crypt_device *cd = NULL;
        int r;
 {
        struct crypt_device *cd = NULL;
        int r;
@@ -411,7 +339,7 @@ static int action_remove(int arg __attribute__((unused)))
        return r;
 }
 
        return r;
 }
 
-static int action_resize(int arg __attribute__((unused)))
+static int action_resize(void)
 {
        struct crypt_device *cd = NULL;
        int r;
 {
        struct crypt_device *cd = NULL;
        int r;
@@ -424,7 +352,7 @@ static int action_resize(int arg __attribute__((unused)))
        return r;
 }
 
        return r;
 }
 
-static int action_status(int arg __attribute__((unused)))
+static int action_status(void)
 {
        crypt_status_info ci;
        struct crypt_active_device cad;
 {
        crypt_status_info ci;
        struct crypt_active_device cad;
@@ -489,6 +417,97 @@ static int action_status(int arg __attribute__((unused)))
        }
 out:
        crypt_free(cd);
        }
 out:
        crypt_free(cd);
+       if (r == -ENOTSUP)
+               r = 0;
+       return r;
+}
+
+static int action_benchmark(void)
+{
+       static struct {
+               char *cipher;
+               char *mode;
+               size_t key_size;
+               size_t iv_size;
+       } bciphers[] = {
+               { "aes",     "cbc", 16, 16 },
+               { "serpent", "cbc", 16, 16 },
+               { "twofish", "cbc", 16, 16 },
+               { "aes",     "cbc", 32, 16 },
+               { "serpent", "cbc", 32, 16 },
+               { "twofish", "cbc", 32, 16 },
+               { "aes",     "xts", 32, 16 },
+               { "serpent", "xts", 32, 16 },
+               { "twofish", "xts", 32, 16 },
+               { "aes",     "xts", 64, 16 },
+               { "serpent", "xts", 64, 16 },
+               { "twofish", "xts", 64, 16 },
+               {  NULL, NULL, 0, 0 }
+       };
+       char *header = "# Tests are approximate using memory only (no storage IO).\n"
+                       "#  Algorithm | Key | Encryption | Decryption\n";
+       char cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
+       double enc_mbr = 0, dec_mbr = 0;
+       int key_size = (opt_key_size ?: DEFAULT_PLAIN_KEYBITS);
+       int iv_size = 16, skipped = 0;
+       int buffer_size = 1024 * 1024;
+       char *c;
+       int i, r;
+
+       if (opt_cipher) {
+               r = crypt_parse_name_and_mode(opt_cipher, cipher, NULL, cipher_mode);
+               if (r < 0) {
+                       log_err(_("No known cipher specification pattern detected.\n"));
+                       return r;
+               }
+               if ((c  = strchr(cipher_mode, '-')))
+                       *c = '\0';
+
+               /* FIXME: not really clever :) */
+               if (strstr(cipher, "des") ||
+                   strstr(cipher, "blowfish") ||
+                   strstr(cipher, "cast5"))
+                       iv_size = 8;
+
+               r = crypt_benchmark(NULL, cipher, cipher_mode,
+                                   key_size / 8, iv_size, buffer_size,
+                                   &enc_mbr, &dec_mbr);
+               if (!r) {
+                       log_std("%s", header);
+                       strncat(cipher, "-", MAX_CIPHER_LEN);
+                       strncat(cipher, cipher_mode, MAX_CIPHER_LEN);
+                       log_std("%12s  %4db  %5.1f MiB/s  %5.1f MiB/s\n",
+                               cipher, key_size, enc_mbr, dec_mbr);
+               } else if (r == -ENOENT)
+                       log_err(_("Cipher %s is not available.\n"), opt_cipher);
+       } else {
+               for (i = 0; bciphers[i].cipher; i++) {
+                       r = crypt_benchmark(NULL, bciphers[i].cipher, bciphers[i].mode,
+                                           bciphers[i].key_size, bciphers[i].iv_size,
+                                           buffer_size, &enc_mbr, &dec_mbr);
+                       if (r == -ENOTSUP)
+                               break;
+                       if (r == -ENOENT)
+                               skipped++;
+                       if (i == 0)
+                               log_std("%s", header);
+
+                       snprintf(cipher, MAX_CIPHER_LEN, "%s-%s",
+                                bciphers[i].cipher, bciphers[i].mode);
+                       if (!r)
+                               log_std("%12s  %4db  %5.1f MiB/s  %5.1f MiB/s\n",
+                                       cipher, bciphers[i].key_size*8, enc_mbr, dec_mbr);
+                       else
+                               log_std("%12s  %4db %12s %12s\n", cipher,
+                                       bciphers[i].key_size*8, _("N/A"), _("N/A"));
+               }
+               if (skipped && skipped == i)
+                       r = -ENOTSUP;
+       }
+
+       if (r == -ENOTSUP)
+               log_err( _("Required kernel crypto interface not available.\n"
+                          "Ensure you have algif_skcipher kernel module loaded.\n"));
        return r;
 }
 
        return r;
 }
 
@@ -518,7 +537,7 @@ fail:
        return -EINVAL;
 }
 
        return -EINVAL;
 }
 
-static int action_luksRepair(int arg __attribute__((unused)))
+static int action_luksRepair(void)
 {
        struct crypt_device *cd = NULL;
        int r;
 {
        struct crypt_device *cd = NULL;
        int r;
@@ -527,15 +546,15 @@ static int action_luksRepair(int arg __attribute__((unused)))
                goto out;
 
        /* Currently only LUKS1 allows repair */
                goto out;
 
        /* Currently only LUKS1 allows repair */
-       crypt_set_log_callback(cd, _quiet_log, NULL);
+       crypt_set_log_callback(cd, quiet_log, NULL);
        r = crypt_load(cd, CRYPT_LUKS1, NULL);
        r = crypt_load(cd, CRYPT_LUKS1, NULL);
-       crypt_set_log_callback(cd, _log, NULL);
+       crypt_set_log_callback(cd, tool_log, NULL);
        if (r == 0) {
                log_verbose( _("No known problems detected for LUKS header.\n"));
                goto out;
        }
 
        if (r == 0) {
                log_verbose( _("No known problems detected for LUKS header.\n"));
                goto out;
        }
 
-       r = _yesDialog(_("Really try to repair LUKS device header?"),
+       r = yesDialog(_("Really try to repair LUKS device header?"),
                       NULL) ? 0 : -EINVAL;
        if (r == 0)
                r = crypt_repair(cd, CRYPT_LUKS1, NULL);
                       NULL) ? 0 : -EINVAL;
        if (r == 0)
                r = crypt_repair(cd, CRYPT_LUKS1, NULL);
@@ -544,7 +563,7 @@ out:
        return r;
 }
 
        return r;
 }
 
-static int action_luksFormat(int arg __attribute__((unused)))
+static int action_luksFormat(void)
 {
        int r = -EINVAL, keysize;
        const char *header_device;
 {
        int r = -EINVAL, keysize;
        const char *header_device;
@@ -566,7 +585,7 @@ static int action_luksFormat(int arg __attribute__((unused)))
                r = -ENOMEM;
                goto out;
        }
                r = -ENOMEM;
                goto out;
        }
-       r = _yesDialog(msg, NULL) ? 0 : -EINVAL;
+       r = yesDialog(msg, NULL) ? 0 : -EINVAL;
        free(msg);
        if (r < 0)
                goto out;
        free(msg);
        if (r < 0)
                goto out;
@@ -623,10 +642,10 @@ out:
        return r;
 }
 
        return r;
 }
 
-static int action_luksOpen(int arg __attribute__((unused)))
+static int action_open_luks(void)
 {
        struct crypt_device *cd = NULL;
 {
        struct crypt_device *cd = NULL;
-       const char *data_device, *header_device;
+       const char *data_device, *header_device, *activated_name;
        char *key = NULL;
        uint32_t flags = 0;
        int r, keysize;
        char *key = NULL;
        uint32_t flags = 0;
        int r, keysize;
@@ -639,6 +658,8 @@ static int action_luksOpen(int arg __attribute__((unused)))
                data_device = NULL;
        }
 
                data_device = NULL;
        }
 
+       activated_name = opt_test_passphrase ? NULL : action_argv[1];
+
        if ((r = crypt_init(&cd, header_device)))
                goto out;
 
        if ((r = crypt_init(&cd, header_device)))
                goto out;
 
@@ -673,15 +694,15 @@ static int action_luksOpen(int arg __attribute__((unused)))
                r = _read_mk(opt_master_key_file, &key, keysize);
                if (r < 0)
                        goto out;
                r = _read_mk(opt_master_key_file, &key, keysize);
                if (r < 0)
                        goto out;
-               r = crypt_activate_by_volume_key(cd, action_argv[1],
+               r = crypt_activate_by_volume_key(cd, activated_name,
                                                 key, keysize, flags);
        } else if (opt_key_file) {
                crypt_set_password_retry(cd, 1);
                                                 key, keysize, flags);
        } else if (opt_key_file) {
                crypt_set_password_retry(cd, 1);
-               r = crypt_activate_by_keyfile_offset(cd, action_argv[1],
+               r = crypt_activate_by_keyfile_offset(cd, activated_name,
                        opt_key_slot, opt_key_file, opt_keyfile_size,
                        opt_keyfile_offset, flags);
        } else
                        opt_key_slot, opt_key_file, opt_keyfile_size,
                        opt_keyfile_offset, flags);
        } else
-               r = crypt_activate_by_passphrase(cd, action_argv[1],
+               r = crypt_activate_by_passphrase(cd, activated_name,
                        opt_key_slot, NULL, 0, flags);
 out:
        crypt_safe_free(key);
                        opt_key_slot, NULL, 0, flags);
 out:
        crypt_safe_free(key);
@@ -700,7 +721,7 @@ static int verify_keyslot(struct crypt_device *cd, int key_slot,
        int i, r;
 
        ki = crypt_keyslot_status(cd, key_slot);
        int i, r;
 
        ki = crypt_keyslot_status(cd, key_slot);
-       if (ki == CRYPT_SLOT_ACTIVE_LAST && msg_last && !_yesDialog(msg_last, NULL))
+       if (ki == CRYPT_SLOT_ACTIVE_LAST && msg_last && !yesDialog(msg_last, NULL))
                return -EPERM;
 
        r = crypt_get_key(msg_pass, &password, &passwordLen,
                return -EPERM;
 
        r = crypt_get_key(msg_pass, &password, &passwordLen,
@@ -727,14 +748,14 @@ static int verify_keyslot(struct crypt_device *cd, int key_slot,
                }
        }
 
                }
        }
 
-       if (r < 0)
+       if (r == -EPERM)
                log_err(_("No key available with this passphrase.\n"));
 out:
        crypt_safe_free(password);
        return r;
 }
 
                log_err(_("No key available with this passphrase.\n"));
 out:
        crypt_safe_free(password);
        return r;
 }
 
-static int action_luksKillSlot(int arg __attribute__((unused)))
+static int action_luksKillSlot(void)
 {
        struct crypt_device *cd = NULL;
        int r;
 {
        struct crypt_device *cd = NULL;
        int r;
@@ -742,7 +763,7 @@ static int action_luksKillSlot(int arg __attribute__((unused)))
        if ((r = crypt_init(&cd, uuid_or_device(action_argv[0]))))
                goto out;
 
        if ((r = crypt_init(&cd, uuid_or_device(action_argv[0]))))
                goto out;
 
-       crypt_set_confirm_callback(cd, _yesDialog, NULL);
+       crypt_set_confirm_callback(cd, yesDialog, NULL);
        crypt_set_timeout(cd, opt_timeout);
 
        if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
        crypt_set_timeout(cd, opt_timeout);
 
        if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
@@ -775,7 +796,7 @@ out:
        return r;
 }
 
        return r;
 }
 
-static int action_luksRemoveKey(int arg __attribute__((unused)))
+static int action_luksRemoveKey(void)
 {
        struct crypt_device *cd = NULL;
        char *password = NULL;
 {
        struct crypt_device *cd = NULL;
        char *password = NULL;
@@ -785,7 +806,7 @@ static int action_luksRemoveKey(int arg __attribute__((unused)))
        if ((r = crypt_init(&cd, uuid_or_device(action_argv[0]))))
                goto out;
 
        if ((r = crypt_init(&cd, uuid_or_device(action_argv[0]))))
                goto out;
 
-       crypt_set_confirm_callback(cd, _yesDialog, NULL);
+       crypt_set_confirm_callback(cd, yesDialog, NULL);
        crypt_set_timeout(cd, opt_timeout);
 
        if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
        crypt_set_timeout(cd, opt_timeout);
 
        if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
@@ -809,7 +830,7 @@ static int action_luksRemoveKey(int arg __attribute__((unused)))
        log_verbose(_("Key slot %d selected for deletion.\n"), opt_key_slot);
 
        if (crypt_keyslot_status(cd, opt_key_slot) == CRYPT_SLOT_ACTIVE_LAST &&
        log_verbose(_("Key slot %d selected for deletion.\n"), opt_key_slot);
 
        if (crypt_keyslot_status(cd, opt_key_slot) == CRYPT_SLOT_ACTIVE_LAST &&
-           !_yesDialog(_("This is the last keyslot. "
+           !yesDialog(_("This is the last keyslot. "
                          "Device will become unusable after purging this key."),
                        NULL)) {
                r = -EPERM;
                          "Device will become unusable after purging this key."),
                        NULL)) {
                r = -EPERM;
@@ -823,7 +844,7 @@ out:
        return r;
 }
 
        return r;
 }
 
-static int action_luksAddKey(int arg __attribute__((unused)))
+static int action_luksAddKey(void)
 {
        int r = -EINVAL, keysize = 0;
        char *key = NULL;
 {
        int r = -EINVAL, keysize = 0;
        char *key = NULL;
@@ -833,7 +854,7 @@ static int action_luksAddKey(int arg __attribute__((unused)))
        if ((r = crypt_init(&cd, uuid_or_device(action_argv[0]))))
                goto out;
 
        if ((r = crypt_init(&cd, uuid_or_device(action_argv[0]))))
                goto out;
 
-       crypt_set_confirm_callback(cd, _yesDialog, NULL);
+       crypt_set_confirm_callback(cd, yesDialog, NULL);
 
        if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
                goto out;
 
        if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
                goto out;
@@ -876,7 +897,7 @@ static int _slots_full(struct crypt_device *cd)
        return 1;
 }
 
        return 1;
 }
 
-static int action_luksChangeKey(int arg __attribute__((unused)))
+static int action_luksChangeKey(void)
 {
        const char *opt_new_key_file = (action_argc > 1 ? action_argv[1] : NULL);
        struct crypt_device *cd = NULL;
 {
        const char *opt_new_key_file = (action_argc > 1 ? action_argv[1] : NULL);
        struct crypt_device *cd = NULL;
@@ -964,7 +985,7 @@ out:
        return r;
 }
 
        return r;
 }
 
-static int action_isLuks(int arg __attribute__((unused)))
+static int action_isLuks(void)
 {
        struct crypt_device *cd = NULL;
        int r;
 {
        struct crypt_device *cd = NULL;
        int r;
@@ -972,14 +993,14 @@ static int action_isLuks(int arg __attribute__((unused)))
        if ((r = crypt_init(&cd, action_argv[0])))
                goto out;
 
        if ((r = crypt_init(&cd, action_argv[0])))
                goto out;
 
-       crypt_set_log_callback(cd, _quiet_log, NULL);
+       crypt_set_log_callback(cd, quiet_log, NULL);
        r = crypt_load(cd, CRYPT_LUKS1, NULL);
 out:
        crypt_free(cd);
        return r;
 }
 
        r = crypt_load(cd, CRYPT_LUKS1, NULL);
 out:
        crypt_free(cd);
        return r;
 }
 
-static int action_luksUUID(int arg __attribute__((unused)))
+static int action_luksUUID(void)
 {
        struct crypt_device *cd = NULL;
        const char *existing_uuid = NULL;
 {
        struct crypt_device *cd = NULL;
        const char *existing_uuid = NULL;
@@ -988,7 +1009,7 @@ static int action_luksUUID(int arg __attribute__((unused)))
        if ((r = crypt_init(&cd, action_argv[0])))
                goto out;
 
        if ((r = crypt_init(&cd, action_argv[0])))
                goto out;
 
-       crypt_set_confirm_callback(cd, _yesDialog, NULL);
+       crypt_set_confirm_callback(cd, yesDialog, NULL);
 
        if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
                goto out;
 
        if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
                goto out;
@@ -1013,9 +1034,9 @@ static int luksDump_with_volume_key(struct crypt_device *cd)
        unsigned i;
        int r;
 
        unsigned i;
        int r;
 
-       crypt_set_confirm_callback(cd, _yesDialog, NULL);
-       if (!_yesDialog(
-           _("LUKS header dump with volume key is sensitive information\n"
+       crypt_set_confirm_callback(cd, yesDialog, NULL);
+       if (!yesDialog(
+           _("Header dump with volume key is sensitive information\n"
              "which allows access to encrypted partition without passphrase.\n"
              "This dump should be always stored encrypted on safe place."),
              NULL))
              "which allows access to encrypted partition without passphrase.\n"
              "This dump should be always stored encrypted on safe place."),
              NULL))
@@ -1058,7 +1079,7 @@ out:
        return r;
 }
 
        return r;
 }
 
-static int action_luksDump(int arg __attribute__((unused)))
+static int action_luksDump(void)
 {
        struct crypt_device *cd = NULL;
        int r;
 {
        struct crypt_device *cd = NULL;
        int r;
@@ -1078,7 +1099,7 @@ out:
        return r;
 }
 
        return r;
 }
 
-static int action_luksSuspend(int arg __attribute__((unused)))
+static int action_luksSuspend(void)
 {
        struct crypt_device *cd = NULL;
        int r;
 {
        struct crypt_device *cd = NULL;
        int r;
@@ -1091,7 +1112,7 @@ static int action_luksSuspend(int arg __attribute__((unused)))
        return r;
 }
 
        return r;
 }
 
-static int action_luksResume(int arg __attribute__((unused)))
+static int action_luksResume(void)
 {
        struct crypt_device *cd = NULL;
        int r;
 {
        struct crypt_device *cd = NULL;
        int r;
@@ -1114,7 +1135,7 @@ out:
        return r;
 }
 
        return r;
 }
 
-static int action_luksBackup(int arg __attribute__((unused)))
+static int action_luksBackup(void)
 {
        struct crypt_device *cd = NULL;
        int r;
 {
        struct crypt_device *cd = NULL;
        int r;
@@ -1127,7 +1148,7 @@ static int action_luksBackup(int arg __attribute__((unused)))
        if ((r = crypt_init(&cd, uuid_or_device(action_argv[0]))))
                goto out;
 
        if ((r = crypt_init(&cd, uuid_or_device(action_argv[0]))))
                goto out;
 
-       crypt_set_confirm_callback(cd, _yesDialog, NULL);
+       crypt_set_confirm_callback(cd, yesDialog, NULL);
 
        r = crypt_header_backup(cd, CRYPT_LUKS1, opt_header_backup_file);
 out:
 
        r = crypt_header_backup(cd, CRYPT_LUKS1, opt_header_backup_file);
 out:
@@ -1135,7 +1156,7 @@ out:
        return r;
 }
 
        return r;
 }
 
-static int action_luksRestore(int arg __attribute__((unused)))
+static int action_luksRestore(void)
 {
        struct crypt_device *cd = NULL;
        int r = 0;
 {
        struct crypt_device *cd = NULL;
        int r = 0;
@@ -1148,24 +1169,73 @@ static int action_luksRestore(int arg __attribute__((unused)))
        if ((r = crypt_init(&cd, action_argv[0])))
                goto out;
 
        if ((r = crypt_init(&cd, action_argv[0])))
                goto out;
 
-       crypt_set_confirm_callback(cd, _yesDialog, NULL);
+       crypt_set_confirm_callback(cd, yesDialog, NULL);
        r = crypt_header_restore(cd, CRYPT_LUKS1, opt_header_backup_file);
 out:
        crypt_free(cd);
        return r;
 }
 
        r = crypt_header_restore(cd, CRYPT_LUKS1, opt_header_backup_file);
 out:
        crypt_free(cd);
        return r;
 }
 
-static __attribute__ ((noreturn)) void usage(poptContext popt_context,
-                                            int exitcode, const char *error,
-                                            const char *more)
+static int action_open(void)
 {
 {
-       poptPrintUsage(popt_context, stderr, 0);
-       if (error)
-               log_err("%s: %s\n", more, error);
-       poptFreeContext(popt_context);
-       exit(exitcode);
+       if (!opt_type)
+               return -EINVAL;
+
+       if (!strcmp(opt_type, "luks") || !strcmp(opt_type, "luks1")) {
+               if (action_argc < 2 && !opt_test_passphrase)
+                       goto args;
+               return action_open_luks();
+       } else if (!strcmp(opt_type, "plain")) {
+               if (action_argc < 2)
+                       goto args;
+               return action_open_plain();
+       } else if (!strcmp(opt_type, "loopaes")) {
+               if (action_argc < 2)
+                       goto args;
+               return action_open_loopaes();
+       } else if (!strcmp(opt_type, "tcrypt")) {
+               if (action_argc < 2 && !opt_test_passphrase)
+                       goto args;
+               return action_open_tcrypt();
+       }
+
+       log_err(_("Unrecognized metadata device type %s.\n"), opt_type);
+       return -EINVAL;
+args:
+       log_err(_("Command requires device and mapped name as arguments.\n"));
+       return -EINVAL;
 }
 
 }
 
+static struct action_type {
+       const char *type;
+       int (*handler)(void);
+       int required_action_argc;
+       int required_memlock;
+       const char *arg_desc;
+       const char *desc;
+} action_types[] = {
+       { "open",         action_open,         1, 1, N_("<device> [<name>]"),N_("open device as mapping <name>") },
+       { "close",        action_close,        1, 1, N_("<name>"), N_("close device (remove mapping)") },
+       { "resize",       action_resize,       1, 1, N_("<name>"), N_("resize active device") },
+       { "status",       action_status,       1, 0, N_("<name>"), N_("show device status") },
+       { "benchmark",    action_benchmark,    0, 0, N_("<name>"), N_("benchmark cipher") },
+       { "repair",       action_luksRepair,   1, 1, N_("<device>"), N_("try to repair on-disk metadata") },
+       { "luksFormat",   action_luksFormat,   1, 1, N_("<device> [<new key file>]"), N_("formats a LUKS device") },
+       { "luksAddKey",   action_luksAddKey,   1, 1, N_("<device> [<new key file>]"), N_("add key to LUKS device") },
+       { "luksRemoveKey",action_luksRemoveKey,1, 1, N_("<device> [<key file>]"), N_("removes supplied key or key file from LUKS device") },
+       { "luksChangeKey",action_luksChangeKey,1, 1, N_("<device> [<key file>]"), N_("changes supplied key or key file of LUKS device") },
+       { "luksKillSlot", action_luksKillSlot, 2, 1, N_("<device> <key slot>"), N_("wipes key with number <key slot> from LUKS device") },
+       { "luksUUID",     action_luksUUID,     1, 0, N_("<device>"), N_("print UUID of LUKS device") },
+       { "isLuks",       action_isLuks,       1, 0, N_("<device>"), N_("tests <device> for LUKS partition header") },
+       { "luksDump",     action_luksDump,     1, 1, N_("<device>"), N_("dump LUKS partition information") },
+       { "tcryptDump",   action_tcryptDump,   1, 1, N_("<device>"), N_("dump TCRYPT device information") },
+       { "luksSuspend",  action_luksSuspend,  1, 1, N_("<device>"), N_("Suspend LUKS device and wipe key (all IOs are frozen).") },
+       { "luksResume",   action_luksResume,   1, 1, N_("<device>"), N_("Resume suspended LUKS device.") },
+       { "luksHeaderBackup", action_luksBackup,1,1, N_("<device>"), N_("Backup LUKS device header and keyslots") },
+       { "luksHeaderRestore",action_luksRestore,1,1,N_("<device>"), N_("Restore LUKS device header and keyslots") },
+       {}
+};
+
 static void help(poptContext popt_context,
                 enum poptCallbackReason reason __attribute__((unused)),
                 struct poptOption *key,
 static void help(poptContext popt_context,
                 enum poptCallbackReason reason __attribute__((unused)),
                 struct poptOption *key,
@@ -1192,10 +1262,12 @@ static void help(poptContext popt_context,
                         "<key file> optional key file for the new key for luksAddKey action\n"),
                        crypt_get_dir());
 
                         "<key file> optional key file for the new key for luksAddKey action\n"),
                        crypt_get_dir());
 
-               log_std(_("\nDefault compiled-in keyfile parameters:\n"
+               log_std(_("\nDefault compiled-in key and passphrase parameters:\n"
                         "\tMaximum keyfile size: %dkB, "
                         "\tMaximum keyfile size: %dkB, "
-                        "Maximum interactive passphrase length %d (characters)\n"),
-                        DEFAULT_KEYFILE_SIZE_MAXKB, DEFAULT_PASSPHRASE_SIZE_MAX);
+                        "Maximum interactive passphrase length %d (characters)\n"
+                        "Default PBKDF2 iteration time for LUKS: %d (ms)\n"),
+                        DEFAULT_KEYFILE_SIZE_MAXKB, DEFAULT_PASSPHRASE_SIZE_MAX,
+                        DEFAULT_LUKS1_ITER_TIME);
 
                log_std(_("\nDefault compiled-in device cipher parameters:\n"
                         "\tloop-AES: %s, Key %d bits\n"
 
                log_std(_("\nDefault compiled-in device cipher parameters:\n"
                         "\tloop-AES: %s, Key %d bits\n"
@@ -1210,17 +1282,12 @@ static void help(poptContext popt_context,
                usage(popt_context, EXIT_SUCCESS, NULL, NULL);
 }
 
                usage(popt_context, EXIT_SUCCESS, NULL, NULL);
 }
 
-static void _dbg_version_and_cmd(int argc, const char **argv)
+static void help_args(struct action_type *action, poptContext popt_context)
 {
 {
-       int i;
+       char buf[128];
 
 
-       log_std("# %s %s processing \"", PACKAGE_NAME, PACKAGE_VERSION);
-       for (i = 0; i < argc; i++) {
-               if (i)
-                       log_std(" ");
-               log_std("%s", argv[i]);
-       }
-       log_std("\"\n");
+       snprintf(buf, sizeof(buf), _("%s: requires %s as arguments"), action->type, action->arg_desc);
+       usage(popt_context, EXIT_FAILURE, buf, poptGetInvocationName(popt_context));
 }
 
 static int run_action(struct action_type *action)
 }
 
 static int run_action(struct action_type *action)
@@ -1232,7 +1299,7 @@ static int run_action(struct action_type *action)
        if (action->required_memlock)
                crypt_memory_lock(NULL, 1);
 
        if (action->required_memlock)
                crypt_memory_lock(NULL, 1);
 
-       r = action->handler(action->arg);
+       r = action->handler();
 
        if (action->required_memlock)
                crypt_memory_lock(NULL, 0);
 
        if (action->required_memlock)
                crypt_memory_lock(NULL, 0);
@@ -1242,22 +1309,7 @@ static int run_action(struct action_type *action)
                r = 0;
 
        show_status(r);
                r = 0;
 
        show_status(r);
-
-       /* Translate exit code to simple codes */
-       switch (r) {
-       case 0:         r = EXIT_SUCCESS; break;
-       case -EEXIST:
-       case -EBUSY:    r = 5; break;
-       case -ENOTBLK:
-       case -ENODEV:   r = 4; break;
-       case -ENOMEM:   r = 3; break;
-       case -EPERM:    r = 2; break;
-       case -EINVAL:
-       case -ENOENT:
-       case -ENOSYS:
-       default:        r = EXIT_FAILURE;
-       }
-       return r;
+       return translate_errno(r);
 }
 
 int main(int argc, const char **argv)
 }
 
 int main(int argc, const char **argv)
@@ -1277,7 +1329,7 @@ int main(int argc, const char **argv)
                { "cipher",            'c',  POPT_ARG_STRING, &opt_cipher,              0, N_("The cipher used to encrypt the disk (see /proc/crypto)"), NULL },
                { "hash",              'h',  POPT_ARG_STRING, &opt_hash,                0, N_("The hash used to create the encryption key from the passphrase"), NULL },
                { "verify-passphrase", 'y',  POPT_ARG_NONE, &opt_verify_passphrase,     0, N_("Verifies the passphrase by asking for it twice"), NULL },
                { "cipher",            'c',  POPT_ARG_STRING, &opt_cipher,              0, N_("The cipher used to encrypt the disk (see /proc/crypto)"), NULL },
                { "hash",              'h',  POPT_ARG_STRING, &opt_hash,                0, N_("The hash used to create the encryption key from the passphrase"), NULL },
                { "verify-passphrase", 'y',  POPT_ARG_NONE, &opt_verify_passphrase,     0, N_("Verifies the passphrase by asking for it twice"), NULL },
-               { "key-file",          'd',  POPT_ARG_STRING, &opt_key_file,            0, N_("Read the key from a file."), NULL },
+               { "key-file",          'd',  POPT_ARG_STRING, &opt_key_file,            5, N_("Read the key from a file."), NULL },
                { "master-key-file",  '\0',  POPT_ARG_STRING, &opt_master_key_file,     0, N_("Read the volume (master) key from file."), NULL },
                { "dump-master-key",  '\0',  POPT_ARG_NONE, &opt_dump_master_key,       0, N_("Dump volume (master) key instead of keyslots info."), NULL },
                { "key-size",          's',  POPT_ARG_INT, &opt_key_size,               0, N_("The size of the encryption key"), N_("BITS") },
                { "master-key-file",  '\0',  POPT_ARG_STRING, &opt_master_key_file,     0, N_("Read the volume (master) key from file."), NULL },
                { "dump-master-key",  '\0',  POPT_ARG_NONE, &opt_dump_master_key,       0, N_("Dump volume (master) key instead of keyslots info."), NULL },
                { "key-size",          's',  POPT_ARG_INT, &opt_key_size,               0, N_("The size of the encryption key"), N_("BITS") },
@@ -1302,15 +1354,17 @@ int main(int argc, const char **argv)
                { "uuid",              '\0', POPT_ARG_STRING, &opt_uuid,                0, N_("UUID for device to use."), NULL },
                { "allow-discards",    '\0', POPT_ARG_NONE, &opt_allow_discards,        0, N_("Allow discards (aka TRIM) requests for device."), NULL },
                { "header",            '\0', POPT_ARG_STRING, &opt_header_device,       0, N_("Device or file with separated LUKS header."), NULL },
                { "uuid",              '\0', POPT_ARG_STRING, &opt_uuid,                0, N_("UUID for device to use."), NULL },
                { "allow-discards",    '\0', POPT_ARG_NONE, &opt_allow_discards,        0, N_("Allow discards (aka TRIM) requests for device."), NULL },
                { "header",            '\0', POPT_ARG_STRING, &opt_header_device,       0, N_("Device or file with separated LUKS header."), NULL },
+               { "test-passphrase",   '\0', POPT_ARG_NONE, &opt_test_passphrase,       0, N_("Do not activate device, just check passphrase."), NULL },
+               { "hidden",            '\0', POPT_ARG_NONE, &opt_hidden,                0, N_("Use hidden header (hidden TCRYPT device) ."), NULL },
+               { "type",              'M',  POPT_ARG_STRING, &opt_type,                0, N_("Type of device metadata: luks, plain, loopaes, tcrypt."), NULL },
                POPT_TABLEEND
        };
        poptContext popt_context;
        struct action_type *action;
        const char *aname;
        int r;
                POPT_TABLEEND
        };
        poptContext popt_context;
        struct action_type *action;
        const char *aname;
        int r;
-       const char *null_action_argv[] = {NULL};
 
 
-       crypt_set_log_callback(NULL, _log, NULL);
+       crypt_set_log_callback(NULL, tool_log, NULL);
 
        setlocale(LC_ALL, "");
        bindtextdomain(PACKAGE, LOCALEDIR);
 
        setlocale(LC_ALL, "");
        bindtextdomain(PACKAGE, LOCALEDIR);
@@ -1320,12 +1374,18 @@ int main(int argc, const char **argv)
 
        popt_context = poptGetContext(PACKAGE, argc, argv, popt_options, 0);
        poptSetOtherOptionHelp(popt_context,
 
        popt_context = poptGetContext(PACKAGE, argc, argv, popt_options, 0);
        poptSetOtherOptionHelp(popt_context,
-                              N_("[OPTION...] <action> <action-specific>]"));
+                              _("[OPTION...] <action> <action-specific>"));
 
        while((r = poptGetNextOpt(popt_context)) > 0) {
                unsigned long long ull_value;
                char *endp;
 
 
        while((r = poptGetNextOpt(popt_context)) > 0) {
                unsigned long long ull_value;
                char *endp;
 
+               if (r == 5) {
+                       if (opt_keyfiles_count < MAX_KEYFILES)
+                               opt_keyfiles[opt_keyfiles_count++] = poptGetOptArg(popt_context);
+                       continue;
+               }
+
                errno = 0;
                ull_value = strtoull(popt_tmp, &endp, 0);
                if (*endp || !*popt_tmp ||
                errno = 0;
                ull_value = strtoull(popt_tmp, &endp, 0);
                if (*endp || !*popt_tmp ||
@@ -1362,12 +1422,6 @@ int main(int argc, const char **argv)
        if (!(aname = poptGetArg(popt_context)))
                usage(popt_context, EXIT_FAILURE, _("Argument <action> missing."),
                      poptGetInvocationName(popt_context));
        if (!(aname = poptGetArg(popt_context)))
                usage(popt_context, EXIT_FAILURE, _("Argument <action> missing."),
                      poptGetInvocationName(popt_context));
-       for(action = action_types; action->type; action++)
-               if (strcmp(action->type, aname) == 0)
-                       break;
-       if (!action->type)
-               usage(popt_context, EXIT_FAILURE, _("Unknown action."),
-                     poptGetInvocationName(popt_context));
 
        action_argc = 0;
        action_argv = poptGetArgs(popt_context);
 
        action_argc = 0;
        action_argv = poptGetArgs(popt_context);
@@ -1379,39 +1433,73 @@ int main(int argc, const char **argv)
        while(action_argv[action_argc] != NULL)
                action_argc++;
 
        while(action_argv[action_argc] != NULL)
                action_argc++;
 
-       if(action_argc < action->required_action_argc) {
-               char buf[128];
-               snprintf(buf, 128,_("%s: requires %s as arguments"), action->type, action->arg_desc);
-               usage(popt_context, EXIT_FAILURE, buf,
-                     poptGetInvocationName(popt_context));
+       /* Handle aliases */
+       if (!strcmp(aname, "create")) {
+               /* create command had historically switched arguments */
+               if (action_argv[0] && action_argv[1]) {
+                       const char *tmp = action_argv[0];
+                       action_argv[0] = action_argv[1];
+                       action_argv[1] = tmp;
+               }
+               aname = "open";
+               opt_type = "plain";
+       } else if (!strcmp(aname, "plainOpen")) {
+               aname = "open";
+               opt_type = "plain";
+       } else if (!strcmp(aname, "luksOpen")) {
+               aname = "open";
+               opt_type = "luks";
+       } else if (!strcmp(aname, "loopaesOpen")) {
+               aname = "open";
+               opt_type = "loopaes";
+       } else if (!strcmp(aname, "tcryptOpen")) {
+               aname = "open";
+               opt_type = "tcrypt";
+       } else if (!strcmp(aname, "remove") ||
+                  !strcmp(aname, "plainClose") ||
+                  !strcmp(aname, "luksClose") ||
+                  !strcmp(aname, "loopaesClose") ||
+                  !strcmp(aname, "tcryptClose")) {
+               aname = "close";
        }
 
        }
 
+       for(action = action_types; action->type; action++)
+               if (strcmp(action->type, aname) == 0)
+                       break;
+
+       if (!action->type)
+               usage(popt_context, EXIT_FAILURE, _("Unknown action."),
+                     poptGetInvocationName(popt_context));
+
+       if(action_argc < action->required_action_argc)
+               help_args(action, popt_context);
+
        /* FIXME: rewrite this from scratch */
 
        /* FIXME: rewrite this from scratch */
 
-       if (opt_shared && strcmp(aname, "create")) {
+       if (opt_shared && (strcmp(aname, "open") || strcmp(opt_type, "plain")) )
                usage(popt_context, EXIT_FAILURE,
                usage(popt_context, EXIT_FAILURE,
-                     _("Option --shared is allowed only for create operation.\n"),
+                     _("Option --shared is allowed only for open of plain device.\n"),
                      poptGetInvocationName(popt_context));
                      poptGetInvocationName(popt_context));
-       }
 
 
-       if (opt_allow_discards &&
-           strcmp(aname, "luksOpen") &&
-           strcmp(aname, "create") &&
-           strcmp(aname, "loopaesOpen")) {
+       if (opt_allow_discards && strcmp(aname, "open"))
                usage(popt_context, EXIT_FAILURE,
                usage(popt_context, EXIT_FAILURE,
-                     _("Option --allow-discards is allowed only for luksOpen, loopaesOpen and create operation.\n"),
+                     _("Option --allow-discards is allowed only for open operation.\n"),
                      poptGetInvocationName(popt_context));
                      poptGetInvocationName(popt_context));
-       }
 
        if (opt_key_size &&
           strcmp(aname, "luksFormat") &&
 
        if (opt_key_size &&
           strcmp(aname, "luksFormat") &&
-          strcmp(aname, "create") &&
-          strcmp(aname, "loopaesOpen")) {
+          strcmp(aname, "open") &&
+          strcmp(aname, "benchmark"))
                usage(popt_context, EXIT_FAILURE,
                usage(popt_context, EXIT_FAILURE,
-                     _("Option --key-size is allowed only for luksFormat, create and loopaesOpen.\n"
+                     _("Option --key-size is allowed only for luksFormat, open and benchmark.\n"
                        "To limit read from keyfile use --keyfile-size=(bytes)."),
                      poptGetInvocationName(popt_context));
                        "To limit read from keyfile use --keyfile-size=(bytes)."),
                      poptGetInvocationName(popt_context));
-       }
+
+       if (opt_test_passphrase && (strcmp(aname, "open") ||
+           (strcmp(opt_type, "luks") && strcmp(opt_type, "tcrypt"))))
+               usage(popt_context, EXIT_FAILURE,
+                     _("Option --test-passphrase is allowed only for open of LUKS and TCRYPT devices.\n"),
+                     poptGetInvocationName(popt_context));
 
        if (opt_key_size % 8)
                usage(popt_context, EXIT_FAILURE,
 
        if (opt_key_size % 8)
                usage(popt_context, EXIT_FAILURE,
@@ -1435,11 +1523,10 @@ int main(int argc, const char **argv)
        }
 
        if (opt_keyfile_size < 0 || opt_new_keyfile_size < 0 || opt_key_size < 0 ||
        }
 
        if (opt_keyfile_size < 0 || opt_new_keyfile_size < 0 || opt_key_size < 0 ||
-           opt_keyfile_offset < 0 || opt_new_keyfile_offset < 0) {
+           opt_keyfile_offset < 0 || opt_new_keyfile_offset < 0)
                usage(popt_context, EXIT_FAILURE,
                      _("Negative number for option not permitted."),
                      poptGetInvocationName(popt_context));
                usage(popt_context, EXIT_FAILURE,
                      _("Negative number for option not permitted."),
                      poptGetInvocationName(popt_context));
-       }
 
        if (opt_random && opt_urandom)
                usage(popt_context, EXIT_FAILURE, _("Only one of --use-[u]random options is allowed."),
 
        if (opt_random && opt_urandom)
                usage(popt_context, EXIT_FAILURE, _("Only one of --use-[u]random options is allowed."),
@@ -1457,20 +1544,28 @@ int main(int argc, const char **argv)
                usage(popt_context, EXIT_FAILURE, _("Option --align-payload is allowed only for luksFormat."),
                      poptGetInvocationName(popt_context));
 
                usage(popt_context, EXIT_FAILURE, _("Option --align-payload is allowed only for luksFormat."),
                      poptGetInvocationName(popt_context));
 
-       if (opt_skip && strcmp(aname, "create") && strcmp(aname, "loopaesOpen"))
+       if (opt_skip && (strcmp(aname, "open") ||
+           (strcmp(opt_type, "plain") && strcmp(opt_type, "loopaes"))))
+               usage(popt_context, EXIT_FAILURE,
+               _("Option --skip is supported only for open of plain and loopaes devices.\n"),
+               poptGetInvocationName(popt_context));
+
+       if (opt_offset && (strcmp(aname, "open") ||
+           (strcmp(opt_type, "plain") && strcmp(opt_type, "loopaes"))))
                usage(popt_context, EXIT_FAILURE,
                usage(popt_context, EXIT_FAILURE,
-               _("Option --skip is supported only for create and loopaesOpen commands.\n"),
+               _("Option --offset is supported only for open of plain and loopaes devices.\n"),
                poptGetInvocationName(popt_context));
 
                poptGetInvocationName(popt_context));
 
-       if (opt_offset && strcmp(aname, "create") && strcmp(aname, "loopaesOpen"))
+       if (opt_hidden && strcmp(aname, "tcryptDump") &&
+           (strcmp(aname, "open") || strcmp(opt_type, "tcrypt")))
                usage(popt_context, EXIT_FAILURE,
                usage(popt_context, EXIT_FAILURE,
-               _("Option --offset is supported only for create and loopaesOpen commands.\n"),
+               _("Option --hidden is supported only for TCRYPT device.\n"),
                poptGetInvocationName(popt_context));
 
        if (opt_debug) {
                opt_verbose = 1;
                crypt_set_debug_level(-1);
                poptGetInvocationName(popt_context));
 
        if (opt_debug) {
                opt_verbose = 1;
                crypt_set_debug_level(-1);
-               _dbg_version_and_cmd(argc, argv);
+               dbg_version_and_cmd(argc, argv);
        }
 
        r = run_action(action);
        }
 
        r = run_action(action);