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