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

« back to all changes in this revision

Viewing changes to 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
#include "config.h"
 
13
#include <sys/types.h>
 
14
#include <sys/stat.h>
 
15
#include <sys/ioctl.h>
 
16
#include <sys/mman.h>
 
17
#include <sys/time.h>
 
18
#include <time.h>
 
19
#include <syscall.h>
 
20
#include <libgen.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 <lzo/lzo1x.h>
 
29
#endif
 
30
 
 
31
#include "swsusp.h"
 
32
#include "config_parser.h"
 
33
#include "md5.h"
 
34
#include "splash.h"
 
35
#include "loglevel.h"
 
36
 
 
37
static char snapshot_dev_name[MAX_STR_LEN] = SNAPSHOT_DEVICE;
 
38
static char resume_dev_name[MAX_STR_LEN] = RESUME_DEVICE;
 
39
static loff_t resume_offset;
 
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 do_decompress;
 
45
#else
 
46
#define do_decompress 0
 
47
#endif
 
48
#ifdef CONFIG_ENCRYPT
 
49
static char do_decrypt;
 
50
#else
 
51
#define do_decrypt 0
 
52
#endif
 
53
static char splash_param;
 
54
#ifdef CONFIG_FBSPLASH
 
55
char fbsplash_theme[MAX_STR_LEN] = "";
 
56
#endif
 
57
static int use_platform_suspend;
 
58
 
 
59
static struct splash splash;
 
60
static char *my_name;
 
61
 
 
62
static struct config_par parameters[] = {
 
63
        {
 
64
                .name = "snapshot device",
 
65
                .fmt = "%s",
 
66
                .ptr = snapshot_dev_name,
 
67
                .len = MAX_STR_LEN
 
68
        },
 
69
        {
 
70
                .name = "resume device",
 
71
                .fmt ="%s",
 
72
                .ptr = resume_dev_name,
 
73
                .len = MAX_STR_LEN
 
74
        },
 
75
        {
 
76
                .name = "resume offset",
 
77
                .fmt = "%llu",
 
78
                .ptr = &resume_offset,
 
79
        },
 
80
        {
 
81
                .name = "suspend loglevel",
 
82
                .fmt = "%d",
 
83
                .ptr = &suspend_loglevel,
 
84
        },
 
85
        {
 
86
                .name = "max loglevel",
 
87
                .fmt = "%d",
 
88
                .ptr = &max_loglevel,
 
89
        },
 
90
        {
 
91
                .name = "image size",
 
92
                .fmt = "%lu",
 
93
                .ptr = NULL,
 
94
        },
 
95
        {
 
96
                .name = "compute checksum",
 
97
                .fmt = "%c",
 
98
                .ptr = NULL,
 
99
        },
 
100
#ifdef CONFIG_COMPRESS
 
101
        {
 
102
                .name = "compress",
 
103
                .fmt = "%c",
 
104
                .ptr = NULL,
 
105
        },
 
106
#endif
 
107
#ifdef CONFIG_ENCRYPT
 
108
        {
 
109
                .name = "encrypt",
 
110
                .fmt = "%c",
 
111
                .ptr = NULL,
 
112
        },
 
113
        {
 
114
                .name = "RSA key file",
 
115
                .fmt = "%s",
 
116
                .ptr = NULL,
 
117
        },
 
118
#endif
 
119
        {
 
120
                .name = "early writeout",
 
121
                .fmt = "%c",
 
122
                .ptr = NULL,
 
123
        },
 
124
        {
 
125
                .name = "splash",
 
126
                .fmt = "%c",
 
127
                .ptr = &splash_param,
 
128
        },
 
129
        {
 
130
                .name = "shutdown method",
 
131
                .fmt = "%s",
 
132
                .ptr = NULL,
 
133
        },
 
134
#ifdef CONFIG_FBSPLASH
 
135
        {
 
136
                .name = "fbsplash theme",
 
137
                .fmt = "%s",
 
138
                .ptr = fbsplash_theme,
 
139
                .len = MAX_STR_LEN,
 
140
        },
 
141
#endif
 
142
        {
 
143
                .name = NULL,
 
144
                .fmt = NULL,
 
145
                .ptr = NULL,
 
146
                .len = 0,
 
147
        }
 
148
};
 
149
 
 
150
static unsigned int page_size;
 
151
static unsigned int buffer_size;
 
152
static void *mem_pool;
 
153
 
 
154
/**
 
155
 *      read_area - Read data from a swap location.
 
156
 *      @fd:            File handle of the resume partition
 
157
 *      @buf:           Pointer to the area we're reading into
 
158
 *      @offset:        Swap offset of the place to read from
 
159
 *      @size:          The number of bytes to read
 
160
 */
 
161
 
 
162
static int read_area(int fd, void *buf, loff_t offset, unsigned int size)
 
