]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/sd-id128.c
virt: detect LXC+libvirt containers
[thirdparty/systemd.git] / src / sd-id128.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2011 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 <errno.h>
23 #include <fcntl.h>
24 #include <unistd.h>
25
26 #include "sd-id128.h"
27
28 #include "util.h"
29 #include "macro.h"
30
31 _public_ char *sd_id128_to_string(sd_id128_t id, char s[33]) {
32 unsigned n;
33
34 if (!s)
35 return NULL;
36
37 for (n = 0; n < 16; n++) {
38 s[n*2] = hexchar(id.bytes[n] >> 4);
39 s[n*2+1] = hexchar(id.bytes[n] & 0xF);
40 }
41
42 s[32] = 0;
43
44 return s;
45 }
46
47 _public_ int sd_id128_from_string(const char s[33], sd_id128_t *ret) {
48 unsigned n;
49 sd_id128_t t;
50
51 if (!s)
52 return -EINVAL;
53 if (!ret)
54 return -EINVAL;
55
56 for (n = 0; n < 16; n++) {
57 int a, b;
58
59 a = unhexchar(s[n*2]);
60 if (a < 0)
61 return -EINVAL;
62
63 b = unhexchar(s[n*2+1]);
64 if (b < 0)
65 return -EINVAL;
66
67 t.bytes[n] = (a << 4) | b;
68 }
69
70 if (s[32] != 0)
71 return -EINVAL;
72
73 *ret = t;
74 return 0;
75 }
76
77 static sd_id128_t make_v4_uuid(sd_id128_t id) {
78 /* Stolen from generate_random_uuid() of drivers/char/random.c
79 * in the kernel sources */
80
81 /* Set UUID version to 4 --- truly random generation */
82 id.bytes[6] = (id.bytes[6] & 0x0F) | 0x40;
83
84 /* Set the UUID variant to DCE */
85 id.bytes[8] = (id.bytes[8] & 0x3F) | 0x80;
86
87 return id;
88 }
89
90 _public_ int sd_id128_get_machine(sd_id128_t *ret) {
91 static __thread sd_id128_t saved_machine_id;
92 static __thread bool saved_machine_id_valid = false;
93 int fd;
94 char buf[32];
95 ssize_t k;
96 unsigned j;
97 sd_id128_t t;
98
99 if (!ret)
100 return -EINVAL;
101
102 if (saved_machine_id_valid) {
103 *ret = saved_machine_id;
104 return 0;
105 }
106
107 fd = open("/etc/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
108 if (fd < 0)
109 return -errno;
110
111 k = loop_read(fd, buf, 32, false);
112 close_nointr_nofail(fd);
113
114 if (k < 0)
115 return (int) k;
116
117 if (k < 32)
118 return -EIO;
119
120 for (j = 0; j < 16; j++) {
121 int a, b;
122
123 a = unhexchar(buf[j*2]);
124 b = unhexchar(buf[j*2+1]);
125
126 if (a < 0 || b < 0)
127 return -EIO;
128
129 t.bytes[j] = a << 4 | b;
130 }
131
132 saved_machine_id = t;
133 saved_machine_id_valid = true;
134
135 *ret = t;
136 return 0;
137 }
138
139 _public_ int sd_id128_get_boot(sd_id128_t *ret) {
140 static __thread sd_id128_t saved_boot_id;
141 static __thread bool saved_boot_id_valid = false;
142 int fd;
143 char buf[36];
144 ssize_t k;
145 unsigned j;
146 sd_id128_t t;
147 char *p;
148
149 if (!ret)
150 return -EINVAL;
151
152 if (saved_boot_id_valid) {
153 *ret = saved_boot_id;
154 return 0;
155 }
156
157 fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
158 if (fd < 0)
159 return -errno;
160
161 k = loop_read(fd, buf, 36, false);
162 close_nointr_nofail(fd);
163
164 if (k < 0)
165 return (int) k;
166
167 if (k < 36)
168 return -EIO;
169
170 for (j = 0, p = buf; j < 16; j++) {
171 int a, b;
172
173 if (*p == '-')
174 p++;
175
176 a = unhexchar(p[0]);
177 b = unhexchar(p[1]);
178
179 if (a < 0 || b < 0)
180 return -EIO;
181
182 t.bytes[j] = a << 4 | b;
183
184 p += 2;
185 }
186
187 saved_boot_id = t;
188 saved_boot_id_valid = true;
189
190 *ret = t;
191 return 0;
192 }
193
194 _public_ int sd_id128_randomize(sd_id128_t *ret) {
195 int fd;
196 ssize_t k;
197 sd_id128_t t;
198
199 if (!ret)
200 return -EINVAL;
201
202 fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
203 if (fd < 0)
204 return -errno;
205
206 k = loop_read(fd, &t, 16, false);
207 close_nointr_nofail(fd);
208
209 if (k < 0)
210 return (int) k;
211
212 if (k < 16)
213 return -EIO;
214
215 /* Turn this into a valid v4 UUID, to be nice. Note that we
216 * only guarantee this for newly generated UUIDs, not for
217 * pre-existing ones.*/
218
219 *ret = make_v4_uuid(t);
220 return 0;
221 }