#include <stdio.h>
#include <string.h>
#include <errno.h>
+#include <ctype.h>
+#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
*result = bytes;
return i;
}
+
+/*
+ * Device size string parsing, suffixes:
+ * s|S - 512 bytes sectors
+ * k |K |m |M |g |G |t |T - 1024 base
+ * kiB|KiB|miB|MiB|giB|GiB|tiB|TiB - 1024 base
+ * kb |KB |mM |MB |gB |GB |tB |TB - 1000 base
+ */
+int crypt_string_to_size(struct crypt_device *cd, const char *s, uint64_t *size)
+{
+ char *endp = NULL;
+ size_t len;
+ uint64_t mult_base, mult, tmp;
+
+ *size = strtoull(s, &endp, 10);
+ if (!isdigit(s[0]) ||
+ (errno == ERANGE && *size == ULLONG_MAX) ||
+ (errno != 0 && *size == 0))
+ return -EINVAL;
+
+ if (!endp)
+ return 0;
+
+ len = strlen(endp);
+ /* Allow "B" and "iB" suffixes */
+ if (len > 3 ||
+ (len == 3 && (endp[1] != 'i' || endp[2] != 'B')) ||
+ (len == 2 && endp[1] != 'B'))
+ return -EINVAL;
+
+ if (len == 1 || len == 3)
+ mult_base = 1024;
+ else
+ mult_base = 1000;
+
+ mult = 1;
+ switch (endp[0]) {
+ case 's':
+ case 'S': mult = 512;
+ break;
+ case 't':
+ case 'T': mult *= mult_base;
+ case 'g':
+ case 'G': mult *= mult_base;
+ case 'm':
+ case 'M': mult *= mult_base;
+ case 'k':
+ case 'K': mult *= mult_base;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ tmp = *size * mult;
+ if ((tmp / *size) != mult) {
+ log_dbg("Device size overflow.");
+ return -EINVAL;
+ }
+
+ *size = tmp;
+ return 0;
+}
You cannot shrink device more than by 64 MiB (131072 sectors).
.TP
+.B "\-\-device-size \fIsize[units]\fR"
+Instead of real device size, use specified value.
+
+It means that only specified area (from the start of the device
+to the specified size) will be reencrypted.
+
+WARNING: This is destructive operation.
+
+If no unit suffix is specified, the size is in bytes.
+
+Unit suffix can be S for 512 byte sectors, K/M/G/T (or KiB,MiB,GiB,TiB)
+for units with 1024 base or KB/MB/GB/TB for 1000 base (SI scale).
+
+WARNING: This is destructive operation.
+
+You cannot shrink device more than by 64 MiB (131072 sectors).
+.TP
.B "\-\-new, N"
Create new header (encrypt not yet encrypted device).
static int opt_key_size = 0;
static int opt_new = 0;
+static const char *opt_device_size_str = NULL;
+static uint64_t opt_device_size = 0;
+
static const char **action_argv;
static volatile int quit = 0;
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;
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.",
}
/* 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;
{ "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") },
+ { "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
};
usage(popt_context, EXIT_FAILURE, _("Option --new must be used together with --reduce_device_size."),
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_debug) {
opt_verbose = 1;
crypt_set_debug_level(-1);