X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fcryptsetup_reencrypt.c;h=8bf064c48b081716f494ad3ee15ac5b0a2f87e5a;hb=ab080ab5449640d964ef67e51547e08757a7e9d7;hp=34ef0d05a7ee128fd67adca41c0175c95634a6da;hpb=cc948df1ddef3511ac8ac48d183f745a13746e57;p=platform%2Fupstream%2Fcryptsetup.git diff --git a/src/cryptsetup_reencrypt.c b/src/cryptsetup_reencrypt.c index 34ef0d0..8bf064c 100644 --- a/src/cryptsetup_reencrypt.c +++ b/src/cryptsetup_reencrypt.c @@ -1,12 +1,13 @@ /* * cryptsetup-reencrypt - crypt utility for offline re-encryption * - * Copyright (C) 2012 Milan Broz All rights reserved. + * Copyright (C) 2012, Milan Broz All rights reserved. * Copyright (C) 2012, Red Hat, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -18,61 +19,49 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#define PACKAGE_REENC "crypt_reencrypt" - -#define _LARGEFILE64_SOURCE -#define _FILE_OFFSET_BITS 64 -#define SECTOR_SIZE 512 - -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "cryptsetup.h" #include #include #include #include -#include -#include -#include -#include "cryptsetup.h" +#define PACKAGE_REENC "crypt_reencrypt" + +#define NO_UUID "cafecafe-cafe-cafe-cafe-cafecafeeeee" +#define MAX_BCK_SECTORS 8192 -static int opt_verbose = 0; -static int opt_debug = 0; static const char *opt_cipher = NULL; static const char *opt_hash = NULL; static const char *opt_key_file = NULL; static long opt_keyfile_size = 0; static long opt_keyfile_offset = 0; static int opt_iteration_time = 1000; -static int opt_batch_mode = 0; static int opt_version_mode = 0; static int opt_random = 0; static int opt_urandom = 0; static int opt_bsize = 4; -static int opt_reduce_device_size = 0; static int opt_directio = 0; static int opt_fsync = 0; static int opt_write_log = 0; static int opt_tries = 3; static int opt_key_slot = CRYPT_ANY_SLOT; static int opt_key_size = 0; +static int opt_new = 0; -static const char **action_argv; +static const char *opt_reduce_size_str = NULL; +static uint64_t opt_reduce_size = 0; + +static const char *opt_device_size_str = NULL; +static uint64_t opt_device_size = 0; -static volatile int quit = 0; +static const char **action_argv; #define MAX_SLOT 8 struct reenc_ctx { char *device; char *device_uuid; - uint64_t device_size; + uint64_t device_size; /* overrided by parameter */ + uint64_t device_size_real; uint64_t device_offset; uint64_t device_shift; @@ -95,7 +84,7 @@ struct reenc_ctx { int keyslot; struct timeval start_time, end_time; - uint64_t restart_bytes; + uint64_t resume_bytes; }; char MAGIC[] = {'L','U','K','S', 0xba, 0xbe}; @@ -109,81 +98,11 @@ typedef enum { CHECK_OPEN, } header_magic; -__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); - } else if (opt_debug) - printf("# %s\n", target); - } - - va_end(argp); - free(target); -} - -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_debug) return; - _log(level, msg, usrptr); -} - -static void int_handler(int sig __attribute__((__unused__))) -{ - quit++; -} - -static void set_int_block(int block) -{ - sigset_t signals_open; - - sigemptyset(&signals_open); - sigaddset(&signals_open, SIGINT); - sigaddset(&signals_open, SIGTERM); - sigprocmask(block ? SIG_SETMASK : SIG_UNBLOCK, &signals_open, NULL); -} - -static void set_int_handler(void) -{ - struct sigaction sigaction_open; - - memset(&sigaction_open, 0, sizeof(struct sigaction)); - sigaction_open.sa_handler = int_handler; - sigaction(SIGINT, &sigaction_open, 0); - sigaction(SIGTERM, &sigaction_open, 0); - set_int_block(0); + tool_log(level, msg, usrptr); } /* The difference in seconds between two times in "timeval" format. */ @@ -236,8 +155,8 @@ static int device_check(struct reenc_ctx *rc, header_magic set_magic) s = read(devfd, buf, SECTOR_SIZE); if (s < 0 || s != SECTOR_SIZE) { log_err(_("Cannot read device %s.\n"), rc->device); - close(devfd); - return -EIO; + r = -EIO; + goto out; } /* Be sure that we do not process new version of header */ @@ -284,20 +203,22 @@ static int create_empty_header(const char *new_file, const char *old_file, uint64_t data_sector) { struct stat st; - ssize_t size; + ssize_t size = 0; int fd, r = 0; char *buf; /* Never create header > 4MiB */ - if (data_sector > 8192) - data_sector = 8192; + if (data_sector > MAX_BCK_SECTORS) + data_sector = MAX_BCK_SECTORS; /* new header file of the same size as old backup */ - if (stat(old_file, &st) == -1 || - (st.st_mode & S_IFMT) != S_IFREG || - (st.st_size > 16 * 1024 * 1024)) - return -EINVAL; - size = st.st_size; + if (old_file) { + if (stat(old_file, &st) == -1 || + (st.st_mode & S_IFMT) != S_IFREG || + (st.st_size > 16 * 1024 * 1024)) + return -EINVAL; + size = st.st_size; + } /* * if requesting key size change, try to use offset @@ -307,12 +228,12 @@ static int create_empty_header(const char *new_file, const char *old_file, size = data_sector * SECTOR_SIZE; /* if reducing size, be sure we have enough space */ - if (opt_reduce_device_size) - size += (opt_reduce_device_size * SECTOR_SIZE); + if (opt_reduce_size) + size += opt_reduce_size; log_dbg("Creating empty file %s of size %lu.", new_file, (unsigned long)size); - if (!(buf = malloc(size))) + if (!size || !(buf = malloc(size))) return -ENOMEM; memset(buf, 0, size); @@ -341,7 +262,9 @@ static int write_log(struct reenc_ctx *rc) 1, rc->device_uuid, rc->reencrypt_direction, rc->device_offset, rc->device_shift); - lseek(rc->log_fd, 0, SEEK_SET); + if (lseek(rc->log_fd, 0, SEEK_SET) == -1) + return -EIO; + r = write(rc->log_fd, rc->log_buf, SECTOR_SIZE); if (r < 0 || r != SECTOR_SIZE) { log_err(_("Cannot write reencryption log file.\n")); @@ -426,38 +349,27 @@ static void close_log(struct reenc_ctx *rc) static int open_log(struct reenc_ctx *rc) { - int flags, create_new; - struct stat st; - - if (!stat(rc->log_file, &st)) - create_new = 0; - else if (errno == ENOENT) - create_new = 1; - else - return -EINVAL; - - if (create_new) { - log_dbg("Creating LUKS reencryption log file %s.", rc->log_file); - flags = opt_directio ? O_RDWR|O_CREAT|O_DIRECT : O_RDWR|O_CREAT; - rc->log_fd = open(rc->log_file, flags, S_IRUSR|S_IWUSR); - if (rc->log_fd == -1) - return -EINVAL; - } else { - log_std(_("Log file %s exists, restarting reencryption.\n"), rc->log_file); - flags = opt_directio ? O_RDWR|O_DIRECT : O_RDWR; - rc->log_fd = open(rc->log_file, flags); - if (rc->log_fd == -1) - return -EINVAL; + int flags = opt_directio ? O_DIRECT : 0; + + rc->log_fd = open(rc->log_file, O_RDWR|O_EXCL|O_CREAT|flags, S_IRUSR|S_IWUSR); + if (rc->log_fd != -1) { + log_dbg("Created LUKS reencryption log file %s.", rc->log_file); + } else if (errno == EEXIST) { + log_std(_("Log file %s exists, resuming reencryption.\n"), rc->log_file); + rc->log_fd = open(rc->log_file, O_RDWR|flags); rc->in_progress = 1; } + if (rc->log_fd == -1) + return -EINVAL; + if (posix_memalign((void *)&rc->log_buf, alignment(rc->log_fd), SECTOR_SIZE)) { log_err(_("Allocation of aligned memory failed.\n")); close_log(rc); return -ENOMEM; } - if (create_new && write_log(rc) < 0) { + if (!rc->in_progress && write_log(rc) < 0) { close_log(rc); return -EIO; } @@ -478,6 +390,7 @@ static int activate_luks_headers(struct reenc_ctx *rc) (r = crypt_set_data_device(cd, rc->device))) goto out; + log_verbose(_("Activating temporary device using old LUKS header.\n")); if ((r = crypt_activate_by_passphrase(cd, rc->header_file_org, opt_key_slot, rc->p[rc->keyslot].password, rc->p[rc->keyslot].passwordLen, CRYPT_ACTIVATE_READONLY|CRYPT_ACTIVATE_PRIVATE)) < 0) @@ -488,6 +401,7 @@ static int activate_luks_headers(struct reenc_ctx *rc) (r = crypt_set_data_device(cd_new, rc->device))) goto out; + log_verbose(_("Activating temporary device using new LUKS header.\n")); if ((r = crypt_activate_by_passphrase(cd_new, rc->header_file_new, opt_key_slot, rc->p[rc->keyslot].password, rc->p[rc->keyslot].passwordLen, CRYPT_ACTIVATE_SHARED|CRYPT_ACTIVATE_PRIVATE)) < 0) @@ -501,12 +415,49 @@ out: return r; } +static int create_new_header(struct reenc_ctx *rc, const char *cipher, + const char *cipher_mode, const char *uuid, + int key_size, struct crypt_params_luks1 *params) +{ + struct crypt_device *cd_new = NULL; + int i, r; + + if ((r = crypt_init(&cd_new, rc->header_file_new))) + goto out; + + if (opt_random) + crypt_set_rng_type(cd_new, CRYPT_RNG_RANDOM); + else if (opt_urandom) + crypt_set_rng_type(cd_new, CRYPT_RNG_URANDOM); + + if (opt_iteration_time) + crypt_set_iteration_time(cd_new, opt_iteration_time); + + if ((r = crypt_format(cd_new, CRYPT_LUKS1, cipher, cipher_mode, + uuid, NULL, key_size, params))) + goto out; + log_verbose(_("New LUKS header for device %s created.\n"), rc->device); + + for (i = 0; i < MAX_SLOT; i++) { + if (!rc->p[i].password) + continue; + if ((r = crypt_keyslot_add_by_volume_key(cd_new, i, + NULL, 0, rc->p[i].password, rc->p[i].passwordLen)) < 0) + goto out; + log_verbose(_("Activated keyslot %i.\n"), r); + r = 0; + } +out: + crypt_free(cd_new); + return r; +} + static int backup_luks_headers(struct reenc_ctx *rc) { - struct crypt_device *cd = NULL, *cd_new = NULL; + struct crypt_device *cd = NULL; struct crypt_params_luks1 params = {0}; char cipher [MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN]; - int i, r; + int r; log_dbg("Creating LUKS header backup for device %s.", rc->device); @@ -525,20 +476,43 @@ static int backup_luks_headers(struct reenc_ctx *rc) params.hash = opt_hash ?: DEFAULT_LUKS1_HASH; params.data_alignment = crypt_get_data_offset(cd); - params.data_alignment += opt_reduce_device_size; + params.data_alignment += ROUND_SECTOR(opt_reduce_size); params.data_device = rc->device; + 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")); + goto out; + } + } + + r = create_new_header(rc, + opt_cipher ? cipher : crypt_get_cipher(cd), + opt_cipher ? cipher_mode : crypt_get_cipher_mode(cd), + crypt_get_uuid(cd), + opt_key_size ? opt_key_size / 8 : crypt_get_volume_key_size(cd), + ¶ms); +out: + crypt_free(cd); + if (r) + log_err(_("Creation of LUKS backup headers failed.\n")); + return r; +} - if ((r = crypt_init(&cd_new, rc->header_file_new))) - goto out; +/* Create fake header for original device */ +static int backup_fake_header(struct reenc_ctx *rc) +{ + struct crypt_device *cd_new = NULL; + struct crypt_params_luks1 params = {0}; + char cipher [MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN]; - if (opt_random) - crypt_set_rng_type(cd_new, CRYPT_RNG_RANDOM); - else if (opt_urandom) - crypt_set_rng_type(cd_new, CRYPT_RNG_URANDOM); + int r; - if (opt_iteration_time) - crypt_set_iteration_time(cd_new, opt_iteration_time); + log_dbg("Creating fake (cipher_null) header for original device."); + + if (!opt_key_size) + opt_key_size = DEFAULT_LUKS1_KEYBITS; if (opt_cipher) { r = crypt_parse_name_and_mode(opt_cipher, cipher, NULL, cipher_mode); @@ -548,30 +522,41 @@ static int backup_luks_headers(struct reenc_ctx *rc) } } - if ((r = crypt_format(cd_new, CRYPT_LUKS1, - opt_cipher ? cipher : crypt_get_cipher(cd), - opt_cipher ? cipher_mode : crypt_get_cipher_mode(cd), - crypt_get_uuid(cd), - NULL, - opt_key_size ? opt_key_size / 8 : crypt_get_volume_key_size(cd), - ¶ms))) + r = create_empty_header(rc->header_file_org, NULL, 0); + if (r < 0) + return r; + + params.hash = opt_hash ?: DEFAULT_LUKS1_HASH; + params.data_alignment = 0; + params.data_device = rc->device; + + r = crypt_init(&cd_new, rc->header_file_org); + if (r < 0) + return r; + + r = crypt_format(cd_new, CRYPT_LUKS1, "cipher_null", "ecb", + NO_UUID, NULL, opt_key_size / 8, ¶ms); + if (r < 0) goto out; - log_verbose(_("New LUKS header for device %s created.\n"), rc->device); - for (i = 0; i < MAX_SLOT; i++) { - if (!rc->p[i].password) - continue; - if ((r = crypt_keyslot_add_by_volume_key(cd_new, i, - NULL, 0, rc->p[i].password, rc->p[i].passwordLen)) < 0) - goto out; - log_verbose(_("Activated keyslot %i.\n"), r); - r = 0; - } + r = crypt_keyslot_add_by_volume_key(cd_new, 0, NULL, 0, + rc->p[0].password, rc->p[0].passwordLen); + if (r < 0) + goto out; + + r = create_empty_header(rc->header_file_new, rc->header_file_org, 0); + if (r < 0) + goto out; + + params.data_alignment = ROUND_SECTOR(opt_reduce_size); + r = create_new_header(rc, + opt_cipher ? cipher : DEFAULT_LUKS1_CIPHER, + opt_cipher ? cipher_mode : DEFAULT_LUKS1_MODE, + NULL, + (opt_key_size ? opt_key_size : DEFAULT_LUKS1_KEYBITS) / 8, + ¶ms); out: - crypt_free(cd); crypt_free(cd_new); - if (r) - log_err(_("Creation of LUKS backup headers failed.\n")); return r; } @@ -631,11 +616,12 @@ static void print_progress(struct reenc_ctx *rc, uint64_t bytes, int final) if (!tdiff) return; - mbytes = (bytes - rc->restart_bytes) / 1024 / 1024; + mbytes = (bytes - rc->resume_bytes) / 1024 / 1024; mib = (double)(mbytes) / tdiff; if (!mib) return; + /* FIXME: calculate this from last minute only and remaining space */ eta = (unsigned long long)(rc->device_size / 1024 / 1024 / mib - tdiff); /* vt100 code clear line */ @@ -660,7 +646,7 @@ static int copy_data_forward(struct reenc_ctx *rc, int fd_old, int fd_new, return -EIO; } - rc->restart_bytes = *bytes = rc->device_offset; + rc->resume_bytes = *bytes = rc->device_offset; if (write_log(rc) < 0) return -EIO; @@ -674,6 +660,10 @@ static int copy_data_forward(struct reenc_ctx *rc, int fd_old, int fd_new, return -EIO; } + /* If device_size is forced, never write more than limit */ + if ((s1 + rc->device_offset) > rc->device_size) + s1 = rc->device_size - rc->device_offset; + s2 = write(fd_new, buf, s1); if (s2 < 0) { log_dbg("Write error, expecting %d, got %d.", @@ -707,11 +697,11 @@ static int copy_data_backward(struct reenc_ctx *rc, int fd_old, int fd_new, if (!rc->in_progress) { rc->device_offset = rc->device_size; - rc->restart_bytes = 0; + rc->resume_bytes = 0; *bytes = 0; } else { - rc->restart_bytes = rc->device_size - rc->device_offset; - *bytes = rc->restart_bytes; + rc->resume_bytes = rc->device_size - rc->device_offset; + *bytes = rc->resume_bytes; } if (write_log(rc) < 0) @@ -785,18 +775,20 @@ static int copy_data(struct reenc_ctx *rc) } /* Check size */ - if (ioctl(fd_new, BLKGETSIZE64, &rc->device_size) < 0) { + if (ioctl(fd_new, BLKGETSIZE64, &rc->device_size_real) < 0) { log_err(_("Cannot get device size.\n")); goto out; } + rc->device_size = opt_device_size ?: rc->device_size_real; + if (posix_memalign((void *)&buf, alignment(fd_new), block_size)) { log_err(_("Allocation of aligned memory failed.\n")); r = -ENOMEM; goto out; } - set_int_handler(); + set_int_handler(0); gettimeofday(&rc->start_time, NULL); if (rc->reencrypt_direction == FORWARD) @@ -829,6 +821,11 @@ static int initialize_uuid(struct reenc_ctx *rc) log_dbg("Initialising UUID."); + if (opt_new) { + rc->device_uuid = strdup(NO_UUID); + return 0; + } + /* Try to load LUKS from device */ if ((r = crypt_init(&cd, rc->device))) return r; @@ -845,15 +842,15 @@ static int initialize_uuid(struct reenc_ctx *rc) } static int init_passphrase1(struct reenc_ctx *rc, struct crypt_device *cd, - const char *msg, int slot_check) + const char *msg, int slot_to_check, int check) { int r = -EINVAL, slot, retry_count; - slot = (slot_check == CRYPT_ANY_SLOT) ? 0 : slot_check; + slot = (slot_to_check == CRYPT_ANY_SLOT) ? 0 : slot_to_check; retry_count = opt_tries ?: 1; while (retry_count--) { - set_int_handler(); + set_int_handler(0); r = crypt_get_key(msg, &rc->p[slot].password, &rc->p[slot].passwordLen, 0, 0, NULL /*opt_key_file*/, @@ -865,8 +862,11 @@ static int init_passphrase1(struct reenc_ctx *rc, struct crypt_device *cd, /* library uses sigint internally, until it is fixed...*/ set_int_block(1); - r = crypt_activate_by_passphrase(cd, NULL, slot_check, - rc->p[slot].password, rc->p[slot].passwordLen, 0); + if (check) + r = crypt_activate_by_passphrase(cd, NULL, slot_to_check, + rc->p[slot].password, rc->p[slot].passwordLen, 0); + else + r = slot; if (r < 0) { crypt_safe_free(rc->p[slot].password); @@ -930,6 +930,11 @@ static int initialize_passphrase(struct reenc_ctx *rc, const char *device) log_dbg("Passhrases initialization."); + if (opt_new && !rc->in_progress) { + r = init_passphrase1(rc, cd, _("Enter new LUKS passphrase: "), 0, 0); + return r > 0 ? 0 : r; + } + if ((r = crypt_init(&cd, device)) || (r = crypt_load(cd, CRYPT_LUKS1, NULL)) || (r = crypt_set_data_device(cd, rc->device))) { @@ -940,14 +945,15 @@ static int initialize_passphrase(struct reenc_ctx *rc, const char *device) if (opt_key_file) { r = init_keyfile(rc, cd, opt_key_slot); } else if (rc->in_progress) { - r = init_passphrase1(rc, cd, _("Enter any LUKS passphrase: "), CRYPT_ANY_SLOT); + r = init_passphrase1(rc, cd, _("Enter any LUKS passphrase: "), + CRYPT_ANY_SLOT, 1); } else for (i = 0; i < MAX_SLOT; i++) { ki = crypt_keyslot_status(cd, i); if (ki != CRYPT_SLOT_ACTIVE && ki != CRYPT_SLOT_ACTIVE_LAST) continue; snprintf(msg, sizeof(msg), _("Enter LUKS passphrase for key slot %u: "), i); - r = init_passphrase1(rc, cd, msg, i); + r = init_passphrase1(rc, cd, msg, i, 1); if (r < 0) break; } @@ -1000,7 +1006,7 @@ static int initialize_context(struct reenc_ctx *rc, const char *device) } if (!rc->in_progress) { - if (!opt_reduce_device_size) + if (!opt_reduce_size) rc->reencrypt_direction = FORWARD; else { rc->reencrypt_direction = BACKWARD; @@ -1047,9 +1053,13 @@ static int run_reencrypt(const char *device) log_dbg("Running reencryption."); if (!rc.in_progress) { - if ((r = initialize_passphrase(&rc, rc.device)) || - (r = backup_luks_headers(&rc)) || - (r = device_check(&rc, MAKE_UNUSABLE))) + if (opt_new) { + if ((r = initialize_passphrase(&rc, rc.device)) || + (r = backup_fake_header(&rc))) + goto out; + } else if ((r = initialize_passphrase(&rc, rc.device)) || + (r = backup_luks_headers(&rc)) || + (r = device_check(&rc, MAKE_UNUSABLE))) goto out; } else { if ((r = initialize_passphrase(&rc, rc.header_file_new))) @@ -1068,17 +1078,6 @@ out: return r; } -static __attribute__ ((noreturn)) void usage(poptContext popt_context, - int exitcode, const char *error, - const char *more) -{ - poptPrintUsage(popt_context, stderr, 0); - if (error) - log_err("%s: %s\n", more, error); - poptFreeContext(popt_context); - exit(exitcode); -} - static void help(poptContext popt_context, enum poptCallbackReason reason __attribute__((unused)), struct poptOption *key, @@ -1093,19 +1092,6 @@ static void help(poptContext popt_context, usage(popt_context, EXIT_SUCCESS, NULL, NULL); } -static void _dbg_version_and_cmd(int argc, const char **argv) -{ - int i; - - log_std("# %s %s processing \"", PACKAGE_REENC, PACKAGE_VERSION); - for (i = 0; i < argc; i++) { - if (i) - log_std(" "); - log_std("%s", argv[i]); - } - log_std("\"\n"); -} - int main(int argc, const char **argv) { static struct poptOption popt_help_options[] = { @@ -1135,13 +1121,15 @@ int main(int argc, const char **argv) { "key-slot", 'S', POPT_ARG_INT, &opt_key_slot, 0, N_("Use only this slot (others will be disabled)."), NULL }, { "keyfile-offset", '\0', POPT_ARG_LONG, &opt_keyfile_offset, 0, N_("Number of bytes to skip in keyfile"), N_("bytes") }, { "keyfile-size", 'l', POPT_ARG_LONG, &opt_keyfile_size, 0, N_("Limits the read from keyfile"), N_("bytes") }, - { "reduce-device-size",'\0', POPT_ARG_INT, &opt_reduce_device_size, 0, N_("Reduce data device size (move data offset). DANGEROUS!"), N_("SECTORS") }, + { "reduce-device-size",'\0', POPT_ARG_STRING, &opt_reduce_size_str, 0, N_("Reduce data device size (move data offset). DANGEROUS!"), N_("bytes") }, + { "device-size", '\0', POPT_ARG_STRING, &opt_device_size_str, 0, N_("Use only specified device size (ignore rest of device). DANGEROUS!"), N_("bytes") }, + { "new", 'N', POPT_ARG_NONE,&opt_new, 0, N_("Create new header on not encrypted device."), NULL }, POPT_TABLEEND }; poptContext popt_context; int r; - crypt_set_log_callback(NULL, _log, NULL); + crypt_set_log_callback(NULL, tool_log, NULL); set_int_block(1); @@ -1151,7 +1139,7 @@ int main(int argc, const char **argv) popt_context = poptGetContext(PACKAGE, argc, argv, popt_options, 0); poptSetOtherOptionHelp(popt_context, - N_("[OPTION...] ")); + _("[OPTION...] ")); while((r = poptGetNextOpt(popt_context)) > 0) ; if (r < -1) @@ -1181,8 +1169,7 @@ int main(int argc, const char **argv) poptGetInvocationName(popt_context)); if (opt_bsize < 0 || opt_key_size < 0 || opt_iteration_time < 0 || - opt_tries < 0 || opt_keyfile_offset < 0 || opt_key_size < 0 || - opt_reduce_device_size < 0) { + opt_tries < 0 || opt_keyfile_offset < 0 || opt_key_size < 0) { usage(popt_context, EXIT_FAILURE, _("Negative number for option not permitted."), poptGetInvocationName(popt_context)); @@ -1190,12 +1177,7 @@ int main(int argc, const char **argv) if (opt_bsize < 1 || opt_bsize > 64) usage(popt_context, EXIT_FAILURE, - _("Only values between 1MiB and 64 MiB allowed for reencryption block size."), - poptGetInvocationName(popt_context)); - - if (opt_reduce_device_size > (64 * 1024 * 1024 / SECTOR_SIZE)) - usage(popt_context, EXIT_FAILURE, - _("Maximum device reduce size is 64 MiB."), + _("Only values between 1 MiB and 64 MiB allowed for reencryption block size."), poptGetInvocationName(popt_context)); if (opt_key_size % 8) @@ -1212,26 +1194,35 @@ int main(int argc, const char **argv) usage(popt_context, EXIT_FAILURE, _("Only one of --use-[u]random options is allowed."), poptGetInvocationName(popt_context)); + if (opt_device_size_str && + crypt_string_to_size(NULL, opt_device_size_str, &opt_device_size)) + usage(popt_context, EXIT_FAILURE, _("Invalid device size specification."), + poptGetInvocationName(popt_context)); + + if (opt_reduce_size_str && + crypt_string_to_size(NULL, opt_reduce_size_str, &opt_reduce_size)) + usage(popt_context, EXIT_FAILURE, _("Invalid device size specification."), + poptGetInvocationName(popt_context)); + if (opt_reduce_size > 64 * 1024 * 1024) + usage(popt_context, EXIT_FAILURE, _("Maximum device reduce size is 64 MiB."), + poptGetInvocationName(popt_context)); + if (opt_reduce_size % SECTOR_SIZE) + usage(popt_context, EXIT_FAILURE, _("Reduce size must be multiple of 512 bytes sector."), + poptGetInvocationName(popt_context)); + + if (opt_new && !opt_reduce_size) + usage(popt_context, EXIT_FAILURE, _("Option --new must be used together with --reduce-device-size."), + 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_reencrypt(action_argv[0]); poptFreeContext(popt_context); - /* 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; - default: r = EXIT_FAILURE; - } - return r; + return translate_errno(r); }