* 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
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;
typedef enum {
MAKE_UNUSABLE,
MAKE_USABLE,
- CHECK_UNUSABLE
+ CHECK_UNUSABLE,
+ CHECK_OPEN,
} header_magic;
__attribute__((format(printf, 5, 6)))
return alignment;
}
-static int device_magic(struct reenc_ctx *rc, header_magic set_magic)
+static int device_check(struct reenc_ctx *rc, header_magic set_magic)
{
char *buf = NULL;
int r, devfd;
ssize_t s;
- devfd = open(rc->device, O_RDWR | O_DIRECT);
- if (devfd == -1)
- return errno == EBUSY ? -EBUSY : -EINVAL;
+ devfd = open(rc->device, O_RDWR | O_EXCL | O_DIRECT);
+ if (devfd == -1) {
+ if (errno == EBUSY) {
+ log_err(_("Cannot exclusively open %s, device in use.\n"),
+ rc->device);
+ return -EBUSY;
+ }
+ log_err(_("Cannot open device %s\n"), rc->device);
+ return -EINVAL;
+ }
+
+ if (set_magic == CHECK_OPEN) {
+ r = 0;
+ goto out;
+ }
if (posix_memalign((void *)&buf, alignment(devfd), SECTOR_SIZE)) {
log_err(_("Allocation of aligned memory failed.\n"));
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 %4.0f 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" :"");
}
(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);
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);
}
(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);
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);
}
rc->device_uuid = strdup(crypt_get_uuid(cd));
else
/* Reencryption already in progress - magic header? */
- r = device_magic(rc, CHECK_UNUSABLE);
+ r = device_check(rc, CHECK_UNUSABLE);
crypt_free(cd);
return r;
retry_count = opt_tries ?: 1;
while (retry_count--) {
+ set_int_handler();
r = crypt_get_key(msg, &rc->p[slot].password,
&rc->p[slot].passwordLen,
0, 0, NULL /*opt_key_file*/,
0, 0, cd);
if (r < 0)
return r;
+ if (quit)
+ return -EAGAIN;
+ /* 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 (!(rc->device = strndup(device, PATH_MAX)))
return -ENOMEM;
+ if (device_check(rc, CHECK_OPEN) < 0)
+ return -EINVAL;
+
if (initialize_uuid(rc)) {
log_err(_("Device %s is not a valid LUKS device.\n"), device);
return -EINVAL;
if ((rc->reencrypt_direction == FORWARD &&
rc->device_offset == rc->device_size) ||
- rc->device_offset == 0) {
+ (rc->reencrypt_direction == BACKWARD &&
+ rc->device_offset == 0)) {
unlink(rc->log_file);
unlink(rc->header_file_org);
unlink(rc->header_file_new);
if (!rc.in_progress) {
if ((r = initialize_passphrase(&rc, rc.device)) ||
(r = backup_luks_headers(&rc)) ||
- (r = device_magic(&rc, MAKE_UNUSABLE)))
+ (r = device_check(&rc, MAKE_UNUSABLE)))
goto out;
} else {
if ((r = initialize_passphrase(&rc, rc.header_file_new)))
{
int i;
- log_std("# %s %s processing \"", PACKAGE_NAME, PACKAGE_VERSION);
+ log_std("# %s %s processing \"", PACKAGE_REENC, PACKAGE_VERSION);
for (i = 0; i < argc; i++) {
if (i)
log_std(" ");
{ "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") },
poptSetOtherOptionHelp(popt_context,
N_("[OPTION...] <device>]"));
- while((r = poptGetNextOpt(popt_context)) > 0) {
- if (r < 0)
- break;
- }
-
+ while((r = poptGetNextOpt(popt_context)) > 0) ;
if (r < -1)
usage(popt_context, EXIT_FAILURE, poptStrerror(r),
poptBadOption(popt_context, POPT_BADOPTION_NOALIAS));
+
if (opt_version_mode) {
- log_std("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION);
+ log_std("%s %s\n", PACKAGE_REENC, PACKAGE_VERSION);
poptFreeContext(popt_context);
exit(EXIT_SUCCESS);
}
case -ENODEV: r = 4; break;
case -ENOMEM: r = 3; break;
case -EPERM: r = 2; break;
- case -EAGAIN:
- case -EINVAL:
- case -ENOENT:
- case -ENOSYS:
default: r = EXIT_FAILURE;
}
return r;