~ubuntu-branches/debian/stretch/uswsusp/stretch

« back to all changes in this revision

Viewing changes to suspend-cvs20060928/resume.c

  • Committer: Bazaar Package Importer
  • Author(s): Christian Perrier
  • Date: 2008-08-20 09:09:13 UTC
  • mfrom: (0.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20080820090913-0eahue1zo8egcxls
Tags: 0.8-1.1
* Non-maintainer upload to fix pending l10n issues.
* Remove extra and useless debian/po/ff/ directory
* Debconf translation updates:
  - Japanese. Closes: #489939
  - German. Closes: #493747
  - French. Closes: #493771
  - Romanian. Closes: #493772
  - Galician. Closes: #494050
  - Finnish. Closes: #494087
  - Italian. Closes: #494096
  - Basque. Closes: #494277
  - Basque. Closes: #494277
  - Czech. Closes: #494410
  - Swedish. Closes: #494412
  - Russian. Closes: #495412
  - Portuguese. Closes: #495451
  - Spanish. Closes: #495499
  - Slovak. Closes: #495516

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * resume.c
3
 
 *
4
 
 * A simple user space resume handler for swsusp.
5
 
 *
6
 
 * Copyright (C) 2005 Rafael J. Wysocki <rjw@sisk.pl>
7
 
 *
8
 
 * This file is released under the GPLv2.
9
 
 *
10
 
 */
11
 
 
12
 
#define _GNU_SOURCE
13
 
#include <sys/types.h>
14
 
#include <sys/stat.h>
15
 
#include <sys/ioctl.h>
16
 
#include <sys/mman.h>
17
 
#include <sys/mount.h>
18
 
#include <sys/time.h>
19
 
#include <time.h>
20
 
#include <syscall.h>
21
 
#include <fcntl.h>
22
 
#include <unistd.h>
23
 
#include <stdio.h>
24
 
#include <stdlib.h>
25
 
#include <string.h>
26
 
#include <errno.h>
27
 
#ifdef CONFIG_COMPRESS
28
 
#include <lzf.h>
29
 
#else
30
 
#define lzf_decompress(a, b, c, d)      0
31
 
#endif
32
 
 
33
 
#include "swsusp.h"
34
 
#include "config.h"
35
 
#include "md5.h"
36
 
#include "splash.h"
37
 
 
38
 
static char snapshot_dev_name[MAX_STR_LEN] = SNAPSHOT_DEVICE;
39
 
static char resume_dev_name[MAX_STR_LEN] = RESUME_DEVICE;
40
 
static int suspend_loglevel = SUSPEND_LOGLEVEL;
41
 
static int max_loglevel = MAX_LOGLEVEL;
42
 
static char verify_checksum;
43
 
#ifdef CONFIG_COMPRESS
44
 
static char decompress;
45
 
#else
46
 
#define decompress 0
47
 
#endif
48
 
#ifdef CONFIG_ENCRYPT
49
 
static char decrypt;
50
 
#else
51
 
#define decrypt 0
52
 
#endif
53
 
static char splash_param;
54
 
 
55
 
static struct splash splash;
56
 
 
57
 
static struct config_par parameters[PARAM_NO] = {
58
 
        {
59
 
                .name = "snapshot device",
60
 
                .fmt = "%s",
61
 
                .ptr = snapshot_dev_name,
62
 
                .len = MAX_STR_LEN
63
 
        },
64
 
        {
65
 
                .name = "resume device",
66
 
                .fmt ="%s",
67
 
                .ptr = resume_dev_name,
68
 
                .len = MAX_STR_LEN
69
 
        },
70
 
        {
71
 
                .name = "suspend loglevel",
72
 
                .fmt = "%d",
73
 
                .ptr = &suspend_loglevel,
74
 
        },
75
 
        {
76
 
                .name = "max loglevel",
77
 
                .fmt = "%d",
78
 
                .ptr = &max_loglevel,
79
 
        },
80
 
        {
81
 
                .name = "image size",
82
 
                .fmt = "%lu",
83
 
                .ptr = NULL,
84
 
        },
85
 
        {
86
 
                .name = "compute checksum",
87
 
                .fmt = "%c",
88
 
                .ptr = NULL,
89
 
        },
90
 
#ifdef CONFIG_COMPRESS
91
 
        {
92
 
                .name = "compress",
93
 
                .fmt = "%c",
94
 
                .ptr = NULL,
95
 
        },
96
 
#endif
97
 
#ifdef CONFIG_ENCRYPT
98
 
        {
99
 
                .name = "encrypt",
100
 
                .fmt = "%c",
101
 
                .ptr = NULL,
102
 
        },
103
 
        {
104
 
                .name = "RSA key file",
105
 
                .fmt = "%s",
106
 
                .ptr = NULL,
107
 
        },
108
 
#endif
109
 
        {
110
 
                .name = "early writeout",
111
 
                .fmt = "%c",
112
 
                .ptr = NULL,
113
 
        },
114
 
        {
115
 
                .name = "splash",
116
 
                .fmt = "%c",
117
 
                .ptr = &splash_param,
118
 
        },
119
 
        {
120
 
                .name = "shutdown method",
121
 
                .fmt = "%s",
122
 
                .ptr = NULL,
123
 
        },
124
 
};
125
 
 
126
 
static unsigned int page_size;
127
 
static unsigned int buffer_size;
128
 
static void *mem_pool;
129
 
 
130
 
/**
131
 
 *      read_area - Read data from a swap location.
132
 
 *      @fd:            File handle of the resume partition
133
 
 *      @buf:           Pointer to the area we're reading into
134
 
 *      @offset:        Swap offset of the place to read from
135
 
 *      @size:          The number of bytes to read
136
 
 */
137
 
 
138
 
static int read_area(int fd, void *buf, loff_t offset, unsigned int size)
139
 
{
140
 
        int res = 0;
141
 
        ssize_t cnt = 0;
142
 
 
143
 
        if (offset) {
144
 
                if (lseek(fd, offset, SEEK_SET) == offset) 
145
 
                        cnt = read(fd, buf, size);
146
 
                if (cnt < (ssize_t)size) {
147
 
                        if (cnt < 0)
148
 
                                res = cnt;
149
 
                        else
150
 
                                res = -EIO;
151
 
                }
152
 
        }
153
 
        return res;
154
 
}
155
 
 
156
 
/*
157
 
 *      The swap_map_handle structure is used for handling the swap map in
158
 
 *      a file-alike way
159
 
 */
160
 
 
161
 
struct swap_map_handle {
162
 
        char *page_buffer;
163
 
        char *read_buffer;
164
 
        struct swap_area *areas;
165
 
        unsigned short areas_per_page;
166
 
        loff_t *next_swap;
167
 
        unsigned int area_size;
168
 
        unsigned int cur_size;
169
 
        unsigned int k;
170
 
        int fd;
171
 
        struct md5_ctx ctx;
172
 
#ifdef CONFIG_ENCRYPT
173
 
        char *decrypt_buffer;
174
 
        gcry_cipher_hd_t cipher_handle;
175
 
#endif
176
 
};
177
 
 
178
 
#define READ_AHEAD_SIZE (8*1024*1024)
179
 
 
180
 
/**
181
 
 *      The following functions allow us to read data using a swap map
182
 
 *      in a file-alike way
183
 
 */
184
 
 
185
 
static int fill_buffer(struct swap_map_handle *handle)
186
 
{
187
 
        void *dst = handle->read_buffer;
188
 
        int error;
189
 
 
190
 
        int read_ahead_areas = READ_AHEAD_SIZE/buffer_size;
191
 
        int advise_first, advise_last, i;
192
 
 
193
 
        if (!handle->k) {
194
 
                /* we've got a new map page */
195
 
                advise_first = 0;
196
 
                advise_last  = read_ahead_areas;
197
 
        } else {
198
 
                advise_first = handle->k + read_ahead_areas;
199
 
                advise_last  = advise_first;
200
 
        }
201
 
 
202
 
        for (i = advise_first;
203
 
        i <= advise_last && i < handle->areas_per_page;
204
 
        i++) {
205
 
                if (handle->areas[i].offset == 0)
206
 
                        break;
207
 
 
208
 
                error = posix_fadvise(handle->fd, handle->areas[i].offset,
209
 
                                handle->areas[i].size, POSIX_FADV_NOREUSE);
210
 
                if (error) {
211
 
                        perror("posix_fadvise");
212
 
                        break;
213
 
                }
214
 
        }
215
 
 
216
 
        handle->area_size = handle->areas[handle->k].size;
217
 
        if (handle->area_size > buffer_size)
218
 
                return -ENOMEM;
219
 
#ifdef CONFIG_ENCRYPT
220
 
        if (decrypt)
221
 
                dst = handle->decrypt_buffer;
222
 
#endif
223
 
        error = read_area(handle->fd, dst,
224
 
                        handle->areas[handle->k].offset,
225
 
                        handle->area_size);
226
 
#ifdef CONFIG_ENCRYPT
227
 
        if (!error && decrypt)
228
 
                error = gcry_cipher_decrypt(handle->cipher_handle,
229
 
                                (void *)handle->read_buffer, handle->area_size,
230
 
                                dst, handle->area_size);
231
 
#endif
232
 
        return error;
233
 
}
234
 
 
235
 
static int init_swap_reader(struct swap_map_handle *handle, int fd, loff_t start, void *buf)
236
 
{
237
 
        int error;
238
 
 
239
 
        if (!start || !buf)
240
 
                return -EINVAL;
241
 
        handle->areas = buf;
242
 
        handle->areas_per_page = (page_size - sizeof(loff_t)) /
243
 
                        sizeof(struct swap_area);
244
 
        handle->next_swap = (loff_t *)(handle->areas + handle->areas_per_page);
245
 
        handle->page_buffer = (char *)buf + page_size;
246
 
        handle->read_buffer = handle->page_buffer + page_size;
247
 
#ifdef CONFIG_ENCRYPT
248
 
        handle->decrypt_buffer = handle->read_buffer + buffer_size;
249
 
#endif
250
 
        error = read_area(fd, handle->areas, start, page_size);
251
 
        if (error)
252
 
                return error;
253
 
        handle->fd = fd;
254
 
        handle->k = 0;
255
 
        error = fill_buffer(handle);
256
 
        if (error)
257
 
                return error;
258
 
        handle->cur_size = 0;
259
 
        if (verify_checksum)
260
 
                md5_init_ctx(&handle->ctx);
261
 
        return 0;
262
 
}
263
 
 
264
 
static int restore(struct swap_map_handle *handle, int disp)
265
 
{
266
 
        struct buf_block *block;
267
 
        void *buf = handle->page_buffer;
268
 
 
269
 
        block = (struct buf_block *)(handle->read_buffer + disp);
270
 
        if (decompress) {
271
 
                unsigned short cnt = block->size;
272
 
 
273
 
                if (cnt == page_size) {
274
 
                        memcpy(buf, block->data, page_size);
275
 
                } else if (cnt < page_size) {
276
 
                        cnt = lzf_decompress(block->data, cnt, buf, page_size);
277
 
                        if (cnt != page_size)
278
 
                                return -ENODATA;
279
 
                } else {
280
 
                        return -EINVAL;
281
 
                }
282
 
                block->size += sizeof(short);
283
 
                return block->size;
284
 
        }
285
 
        memcpy(buf, block, page_size);
286
 
        return page_size;
287
 
}
288
 
 
289
 
static inline int swap_read_page(struct swap_map_handle *handle)
290
 
{
291
 
        loff_t offset;
292
 
        size_t size;
293
 
        int error = 0;
294
 
 
295
 
        if (handle->cur_size < handle->area_size) {
296
 
                /* Get the data from the read buffer */
297
 
                size = restore(handle, handle->cur_size);
298
 
                if (size < 0)
299
 
                        return size;
300
 
                handle->cur_size += size;
301
 
                goto MD5;
302
 
        }
303
 
 
304
 
        /* There are no more data in the read buffer.  Read more */
305
 
        if (++handle->k >= handle->areas_per_page) {
306
 
                handle->k = 0;
307
 
                offset = *handle->next_swap;
308
 
                if (offset)
309
 
                        error = read_area(handle->fd, handle->areas, offset, page_size);
310
 
                else
311
 
                        error = -EINVAL;
312
 
        }
313
 
        if (!error)
314
 
                error = fill_buffer(handle);
315
 
        if (error)
316
 
                return error;
317
 
 
318
 
        size = restore(handle, 0);
319
 
        if (size < 0)
320
 
                return size;
321
 
        handle->cur_size = size;
322
 
 
323
 
MD5:
324
 
        if (verify_checksum)
325
 
                md5_process_block(handle->page_buffer, page_size, &handle->ctx);
326
 
 
327
 
        return 0;
328
 
}
329
 
 
330
 
/**
331
 
 *      load_image - load the image using the swap map handle
332
 
 *      @handle and the snapshot handle @snapshot
333
 
 *      (assume there are @nr_pages pages to load)
334
 
 */
335
 
 
336
 
static inline int load_image(struct swap_map_handle *handle, int dev,
337
 
                      unsigned int nr_pages)
338
 
{
339
 
        unsigned int m, n;
340
 
        int ret;
341
 
        int error = 0;
342
 
 
343
 
        printf("Loading image data pages (%u pages) ...     ", nr_pages);
344
 
        m = nr_pages / 100;
345
 
        if (!m)
346
 
                m = 1;
347
 
        n = 0;
348
 
        do {
349
 
                error = swap_read_page(handle);
350
 
                if (error)
351
 
                        break;
352
 
                ret = write(dev, handle->page_buffer, page_size);
353
 
                if (ret < (int)page_size) {
354
 
                        error = ret < 0 ? -errno : -ENOSPC;
355
 
                        break;
356
 
                }
357
 
                if (!(n % m)) {
358
 
                        printf("\b\b\b\b%3d%%", n / m);
359
 
                        if (n / m > 15)
360
 
                                splash.progress(n / m);
361
 
                }
362
 
                n++;
363
 
        } while (n < nr_pages);
364
 
        if (!error)
365
 
                printf(" done\n");
366
 
        return error;
367
 
}
368
 
 
369
 
static char * print_checksum(char * buf, unsigned char *checksum)
370
 
{
371
 
        int j;
372
 
 
373
 
        for (j = 0; j < 16; j++)
374
 
                buf += sprintf(buf, "%02hhx ", checksum[j]);
375
 
 
376
 
        return buf;
377
 
}
378
 
 
379
 
#ifdef CONFIG_ENCRYPT
380
 
static int decrypt_key(struct swsusp_info *header, unsigned char *key,
381
 
                        unsigned char *ivec, void *buffer)
382
 
{
383
 
        gcry_ac_handle_t rsa_hd;
384
 
        gcry_ac_data_t rsa_data_set, key_set;
385
 
        gcry_ac_key_t rsa_priv;
386
 
        gcry_mpi_t mpi;
387
 
        unsigned char *buf, *out, *key_buf, *ivec_buf;
388
 
        char *pass_buf;
389
 
        struct md5_ctx ctx;
390
 
        struct RSA_data *rsa;
391
 
        gcry_cipher_hd_t sym_hd;
392
 
        int j, ret = 0;
393
 
 
394
 
        rsa = &header->rsa;
395
 
 
396
 
        ret = gcry_ac_open(&rsa_hd, GCRY_AC_RSA, 0);
397
 
        if (ret)
398
 
                return ret;
399
 
 
400
 
        if (!ret)
401
 
                ret = gcry_cipher_open(&sym_hd, PK_CIPHER,
402
 
                                GCRY_CIPHER_MODE_CFB, GCRY_CIPHER_SECURE);
403
 
 
404
 
        if (ret)
405
 
                goto Free_rsa;
406
 
 
407
 
        pass_buf = buffer;
408
 
        key_buf = (unsigned char *)pass_buf + PASS_SIZE;
409
 
        ivec_buf = key_buf + PK_KEY_SIZE;
410
 
        out = ivec_buf + PK_CIPHER_BLOCK;
411
 
        do {
412
 
                splash.read_password(pass_buf, 0);
413
 
                memset(ivec_buf, 0, PK_CIPHER_BLOCK);
414
 
                strncpy((char *)ivec_buf, pass_buf, PK_CIPHER_BLOCK);
415
 
                md5_init_ctx(&ctx);
416
 
                md5_process_bytes(pass_buf, strlen(pass_buf), &ctx);
417
 
                md5_finish_ctx(&ctx, key_buf);
418
 
                ret = gcry_cipher_setkey(sym_hd, key_buf, PK_KEY_SIZE);
419
 
                if (!ret)
420
 
                        ret = gcry_cipher_setiv(sym_hd, ivec_buf,
421
 
                                                PK_CIPHER_BLOCK);
422
 
 
423
 
                if (!ret)
424
 
                        ret = gcry_cipher_encrypt(sym_hd,
425
 
                                        out, KEY_TEST_SIZE,
426
 
                                        KEY_TEST_DATA, KEY_TEST_SIZE);
427
 
 
428
 
                if (ret)
429
 
                        break;
430
 
 
431
 
                ret = memcmp(out, rsa->key_test, KEY_TEST_SIZE);
432
 
 
433
 
                if (ret)
434
 
                        printf("resume: Wrong passphrase, try again.\n");
435
 
        } while (ret);
436
 
 
437
 
        gcry_cipher_close(sym_hd);
438
 
        if (!ret)
439
 
                ret = gcry_cipher_open(&sym_hd, PK_CIPHER,
440
 
                                GCRY_CIPHER_MODE_CFB, GCRY_CIPHER_SECURE);
441
 
 
442
 
        if (ret)
443
 
                goto Free_rsa;
444
 
 
445
 
        ret = gcry_cipher_setkey(sym_hd, key_buf, PK_KEY_SIZE);
446
 
        if (!ret)
447
 
                ret = gcry_cipher_setiv(sym_hd, ivec_buf, PK_CIPHER_BLOCK);
448
 
 
449
 
        if (!ret)
450
 
                ret = gcry_ac_data_new(&rsa_data_set);
451
 
 
452
 
        if (ret) {
453
 
                gcry_cipher_close(sym_hd);
454
 
                goto Free_rsa;
455
 
        }
456
 
 
457
 
        buf = rsa->data;
458
 
        for (j = 0; j < RSA_FIELDS; j++) {
459
 
                size_t s = rsa->size[j];
460
 
 
461
 
                /* We need to decrypt some components */
462
 
                if (j >= RSA_FIELDS_PUB) {
463
 
                        /* We use the in-place decryption */
464
 
                        ret = gcry_cipher_decrypt(sym_hd, buf, s, NULL, 0);
465
 
                        if (ret)
466
 
                                break;
467
 
                }
468
 
 
469
 
                gcry_mpi_scan(&mpi, GCRYMPI_FMT_USG, buf, s, NULL);
470
 
                ret = gcry_ac_data_set(rsa_data_set, GCRY_AC_FLAG_COPY,
471
 
                                        rsa->field[j], mpi);
472
 
                gcry_mpi_release(mpi);
473
 
                if (ret)
474
 
                        break;
475
 
 
476
 
                buf += s;
477
 
        }
478
 
        if (!ret)
479
 
                ret = gcry_ac_key_init(&rsa_priv, rsa_hd,
480
 
                                        GCRY_AC_KEY_SECRET, rsa_data_set);
481
 
 
482
 
        if (!ret) {
483
 
                ret = gcry_ac_data_new(&key_set);
484
 
                if (!ret) {
485
 
                        gcry_mpi_scan(&mpi, GCRYMPI_FMT_USG, header->key.data,
486
 
                                        header->key.size, NULL);
487
 
                        ret = gcry_ac_data_set(key_set, GCRY_AC_FLAG_COPY,
488
 
                                                "a", mpi);
489
 
                        if (!ret) {
490
 
                                gcry_mpi_release(mpi);
491
 
                                ret = gcry_ac_data_decrypt(rsa_hd, 0, rsa_priv,
492
 
                                                &mpi, key_set);
493
 
                        }
494
 
                        if (!ret) {
495
 
                                unsigned char *res;
496
 
                                size_t s;
497
 
 
498
 
                                gcry_mpi_aprint(GCRYMPI_FMT_USG, &res, &s, mpi);
499
 
                                if (s == KEY_SIZE + CIPHER_BLOCK) {
500
 
                                        memcpy(key, res, KEY_SIZE);
501
 
                                        memcpy(ivec, res + KEY_SIZE,
502
 
                                                        CIPHER_BLOCK);
503
 
                                } else {
504
 
                                        ret = -ENODATA;
505
 
                                }
506
 
                                gcry_free(res);
507
 
                        }
508
 
                        gcry_mpi_release(mpi);
509
 
                        gcry_ac_data_destroy(key_set);
510
 
                }
511
 
                gcry_ac_key_destroy(rsa_priv);
512
 
        } else {
513
 
                gcry_ac_data_destroy(rsa_data_set);
514
 
        }
515
 
 
516
 
        gcry_cipher_close(sym_hd);
517
 
 
518
 
Free_rsa:
519
 
        gcry_ac_close(rsa_hd);
520
 
 
521
 
        return ret;
522
 
}
523
 
#endif
524
 
 
525
 
static int read_image(int dev, char *resume_dev_name)
526
 
{
527
 
        static struct swsusp_header swsusp_header;
528
 
        static struct swap_map_handle handle;
529
 
        static unsigned char orig_checksum[16], checksum[16];
530
 
        int fd, ret, error = 0;
531
 
        struct swsusp_info *header = mem_pool;
532
 
        char *buffer = (char *)mem_pool + page_size;
533
 
        unsigned int nr_pages;
534
 
        unsigned int size = sizeof(struct swsusp_header);
535
 
        unsigned int shift = page_size - size;
536
 
        char c;
537
 
 
538
 
        fd = open(resume_dev_name, O_RDWR);
539
 
        if (fd < 0) {
540
 
                ret = -errno;
541
 
                fprintf(stderr,"resume: Could not open the resume device\n");
542
 
                return ret;
543
 
        }
544
 
        if (lseek(fd, shift, SEEK_SET) != shift)
545
 
                return -EIO;
546
 
        ret = read(fd, &swsusp_header, size);
547
 
        if (ret == size) {
548
 
                if (memcmp(SWSUSP_SIG, swsusp_header.sig, 10))
549
 
                        return -EINVAL;
550
 
        } else {
551
 
                error = ret < 0 ? ret : -EIO;
552
 
        }
553
 
        if (!error)
554
 
                error = read_area(fd, header, swsusp_header.image, page_size);
555
 
        if (!error) {
556
 
                if(header->image_flags & IMAGE_CHECKSUM) {
557
 
                        memcpy(orig_checksum, header->checksum, 16);
558
 
                        printf("resume: MD5 checksum %s\n",
559
 
                                print_checksum(buffer, orig_checksum));
560
 
                        verify_checksum = 1;
561
 
                }
562
 
                splash.progress(10);
563
 
                if (header->image_flags & IMAGE_COMPRESSED) {
564
 
                        printf("resume: Compressed image\n");
565
 
#ifdef CONFIG_COMPRESS
566
 
                        decompress = 1;
567
 
#else
568
 
                        fprintf(stderr,"resume: Compression not supported\n");
569
 
                        error = -EINVAL;
570
 
#endif
571
 
                }
572
 
                if (!error && (header->image_flags & IMAGE_ENCRYPTED)) {
573
 
#ifdef CONFIG_ENCRYPT
574
 
                        static unsigned char key[KEY_SIZE], ivec[CIPHER_BLOCK];
575
 
 
576
 
                        printf("resume: Encrypted image\n");
577
 
                        if (header->image_flags & IMAGE_USE_RSA) {
578
 
                                error = decrypt_key(header, key, ivec, buffer);
579
 
                        } else {
580
 
                                int j;
581
 
 
582
 
                                splash.read_password(buffer, 0);
583
 
                                encrypt_init(key, ivec, buffer);
584
 
                                for (j = 0; j < CIPHER_BLOCK; j++)
585
 
                                        ivec[j] ^= header->salt[j];
586
 
                        }
587
 
                        splash.progress(15);
588
 
                        if (!error)
589
 
                                error = gcry_cipher_open(&handle.cipher_handle,
590
 
                                        IMAGE_CIPHER, GCRY_CIPHER_MODE_CFB,
591
 
                                        GCRY_CIPHER_SECURE);
592
 
                        if (!error) {
593
 
                                decrypt = 1;
594
 
                                error = gcry_cipher_setkey(handle.cipher_handle,
595
 
                                                        key, KEY_SIZE);
596
 
                        }
597
 
                        if (!error)
598
 
                                error = gcry_cipher_setiv(handle.cipher_handle,
599
 
                                                        ivec, CIPHER_BLOCK);
600
 
 
601
 
                        if (error) {
602
 
                                if (decrypt)
603
 
                                        gcry_cipher_close(handle.cipher_handle);
604
 
                                decrypt = 0;
605
 
                                fprintf(stderr, "resume: libgcrypt error: %s\n",
606
 
                                                gcry_strerror(error));
607
 
                        }
608
 
#else
609
 
                        fprintf(stderr, "resume: Encryption not supported\n");
610
 
                        error = -EINVAL;
611
 
#endif
612
 
                }
613
 
                if (!error) {
614
 
                        error = init_swap_reader(&handle, fd,
615
 
                                        header->map_start, buffer);
616
 
                        nr_pages = header->pages - 1;
617
 
                        ret = write(dev, header, page_size);
618
 
                        if (ret < (int)page_size)
619
 
                                error = ret < 0 ? ret : -EIO;
620
 
                }
621
 
                if (!error) {
622
 
                        struct timeval begin, end;
623
 
                        double delta, mb = header->size / (1024.0 * 1024.0);
624
 
 
625
 
                        gettimeofday(&begin, NULL);
626
 
                        error = load_image(&handle, dev, nr_pages);
627
 
                        gettimeofday(&end, NULL);
628
 
 
629
 
                        timersub(&end, &begin, &end);
630
 
                        delta = end.tv_usec / 1000000.0 + end.tv_sec;
631
 
 
632
 
                        printf("wrote %0.1lf MB in %0.1lf seconds (%0.1lf MB/s)\n",
633
 
                                mb, header->writeout_time, mb / header->writeout_time);
634
 
 
635
 
                        printf("read %0.1lf MB in %0.1lf seconds (%0.1lf MB/s)\n",
636
 
                                mb, delta, mb / delta);
637
 
 
638
 
                        mb *= 2.0;
639
 
                        delta += header->writeout_time;
640
 
                        printf("total image i/o %0.1lf MB in %0.1lf seconds (%0.1lf MB/s)\n",
641
 
                                mb, delta, mb / delta);
642
 
                }
643
 
        }
644
 
        if (error) {
645
 
                c = splash.dialog(
646
 
                        "\nresume: The system snapshot image could not be read.\n\n"
647
 
#ifdef CONFIG_ENCRYPT
648
 
                        "\tThis might be a result of booting a wrong kernel\n"
649
 
                        "\tor typing in a wrong passphrase.\n\n"
650
 
#else
651
 
                        "\tThis might be a result of booting a wrong kernel.\n\n"
652
 
#endif
653
 
                        "\tYou can continue to boot the system and lose the saved state\n"
654
 
                        "\tor reboot and try again.\n\n"
655
 
                        "\t[Notice that you may not mount any filesystem between\n"
656
 
                        "\tnow and successful resume. That would badly damage\n"
657
 
                        "\taffected filesystems.]\n\n"
658
 
                        "\tDo you want to continue boot (Y/n)? ");
659
 
                ret = (c == 'n' || c == 'N');
660
 
                if (ret) {
661
 
                        close(fd);
662
 
                        reboot();
663
 
                }
664
 
        }
665
 
        if (!error || !ret) {
666
 
                if (!error && verify_checksum) {
667
 
                        md5_finish_ctx(&handle.ctx, checksum);
668
 
                        if (memcmp(orig_checksum, checksum, 16)) {
669
 
                                fprintf(stderr,"resume: MD5 checksum does not match\n");
670
 
                                fprintf(stderr,"resume: Computed MD5 checksum %s\n",
671
 
                                        print_checksum(buffer, checksum));
672
 
                                error = -EINVAL;
673
 
                        }
674
 
                }
675
 
                /* Reset swap signature now */
676
 
                memcpy(swsusp_header.sig, swsusp_header.orig_sig, 10);
677
 
                if (lseek(fd, shift, SEEK_SET) != shift) {
678
 
                        error = -EIO;
679
 
                } else {
680
 
                        ret = write(fd, &swsusp_header, size);
681
 
                        if (ret != size) {
682
 
                                error = ret < 0 ? -errno : -EIO;
683
 
                                fprintf(stderr,
684
 
                                        "resume: Could not restore the partition header\n");
685
 
                        }
686
 
                }
687
 
        }
688
 
        fsync(fd);
689
 
        close(fd);
690
 
#ifdef CONFIG_ENCRYPT
691
 
        if (decrypt)
692
 
                gcry_cipher_close(handle.cipher_handle);
693
 
#endif
694
 
 
695
 
        if (!error) {
696
 
                printf("resume: Image successfully loaded\n");
697
 
        } else {
698
 
                sprintf(buffer, "resume: Error %d loading the image\n"
699
 
                        "\nPress ENTER to continue\n", error);
700
 
                splash.dialog(buffer);
701
 
        }
702
 
        return error;
703
 
}
704
 
 
705
 
static void set_kernel_console_loglevel(int level)
706
 
{
707
 
        FILE *file;
708
 
        struct stat stat_buf;
709
 
        char *procname = "/proc/sys/kernel/printk";
710
 
        int proc_mounted = 0;
711
 
 
712
 
        if (stat(procname, &stat_buf) && errno == ENOENT) {
713
 
                if (mount("none", "/proc", "proc", 0, NULL)) {
714
 
                        fprintf(stderr, "resume: Could not mount proc\n");
715
 
                        return;
716
 
                } else
717
 
                        proc_mounted = 1;
718
 
        }
719
 
        file = fopen(procname, "w");
720
 
        if (file) {
721
 
                fprintf(file, "%d\n", level);
722
 
                fclose(file);
723
 
        }
724
 
        if (proc_mounted)
725
 
                umount("/proc");
726
 
}
727
 
 
728
 
int main(int argc, char *argv[])
729
 
{
730
 
        unsigned int mem_size;
731
 
        struct stat stat_buf;
732
 
        int dev;
733
 
        int n, error = 0;
734
 
 
735
 
        page_size = getpagesize();
736
 
        buffer_size = BUFFER_PAGES * page_size;
737
 
 
738
 
#ifdef CONFIG_ENCRYPT
739
 
        printf("resume: libgcrypt version: %s\n", gcry_check_version(NULL));
740
 
        gcry_control(GCRYCTL_INIT_SECMEM, page_size, 0);
741
 
        mem_size = 3 * page_size + 2 * buffer_size;
742
 
#else
743
 
        mem_size = 3 * page_size + buffer_size;
744
 
#endif
745
 
        mem_pool = malloc(mem_size);
746
 
        if (!mem_pool) {
747
 
                error = errno;
748
 
                fprintf(stderr, "resume: Could not allocate memory\n");
749
 
                return error;
750
 
        }
751
 
 
752
 
        if (get_config("resume", argc, argv, PARAM_NO, parameters, resume_dev_name))
753
 
                return EINVAL;
754
 
 
755
 
        if (splash_param != 'y' && splash_param != 'Y')
756
 
                splash_param = 0;
757
 
 
758
 
        while (stat(resume_dev_name, &stat_buf)) {
759
 
                fprintf(stderr, 
760
 
                        "resume: Could not stat the resume device file.\n"
761
 
                        "\tPlease type in the file name to try again"
762
 
                        "\tor press ENTER to boot the system: ");
763
 
                fgets(resume_dev_name, MAX_STR_LEN - 1, stdin);
764
 
                n = strlen(resume_dev_name) - 1;
765
 
                if (n <= 0)
766
 
                        return ENOENT;
767
 
                if (resume_dev_name[n] == '\n')
768
 
                        resume_dev_name[n] = '\0';
769
 
        }
770
 
 
771
 
        set_kernel_console_loglevel(suspend_loglevel);
772
 
 
773
 
        setvbuf(stdout, NULL, _IONBF, 0);
774
 
        setvbuf(stderr, NULL, _IONBF, 0);
775
 
 
776
 
        if (mlockall(MCL_CURRENT | MCL_FUTURE)) {
777
 
                fprintf(stderr, "resume: Could not lock myself\n");
778
 
                return 1;
779
 
        }
780
 
 
781
 
        splash_prepare(&splash, splash_param);
782
 
        splash.progress(5);
783
 
 
784
 
        dev = open(snapshot_dev_name, O_WRONLY);
785
 
        if (dev < 0)
786
 
                return ENOENT;
787
 
        error = read_image(dev, resume_dev_name);
788
 
        if (error) {
789
 
                fprintf(stderr, "resume: Could not read the image\n");
790
 
                error = -error;
791
 
                goto Close;
792
 
        }
793
 
        if (freeze(dev)) {
794
 
                error = errno;
795
 
                fprintf(stderr, "resume: Could not freeze processes\n");
796
 
                goto Close;
797
 
        }
798
 
        atomic_restore(dev);
799
 
        unfreeze(dev);
800
 
        splash.finish();
801
 
Close:
802
 
        close(dev);
803
 
 
804
 
        set_kernel_console_loglevel(max_loglevel);
805
 
 
806
 
        free(mem_pool);
807
 
 
808
 
        return error;
809
 
}