163
{
 
164
        int res = 0;
 
165
        ssize_t cnt = 0;
 
166
 
 
167
        if (!offset)
 
168
                return 0;
 
169
 
 
170
        if (lseek(fd, offset, SEEK_SET) == offset)
 
171
                cnt = read(fd, buf, size);
 
172
        if (cnt < (ssize_t)size)
 
173
                res = cnt < 0 ? cnt : -EIO;
 
174
 
 
175
        return res;
 
176
}
 
177
 
 
178
/*
 
179
 *      The swap_map_handle structure is used for handling the swap map in
 
180
 *      a file-alike way
 
181
 */
 
182
 
 
183
struct swap_map_handle {
 
184
        char *page_buffer;
 
185
        char *read_buffer;
 
186
        struct swap_area *areas;
 
187
        unsigned short areas_per_page;
 
188
        loff_t *next_swap;
 
189
        unsigned int area_size;
 
190
        unsigned int cur_size;
 
191
        unsigned int k;
 
192
        int fd;
 
193
        struct md5_ctx ctx;
 
194
#ifdef CONFIG_ENCRYPT
 
195
        char *decrypt_buffer;
 
196
        gcry_cipher_hd_t cipher_handle;
 
197
#endif
 
198
};
 
199
 
 
200
#define READ_AHEAD_SIZE (8*1024*1024)
 
201
 
 
202
/**
 
203
 *      The following functions allow us to read data using a swap map
 
204
 *      in a file-alike way
 
205
 */
 
206
 
 
207
static int fill_buffer(struct swap_map_handle *handle)
 
208
{
 
209
        void *dst = handle->read_buffer;
 
210
        int error;
 
211
 
 
212
        int read_ahead_areas = READ_AHEAD_SIZE/buffer_size;
 
213
        int advise_first, advise_last, i;
 
214
 
 
215
        if (!handle->k) {
 
216
                /* we've got a new map page */
 
217
                advise_first = 0;
 
218
                advise_last  = read_ahead_areas;
 
219
        } else {
 
220
                advise_first = handle->k + read_ahead_areas;
 
221
                advise_last  = advise_first;
 
222
        }
 
223
 
 
224
        for (i = advise_first;
 
225
             i <= advise_last && i < handle->areas_per_page;
 
226
             i++) {
 
227
                if (handle->areas[i].offset == 0)
 
228
                        break;
 
229
 
 
230
                error = posix_fadvise(handle->fd, handle->areas[i].offset,
 
231
                                handle->areas[i].size, POSIX_FADV_NOREUSE);
 
232
                if (error) {
 
233
                        perror("posix_fadvise");
 
234
                        break;
 
235
                }
 
236
        }
 
237
 
 
238
        handle->area_size = handle->areas[handle->k].size;
 
239
        if (handle->area_size > buffer_size)
 
240
                return -ENOMEM;
 
241
#ifdef CONFIG_ENCRYPT
 
242
        if (do_decrypt)
 
243
                dst = handle->decrypt_buffer;
 
244
#endif
 
245
        error = read_area(handle->fd, dst,
 
246
                        handle->areas[handle->k].offset,
 
247
                        handle->area_size);
 
248
#ifdef CONFIG_ENCRYPT
 
249
        if (!error && do_decrypt)
 
250
                error = gcry_cipher_decrypt(handle->cipher_handle,
 
251
                                (void *)handle->read_buffer, handle->area_size,
 
252
                                dst, handle->area_size);
 
253
#endif
 
254
        return error;
 
255
}
 
256
 
 
257
static int init_swap_reader(struct swap_map_handle *handle, int fd, loff_t start, void *buf)
 
258
{
 
259
        int error;
 
260
 
 
261
        if (!start || !buf)
 
262
                return -EINVAL;
 
263
        handle->areas = buf;
 
264
        handle->areas_per_page = (page_size - sizeof(loff_t)) /
 
265
                        sizeof(struct swap_area);
 
266
        handle->next_swap = (loff_t *)(handle->areas + handle->areas_per_page);
 
267
        handle->page_buffer = (char *)buf + page_size;
 
268
        handle->read_buffer = handle->page_buffer + page_size;
 
269
#ifdef CONFIG_ENCRYPT
 
270
        handle->decrypt_buffer = handle->read_buffer + buffer_size;
 
271
#endif
 
272
        error = read_area(fd, handle->areas, start, page_size);
 
273
        if (error)
 
274
                return error;
 
275
        handle->fd = fd;
 
276
        handle->k = 0;
 
277
        error = fill_buffer(handle);
 
278
        if (error)
 
279
                return error;
 
280
        handle->cur_size = 0;
 
281
        if (verify_checksum)
 
282
                md5_init_ctx(&handle->ctx);
 
283
        return 0;
 
284
}
 
285
 
 
286
static int restore(struct swap_map_handle *handle, int disp)
 
