summaryrefslogtreecommitdiff
path: root/src/random-seed.c
blob: 9b04b9b07f4b0479b37bc47255e4ff437a9946ba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// SPDX-License-Identifier: BSD-3-Clause

#include "config.h"

#include "random-seed.h"
#include "util.h"

#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>

/* 3 hours */
#define DAEMONIZE_SLEEP_TIME (3*60*60)

static sig_atomic_t sigint = 0;
static sig_atomic_t sigterm = 0;

static void sighandler(int signum) {
    switch (signum) {
        case SIGHUP: /* do nothing; we just needed to interrupt sleep */ break;
        case SIGINT: sigint = 1; break;
        case SIGTERM: sigterm = 1; break;
        default: abort();
    }
}

void run(const char *mode, const char *seed_path) {
    int exit_status = 0;

    if (streq(mode, "load")) {
        if (!load(seed_path)) {
            if (noperms)
                exit_status = 15;
            else
                exit_status = 1;
        }
        if (streq(seed_path, "-")) {
            fputs("warning: cannot refresh stdin seed\n", stderr);
        } else {
            unsigned char random_buf[RAND_POOL_SIZE];
            unsigned char *random_ptr = random_buf;
            switch (random_get(random_buf, RAND_POOL_SIZE, GRND_NONBLOCK)) {
                case RAND_POOL_SIZE:
                    break;
                case -1:
                    if (errno != EAGAIN) {
                        perror("getrandom");
                        exit(1);
                    }
                    FALLS_THROUGH;
                default:
                    if (daemon(0, 1) == -1) {
                        perror("error daemonizing, continuing without");
                    }
                    close(0);
                    close(1);
                    random_ptr = NULL;
            }
            if (!save(seed_path, random_ptr))
                exit_status = 1;
        }
        exit(exit_status);
    } else if (streq(mode, "save")) {
        exit(!save(seed_path, NULL));
    } else if (streq(mode, "daemonize")) {
        if (streq(seed_path, "-")) {
            fputs("error: seed_path cannot be - for daemonize\n", stderr);
            exit(2);
        }
        if (!load(seed_path))
            fputs("warning: failed to load initial entropy\n", stderr);

        struct sigaction sa;
        sa.sa_handler = sighandler;
        sigemptyset(&sa.sa_mask);
        sa.sa_flags = 0;
        sigaction(SIGHUP, &sa, NULL);
        sigaction(SIGINT, &sa, NULL);
        sigaction(SIGTERM, &sa, NULL);

        if (daemon(seed_path[0] != '/', 1) == -1) {
            perror("error daemonizing");
            exit(1);
        }
        close(0);
        close(1);
        // don't close stderr because we log there

        while (true) {
            if (sigint)
                exit(exit_status);
            if (!save(seed_path, NULL)) {
                exit_status = 1;
                fputs("an error occurred while saving, trying again later\n", stderr);
            }
            if (sigterm)
                exit(exit_status);
            sleep(DAEMONIZE_SLEEP_TIME);
        }
    } else if (streq(mode, "daemonise")) {
        fputs("invalid mode (did you mean `daemonize'?)\n", stderr);
        exit(2);
    } else {
        fputs("invalid mode, expected load, save, or daemonize\n", stderr);
        exit(2);
    }
}