static int opt_urandom = 0;
static int opt_bsize = 4;
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;
char crypt_path_org[PATH_MAX];
char crypt_path_new[PATH_MAX];
int log_fd;
+ char *log_buf;
struct {
char *password;
}
/* The difference in seconds between two times in "timeval" format. */
-double time_diff(struct timeval start, struct timeval end)
+static double time_diff(struct timeval start, struct timeval end)
{
return (end.tv_sec - start.tv_sec)
+ (end.tv_usec - start.tv_usec) / 1E6;
static int create_empty_header(const char *new_file, const char *old_file)
{
struct stat st;
- size_t size;
+ ssize_t size;
int fd, r = 0;
char *buf;
- if (stat(old_file, &st) == -1 || (st.st_mode & S_IFMT) != S_IFREG)
+ 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;
static int write_log(struct reenc_ctx *rc)
{
- static char buf[SECTOR_SIZE];
ssize_t r;
- memset(buf, 0, SECTOR_SIZE);
- snprintf(buf, SECTOR_SIZE, "# LUKS reencryption log, DO NOT EDIT OR DELETE.\n"
+ memset(rc->log_buf, 0, SECTOR_SIZE);
+ snprintf(rc->log_buf, SECTOR_SIZE, "# LUKS reencryption log, DO NOT EDIT OR DELETE.\n"
"version = %d\nUUID = %s\ndirection = %d\n"
"offset = %" PRIu64 "\nshift = %" PRIu64 "\n# EOF\n",
1, rc->device_uuid, rc->reencrypt_direction,
rc->device_offset, rc->device_shift);
lseek(rc->log_fd, 0, SEEK_SET);
- r = write(rc->log_fd, buf, SECTOR_SIZE);
+ r = write(rc->log_fd, rc->log_buf, SECTOR_SIZE);
if (r < 0 || r != SECTOR_SIZE) {
log_err(_("Cannot write reencryption log file.\n"));
return -EIO;
static int parse_log(struct reenc_ctx *rc)
{
- static char buf[SECTOR_SIZE];
char *start, *end;
ssize_t s;
- s = read(rc->log_fd, buf, SECTOR_SIZE);
+ s = read(rc->log_fd, rc->log_buf, SECTOR_SIZE);
if (s == -1) {
log_err(_("Cannot read reencryption log file.\n"));
return -EIO;
}
- buf[SECTOR_SIZE - 1] = '\0';
- start = buf;
+ rc->log_buf[SECTOR_SIZE - 1] = '\0';
+ start = rc->log_buf;
do {
end = strchr(start, '\n');
if (end) {
return 0;
}
+static void close_log(struct reenc_ctx *rc)
+{
+ log_dbg("Closing LUKS reencryption log file %s.", rc->log_file);
+ if (rc->log_fd != -1)
+ close(rc->log_fd);
+ free(rc->log_buf);
+ rc->log_buf = NULL;
+}
+
static int open_log(struct reenc_ctx *rc)
{
- int flags;
+ int flags, create_new;
struct stat st;
- if(stat(rc->log_file, &st) < 0) {
+ 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;
- if (write_log(rc) < 0)
- return -EIO;
} else {
log_dbg("Log file %s exists, restarting.", rc->log_file);
flags = opt_directio ? O_RDWR|O_DIRECT : O_RDWR;
rc->in_progress = 1;
}
+ 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) {
+ close_log(rc);
+ return -EIO;
+ }
+
/* Be sure it is correct format */
return parse_log(rc);
}
-static void close_log(struct reenc_ctx *rc)
-{
- log_dbg("Closing LUKS reencryption log file %s.", rc->log_file);
- if (rc->log_fd != -1)
- close(rc->log_fd);
-}
-
static int activate_luks_headers(struct reenc_ctx *rc)
{
struct crypt_device *cd = NULL, *cd_new = NULL;
crypt_free(cd);
}
-static int restore_luks_header(struct reenc_ctx *rc, const char *backup)
+static int restore_luks_header(struct reenc_ctx *rc)
{
struct crypt_device *cd = NULL;
int r;
- log_dbg("Restoring header for %s from %s.", rc->device, backup);
+ log_dbg("Restoring header for %s from %s.", rc->device, rc->header_file_new);
r = crypt_init(&cd, rc->device);
if (r == 0) {
crypt_set_confirm_callback(cd, NULL, NULL);
- r = crypt_header_restore(cd, CRYPT_LUKS1, backup);
+ r = crypt_header_restore(cd, CRYPT_LUKS1, rc->header_file_new);
}
crypt_free(cd);
return r;
}
-void print_progress(struct reenc_ctx *rc, uint64_t bytes, int final)
+static void print_progress(struct reenc_ctx *rc, uint64_t bytes, int final)
{
- uint64_t mbytes = (bytes - rc->restart_bytes) / 1024 / 1024;
+ unsigned long long mbytes, eta;
struct timeval now_time;
- double tdiff;
+ double tdiff, mib;
gettimeofday(&now_time, NULL);
if (!final && time_diff(rc->end_time, now_time) < 0.5)
if (!tdiff)
return;
+ mbytes = (bytes - rc->restart_bytes) / 1024 / 1024;
+ mib = (double)(mbytes) / tdiff;
+ if (!mib)
+ return;
+
+ eta = (unsigned long long)(rc->device_size / 1024 / 1024 / mib - tdiff);
+
/* vt100 code clear line */
log_err("\33[2K\r");
- log_err(_("Progress: %5.1f%%, time elapsed %3.1f seconds, "
+ log_err(_("Progress: %5.1f%%, ETA %02llu:%02llu, "
"%4llu MiB written, speed %5.1f MiB/s%s"),
(double)bytes / rc->device_size * 100,
- time_diff(rc->start_time, rc->end_time),
- (unsigned long long)mbytes, (double)(mbytes) / tdiff,
+ eta / 60, eta % 60, mbytes, mib,
final ? "\n" :"");
}
while (!quit && rc->device_offset < rc->device_size) {
s1 = read(fd_old, buf, block_size);
- if (s1 < 0 || (s1 != block_size && (rc->device_offset + s1) != rc->device_size)) {
- log_dbg("Read error, expecting %d, got %d.", (int)block_size, (int)s1);
+ if (s1 < 0 || ((size_t)s1 != block_size &&
+ (rc->device_offset + s1) != rc->device_size)) {
+ log_dbg("Read error, expecting %d, got %d.",
+ (int)block_size, (int)s1);
return -EIO;
}
+
s2 = write(fd_new, buf, s1);
if (s2 < 0) {
- log_dbg("Write error, expecting %d, got %d.", (int)block_size, (int)s2);
+ log_dbg("Write error, expecting %d, got %d.",
+ (int)block_size, (int)s2);
return -EIO;
}
+
rc->device_offset += s1;
if (opt_write_log && write_log(rc) < 0)
return -EIO;
+ if (opt_fsync && fsync(fd_new) < 0) {
+ log_dbg("Write error, fsync.");
+ return -EIO;
+ }
+
*bytes += (uint64_t)s2;
print_progress(rc, *bytes, 0);
}
s1 = read(fd_old, buf, working_block);
if (s1 < 0 || (s1 != working_block)) {
- log_dbg("Read error, expecting %d, got %d.", (int)block_size, (int)s1);
+ log_dbg("Read error, expecting %d, got %d.",
+ (int)block_size, (int)s1);
return -EIO;
}
+
s2 = write(fd_new, buf, working_block);
if (s2 < 0) {
- log_dbg("Write error, expecting %d, got %d.", (int)block_size, (int)s2);
+ log_dbg("Write error, expecting %d, got %d.",
+ (int)block_size, (int)s2);
return -EIO;
}
+
rc->device_offset -= s1;
if (opt_write_log && write_log(rc) < 0)
return -EIO;
+ if (opt_fsync && fsync(fd_new) < 0) {
+ log_dbg("Write error, fsync.");
+ return -EIO;
+ }
+
*bytes += (uint64_t)s2;
print_progress(rc, *bytes, 0);
}
if (ki != CRYPT_SLOT_ACTIVE && ki != CRYPT_SLOT_ACTIVE_LAST)
continue;
- snprintf(msg, sizeof(msg), _("Enter LUKS passphrase for key slot %u): "), i);
+ snprintf(msg, sizeof(msg), _("Enter LUKS passphrase for key slot %u: "), i);
r = init_passphrase1(rc, cd, msg, i);
if (r < 0)
break;
free(rc->device_uuid);
}
-int run_reencrypt(const char *device)
+static int run_reencrypt(const char *device)
{
int r = -EINVAL;
struct reenc_ctx rc = {};
if ((r = copy_data(&rc)))
goto out;
- r = restore_luks_header(&rc, rc.header_file_new);
+ r = restore_luks_header(&rc);
out:
destroy_context(&rc);
return r;
{ "use-random", '\0', POPT_ARG_NONE, &opt_random, 0, N_("Use /dev/random for generating volume key."), NULL },
{ "use-urandom", '\0', POPT_ARG_NONE, &opt_urandom, 0, N_("Use /dev/urandom for generating volume key."), NULL },
{ "use-directio", '\0', POPT_ARG_NONE, &opt_directio, 0, N_("Use direct-io when accesing devices."), NULL },
+ { "use-fsync", '\0', POPT_ARG_NONE, &opt_fsync, 0, N_("Use fsync after each block."), NULL },
{ "write-log", '\0', POPT_ARG_NONE, &opt_write_log, 0, N_("Update log file after every block."), NULL },
{ "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") },