287
{
 
288
        struct buf_block *block;
 
289
        void *buf = handle->page_buffer;
 
290
 
 
291
        block = (struct buf_block *)(handle->read_buffer + disp);
 
292
#ifdef CONFIG_COMPRESS
 
293
        if (do_decompress) {
 
294
                int error;
 
295
                lzo_uint cnt = page_size;
 
296
 
 
297
                error = lzo1x_decompress_safe((lzo_bytep)block->data,
 
298
                                                block->size,
 
299
                                                buf, &cnt, NULL);
 
300
                if (error)
 
301
                        return -EINVAL;
 
302
                return cnt == page_size ?
 
303
                                block->size + sizeof(short) : -ENODATA;
 
304
        }
 
305
#endif
 
306
        memcpy(buf, block, page_size);
 
307
        return page_size;
 
308
}
 
309
 
 
310
static int swap_read_page(struct swap_map_handle *handle)
 
311
{
 
312
        loff_t offset;
 
313
        size_t size;
 
314
        int error = 0;
 
315
 
 
316
        if (handle->cur_size < handle->area_size) {
 
317
                /* Get the data from the read buffer */
 
318
                size = restore(handle, handle->cur_size);
 
319
                if (size < 0)
 
320
                        return size;
 
321
                handle->cur_size += size;
 
322
                goto MD5;
 
323
        }
 
324
 
 
325
        /* There are no more data in the read buffer.  Read more */
 
326
        if (++handle->k >= handle->areas_per_page) {
 
327
                handle->k = 0;
 
328
                offset = *handle->next_swap;
 
329
                error = offset ?
 
330
                        read_area(handle->fd, handle->areas, offset, page_size)
 
331
                        : -EINVAL;
 
332
        }
 
333
        if (!error)
 
334
                error = fill_buffer(handle);
 
335
        if (error)
 
336
                return error;
 
337
 
 
338
        size = restore(handle, 0);
 
339
        if (size < 0)
 
340
                return size;
 
341
        handle->cur_size = size;
 
342
 
 
343
MD5:
 
344
        if (verify_checksum)
 
345
                md5_process_block(handle->page_buffer, page_size, &handle->ctx);
 
346
 
 
347
        return 0;
 
348
}
 
349
 
 
350
/**
 
351
 *      load_image - load the image using the swap map handle
 
352
 *      @handle and the snapshot handle @snapshot
 
353
 *      (assume there are @nr_pages pages to load)
 
354
 */
 
355
 
 
356
static int load_image(struct swap_map_handle *handle, int dev,
 
357
                      unsigned int nr_pages)
 
358
{
 
359
        unsigned int m, n;
 
360
        int ret;
 
361
        int error = 0;
 
362
        char message[SPLASH_GENERIC_MESSAGE_SIZE];
 
363
 
 
364
        sprintf(message, "Loading image data pages (%u pages)...", nr_pages);
 
365
        splash.set_caption(message);
 
366
        printf("%s     ", message);
 
367
 
 
368
        m = nr_pages / 100;
 
369
        if (!m)
 
370
                m = 1;
 
371
        n = 0;
 
372
        do {
 
373
                error = swap_read_page(handle);
 
374
                if (error)
 
375
                        break;
 
376
                ret = write(dev, handle->page_buffer, page_size);
 
377
                if (ret < (int)page_size) {
 
378
                        error = ret < 0 ? -errno : -ENOSPC;
 
379
                        break;
 
380
                }
 
381
                if (!(n % m)) {
 
382
                        printf("\b\b\b\b%3d%%", n / m);
 
383
                        if (n / m > 15)
 
384
                                splash.progress(n / m);
 
385
                }
 
386
                n++;
 
387
        } while (n < nr_pages);
 
388
        if (!error)
 
389
                printf(" done\n");
 
390
        return error;
 
391
}
 
392
 
 
393
static char *print_checksum(char * buf, unsigned char *checksum)
 
394
{
 
395
        int j;
 
396
 
 
397
        for (j = 0; j < 16; j++)
 
398
                buf += sprintf(buf, "%02hhx ", checksum[j]);
 
399
 
 
400
        return buf;
 
401
}
 
402
 
 
403
#ifdef CONFIG_ENCRYPT
 
404
static int decrypt_key(struct swsusp_info *header, unsigned char *key,
 
405
                        unsigned char *ivec, void *buffer)
 
