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