]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/machine-id-setup.c
util: replace close_nointr_nofail() by a more useful safe_close()
[thirdparty/systemd.git] / src / core / machine-id-setup.c
CommitLineData
d7ccca2e
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
d7ccca2e
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.
d7ccca2e 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
d7ccca2e
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <unistd.h>
23#include <stdio.h>
24#include <errno.h>
25#include <string.h>
26#include <stdlib.h>
27#include <fcntl.h>
28#include <sys/mount.h>
29
81527be1
LP
30#include <systemd/sd-id128.h>
31
b6e66135 32#include "machine-id-setup.h"
d7ccca2e
LP
33#include "macro.h"
34#include "util.h"
49e942b2 35#include "mkdir.h"
d7ccca2e 36#include "log.h"
d4eb120a 37#include "virt.h"
a5c32cff 38#include "fileio.h"
fe970a8a 39#include "path-util.h"
8d41a963 40
09b967ea
LP
41static int shorten_uuid(char destination[36], const char *source) {
42 unsigned i, j;
43
44 for (i = 0, j = 0; i < 36 && j < 32; i++) {
45 int t;
46
47 t = unhexchar(source[i]);
48 if (t < 0)
49 continue;
50
51 destination[j++] = hexchar(t);
52 }
53
54 if (i == 36 && j == 32) {
55 destination[32] = '\n';
56 destination[33] = 0;
57 return 0;
58 }
59
60 return -EINVAL;
61}
62
92f2f92e 63static int generate(char id[34], const char *root) {
87d2c1ff
LP
64 int fd, r;
65 unsigned char *p;
66 sd_id128_t buf;
8d41a963 67 char *q;
d7ccca2e 68 ssize_t k;
d4eb120a 69 const char *vm_id;
92f2f92e 70 _cleanup_free_ char *dbus_machine_id = NULL;
d7ccca2e
LP
71
72 assert(id);
73
92f2f92e
GKH
74 if (asprintf(&dbus_machine_id, "%s/var/lib/dbus/machine-id", root) < 0)
75 return log_oom();
76
d7ccca2e 77 /* First, try reading the D-Bus machine id, unless it is a symlink */
92f2f92e 78 fd = open(dbus_machine_id, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
8d41a963 79 if (fd >= 0) {
aa96c6cb 80 k = loop_read(fd, id, 33, false);
03e334a1 81 safe_close(fd);
d7ccca2e 82
aa96c6cb 83 if (k == 33 && id[32] == '\n') {
d7ccca2e 84
aa96c6cb
LP
85 id[32] = 0;
86 if (id128_is_valid(id)) {
87 id[32] = '\n';
88 id[33] = 0;
89
90 log_info("Initializing machine ID from D-Bus machine ID.");
91 return 0;
92 }
d7ccca2e
LP
93 }
94 }
95
d4eb120a
LP
96 /* If that didn't work, see if we are running in qemu/kvm and a
97 * machine ID was passed in via -uuid on the qemu/kvm command
98 * line */
99
100 r = detect_vm(&vm_id);
101 if (r > 0 && streq(vm_id, "kvm")) {
102 char uuid[37];
103
104 fd = open("/sys/class/dmi/id/product_uuid", O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
105 if (fd >= 0) {
106 k = loop_read(fd, uuid, 36, false);
03e334a1 107 safe_close(fd);
d4eb120a
LP
108
109 if (k >= 36) {
09b967ea
LP
110 r = shorten_uuid(id, uuid);
111 if (r >= 0) {
8e47b1d2 112 log_info("Initializing machine ID from KVM UUID.");
09b967ea
LP
113 return 0;
114 }
115 }
116 }
117 }
d4eb120a 118
09b967ea
LP
119 /* If that didn't work either, see if we are running in a
120 * container, and a machine ID was passed in via
121 * $container_uuid the way libvirt/LXC does it */
09b967ea
LP
122 r = detect_container(NULL);
123 if (r > 0) {
aa96c6cb 124 _cleanup_free_ char *e = NULL;
09b967ea 125
ab94af92
LP
126 r = getenv_for_pid(1, "container_uuid", &e);
127 if (r > 0) {
128 if (strlen(e) >= 36) {
129 r = shorten_uuid(id, e);
130 if (r >= 0) {
8e47b1d2 131 log_info("Initializing machine ID from container UUID.");
ab94af92 132 return 0;
09b967ea 133 }
ab94af92 134 }
d4eb120a
LP
135 }
136 }
137
d7ccca2e 138 /* If that didn't work, generate a random machine id */
87d2c1ff
LP
139 r = sd_id128_randomize(&buf);
140 if (r < 0) {
141 log_error("Failed to open /dev/urandom: %s", strerror(-r));
142 return r;
d7ccca2e
LP
143 }
144
87d2c1ff 145 for (p = buf.bytes, q = id; p < buf.bytes + sizeof(buf); p++, q += 2) {
d7ccca2e
LP
146 q[0] = hexchar(*p >> 4);
147 q[1] = hexchar(*p & 15);
148 }
149
150 id[32] = '\n';
151 id[33] = 0;
152
153 log_info("Initializing machine ID from random generator.");
154
155 return 0;
156}
157
92f2f92e 158int machine_id_setup(const char *root) {
4b73a0c0
LP
159 _cleanup_close_ int fd = -1;
160 int r;
df28bc08 161 bool writable = false;
d7ccca2e
LP
162 struct stat st;
163 char id[34]; /* 32 + \n + \0 */
fe970a8a 164 char *etc_machine_id, *run_machine_id;
92f2f92e 165
fe970a8a
ZJS
166 etc_machine_id = strappenda(root, "/etc/machine-id");
167 path_kill_slashes(etc_machine_id);
92f2f92e 168
fe970a8a
ZJS
169 run_machine_id = strappenda(root, "/run/machine-id");
170 path_kill_slashes(run_machine_id);
d7ccca2e 171
5c0d398d
LP
172 RUN_WITH_UMASK(0000) {
173 /* We create this 0444, to indicate that this isn't really
174 * something you should ever modify. Of course, since the file
175 * will be owned by root it doesn't matter much, but maybe
176 * people look. */
177
92f2f92e 178 fd = open(etc_machine_id, O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY, 0444);
5c0d398d
LP
179 if (fd >= 0)
180 writable = true;
181 else {
92f2f92e 182 fd = open(etc_machine_id, O_RDONLY|O_CLOEXEC|O_NOCTTY);
5c0d398d 183 if (fd < 0) {
92f2f92e 184 log_error("Cannot open %s: %m", etc_machine_id);
5c0d398d
LP
185 return -errno;
186 }
76526bad 187
5c0d398d 188 writable = false;
d7ccca2e 189 }
d7ccca2e
LP
190 }
191
d7ccca2e
LP
192 if (fstat(fd, &st) < 0) {
193 log_error("fstat() failed: %m");
4b73a0c0 194 return -errno;
d7ccca2e
LP
195 }
196
4b73a0c0 197 if (S_ISREG(st.st_mode))
aa96c6cb
LP
198 if (loop_read(fd, id, 33, false) == 33 && id[32] == '\n') {
199 id[32] = 0;
200
201 if (id128_is_valid(id))
202 return 0;
203 }
d7ccca2e
LP
204
205 /* Hmm, so, the id currently stored is not useful, then let's
206 * generate one */
207
92f2f92e 208 r = generate(id, root);
8d41a963 209 if (r < 0)
4b73a0c0 210 return r;
d7ccca2e
LP
211
212 if (S_ISREG(st.st_mode) && writable) {
213 lseek(fd, 0, SEEK_SET);
214
4b73a0c0
LP
215 if (loop_write(fd, id, 33, false) == 33)
216 return 0;
d7ccca2e
LP
217 }
218
03e334a1 219 fd = safe_close(fd);
d7ccca2e
LP
220
221 /* Hmm, we couldn't write it? So let's write it to
6996295f 222 * /run/machine-id as a replacement */
d7ccca2e 223
5c0d398d 224 RUN_WITH_UMASK(0022) {
92f2f92e 225 r = write_string_file(run_machine_id, id);
5c0d398d 226 }
8d41a963 227 if (r < 0) {
92f2f92e
GKH
228 log_error("Cannot write %s: %s", run_machine_id, strerror(-r));
229 unlink(run_machine_id);
4b73a0c0 230 return r;
d7ccca2e
LP
231 }
232
233 /* And now, let's mount it over */
92f2f92e 234 r = mount(run_machine_id, etc_machine_id, NULL, MS_BIND, NULL);
6996295f 235 if (r < 0) {
92f2f92e
GKH
236 log_error("Failed to mount %s: %m", etc_machine_id);
237 unlink_noerrno(run_machine_id);
4b73a0c0 238 return -errno;
aed5a525
LP
239 }
240
92f2f92e 241 log_info("Installed transient %s file.", etc_machine_id);
d7ccca2e 242
4b73a0c0 243 /* Mark the mount read-only */
92f2f92e
GKH
244 if (mount(NULL, etc_machine_id, NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, NULL) < 0)
245 log_warning("Failed to make transient %s read-only: %m", etc_machine_id);
d7ccca2e 246
4b73a0c0 247 return 0;
d7ccca2e 248}