406
{
 
407
        gcry_ac_handle_t rsa_hd;
 
408
        gcry_ac_data_t rsa_data_set, key_set;
 
409
        gcry_ac_key_t rsa_priv;
 
410
        gcry_mpi_t mpi;
 
411
        unsigned char *buf, *out, *key_buf, *ivec_buf;
 
412
        char *pass_buf;
 
413
        struct md5_ctx ctx;
 
414
        struct RSA_data *rsa;
 
415
        gcry_cipher_hd_t sym_hd;
 
416
        int j, ret = 0;
 
417
 
 
418
        rsa = &header->rsa;
 
419
 
 
420
        ret = gcry_ac_open(&rsa_hd, GCRY_AC_RSA, 0);
 
421
        if (ret)
 
422
                return ret;
 
423
 
 
424
        if (!ret)
 
425
                ret = gcry_cipher_open(&sym_hd, PK_CIPHER,
 
426
                                GCRY_CIPHER_MODE_CFB, GCRY_CIPHER_SECURE);
 
427
 
 
428
        if (ret)
 
429
                goto Free_rsa;
 
430
 
 
431
        pass_buf = buffer;
 
432
        key_buf = (unsigned char *)pass_buf + PASS_SIZE;
 
433
        ivec_buf = key_buf + PK_KEY_SIZE;
 
434
        out = ivec_buf + PK_CIPHER_BLOCK;
 
435
        do {
 
436
                splash.read_password(pass_buf, 0);
 
437
                memset(ivec_buf, 0, PK_CIPHER_BLOCK);
 
438
                strncpy((char *)ivec_buf, pass_buf, PK_CIPHER_BLOCK);
 
439
                md5_init_ctx(&ctx);
 
440
                md5_process_bytes(pass_buf, strlen(pass_buf), &ctx);
 
441
                md5_finish_ctx(&ctx, key_buf);
 
442
                ret = gcry_cipher_setkey(sym_hd, key_buf, PK_KEY_SIZE);
 
443
                if (!ret)
 
444
                        ret = gcry_cipher_setiv(sym_hd, ivec_buf,
 
445
                                                PK_CIPHER_BLOCK);
 
446
 
 
447
                if (!ret)
 
448
                        ret = gcry_cipher_encrypt(sym_hd,
 
449
                                        out, KEY_TEST_SIZE,
 
450
                                        KEY_TEST_DATA, KEY_TEST_SIZE);
 
451
 
 
452
                if (ret)
 
453
                        break;
 
454
 
 
455
                ret = memcmp(out, rsa->key_test, KEY_TEST_SIZE);
 
456
 
 
457
                if (ret)
 
458
                        printf("%s: Wrong passphrase, try again.\n", my_name);
 
459
        } while (ret);
 
460
 
 
461
        gcry_cipher_close(sym_hd);
 
462
        if (!ret)
 
463
                ret = gcry_cipher_open(&sym_hd, PK_CIPHER,
 
464
                                GCRY_CIPHER_MODE_CFB, GCRY_CIPHER_SECURE);
 
465
        if (ret)
 
466
                goto Free_rsa;
 
467
 
 
468
        ret = gcry_cipher_setkey(sym_hd, key_buf, PK_KEY_SIZE);
 
469
        if (!ret)
 
470
                ret = gcry_cipher_setiv(sym_hd, ivec_buf, PK_CIPHER_BLOCK);
 
471
        if (!ret)
 
472
                ret = gcry_ac_data_new(&rsa_data_set);
 
473
        if (ret)
 
474
                goto Close_cypher;
 
475
 
 
476
        buf = rsa->data;
 
477
        for (j = 0; j < RSA_FIELDS; j++) {
 
478
                size_t s = rsa->size[j];
 
479
 
 
480
                /* We need to decrypt some components */
 
481
                if (j >= RSA_FIELDS_PUB) {
 
482
                        /* We use the in-place decryption */
 
483
                        ret = gcry_cipher_decrypt(sym_hd, buf, s, NULL, 0);
 
484
                        if (ret)
 
485
                                break;
 
486
                }
 
487
 
 
488
                gcry_mpi_scan(&mpi, GCRYMPI_FMT_USG, buf, s, NULL);
 
489
                ret = gcry_ac_data_set(rsa_data_set, GCRY_AC_FLAG_COPY,
 
490
                                        rsa->field[j], mpi);
 
491
                gcry_mpi_release(mpi);
 
492
                if (ret)
 
493
                        break;
 
494
 
 
495
                buf += s;
 
496
        }
 
497
        if (!ret)
 
498
                ret = gcry_ac_key_init(&rsa_priv, rsa_hd,
 
499
                                        GCRY_AC_KEY_SECRET, rsa_data_set);
 
500
        if (ret)
 
501
                goto Destroy_data_set;
 
502
 
 
503
        ret = gcry_ac_data_new(&key_set);
 
504
        if (ret)
 
505
                goto Destroy_key;
 
506
 
 
507
        gcry_mpi_scan(&mpi, GCRYMPI_FMT_USG, header->key.data,
 
508
                        header->key.size, NULL);
 
509
        ret = gcry_ac_data_set(key_set, GCRY_AC_FLAG_COPY, "a", mpi);
 
510
        if (ret)
 
511
                goto Destroy_key_set;
 
512
 
 
513
        gcry_mpi_release(mpi);
 
514
        ret = gcry_ac_data_decrypt(rsa_hd, 0, rsa_priv, &mpi, key_set);
 
515
        if (!ret) {
 
516
                unsigned char *res;
 
517
                size_t s;
 
518
 
 
519
                gcry_mpi_aprint(GCRYMPI_FMT_USG, &res, &s, mpi);
 
520
                if (s == KEY_SIZE + CIPHER_BLOCK) {
 
521
                        memcpy(key, res, KEY_SIZE);
 
522
                        memcpy(ivec, res + KEY_SIZE, CIPHER_BLOCK);
 
523
                } else {
 
524
                        ret = -ENODATA;
 
525
                }
 
526
                gcry_free(res);
 
527
        }
 
528
 
 
529
Destroy_key_set:
 
530
        gcry_mpi_release(mpi);
 
531
        gcry_ac_data_destroy(key_set);
 
532
 
 
533
Destroy_key:
 
534
        gcry_ac_key_destroy(rsa_priv);
 
535
 
 
536
Destroy_data_set:
 
537
        gcry_ac_data_destroy(rsa_data_set);
 
538
 
 
539
Close_cypher:
 
540
        gcry_cipher_close(sym_hd);
 
541
 
 
542
Free_rsa:
 
543
        gcry_ac_close(rsa_hd);
 
544
 
 
545
        return ret;
 
546
}
 
