Add some simple timer.
[platform/upstream/cryptsetup.git] / src / crypt_reencrypt.c
1 /*
2  * crypt_reencrypt - crypt utility for offline reencryption
3  *
4  * Copyright (C) 2012 Milan Broz All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * version 2 as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19
20 /* The code works as follows:
21  *  - create backup (detached) headers fo old and new device
22  *  - mark original device unusable
23  *  - maps two devices, one with old header one with new onto
24  *    the _same_ underlying device
25  *  - with direct-io reads old device and copy to new device in defined steps
26  *  - keps simple off in file (allows restart)
27  *  - there is several windows when corruption can happen
28  *
29  * null target
30  * dmsetup create x --table "0 $(blockdev --getsz DEV) crypt cipher_null-ecb-null - 0 DEV 0"
31  */
32 #include <string.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <stdint.h>
36 #include <stdarg.h>
37 #include <inttypes.h>
38 #include <errno.h>
39 #include <unistd.h>
40 #include <sys/stat.h>
41 #include <sys/ioctl.h>
42 #include <sys/time.h>
43 #include <linux/fs.h>
44 #include <fcntl.h>
45 #include <limits.h>
46 #include <signal.h>
47 #include <libcryptsetup.h>
48 #include <popt.h>
49
50 #include "cryptsetup.h"
51
52 static int opt_verbose = 0;
53 static int opt_debug = 0;
54 static const char *opt_cipher = NULL;
55 static const char *opt_hash = NULL;
56 static const char *opt_key_file = NULL;
57 static int opt_iteration_time = 1000;
58 static int opt_batch_mode = 0;
59 static int opt_version_mode = 0;
60 static int opt_random = 0;
61 static int opt_urandom = 0;
62 static int opt_bsize = 4;
63 static int opt_new = 0;
64 static int opt_directio = 0;
65 static int opt_write_log = 0;
66 static const char *opt_new_file = NULL;
67
68 static const char **action_argv;
69 sigset_t signals_open;
70
71 struct {
72         char *device;
73         char *device_uuid;
74         uint64_t device_size;
75         uint64_t device_offset;
76         uint64_t device_shift;
77
78         int in_progress:1;
79         enum { FORWARD = 0, BACKWARD = 1 } reencrypt_direction;
80
81         char header_file_org[PATH_MAX];
82         char header_file_new[PATH_MAX];
83         char log_file[PATH_MAX];
84
85         char crypt_path_org[PATH_MAX];
86         char crypt_path_new[PATH_MAX];
87         int log_fd;
88
89         char *password;
90         size_t passwordLen;
91         int keyslot;
92 } rnc;
93
94 char MAGIC[]   = {'L','U','K','S', 0xba, 0xbe};
95 char NOMAGIC[] = {'L','U','K','S', 0xde, 0xad};
96 int  MAGIC_L = 6;
97
98 typedef enum {
99         MAKE_UNUSABLE,
100         MAKE_USABLE,
101         CHECK_UNUSABLE
102 } header_magic;
103
104 __attribute__((format(printf, 5, 6)))
105 static void clogger(struct crypt_device *cd, int level, const char *file,
106                    int line, const char *format, ...)
107 {
108         va_list argp;
109         char *target = NULL;
110
111         va_start(argp, format);
112
113         if (vasprintf(&target, format, argp) > 0) {
114                 if (level >= 0) {
115                         crypt_log(cd, level, target);
116                 } else if (opt_debug)
117                         printf("# %s\n", target);
118         }
119
120         va_end(argp);
121         free(target);
122 }
123
124 static void _log(int level, const char *msg, void *usrptr __attribute__((unused)))
125 {
126         switch(level) {
127
128         case CRYPT_LOG_NORMAL:
129                 fputs(msg, stdout);
130                 break;
131         case CRYPT_LOG_VERBOSE:
132                 if (opt_verbose)
133                         fputs(msg, stdout);
134                 break;
135         case CRYPT_LOG_ERROR:
136                 fputs(msg, stderr);
137                 break;
138         case CRYPT_LOG_DEBUG:
139                 if (opt_debug)
140                         printf("# %s\n", msg);
141                 break;
142         default:
143                 fprintf(stderr, "Internal error on logging class for msg: %s", msg);
144                 break;
145         }
146 }
147
148 static void _quiet_log(int level, const char *msg, void *usrptr)
149 {
150         if (!opt_verbose && (level == CRYPT_LOG_ERROR || level == CRYPT_LOG_NORMAL))
151                 level = CRYPT_LOG_VERBOSE;
152         _log(level, msg, usrptr);
153 }
154
155 /* The difference in seconds between two times in "timeval" format. */
156 double time_diff(struct timeval start, struct timeval end)
157 {
158         return (end.tv_sec - start.tv_sec)
159                 + (end.tv_usec - start.tv_usec) / 1E6;
160 }
161
162 static int alignment(int fd)
163 {
164         int alignment;
165
166         alignment = fpathconf(fd, _PC_REC_XFER_ALIGN);
167         if (alignment < 0)
168                 alignment = 4096;
169         return alignment;
170 }
171
172 static int device_magic(header_magic set_magic)
173 {
174         char *buf = NULL;
175         size_t block_size = 512;
176         int r, devfd;
177         ssize_t s;
178
179         devfd = open(rnc.device, O_RDWR | O_DIRECT);
180         if (devfd == -1)
181                 return errno == EBUSY ? -EBUSY : -EINVAL;
182
183         if (posix_memalign((void *)&buf, alignment(devfd), block_size)) {
184                 r = -ENOMEM;
185                 goto out;
186         }
187
188         s = read(devfd, buf, block_size);
189         if (s < 0 || s != block_size) {
190                 log_verbose(_("Cannot read device %s.\n"), rnc.device);
191                 close(devfd);
192                 return -EIO;
193         }
194
195         if (set_magic == MAKE_UNUSABLE && !memcmp(buf, MAGIC, MAGIC_L)) {
196                 log_dbg("Marking LUKS device %s unusable.", rnc.device);
197                 memcpy(buf, NOMAGIC, MAGIC_L);
198                 r = 0;
199
200         } else if (set_magic == MAKE_USABLE && !memcmp(buf, NOMAGIC, MAGIC_L)) {
201                 log_dbg("Marking LUKS device %s usable.", rnc.device);
202                 memcpy(buf, MAGIC, MAGIC_L);
203                 r = 0;
204         } else if (set_magic == CHECK_UNUSABLE) {
205                 r = memcmp(buf, NOMAGIC, MAGIC_L) ? -EINVAL : 0;
206                 if (!r)
207                         rnc.device_uuid = strndup(&buf[0xa8], 40);
208                 goto out;
209         } else
210                 r = -EINVAL;
211
212         if (!r) {
213                 if (lseek(devfd, 0, SEEK_SET) == -1)
214                         goto out;
215                 s = write(devfd, buf, block_size);
216                 if (s < 0 || s != block_size) {
217                         log_verbose(_("Cannot write device %s.\n"), rnc.device);
218                         r = -EIO;
219                 }
220         } else
221                 log_dbg("LUKS signature check failed for %s.", rnc.device);
222 out:
223         if (buf)
224                 memset(buf, 0, block_size);
225         free(buf);
226         close(devfd);
227         return r;
228 }
229
230 static int create_empty_header(const char *new_file, uint64_t size)
231 {
232         int fd, r = 0;
233         char *buf;
234
235         log_dbg("Creating empty file %s of size %lu.", new_file, (unsigned long)size);
236
237         if (!(buf = malloc(size)))
238                 return -ENOMEM;
239         memset(buf, 0, size);
240
241         fd = creat(new_file, S_IRUSR|S_IWUSR);
242         if(fd == -1) {
243                 free(buf);
244                 return -EINVAL;
245         }
246
247         if (write(fd, buf, size) < size)
248                 r = -EIO;
249
250         close(fd);
251         free(buf);
252         return r;
253 }
254
255 static int write_log(void)
256 {
257         static char buf[512];
258         ssize_t r;
259
260         //log_dbg("Updating LUKS reencryption log offset %" PRIu64 ".", offset);
261         memset(buf, 0, sizeof(buf));
262         snprintf(buf, sizeof(buf), "# LUKS reencryption log, DO NOT EDIT OR DELETE.\n"
263                 "version = %d\nUUID = %s\ndirection = %d\n"
264                 "offset = %" PRIu64 "\nshift = %" PRIu64 "\n# EOF\n",
265                 1, rnc.device_uuid, rnc.reencrypt_direction,
266                 rnc.device_offset, rnc.device_shift);
267
268         lseek(rnc.log_fd, 0, SEEK_SET);
269         r = write(rnc.log_fd, buf, sizeof(buf));
270         if (r < 0 || r != sizeof(buf))
271                 return -EIO;
272
273         return 0;
274 }
275
276 static int parse_line_log(const char *line)
277 {
278         uint64_t u64;
279         int i;
280         char s[64];
281
282         /* comment */
283         if (*line == '#')
284                 return 0;
285
286         if (sscanf(line, "version = %d", &i) == 1) {
287                 if (i != 1) {
288                         log_dbg("Log: Unexpected version = %i", i);
289                         return -EINVAL;
290                 }
291         } else if (sscanf(line, "UUID = %40s", s) == 1) {
292                 if (!rnc.device_uuid || strcmp(rnc.device_uuid, s)) {
293                         log_dbg("Log: Unexpected UUID %s", s);
294                         return -EINVAL;
295                 }
296         } else if (sscanf(line, "direction = %d", &i) == 1) {
297                 log_dbg("Log: direction = %i", i);
298                 rnc.reencrypt_direction = i;
299         } else if (sscanf(line, "offset = %" PRIu64, &u64) == 1) {
300                 log_dbg("Log: offset = %" PRIu64, u64);
301                 rnc.device_offset = u64;
302         } else if (sscanf(line, "shift = %" PRIu64, &u64) == 1) {
303                 log_dbg("Log: shift = %" PRIu64, u64);
304                 rnc.device_shift = u64;
305         } else
306                 return -EINVAL;
307
308         return 0;
309 }
310
311 static int parse_log(void)
312 {
313         static char buf[512];
314         char *start, *end;
315         ssize_t s;
316
317         s = read(rnc.log_fd, buf, sizeof(buf));
318         if (s == -1)
319                 return -EIO;
320
321         buf[511] = '\0';
322         start = buf;
323         do {
324                 end = strchr(start, '\n');
325                 if (end) {
326                         *end++ = '\0';
327                         if (parse_line_log(start)) {
328                                 log_err("Wrong log format.\n");
329                                 return -EINVAL;
330                         }
331                 }
332
333                 start = end;
334         } while (start);
335
336         return 0;
337 }
338
339 static int open_log(void)
340 {
341         int flags;
342         struct stat st;
343
344         if(stat(rnc.log_file, &st) < 0) {
345                 log_dbg("Creating LUKS reencryption log file %s.", rnc.log_file);
346
347                 // FIXME: move that somewhere else
348                 rnc.reencrypt_direction = BACKWARD;
349
350                 flags = opt_directio ? O_RDWR|O_CREAT|O_DIRECT : O_RDWR|O_CREAT;
351                 rnc.log_fd = open(rnc.log_file, flags, S_IRUSR|S_IWUSR);
352                 if (rnc.log_fd == -1)
353                         return -EINVAL;
354                 if (write_log() < 0)
355                         return -EIO;
356         } else {
357                 log_dbg("Log file %s exists, restarting.", rnc.log_file);
358                 flags = opt_directio ? O_RDWR|O_DIRECT : O_RDWR;
359                 rnc.log_fd = open(rnc.log_file, O_RDWR|O_DIRECT);
360                 if (rnc.log_fd == -1)
361                         return -EINVAL;
362                 rnc.in_progress = 1;
363         }
364
365         /* Be sure it is correct format */
366         return parse_log();
367 }
368
369 static void close_log(void)
370 {
371         log_dbg("Closing LUKS reencryption log file %s.", rnc.log_file);
372         if (rnc.log_fd != -1)
373                 close(rnc.log_fd);
374 }
375
376 static int activate_luks_headers(void)
377 {
378         struct crypt_device *cd = NULL, *cd_new = NULL;
379         int r;
380
381         log_dbg("Activating LUKS devices from headers.");
382
383         if ((r = crypt_init(&cd, rnc.header_file_org)) ||
384             (r = crypt_load(cd, CRYPT_LUKS1, NULL)) ||
385             (r = crypt_set_data_device(cd, rnc.device)))
386                 goto out;
387
388         if ((r = crypt_activate_by_passphrase(cd, rnc.header_file_org,
389                 CRYPT_ANY_SLOT, rnc.password, rnc.passwordLen,
390                 CRYPT_ACTIVATE_READONLY|CRYPT_ACTIVATE_PRIVATE)) < 0)
391                 goto out;
392
393         if ((r = crypt_init(&cd_new, rnc.header_file_new)) ||
394             (r = crypt_load(cd_new, CRYPT_LUKS1, NULL)) ||
395             (r = crypt_set_data_device(cd_new, rnc.device)))
396                 goto out;
397
398         if ((r = crypt_activate_by_passphrase(cd_new, rnc.header_file_new,
399                 CRYPT_ANY_SLOT, rnc.password, rnc.passwordLen,
400                 CRYPT_ACTIVATE_SHARED|CRYPT_ACTIVATE_PRIVATE)) < 0)
401                 goto out;
402 out:
403         crypt_free(cd);
404         crypt_free(cd_new);
405         return r;
406 }
407
408 static int backup_luks_headers(void)
409 {
410         struct crypt_device *cd = NULL, *cd_new = NULL;
411         struct crypt_params_luks1 params = {0};
412         char cipher [MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
413         int r;
414
415         log_dbg("Creating LUKS header backup for device %s.", rnc.device);
416         if ((r = crypt_init(&cd, rnc.device)) ||
417             (r = crypt_load(cd, CRYPT_LUKS1, NULL)))
418                 goto out;
419
420         crypt_set_confirm_callback(cd, NULL, NULL);
421         if ((r = crypt_header_backup(cd, CRYPT_LUKS1, rnc.header_file_org)))
422                 goto out;
423
424         if ((r = create_empty_header(rnc.header_file_new,
425                                      crypt_get_data_offset(cd) * 512)))
426                 goto out;
427
428         params.hash = opt_hash ?: DEFAULT_LUKS1_HASH;
429         params.data_alignment = crypt_get_data_offset(cd);
430         params.data_device = rnc.device;
431
432         if ((r = crypt_init(&cd_new, rnc.header_file_new)))
433                 goto out;
434
435         if (opt_random)
436                 crypt_set_rng_type(cd_new, CRYPT_RNG_RANDOM);
437         else if (opt_urandom)
438                 crypt_set_rng_type(cd_new, CRYPT_RNG_URANDOM);
439
440         if (opt_iteration_time)
441                 crypt_set_iteration_time(cd_new, opt_iteration_time);
442
443         if (opt_cipher) {
444                 r = crypt_parse_name_and_mode(opt_cipher, cipher, NULL, cipher_mode);
445                 if (r < 0) {
446                         log_err(_("No known cipher specification pattern detected.\n"));
447                         goto out;
448                 }
449         }
450
451         if ((r = crypt_format(cd_new, CRYPT_LUKS1,
452                         opt_cipher ? cipher : crypt_get_cipher(cd),
453                         opt_cipher ? cipher_mode : crypt_get_cipher_mode(cd),
454                         crypt_get_uuid(cd),
455                         NULL, crypt_get_volume_key_size(cd), &params)))
456                 goto out;
457
458         if ((r = crypt_keyslot_add_by_volume_key(cd_new, rnc.keyslot,
459                                 NULL, 0, rnc.password, rnc.passwordLen)) < 0)
460                 goto out;
461
462 out:
463         crypt_free(cd);
464         crypt_free(cd_new);
465         return r;
466 }
467
468 static void remove_headers(void)
469 {
470         struct crypt_device *cd = NULL;
471
472         if (crypt_init(&cd, NULL))
473                 return;
474         crypt_set_log_callback(cd, _quiet_log, NULL);
475         (void)crypt_deactivate(cd, rnc.header_file_org);
476         (void)crypt_deactivate(cd, rnc.header_file_new);
477         crypt_free(cd);
478 }
479
480 static int restore_luks_header(const char *backup)
481 {
482         struct crypt_device *cd = NULL;
483         int r;
484
485         r = crypt_init(&cd, rnc.device);
486
487         if (r == 0) {
488                 crypt_set_confirm_callback(cd, NULL, NULL);
489                 r = crypt_header_restore(cd, CRYPT_LUKS1, backup);
490         }
491
492         crypt_free(cd);
493         return r;
494 }
495
496 static int copy_data_forward(int fd_old, int fd_new, size_t block_size, void *buf, uint64_t *bytes)
497 {
498         ssize_t s1, s2;
499         int j;
500
501         *bytes = 0;
502         log_err("Reencrypting [");
503         j = 0;
504         while (rnc.device_offset < rnc.device_size) {
505                 s1 = read(fd_old, buf, block_size);
506                 if (s1 < 0 || (s1 != block_size && (rnc.device_offset + s1) != rnc.device_size)) {
507                         log_err("Read error, expecting %d, got %d.\n", (int)block_size, (int)s1);
508                         return -EIO;
509                 }
510                 s2 = write(fd_new, buf, s1);
511                 if (s2 < 0) {
512                         log_err("Write error, expecting %d, got %d.\n", (int)block_size, (int)s2);
513                         return -EIO;
514                 }
515                 rnc.device_offset += s1;
516                 if (opt_write_log && write_log() < 0) {
517                         log_err("Log write error, some data are perhaps lost.\n");
518                         return -EIO;
519                 }
520
521                 *bytes += (uint64_t)s2;
522                 if (rnc.device_offset > (j * (rnc.device_size / 10))) {
523                         log_err("-");
524                         j++;
525                 }
526         }
527         log_err("] Done.\n");
528
529         return 0;
530 }
531
532 static int copy_data_backward(int fd_old, int fd_new, size_t block_size, void *buf, uint64_t *bytes)
533 {
534         ssize_t s1, s2, working_offset, working_block;
535         int j;
536
537         *bytes = 0;
538         log_err("Reencrypting [");
539         j = 10;
540
541         while (rnc.device_offset) {
542                 if (rnc.device_offset < block_size) {
543                         working_offset = 0;
544                         working_block = rnc.device_offset;
545                 } else {
546                         working_offset = rnc.device_offset - block_size;
547                         working_block = block_size;
548                 }
549
550                 if (lseek(fd_old, working_offset, SEEK_SET) < 0 ||
551                     lseek(fd_new, working_offset, SEEK_SET) < 0)
552                         return -EIO;
553 //log_err("off: %06d, size %06d\n", working_offset, block_size);
554
555                 s1 = read(fd_old, buf, working_block);
556                 if (s1 < 0 || (s1 != working_block)) {
557                         log_err("Read error, expecting %d, got %d.\n", (int)block_size, (int)s1);
558                         return -EIO;
559                 }
560                 s2 = write(fd_new, buf, working_block);
561                 if (s2 < 0) {
562                         log_err("Write error, expecting %d, got %d.\n", (int)block_size, (int)s2);
563                         return -EIO;
564                 }
565                 rnc.device_offset -= s1;
566                 if (opt_write_log && write_log() < 0) {
567                         log_err("Log write error, some data are perhaps lost.\n");
568                         return -EIO;
569                 }
570
571                 *bytes += (uint64_t)s2;
572                 if (rnc.device_offset < (j * (rnc.device_size / 10))) {
573                         log_err("-");
574                         j--;
575                 }
576         }
577         log_err("] Done.\n");
578
579         return 0;
580 }
581
582 static int copy_data(void)
583 {
584         size_t block_size = opt_bsize * 1024 * 1024;
585         int fd_old = -1, fd_new = -1;
586         int r = -EINVAL;
587         void *buf = NULL;
588         struct timeval start_time, end_time;
589         double tdiff;
590         uint64_t bytes = 0;
591
592         fd_old = open(rnc.crypt_path_org, O_RDONLY | (opt_directio ? O_DIRECT : 0));
593         if (fd_old == -1)
594                 goto out;
595
596         fd_new = open(rnc.crypt_path_new, O_WRONLY | (opt_directio ? O_DIRECT : 0));
597         if (fd_new == -1)
598                 goto out;
599
600         if (lseek(fd_old, rnc.device_offset, SEEK_SET) == -1)
601                 goto out;
602
603         if (lseek(fd_new, rnc.device_offset, SEEK_SET) == -1)
604                 goto out;
605
606         /* Check size */
607         if (ioctl(fd_old, BLKGETSIZE64, &rnc.device_size) < 0)
608                 goto out;
609
610         if (posix_memalign((void *)&buf, alignment(fd_new), block_size)) {
611                 r = -ENOMEM;
612                 goto out;
613         }
614
615         // FIXME: all this should be in init
616         if (!rnc.in_progress && rnc.reencrypt_direction == BACKWARD)
617                 rnc.device_offset = rnc.device_size;
618
619         gettimeofday(&start_time, NULL);
620
621         if (rnc.reencrypt_direction == FORWARD)
622                 r = copy_data_forward(fd_old, fd_new, block_size, buf, &bytes);
623         else
624                 r = copy_data_backward(fd_old, fd_new, block_size, buf, &bytes);
625
626         gettimeofday(&end_time, NULL);
627
628         if (r < 0)
629                 log_err("ERROR during reencryption.\n");
630
631         if (write_log() < 0)
632                 log_err("Log write error, ignored.\n");
633
634         tdiff = time_diff(start_time, end_time);
635         log_err("Time elapsed %.2f seconds, %" PRIu64 " MB written, speed %.2f MB/s\n",
636                 tdiff, bytes / 1024 / 1024, (double)(bytes / 1024 / 1024) / tdiff);
637 out:
638         if (fd_old != -1)
639                 close(fd_old);
640         if (fd_new != -1)
641                 close(fd_new);
642         free(buf);
643         return r;
644 }
645
646 static int initialize_uuid(void)
647 {
648         struct crypt_device *cd = NULL;
649         int r;
650
651         /* Try to load LUKS from device */
652         if ((r = crypt_init(&cd, rnc.device)))
653                 return r;
654         crypt_set_log_callback(cd, _quiet_log, NULL);
655         r = crypt_load(cd, CRYPT_LUKS1, NULL);
656         if (!r)
657                 rnc.device_uuid = strdup(crypt_get_uuid(cd));
658         else
659                 /* Reencryption already in progress - magic header? */
660                 r = device_magic(CHECK_UNUSABLE);
661
662         crypt_free(cd);
663         return r;
664 }
665
666 static int initialize_passphrase(const char *device)
667 {
668         struct crypt_device *cd = NULL;
669         int r;
670
671         if ((r = crypt_init(&cd, device)) ||
672             (r = crypt_load(cd, CRYPT_LUKS1, NULL)) ||
673             (r = crypt_set_data_device(cd, rnc.device)))
674                 goto out;
675
676         if ((r = crypt_get_key(_("Enter LUKS passphrase: "),
677                           &rnc.password, &rnc.passwordLen,
678                           0, 0, opt_key_file,
679                           0, 0, cd)) <0)
680                 goto out;
681
682         if ((r = crypt_activate_by_passphrase(cd, NULL,
683                 CRYPT_ANY_SLOT, rnc.password, rnc.passwordLen, 0) < 0))
684                 goto out;
685
686         if (r >= 0) {
687                 rnc.keyslot = r;
688                 r = 0;
689         }
690 out:
691         crypt_free(cd);
692         return r;
693 }
694
695 static int initialize_context(const char *device)
696 {
697         log_dbg("Initialising reencryption context.");
698
699         rnc.log_fd =-1;
700
701         if (!(rnc.device = strndup(device, PATH_MAX)))
702                 return -ENOMEM;
703 /*
704         if (opt_new_file && !create_uuid()) {
705                 log_err("Cannot create fake header.\n");
706                 return -EINVAL;
707         }
708 */
709         if (initialize_uuid()) {
710                 log_err("No header found on device.\n");
711                 return -EINVAL;
712         }
713
714         /* Prepare device names */
715         if (snprintf(rnc.log_file, PATH_MAX,
716                      "LUKS-%s.log", rnc.device_uuid) < 0)
717                 return -ENOMEM;
718         if (snprintf(rnc.header_file_org, PATH_MAX,
719                      "LUKS-%s.org", rnc.device_uuid) < 0)
720                 return -ENOMEM;
721         if (snprintf(rnc.header_file_new, PATH_MAX,
722                      "LUKS-%s.new", rnc.device_uuid) < 0)
723                 return -ENOMEM;
724
725         /* Paths to encrypted devices */
726         if (snprintf(rnc.crypt_path_org, PATH_MAX,
727                      "%s/%s", crypt_get_dir(), rnc.header_file_org) < 0)
728                 return -ENOMEM;
729         if (snprintf(rnc.crypt_path_new, PATH_MAX,
730                      "%s/%s", crypt_get_dir(), rnc.header_file_new) < 0)
731                 return -ENOMEM;
732
733         remove_headers();
734
735         /* Block ctrl+c */
736         // FIXME: add some routine to handle it
737         sigemptyset(&signals_open);
738         sigaddset(&signals_open, SIGINT);
739         sigprocmask(SIG_SETMASK, &signals_open, NULL);
740
741         return open_log();
742 }
743
744 static void destroy_context(void)
745 {
746         log_dbg("Destroying reencryption context.");
747
748         close_log();
749         remove_headers();
750
751         if ((rnc.reencrypt_direction == FORWARD &&
752              rnc.device_offset == rnc.device_size) ||
753              rnc.device_offset == 0) {
754                 unlink(rnc.log_file);
755                 unlink(rnc.header_file_org);
756                 unlink(rnc.header_file_new);
757         }
758
759         crypt_safe_free(rnc.password);
760
761         free(rnc.device);
762         free(rnc.device_uuid);
763
764         sigprocmask(SIG_UNBLOCK, &signals_open, NULL);
765 }
766
767 int run_reencrypt(const char *device)
768 {
769         int r = -EINVAL;
770
771         if (initialize_context(device))
772                 goto out;
773
774         log_dbg("Running reencryption.");
775
776         if (!rnc.in_progress) {
777                 if ((r = initialize_passphrase(rnc.device)) ||
778                     (r = backup_luks_headers()) ||
779                     (r = device_magic(MAKE_UNUSABLE)))
780                         goto out;
781         } else {
782                 if ((r = initialize_passphrase(rnc.header_file_org)))
783                         goto out;
784         }
785
786         if ((r = activate_luks_headers()))
787                 goto out;
788
789         if ((r = copy_data()))
790                 goto out;
791
792         r = restore_luks_header(rnc.header_file_new);
793 out:
794         destroy_context();
795         return r;
796 }
797
798 static __attribute__ ((noreturn)) void usage(poptContext popt_context,
799                                              int exitcode, const char *error,
800                                              const char *more)
801 {
802         poptPrintUsage(popt_context, stderr, 0);
803         if (error)
804                 log_err("%s: %s\n", more, error);
805         poptFreeContext(popt_context);
806         exit(exitcode);
807 }
808
809 static void help(poptContext popt_context,
810                  enum poptCallbackReason reason __attribute__((unused)),
811                  struct poptOption *key,
812                  const char *arg __attribute__((unused)),
813                  void *data __attribute__((unused)))
814 {
815         usage(popt_context, EXIT_SUCCESS, NULL, NULL);
816 }
817
818 static void _dbg_version_and_cmd(int argc, const char **argv)
819 {
820         int i;
821
822         log_std("# %s %s processing \"", PACKAGE_NAME, PACKAGE_VERSION);
823         for (i = 0; i < argc; i++) {
824                 if (i)
825                         log_std(" ");
826                 log_std("%s", argv[i]);
827         }
828         log_std("\"\n");
829 }
830
831 int main(int argc, const char **argv)
832 {
833         static struct poptOption popt_help_options[] = {
834                 { NULL,    '\0', POPT_ARG_CALLBACK, help, 0, NULL,                         NULL },
835                 { "help",  '?',  POPT_ARG_NONE,     NULL, 0, N_("Show this help message"), NULL },
836                 { "usage", '\0', POPT_ARG_NONE,     NULL, 0, N_("Display brief usage"),    NULL },
837                 POPT_TABLEEND
838         };
839         static struct poptOption popt_options[] = {
840                 { NULL,                '\0', POPT_ARG_INCLUDE_TABLE, popt_help_options, 0, N_("Help options:"), NULL },
841                 { "version",           '\0', POPT_ARG_NONE, &opt_version_mode,          0, N_("Print package version"), NULL },
842                 { "verbose",           'v',  POPT_ARG_NONE, &opt_verbose,               0, N_("Shows more detailed error messages"), NULL },
843                 { "debug",             '\0', POPT_ARG_NONE, &opt_debug,                 0, N_("Show debug messages"), NULL },
844                 { "block-size",        'B',  POPT_ARG_INT, &opt_bsize,                  0, N_("Reencryption block size"), N_("MB") },
845                 { "new-header",        'N',  POPT_ARG_INT, &opt_new,                    0, N_("Create new header, need size on the end of device"), N_("MB") },
846                 { "new-crypt",         'f',  POPT_ARG_STRING, &opt_new_file,            0, N_("Log suffix for new reencryption file."), NULL },
847                 { "cipher",            'c',  POPT_ARG_STRING, &opt_cipher,              0, N_("The cipher used to encrypt the disk (see /proc/crypto)"), NULL },
848                 { "hash",              'h',  POPT_ARG_STRING, &opt_hash,                0, N_("The hash used to create the encryption key from the passphrase"), NULL },
849                 { "key-file",          'd',  POPT_ARG_STRING, &opt_key_file,            0, N_("Read the key from a file."), NULL },
850                 { "iter-time",         'i',  POPT_ARG_INT, &opt_iteration_time,         0, N_("PBKDF2 iteration time for LUKS (in ms)"), N_("msecs") },
851                 { "batch-mode",        'q',  POPT_ARG_NONE, &opt_batch_mode,            0, N_("Do not ask for confirmation"), NULL },
852                 { "use-random",        '\0', POPT_ARG_NONE, &opt_random,                0, N_("Use /dev/random for generating volume key."), NULL },
853                 { "use-urandom",       '\0', POPT_ARG_NONE, &opt_urandom,               0, N_("Use /dev/urandom for generating volume key."), NULL },
854                 { "use-directio",      '\0', POPT_ARG_NONE, &opt_directio,              0, N_("Use direct-io when accesing devices."), NULL },
855                 { "write-log",         '\0', POPT_ARG_NONE, &opt_write_log,             0, N_("Update log file after every block."), NULL },
856                 POPT_TABLEEND
857         };
858         poptContext popt_context;
859         int r;
860
861         crypt_set_log_callback(NULL, _log, NULL);
862         log_err("WARNING: this is experimental code, it can completely break your data.\n");
863
864         setlocale(LC_ALL, "");
865         bindtextdomain(PACKAGE, LOCALEDIR);
866         textdomain(PACKAGE);
867
868         popt_context = poptGetContext(PACKAGE, argc, argv, popt_options, 0);
869         poptSetOtherOptionHelp(popt_context,
870                                N_("[OPTION...] <device>]"));
871
872         while((r = poptGetNextOpt(popt_context)) > 0) {
873                 if (r < 0)
874                         break;
875         }
876
877         if (r < -1)
878                 usage(popt_context, EXIT_FAILURE, poptStrerror(r),
879                       poptBadOption(popt_context, POPT_BADOPTION_NOALIAS));
880         if (opt_version_mode) {
881                 log_std("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION);
882                 poptFreeContext(popt_context);
883                 exit(EXIT_SUCCESS);
884         }
885
886         action_argv = poptGetArgs(popt_context);
887         if(!action_argv)
888                 usage(popt_context, EXIT_FAILURE, _("Argument required."),
889                       poptGetInvocationName(popt_context));
890
891         if (opt_random && opt_urandom)
892                 usage(popt_context, EXIT_FAILURE, _("Only one of --use-[u]random options is allowed."),
893                       poptGetInvocationName(popt_context));
894
895         if (opt_new && !opt_new_file)
896                 usage(popt_context, EXIT_FAILURE, _("You have to use -f with -N."),
897                       poptGetInvocationName(popt_context));
898
899         if (opt_debug) {
900                 opt_verbose = 1;
901                 crypt_set_debug_level(-1);
902                 _dbg_version_and_cmd(argc, argv);
903         }
904
905         r = run_reencrypt(action_argv[0]);
906
907         poptFreeContext(popt_context);
908
909         /* Translate exit code to simple codes */
910         switch (r) {
911         case 0:         r = EXIT_SUCCESS; break;
912         case -EEXIST:
913         case -EBUSY:    r = 5; break;
914         case -ENOTBLK:
915         case -ENODEV:   r = 4; break;
916         case -ENOMEM:   r = 3; break;
917         case -EPERM:    r = 2; break;
918         case -EINVAL:
919         case -ENOENT:
920         case -ENOSYS:
921         default:        r = EXIT_FAILURE;
922         }
923         return r;
924 }