]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/random-seed/random-seed.c
treewide: use log_*_errno whenever %m is in the format string
[thirdparty/systemd.git] / src / random-seed / random-seed.c
CommitLineData
6e200d55
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
6e200d55
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
6e200d55 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
6e200d55
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <unistd.h>
23#include <fcntl.h>
24#include <errno.h>
25#include <string.h>
26#include <sys/stat.h>
27
28#include "log.h"
29#include "util.h"
49e942b2 30#include "mkdir.h"
6e200d55 31
26192dfc
LP
32#define POOL_SIZE_MIN 512
33
6e200d55 34int main(int argc, char *argv[]) {
ce179470
LP
35 _cleanup_close_ int seed_fd = -1, random_fd = -1;
36 _cleanup_free_ void* buf = NULL;
26192dfc 37 size_t buf_size = 0;
ce179470
LP
38 ssize_t k;
39 int r;
26192dfc 40 FILE *f;
6e200d55
LP
41
42 if (argc != 2) {
43 log_error("This program requires one argument.");
22f4096c 44 return EXIT_FAILURE;
6e200d55
LP
45 }
46
4cfa2c99 47 log_set_target(LOG_TARGET_AUTO);
6e200d55 48 log_parse_environment();
2396fb04 49 log_open();
6e200d55 50
4c12626c
LP
51 umask(0022);
52
26192dfc 53 /* Read pool size, if possible */
ce179470
LP
54 f = fopen("/proc/sys/kernel/random/poolsize", "re");
55 if (f) {
7c2ec009
TG
56 if (fscanf(f, "%zu", &buf_size) > 0) {
57 /* poolsize is in bits on 2.6, but we want bytes */
58 buf_size /= 8;
59 }
60
26192dfc
LP
61 fclose(f);
62 }
63
64 if (buf_size <= POOL_SIZE_MIN)
65 buf_size = POOL_SIZE_MIN;
66
ce179470
LP
67 buf = malloc(buf_size);
68 if (!buf) {
69 r = log_oom();
26192dfc
LP
70 goto finish;
71 }
72
ce179470
LP
73 r = mkdir_parents_label(RANDOM_SEED, 0755);
74 if (r < 0) {
da927ba9 75 log_error_errno(r, "Failed to create directory " RANDOM_SEED_DIR ": %m");
b56e5747
GSB
76 goto finish;
77 }
78
6e200d55
LP
79 /* When we load the seed we read it and write it to the device
80 * and then immediately update the saved seed with new data,
81 * to make sure the next boot gets seeded differently. */
82
83 if (streq(argv[1], "load")) {
84
ce179470
LP
85 seed_fd = open(RANDOM_SEED, O_RDWR|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600);
86 if (seed_fd < 0) {
87 seed_fd = open(RANDOM_SEED, O_RDONLY|O_CLOEXEC|O_NOCTTY);
88 if (seed_fd < 0) {
56f64d95 89 log_error_errno(errno, "Failed to open " RANDOM_SEED ": %m");
ce179470 90 r = -errno;
6e200d55
LP
91 goto finish;
92 }
93 }
94
ce179470
LP
95 random_fd = open("/dev/urandom", O_RDWR|O_CLOEXEC|O_NOCTTY, 0600);
96 if (random_fd < 0) {
97 random_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY, 0600);
98 if (random_fd < 0) {
56f64d95 99 log_error_errno(errno, "Failed to open /dev/urandom: %m");
ce179470 100 r = -errno;
6e200d55
LP
101 goto finish;
102 }
103 }
104
ce179470
LP
105 k = loop_read(seed_fd, buf, buf_size, false);
106 if (k <= 0) {
ba1a5515
LP
107
108 if (r != 0)
56f64d95 109 log_error_errno(errno, "Failed to read seed from " RANDOM_SEED ": %m");
ce179470
LP
110
111 r = k == 0 ? -EIO : (int) k;
112
ba1a5515 113 } else {
6e200d55
LP
114 lseek(seed_fd, 0, SEEK_SET);
115
ce179470
LP
116 k = loop_write(random_fd, buf, (size_t) k, false);
117 if (k <= 0) {
118 log_error("Failed to write seed to /dev/urandom: %s", r < 0 ? strerror(-r) : "short write");
119
120 r = k == 0 ? -EIO : (int) k;
121 }
6e200d55
LP
122 }
123
124 } else if (streq(argv[1], "save")) {
125
ce179470
LP
126 seed_fd = open(RANDOM_SEED, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600);
127 if (seed_fd < 0) {
56f64d95 128 log_error_errno(errno, "Failed to open " RANDOM_SEED ": %m");
ce179470 129 r = -errno;
6e200d55
LP
130 goto finish;
131 }
132
ce179470
LP
133 random_fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
134 if (random_fd < 0) {
56f64d95 135 log_error_errno(errno, "Failed to open /dev/urandom: %m");
ce179470 136 r = -errno;
6e200d55
LP
137 goto finish;
138 }
ce179470 139
6e200d55
LP
140 } else {
141 log_error("Unknown verb %s.", argv[1]);
ce179470 142 r = -EINVAL;
6e200d55
LP
143 goto finish;
144 }
145
146 /* This is just a safety measure. Given that we are root and
147 * most likely created the file ourselves the mode and owner
148 * should be correct anyway. */
149 fchmod(seed_fd, 0600);
150 fchown(seed_fd, 0, 0);
151
ce179470
LP
152 k = loop_read(random_fd, buf, buf_size, false);
153 if (k <= 0) {
154 log_error("Failed to read new seed from /dev/urandom: %s", r < 0 ? strerror(-r) : "EOF");
155 r = k == 0 ? -EIO : (int) k;
156 } else {
157 r = loop_write(seed_fd, buf, (size_t) k, false);
158 if (r <= 0) {
159 log_error("Failed to write new random seed file: %s", r < 0 ? strerror(-r) : "short write");
2dba165c 160 r = r == 0 ? -EIO : r;
ce179470 161 }
6e200d55
LP
162 }
163
6e200d55 164finish:
ce179470 165 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
6e200d55 166}