547
#endif
 
548
 
 
549
static int open_resume_dev(char *resume_dev_name, 
 
550
                            struct swsusp_header *swsusp_header)
 
551
{
 
552
        unsigned int size = sizeof(struct swsusp_header);
 
553
        unsigned int shift = (resume_offset + 1) * page_size - size;
 
554
        int fd, ret;
 
555
 
 
556
        fd = open(resume_dev_name, O_RDWR);
 
557
        if (fd < 0) {
 
558
                ret = -errno;
 
559
                fprintf(stderr, "%s: Could not open the resume device\n",
 
560
                                my_name);
 
561
                return ret;
 
562
        }
 
563
        if (lseek(fd, shift, SEEK_SET) != shift)
 
564
                return -EIO;
 
565
        ret = read(fd, swsusp_header, size);
 
566
        if (ret == size) {
 
567
                if (memcmp(SWSUSP_SIG, swsusp_header->sig, 10)) {
 
568
                        close(fd);
 
569
                        return -ENOMEDIUM;
 
570
                }
 
571
        } else {
 
572
                ret = ret < 0 ? ret : -EIO;
 
573
                return ret;
 
574
        }
 
575
        
 
576
        return fd;
 
577
}
 
578
 
 
579
static int read_image(int dev, int fd, struct swsusp_header *swsusp_header)
 
