]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/machine-id-setup.c
build: remove repeated KMOD section
[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
73f860db 30#include "systemd/sd-id128.h"
81527be1 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
34f750b7 41static int shorten_uuid(char destination[34], const char source[36]) {
09b967ea
LP
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
0b36bbc4
LP
96 /* If that didn't work, see if we are running in a container,
97 * and a machine ID was passed in via $container_uuid the way
98 * libvirt/LXC does it */
09b967ea
LP
99 r = detect_container(NULL);
100 if (r > 0) {
aa96c6cb 101 _cleanup_free_ char *e = NULL;
09b967ea 102
ab94af92
LP
103 r = getenv_for_pid(1, "container_uuid", &e);
104 if (r > 0) {
105 if (strlen(e) >= 36) {
106 r = shorten_uuid(id, e);
107 if (r >= 0) {
8e47b1d2 108 log_info("Initializing machine ID from container UUID.");
ab94af92 109 return 0;
09b967ea 110 }
ab94af92 111 }
d4eb120a 112 }
0b36bbc4
LP
113
114 } else {
115 /* If we are not running in a container, see if we are
116 * running in qemu/kvm and a machine ID was passed in
117 * via -uuid on the qemu/kvm command line */
118
119 r = detect_vm(&vm_id);
120 if (r > 0 && streq(vm_id, "kvm")) {
121 char uuid[37];
122
123 fd = open("/sys/class/dmi/id/product_uuid", O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
124 if (fd >= 0) {
125 k = loop_read(fd, uuid, 36, false);
126 safe_close(fd);
127
128 if (k >= 36) {
129 r = shorten_uuid(id, uuid);
130 if (r >= 0) {
131 log_info("Initializing machine ID from KVM UUID.");
132 return 0;
133 }
134 }
135 }
136 }
d4eb120a
LP
137 }
138
d7ccca2e 139 /* If that didn't work, generate a random machine id */
87d2c1ff
LP
140 r = sd_id128_randomize(&buf);
141 if (r < 0) {
142 log_error("Failed to open /dev/urandom: %s", strerror(-r));
143 return r;
d7ccca2e
LP
144 }
145
87d2c1ff 146 for (p = buf.bytes, q = id; p < buf.bytes + sizeof(buf); p++, q += 2) {
d7ccca2e
LP
147 q[0] = hexchar(*p >> 4);
148 q[1] = hexchar(*p & 15);
149 }
150
151 id[32] = '\n';
152 id[33] = 0;
153
154 log_info("Initializing machine ID from random generator.");
155
156 return 0;
157}
158
92f2f92e 159int machine_id_setup(const char *root) {
489388fb 160 const char *etc_machine_id, *run_machine_id;
4b73a0c0 161 _cleanup_close_ int fd = -1;
df28bc08 162 bool writable = false;
d7ccca2e
LP
163 struct stat st;
164 char id[34]; /* 32 + \n + \0 */
489388fb 165 int r;
92f2f92e 166
489388fb
LP
167 if (isempty(root)) {
168 etc_machine_id = "/etc/machine-id";
169 run_machine_id = "/run/machine-id";
170 } else {
171 etc_machine_id = strappenda(root, "/etc/machine-id");
172 path_kill_slashes((char*) etc_machine_id);
92f2f92e 173
489388fb
LP
174 run_machine_id = strappenda(root, "/run/machine-id");
175 path_kill_slashes((char*) run_machine_id);
176 }
d7ccca2e 177
5c0d398d
LP
178 RUN_WITH_UMASK(0000) {
179 /* We create this 0444, to indicate that this isn't really
180 * something you should ever modify. Of course, since the file
181 * will be owned by root it doesn't matter much, but maybe
182 * people look. */
183
3577de7a 184 mkdir_parents(etc_machine_id, 0755);
92f2f92e 185 fd = open(etc_machine_id, O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY, 0444);
5c0d398d
LP
186 if (fd >= 0)
187 writable = true;
188 else {
92f2f92e 189 fd = open(etc_machine_id, O_RDONLY|O_CLOEXEC|O_NOCTTY);
5c0d398d 190 if (fd < 0) {
92f2f92e 191 log_error("Cannot open %s: %m", etc_machine_id);
5c0d398d
LP
192 return -errno;
193 }
76526bad 194
5c0d398d 195 writable = false;
d7ccca2e 196 }
d7ccca2e
LP
197 }
198
d7ccca2e
LP
199 if (fstat(fd, &st) < 0) {
200 log_error("fstat() failed: %m");
4b73a0c0 201 return -errno;
d7ccca2e
LP
202 }
203
4b73a0c0 204 if (S_ISREG(st.st_mode))
aa96c6cb
LP
205 if (loop_read(fd, id, 33, false) == 33 && id[32] == '\n') {
206 id[32] = 0;
207
208 if (id128_is_valid(id))
209 return 0;
210 }
d7ccca2e
LP
211
212 /* Hmm, so, the id currently stored is not useful, then let's
213 * generate one */
214
92f2f92e 215 r = generate(id, root);
8d41a963 216 if (r < 0)
4b73a0c0 217 return r;
d7ccca2e
LP
218
219 if (S_ISREG(st.st_mode) && writable) {
220 lseek(fd, 0, SEEK_SET);
221
4b73a0c0
LP
222 if (loop_write(fd, id, 33, false) == 33)
223 return 0;
d7ccca2e
LP
224 }
225
03e334a1 226 fd = safe_close(fd);
d7ccca2e
LP
227
228 /* Hmm, we couldn't write it? So let's write it to
6996295f 229 * /run/machine-id as a replacement */
d7ccca2e 230
5c0d398d 231 RUN_WITH_UMASK(0022) {
92f2f92e 232 r = write_string_file(run_machine_id, id);
5c0d398d 233 }
8d41a963 234 if (r < 0) {
92f2f92e
GKH
235 log_error("Cannot write %s: %s", run_machine_id, strerror(-r));
236 unlink(run_machine_id);
4b73a0c0 237 return r;
d7ccca2e
LP
238 }
239
240 /* And now, let's mount it over */
92f2f92e 241 r = mount(run_machine_id, etc_machine_id, NULL, MS_BIND, NULL);
6996295f 242 if (r < 0) {
92f2f92e
GKH
243 log_error("Failed to mount %s: %m", etc_machine_id);
244 unlink_noerrno(run_machine_id);
4b73a0c0 245 return -errno;
aed5a525
LP
246 }
247
92f2f92e 248 log_info("Installed transient %s file.", etc_machine_id);
d7ccca2e 249
4b73a0c0 250 /* Mark the mount read-only */
92f2f92e
GKH
251 if (mount(NULL, etc_machine_id, NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, NULL) < 0)
252 log_warning("Failed to make transient %s read-only: %m", etc_machine_id);
d7ccca2e 253
4b73a0c0 254 return 0;
d7ccca2e 255}