]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine-id-setup.c
udev: move man pages to udev section
[thirdparty/systemd.git] / src / 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
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
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
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
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
d7ccca2e
LP
32#include "machine-id-setup.h"
33#include "macro.h"
34#include "util.h"
35#include "log.h"
d4eb120a 36#include "virt.h"
8d41a963 37
09b967ea
LP
38static int shorten_uuid(char destination[36], const char *source) {
39 unsigned i, j;
40
41 for (i = 0, j = 0; i < 36 && j < 32; i++) {
42 int t;
43
44 t = unhexchar(source[i]);
45 if (t < 0)
46 continue;
47
48 destination[j++] = hexchar(t);
49 }
50
51 if (i == 36 && j == 32) {
52 destination[32] = '\n';
53 destination[33] = 0;
54 return 0;
55 }
56
57 return -EINVAL;
58}
59
d7ccca2e 60static int generate(char id[34]) {
87d2c1ff
LP
61 int fd, r;
62 unsigned char *p;
63 sd_id128_t buf;
8d41a963 64 char *q;
d7ccca2e 65 ssize_t k;
d4eb120a 66 const char *vm_id;
d7ccca2e
LP
67
68 assert(id);
69
70 /* First, try reading the D-Bus machine id, unless it is a symlink */
8d41a963
LP
71 fd = open("/var/lib/dbus/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
72 if (fd >= 0) {
d7ccca2e 73
d4eb120a 74 k = loop_read(fd, id, 32, false);
d7ccca2e
LP
75 close_nointr_nofail(fd);
76
77 if (k >= 32) {
78 id[32] = '\n';
79 id[33] = 0;
80
81 log_info("Initializing machine ID from D-Bus machine ID.");
82 return 0;
83 }
84 }
85
d4eb120a
LP
86 /* If that didn't work, see if we are running in qemu/kvm and a
87 * machine ID was passed in via -uuid on the qemu/kvm command
88 * line */
89
90 r = detect_vm(&vm_id);
91 if (r > 0 && streq(vm_id, "kvm")) {
92 char uuid[37];
93
94 fd = open("/sys/class/dmi/id/product_uuid", O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
95 if (fd >= 0) {
96 k = loop_read(fd, uuid, 36, false);
97 close_nointr_nofail(fd);
98
99 if (k >= 36) {
09b967ea
LP
100 r = shorten_uuid(id, uuid);
101 if (r >= 0) {
102 log_info("Initializing machine ID from KVM UUID");
103 return 0;
104 }
105 }
106 }
107 }
d4eb120a 108
09b967ea
LP
109 /* If that didn't work either, see if we are running in a
110 * container, and a machine ID was passed in via
111 * $container_uuid the way libvirt/LXC does it */
d4eb120a 112
09b967ea
LP
113 r = detect_container(NULL);
114 if (r > 0) {
115 FILE *f;
d4eb120a 116
09b967ea
LP
117 f = fopen("/proc/1/environ", "re");
118 if (f) {
119 bool done = false;
d4eb120a 120
09b967ea
LP
121 do {
122 char line[LINE_MAX];
123 unsigned i;
d4eb120a 124
09b967ea
LP
125 for (i = 0; i < sizeof(line)-1; i++) {
126 int c;
127
128 c = getc(f);
129 if (_unlikely_(c == EOF)) {
130 done = true;
131 break;
132 } else if (c == 0)
133 break;
134
135 line[i] = c;
d4eb120a 136 }
09b967ea
LP
137 line[i] = 0;
138
139 if (startswith(line, "container_uuid=") &&
140 strlen(line + 15) >= 36) {
141 r = shorten_uuid(id, line + 15);
142 if (r >= 0) {
143 log_info("Initializing machine ID from container UUID");
144 return 0;
145 }
146 }
147
148 } while (!done);
149
150 fclose(f);
d4eb120a
LP
151 }
152 }
153
d7ccca2e 154 /* If that didn't work, generate a random machine id */
87d2c1ff
LP
155 r = sd_id128_randomize(&buf);
156 if (r < 0) {
157 log_error("Failed to open /dev/urandom: %s", strerror(-r));
158 return r;
d7ccca2e
LP
159 }
160
87d2c1ff 161 for (p = buf.bytes, q = id; p < buf.bytes + sizeof(buf); p++, q += 2) {
d7ccca2e
LP
162 q[0] = hexchar(*p >> 4);
163 q[1] = hexchar(*p & 15);
164 }
165
166 id[32] = '\n';
167 id[33] = 0;
168
169 log_info("Initializing machine ID from random generator.");
170
171 return 0;
172}
173
174int machine_id_setup(void) {
175 int fd, r;
176 bool writable;
177 struct stat st;
178 char id[34]; /* 32 + \n + \0 */
179 mode_t m;
180
181 m = umask(0000);
182
76526bad
LP
183 /* We create this 0444, to indicate that this isn't really
184 * something you should ever modify. Of course, since the file
185 * will be owned by root it doesn't matter much, but maybe
186 * people look. */
187
8d41a963
LP
188 fd = open("/etc/machine-id", O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY, 0444);
189 if (fd >= 0)
d7ccca2e
LP
190 writable = true;
191 else {
8d41a963
LP
192 fd = open("/etc/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
193 if (fd < 0) {
d7ccca2e
LP
194 umask(m);
195 log_error("Cannot open /etc/machine-id: %m");
196 return -errno;
197 }
198
199 writable = false;
200 }
201
202 umask(m);
203
204 if (fstat(fd, &st) < 0) {
205 log_error("fstat() failed: %m");
206 r = -errno;
207 goto finish;
208 }
209
210 if (S_ISREG(st.st_mode)) {
211 if (loop_read(fd, id, 32, false) >= 32) {
212 r = 0;
213 goto finish;
214 }
215 }
216
217 /* Hmm, so, the id currently stored is not useful, then let's
218 * generate one */
219
8d41a963
LP
220 r = generate(id);
221 if (r < 0)
d7ccca2e
LP
222 goto finish;
223
224 if (S_ISREG(st.st_mode) && writable) {
225 lseek(fd, 0, SEEK_SET);
226
227 if (loop_write(fd, id, 33, false) == 33) {
228 r = 0;
229 goto finish;
230 }
231 }
232
233 close_nointr_nofail(fd);
234 fd = -1;
235
236 /* Hmm, we couldn't write it? So let's write it to
2b583ce6 237 * /run/systemd/machine-id as a replacement */
d7ccca2e 238
2b583ce6 239 mkdir_p("/run/systemd", 0755);
d7ccca2e 240
4c12626c 241 m = umask(0022);
8d41a963 242 r = write_one_line_file("/run/systemd/machine-id", id);
4c12626c
LP
243 umask(m);
244
8d41a963 245 if (r < 0) {
2b583ce6 246 log_error("Cannot write /run/systemd/machine-id: %s", strerror(-r));
d7ccca2e 247
2b583ce6 248 unlink("/run/systemd/machine-id");
d7ccca2e
LP
249 goto finish;
250 }
251
252 /* And now, let's mount it over */
2b583ce6
KS
253 r = mount("/run/systemd/machine-id", "/etc/machine-id", "bind", MS_BIND|MS_RDONLY, NULL) < 0 ? -errno : 0;
254 unlink("/run/systemd/machine-id");
d7ccca2e
LP
255
256 if (r < 0)
257 log_error("Failed to mount /etc/machine-id: %s", strerror(-r));
258 else
9b4f818b 259 log_info("Installed transient /etc/machine-id file.");
d7ccca2e
LP
260
261finish:
262
263 if (fd >= 0)
264 close_nointr_nofail(fd);
265
266 return r;
267}