580
{
 
581
        static struct swap_map_handle handle;
 
582
        static unsigned char orig_checksum[16], checksum[16];
 
583
        int ret, error = 0;
 
584
        struct swsusp_info *header = mem_pool;
 
585
        char *buffer = (char *)mem_pool + page_size;
 
586
        unsigned int nr_pages = 0;
 
587
        unsigned int size = sizeof(struct swsusp_header);
 
588
        unsigned int shift = (resume_offset + 1) * page_size - size;
 
589
        char c;
 
590
 
 
591
        error = read_area(fd, header, swsusp_header->image, page_size);
 
592
        if (error)
 
593
                goto Reboot_question;
 
594
 
 
595
        if (header->image_flags & PLATFORM_SUSPEND)
 
596
                use_platform_suspend = 1;
 
597
 
 
598
        if (header->image_flags & IMAGE_CHECKSUM) {
 
599
                memcpy(orig_checksum, header->checksum, 16);
 
600
                print_checksum(buffer, orig_checksum);
 
601
                printf("%s: MD5 checksum %s\n", my_name, buffer);
 
602
                verify_checksum = 1;
 
603
        }
 
604
        splash.progress(10);
 
605
        if (header->image_flags & IMAGE_COMPRESSED) {
 
606
                printf("%s: Compressed image\n", my_name);
 
607
#ifdef CONFIG_COMPRESS
 
608
                if (lzo_init() == LZO_E_OK) {
 
609
                        do_decompress = 1;
 
610
                } else {
 
611
                        fprintf(stderr, "%s: Failed to initialize LZO\n",
 
612
                                        my_name);
 
613
                        error = -EFAULT;
 
614
                }
 
615
#else
 
616
                fprintf(stderr, "%s: Compression not supported\n", my_name);
 
617
                error = -EINVAL;
 
618
#endif
 
619
        }
 
620
        if (error)
 
621
                goto Reboot_question;
 
622
 
 
623
        if (header->image_flags & IMAGE_ENCRYPTED) {
 
624
#ifdef CONFIG_ENCRYPT
 
625
                static unsigned char key[KEY_SIZE], ivec[CIPHER_BLOCK];
 
626
 
 
627
                printf("%s: Encrypted image\n", my_name);
 
628
                if (header->image_flags & IMAGE_USE_RSA) {
 
629
                        error = decrypt_key(header, key, ivec, buffer);
 
630
                } else {
 
631
                        int j;
 
632
 
 
633
                        splash.read_password(buffer, 0);
 
634
                        encrypt_init(key, ivec, buffer);
 
635
                        for (j = 0; j < CIPHER_BLOCK; j++)
 
636
                                ivec[j] ^= header->salt[j];
 
637
                }
 
638
                splash.progress(15);
 
639
                if (!error)
 
640
                        error = gcry_cipher_open(&handle.cipher_handle,
 
641
                                IMAGE_CIPHER, GCRY_CIPHER_MODE_CFB,
 
642
                                GCRY_CIPHER_SECURE);
 
643
                if (!error) {
 
644
                        do_decrypt = 1;
 
645
                        error = gcry_cipher_setkey(handle.cipher_handle,
 
646
                                                key, KEY_SIZE);
 
647
                }
 
648
                if (!error)
 
649
                        error = gcry_cipher_setiv(handle.cipher_handle,
 
650
                                                ivec, CIPHER_BLOCK);
 
651
 
 
652
                if (error) {
 
653
                        if (do_decrypt)
 
654
                                gcry_cipher_close(handle.cipher_handle);
 
655
                        do_decrypt = 0;
 
656
                        fprintf(stderr, "%s: libgcrypt error: %s\n",
 
657
                                        my_name,
 
658
                                        gcry_strerror(error));
 
659
                }
 
660
#else
 
661
                fprintf(stderr, "%s: Encryption not supported\n",
 
662
                                my_name);
 
663
                error = -EINVAL;
 
664
#endif
 
665
        }
 
666
 
 
667
        if (error)
 
668
                goto Reboot_question;
 
669
 
 
670
        error = init_swap_reader(&handle, fd, header->map_start, buffer);
 
671
        nr_pages = header->pages - 1;
 
672
        ret = write(dev, header, page_size);
 
673
        if (ret < (int)page_size)
 
674
                error = ret < 0 ? ret : -EIO;
 
675
 
 
676
        if (!error) {
 
677
                struct timeval begin, end;
 
678
                double delta, mb = header->size / (1024.0 * 1024.0);
 
679
 
 
680
                gettimeofday(&begin, NULL);
 
681
                error = load_image(&handle, dev, nr_pages);
 
682
                gettimeofday(&end, NULL);
 
683
 
 
684
                timersub(&end, &begin, &end);
 
685
                delta = end.tv_usec / 1000000.0 + end.tv_sec;
 
686
 
 
687
                printf("wrote %0.1lf MB in %0.1lf seconds (%0.1lf MB/s)\n",
 
688
                        mb, header->writeout_time, mb / header->writeout_time);
 
689
 
 
690
                printf("read %0.1lf MB in %0.1lf seconds (%0.1lf MB/s)\n",
 
691
                        mb, delta, mb / delta);
 
692
 
 
693
                mb *= 2.0;
 
694
                delta += header->writeout_time;
 
695
                printf("total image i/o %0.1lf MB in %0.1lf seconds (%0.1lf MB/s)\n",
 
696
                        mb, delta, mb / delta);
 
697
        }
 
698
 
 
699
Reboot_question:
 
700
        if (error) {
 
701
                c = splash.dialog(
 
702
                        "\nThe system snapshot image could not be read.\n\n"
 
703
#ifdef CONFIG_ENCRYPT
 
704
                        "\tThis might be a result of booting a wrong kernel\n"
 
705
                        "\tor typing in a wrong passphrase.\n\n"
 
706
#else
 
707
                        "\tThis might be a result of booting a wrong kernel.\n\n"
 
708
#endif
 
709
                        "\tYou can continue to boot the system and lose the saved state\n"
 
710
                        "\tor reboot and try again.\n\n"
 
711
                        "\t[Notice that you may not mount any filesystem between\n"
 
712
                        "\tnow and successful resume. That would badly damage\n"
 
713
                        "\taffected filesystems.]\n\n"
 
714
                        "\tDo you want to continue boot (Y/n)? ");
 
715
                ret = (c == 'n' || c == 'N');
 
716
                if (ret) {
 
717
                        close(fd);
 
718
                        reboot();
 
719
                        fprintf(stderr, "%s: Reboot failed, please reboot manually.\n",
 
720
                                        my_name);
 
721
                       while(1)
 
722
                           sleep(1);
 
723
                }
 
724
        }
 
725
 
 
726
        /* I guess this is after the 'continue boot'-question because
 
727
         * there is no sense in not reseting the signature on error */
 
728
        if (!error && verify_checksum) {
 
729
                md5_finish_ctx(&handle.ctx, checksum);
 
730
                if (memcmp(orig_checksum, checksum, 16)) {
 
731
                        fprintf(stderr,"%s: MD5 checksum does not match\n",
 
732
                                        my_name);
 
733
                        print_checksum(buffer, checksum);
 
734
                        fprintf(stderr, "%s: Computed MD5 checksum %s\n",
 
735
                                        my_name, buffer);
 
736
                        error = -EINVAL;
 
737
                }
 
738
        }
 
739
        /* Reset swap signature now */
 
740
        memcpy(swsusp_header->sig, swsusp_header->orig_sig, 10);
 
741
        if (lseek(fd, shift, SEEK_SET) != shift) {
 
742
                error = -EIO;
 
743
        } else {
 
744
                ret = write(fd, swsusp_header, size);
 
745
                if (ret != size) {
 
746
                        error = ret < 0 ? -errno : -EIO;
 
747
                        fprintf(stderr,
 
748
                                "%s: Could not restore the partition header\n",
 
749
                                my_name);
 
750
                }
 
751
        }
 
752
 
 
753
        fsync(fd);
 
754
        close(fd);
 
755
#ifdef CONFIG_ENCRYPT
 
756
        if (do_decrypt)
 
757
                gcry_cipher_close(handle.cipher_handle);
 
758
#endif
 
759
 
 
760
        if (error) {
 
761
                sprintf(buffer, "%s: Error %d loading the image\n"
 
762
                        "\nPress ENTER to continue\n", my_name, error);
 
763
                splash.dialog(buffer);
 
764
        } else {
 
765
                printf("%s: Image successfully loaded\n", my_name);
 
766
        }
 
767
 
 
768
        return error;
 
769
}
 
