]> git.proxmox.com Git - systemd.git/blame - src/libsystemd/sd-id128/sd-id128.c
Merge tag 'upstream/229'
[systemd.git] / src / libsystemd / sd-id128 / sd-id128.c
CommitLineData
663996b3
MS
1/***
2 This file is part of systemd.
3
4 Copyright 2011 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
20#include <errno.h>
21#include <fcntl.h>
22#include <unistd.h>
23
60f067b4 24#include "sd-id128.h"
db2df898
MP
25
26#include "fd-util.h"
27#include "hexdecoct.h"
28#include "io-util.h"
29#include "macro.h"
e3bff60a 30#include "random-util.h"
db2df898 31#include "util.h"
663996b3 32
6300502b 33_public_ char *sd_id128_to_string(sd_id128_t id, char s[SD_ID128_STRING_MAX]) {
663996b3
MS
34 unsigned n;
35
60f067b4 36 assert_return(s, NULL);
663996b3
MS
37
38 for (n = 0; n < 16; n++) {
39 s[n*2] = hexchar(id.bytes[n] >> 4);
40 s[n*2+1] = hexchar(id.bytes[n] & 0xF);
41 }
42
43 s[32] = 0;
44
45 return s;
46}
47
48_public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) {
49 unsigned n, i;
50 sd_id128_t t;
51 bool is_guid = false;
52
60f067b4
JS
53 assert_return(s, -EINVAL);
54 assert_return(ret, -EINVAL);
663996b3
MS
55
56 for (n = 0, i = 0; n < 16;) {
57 int a, b;
58
59 if (s[i] == '-') {
60 /* Is this a GUID? Then be nice, and skip over
61 * the dashes */
62
63 if (i == 8)
64 is_guid = true;
65 else if (i == 13 || i == 18 || i == 23) {
66 if (!is_guid)
67 return -EINVAL;
68 } else
69 return -EINVAL;
70
71 i++;
72 continue;
73 }
74
75 a = unhexchar(s[i++]);
76 if (a < 0)
77 return -EINVAL;
78
79 b = unhexchar(s[i++]);
80 if (b < 0)
81 return -EINVAL;
82
83 t.bytes[n++] = (a << 4) | b;
84 }
85
86 if (i != (is_guid ? 36 : 32))
87 return -EINVAL;
88
89 if (s[i] != 0)
90 return -EINVAL;
91
92 *ret = t;
93 return 0;
94}
95
96static sd_id128_t make_v4_uuid(sd_id128_t id) {
97 /* Stolen from generate_random_uuid() of drivers/char/random.c
98 * in the kernel sources */
99
100 /* Set UUID version to 4 --- truly random generation */
101 id.bytes[6] = (id.bytes[6] & 0x0F) | 0x40;
102
103 /* Set the UUID variant to DCE */
104 id.bytes[8] = (id.bytes[8] & 0x3F) | 0x80;
105
106 return id;
107}
108
109_public_ int sd_id128_get_machine(sd_id128_t *ret) {
60f067b4
JS
110 static thread_local sd_id128_t saved_machine_id;
111 static thread_local bool saved_machine_id_valid = false;
663996b3
MS
112 _cleanup_close_ int fd = -1;
113 char buf[33];
663996b3
MS
114 unsigned j;
115 sd_id128_t t;
e3bff60a 116 int r;
663996b3 117
60f067b4 118 assert_return(ret, -EINVAL);
663996b3
MS
119
120 if (saved_machine_id_valid) {
121 *ret = saved_machine_id;
122 return 0;
123 }
124
125 fd = open("/etc/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
126 if (fd < 0)
127 return -errno;
128
e3bff60a
MP
129 r = loop_read_exact(fd, buf, 33, false);
130 if (r < 0)
131 return r;
663996b3
MS
132 if (buf[32] !='\n')
133 return -EIO;
134
135 for (j = 0; j < 16; j++) {
136 int a, b;
137
138 a = unhexchar(buf[j*2]);
139 b = unhexchar(buf[j*2+1]);
140
141 if (a < 0 || b < 0)
142 return -EIO;
143
144 t.bytes[j] = a << 4 | b;
145 }
146
147 saved_machine_id = t;
148 saved_machine_id_valid = true;
149
150 *ret = t;
151 return 0;
152}
153
154_public_ int sd_id128_get_boot(sd_id128_t *ret) {
60f067b4
JS
155 static thread_local sd_id128_t saved_boot_id;
156 static thread_local bool saved_boot_id_valid = false;
663996b3
MS
157 _cleanup_close_ int fd = -1;
158 char buf[36];
663996b3
MS
159 unsigned j;
160 sd_id128_t t;
161 char *p;
e3bff60a 162 int r;
663996b3 163
60f067b4 164 assert_return(ret, -EINVAL);
663996b3
MS
165
166 if (saved_boot_id_valid) {
167 *ret = saved_boot_id;
168 return 0;
169 }
170
171 fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
172 if (fd < 0)
173 return -errno;
174
e3bff60a
MP
175 r = loop_read_exact(fd, buf, 36, false);
176 if (r < 0)
177 return r;
663996b3
MS
178
179 for (j = 0, p = buf; j < 16; j++) {
180 int a, b;
181
e3bff60a 182 if (p >= buf + 35)
663996b3
MS
183 return -EIO;
184
5eef597e 185 if (*p == '-') {
663996b3 186 p++;
e3bff60a 187 if (p >= buf + 35)
5eef597e
MP
188 return -EIO;
189 }
663996b3
MS
190
191 a = unhexchar(p[0]);
192 b = unhexchar(p[1]);
193
194 if (a < 0 || b < 0)
195 return -EIO;
196
197 t.bytes[j] = a << 4 | b;
198
199 p += 2;
200 }
201
202 saved_boot_id = t;
203 saved_boot_id_valid = true;
204
205 *ret = t;
206 return 0;
207}
208
209_public_ int sd_id128_randomize(sd_id128_t *ret) {
663996b3 210 sd_id128_t t;
60f067b4 211 int r;
663996b3 212
60f067b4 213 assert_return(ret, -EINVAL);
663996b3 214
60f067b4
JS
215 r = dev_urandom(&t, sizeof(t));
216 if (r < 0)
217 return r;
663996b3
MS
218
219 /* Turn this into a valid v4 UUID, to be nice. Note that we
220 * only guarantee this for newly generated UUIDs, not for
e735f4d4 221 * pre-existing ones. */
663996b3
MS
222
223 *ret = make_v4_uuid(t);
224 return 0;
225}