770
 
 
771
/* Parse the command line and/or configuration file */
 
772
static inline int get_config(int argc, char *argv[])
 
773
{
 
774
        static struct option options[] = {
 
775
                   {
 
776
                       "help\0\t\t\tthis text",
 
777
                       no_argument,             NULL, 'h'
 
778
                   },
 
779
                   {
 
780
                       "version\0\t\t\tversion information",
 
781
                       no_argument,             NULL, 'V'
 
782
                   },
 
783
                   {
 
784
                       "config\0\t\talternative configuration file.",
 
785
                       required_argument,       NULL, 'f'
 
786
                   },
 
787
                   {
 
788
                       "resume_device\0device that contains swap area", 
 
789
                       required_argument,       NULL, 'r'
 
790
                   },
 
791
                   {
 
792
                       "resume_offset\0offset of swap file in resume device.",  
 
793
                       required_argument,       NULL, 'o'
 
794
                   },
 
795
                   {
 
796
                       "parameter\0\toverride config file parameter.",
 
797
                       required_argument,       NULL, 'P'
 
798
                   },
 
799
                   { NULL,              0,                      NULL,  0 }
 
800
        };
 
801
        int i, error;
 
802
        char *conf_name = CONFIG_FILE;
 
803
        const char *optstring = "hVf:o:r:P:";
 
804
        struct stat stat_buf;
 
805
        int fail_missing_config = 0;
 
806
 
 
807
        /* parse only config file argument */
 
808
        while ((i = getopt_long(argc, argv, optstring, options, NULL)) != -1) {
 
809
                switch (i) {
 
810
                case 'h':
 
811
                        usage(my_name, options, optstring);
 
812
                        exit(EXIT_SUCCESS);
 
813
                case 'V':
 
814
                        version(my_name, NULL);
 
815
                        exit(EXIT_SUCCESS);
 
816
                case 'f':
 
817
                        conf_name = optarg;
 
818
                        fail_missing_config = 1;
 
819
                        break;
 
820
                }
 
821
        }
 
822
 
 
823
        if (stat(conf_name, &stat_buf)) {
 
824
                if (fail_missing_config) {
 
825
                        fprintf(stderr, "%s: Could not stat configuration file\n",
 
826
                                my_name);
 
827
                        return -ENOENT;
 
828
                }
 
829
        }
 
830
        else {
 
831
                error = parse(my_name, conf_name, parameters);
 
832
                if (error) {
 
833
                        fprintf(stderr, "%s: Could not parse config file\n", my_name);
 
834
                        return error;
 
835
                }
 
836
        }
 
837
 
 
838
        optind = 0;
 
839
        while ((i = getopt_long(argc, argv, optstring, options, NULL)) != -1) {
 
840
                switch (i) {
 
841
                case 'f':
 
842
                        /* already handled */
 
843
                        break;
 
844
                case 'o':
 
845
                        resume_offset = atoll(optarg);
 
846
                        break;
 
847
                case 'r':
 
848
                        strncpy(resume_dev_name, optarg, MAX_STR_LEN -1);
 
849
                        break;
 
850
                case 'P':
 
851
                        error = parse_line(optarg, parameters);
 
852
                        if (error) {
 
853
                                fprintf(stderr,
 
854
                                        "%s: Could not parse config string '%s'\n",
 
855
                                                my_name, optarg);
 
856
                                return error;
 
857
                        }
 
858
                        break;
 
859
                default:
 
860
                        usage(my_name, options, optstring);
 
861
                        return -EINVAL;
 
862
                }
 
863
        }
 
864
 
 
865
        if (optind < argc)
 
866
                strncpy(resume_dev_name, argv[optind], MAX_STR_LEN - 1);
 
867
 
 
868
        return 0;
 
869
}
 
870
 
 
871
int main(int argc, char *argv[])
 
872
{
 
873
        unsigned int mem_size;
 
874
        struct stat stat_buf;
 
875
        int dev, resume_dev;
 
876
        int n, error, orig_loglevel;
 
877
        static struct swsusp_header swsusp_header;
 
878
 
 
879
        my_name = basename(argv[0]);
 
880
 
 
881
        error = get_config(argc, argv);
 
882
        if (error)
 
883
                return -error;
 
884
 
 
885
        if (splash_param != 'y' && splash_param != 'Y')
 
886
                splash_param = 0;
 
887
        else
 
888
                splash_param = SPL_RESUME;
 
889
 
 
890
        page_size = getpagesize();
 
891
        buffer_size = BUFFER_PAGES * page_size;
 
892
#ifdef CONFIG_ENCRYPT
 
893
        printf("%s: libgcrypt version: %s\n", my_name,
 
894
                gcry_check_version(NULL));
 
895
        gcry_control(GCRYCTL_INIT_SECMEM, page_size, 0);
 
896
        mem_size = 3 * page_size + 2 * buffer_size;
 
897
#else
 
898
        mem_size = 3 * page_size + buffer_size;
 
899
#endif
 
900
        mem_pool = malloc(mem_size);
 
901
        if (!mem_pool) {
 
902
                error = errno;
 
903
                fprintf(stderr, "%s: Could not allocate memory\n", my_name);
 
904
                return error;
 
905
        }
 
906
 
 
907
        open_printk();
 
908
        orig_loglevel = get_kernel_console_loglevel();
 
909
        set_kernel_console_loglevel(suspend_loglevel);
 
910
 
 
911
        while (stat(resume_dev_name, &stat_buf)) {
 
912
                fprintf(stderr, 
 
913
                        "%s: Could not stat the resume device file '%s'\n"
 
914
                        "\tPlease type in the full path name to try again\n"
 
915
                        "\tor press ENTER to boot the system: ", my_name,
 
916
                        resume_dev_name);
 
917
                fgets(resume_dev_name, MAX_STR_LEN - 1, stdin);
 
918
                n = strlen(resume_dev_name) - 1;
 
919
                if (n <= 0) {
 
920
                        error = EINVAL;
 
921
                        goto Free;
 
922
                }
 
923
 
 
924
                if (resume_dev_name[n] == '\n')
 
925
                        resume_dev_name[n] = '\0';
 
926
        }
 
927
 
 
928
        setvbuf(stdout, NULL, _IONBF, 0);
 
929
        setvbuf(stderr, NULL, _IONBF, 0);
 
930
 
 
931
        if (mlockall(MCL_CURRENT | MCL_FUTURE)) {
 
932
                error = errno;
 
933
                fprintf(stderr, "%s: Could not lock myself\n", my_name);
 
934
                goto Free;
 
935
        }
 
936
 
 
937
 
 
938
        dev = open(snapshot_dev_name, O_WRONLY);
 
939
        if (dev < 0) {
 
940
                error = ENOENT;
 
941
                goto Free;
 
942
        }
 
943
 
 
944
        resume_dev = open_resume_dev(resume_dev_name, &swsusp_header);
 
945
        if (resume_dev == -ENOMEDIUM) {
 
946
                error = 0;
 
947
                goto Close;
 
948
        } else if (resume_dev < 0) {
 
949
                error = -resume_dev;
 
950
                goto Close;
 
951
        }
 
952
 
 
953
        splash_prepare(&splash, splash_param);
 
954
        splash.progress(5);
 
955
 
 
956
        error = read_image(dev, resume_dev, &swsusp_header);
 
957
        if (error) {
 
958
                fprintf(stderr, "%s: Could not read the image\n", my_name);
 
959
                error = -error;
 
960
                goto Close_splash;
 
961
        }
 
962
 
 
963
        if (freeze(dev)) {
 
964
                error = errno;
 
965
                fprintf(stderr, "%s: Could not freeze processes\n", my_name);
 
966
                goto Close_splash;
 
967
        }
 
968
        if (use_platform_suspend) {
 
969
                int ret = platform_prepare(dev);
 
970
                if (ret < 0) {
 
971
                        fprintf(stderr, "%s: pm_ops->prepare returned "
 
972
                                        "error %d\n", my_name, ret);
 
973
                        use_platform_suspend = 0;
 
974
                }
 
975
        }
 
976
        atomic_restore(dev);
 
977
        /* We only get here if the atomic restore fails.  Clean up. */
 
978
        if (use_platform_suspend)
 
979
                platform_finish(dev);
 
980
 
 
981
        unfreeze(dev);
 
982
 
 
983
Close_splash:
 
984
        splash.finish();
 
985
Close:
 
986
        close(dev);
 
987
Free:
 
988
        if (error)
 
989
            set_kernel_console_loglevel(max_loglevel);
 
990
        else if (orig_loglevel >= 0)
 
991
            set_kernel_console_loglevel(orig_loglevel);
 
992
 
 
993
        close_printk();
 
994
 
 
995
        free(mem_pool);
 
996
 
 
997
        return error;
 
998
}