]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-id128/sd-id128.c
tree-wide: add missing includes
[thirdparty/systemd.git] / src / libsystemd / sd-id128 / sd-id128.c
CommitLineData
87d2c1ff
LP
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
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
87d2c1ff
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.
87d2c1ff 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
87d2c1ff
LP
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
80514f9c 26#include "sd-id128.h"
07630cea 27
c004493c
LP
28#include "fd-util.h"
29#include "io-util.h"
07630cea 30#include "macro.h"
e4e73a63 31#include "hexdecoct.h"
3df3e884 32#include "random-util.h"
07630cea 33#include "util.h"
87d2c1ff 34
3ade55d3 35_public_ char *sd_id128_to_string(sd_id128_t id, char s[SD_ID128_STRING_MAX]) {
87d2c1ff
LP
36 unsigned n;
37
1ae464e0 38 assert_return(s, NULL);
87d2c1ff
LP
39
40 for (n = 0; n < 16; n++) {
41 s[n*2] = hexchar(id.bytes[n] >> 4);
42 s[n*2+1] = hexchar(id.bytes[n] & 0xF);
43 }
44
45 s[32] = 0;
46
47 return s;
48}
49
aa96c6cb
LP
50_public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) {
51 unsigned n, i;
87d2c1ff 52 sd_id128_t t;
aa96c6cb 53 bool is_guid = false;
87d2c1ff 54
1ae464e0
TA
55 assert_return(s, -EINVAL);
56 assert_return(ret, -EINVAL);
87d2c1ff 57
aa96c6cb 58 for (n = 0, i = 0; n < 16;) {
87d2c1ff
LP
59 int a, b;
60
aa96c6cb
LP
61 if (s[i] == '-') {
62 /* Is this a GUID? Then be nice, and skip over
63 * the dashes */
64
65 if (i == 8)
66 is_guid = true;
67 else if (i == 13 || i == 18 || i == 23) {
68 if (!is_guid)
69 return -EINVAL;
70 } else
71 return -EINVAL;
72
73 i++;
74 continue;
75 }
76
77 a = unhexchar(s[i++]);
87d2c1ff
LP
78 if (a < 0)
79 return -EINVAL;
80
aa96c6cb 81 b = unhexchar(s[i++]);
87d2c1ff
LP
82 if (b < 0)
83 return -EINVAL;
84
aa96c6cb 85 t.bytes[n++] = (a << 4) | b;
87d2c1ff
LP
86 }
87
aa96c6cb
LP
88 if (i != (is_guid ? 36 : 32))
89 return -EINVAL;
90
91 if (s[i] != 0)
87d2c1ff
LP
92 return -EINVAL;
93
94 *ret = t;
95 return 0;
96}
97
e4bac488 98static sd_id128_t make_v4_uuid(sd_id128_t id) {
87d2c1ff
LP
99 /* Stolen from generate_random_uuid() of drivers/char/random.c
100 * in the kernel sources */
101
102 /* Set UUID version to 4 --- truly random generation */
103 id.bytes[6] = (id.bytes[6] & 0x0F) | 0x40;
104
105 /* Set the UUID variant to DCE */
106 id.bytes[8] = (id.bytes[8] & 0x3F) | 0x80;
107
108 return id;
109}
110
000a2c98 111_public_ int sd_id128_get_machine(sd_id128_t *ret) {
ec202eae
SL
112 static thread_local sd_id128_t saved_machine_id;
113 static thread_local bool saved_machine_id_valid = false;
aa96c6cb
LP
114 _cleanup_close_ int fd = -1;
115 char buf[33];
87d2c1ff
LP
116 unsigned j;
117 sd_id128_t t;
a6dcc7e5 118 int r;
87d2c1ff 119
1ae464e0 120 assert_return(ret, -EINVAL);
000a2c98 121
87d2c1ff
LP
122 if (saved_machine_id_valid) {
123 *ret = saved_machine_id;
124 return 0;
125 }
126
127 fd = open("/etc/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
128 if (fd < 0)
129 return -errno;
130
a6dcc7e5
ZJS
131 r = loop_read_exact(fd, buf, 33, false);
132 if (r < 0)
133 return r;
aa96c6cb 134 if (buf[32] !='\n')
87d2c1ff
LP
135 return -EIO;
136
137 for (j = 0; j < 16; j++) {
138 int a, b;
139
140 a = unhexchar(buf[j*2]);
141 b = unhexchar(buf[j*2+1]);
142
143 if (a < 0 || b < 0)
144 return -EIO;
145
146 t.bytes[j] = a << 4 | b;
147 }
148
149 saved_machine_id = t;
150 saved_machine_id_valid = true;
151
152 *ret = t;
153 return 0;
154}
155
000a2c98 156_public_ int sd_id128_get_boot(sd_id128_t *ret) {
ec202eae
SL
157 static thread_local sd_id128_t saved_boot_id;
158 static thread_local bool saved_boot_id_valid = false;
aa96c6cb 159 _cleanup_close_ int fd = -1;
87d2c1ff 160 char buf[36];
87d2c1ff
LP
161 unsigned j;
162 sd_id128_t t;
163 char *p;
a6dcc7e5 164 int r;
87d2c1ff 165
1ae464e0 166 assert_return(ret, -EINVAL);
000a2c98 167
87d2c1ff
LP
168 if (saved_boot_id_valid) {
169 *ret = saved_boot_id;
170 return 0;
171 }
172
173 fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
174 if (fd < 0)
175 return -errno;
176
a6dcc7e5
ZJS
177 r = loop_read_exact(fd, buf, 36, false);
178 if (r < 0)
179 return r;
87d2c1ff
LP
180
181 for (j = 0, p = buf; j < 16; j++) {
182 int a, b;
183
a6dcc7e5 184 if (p >= buf + 35)
54c7d1f4
ZJS
185 return -EIO;
186
cef35669 187 if (*p == '-') {
87d2c1ff 188 p++;
a6dcc7e5 189 if (p >= buf + 35)
cef35669
ZJS
190 return -EIO;
191 }
87d2c1ff
LP
192
193 a = unhexchar(p[0]);
194 b = unhexchar(p[1]);
195
196 if (a < 0 || b < 0)
197 return -EIO;
198
199 t.bytes[j] = a << 4 | b;
200
201 p += 2;
202 }
203
204 saved_boot_id = t;
205 saved_boot_id_valid = true;
206
207 *ret = t;
208 return 0;
209}
210
000a2c98 211_public_ int sd_id128_randomize(sd_id128_t *ret) {
87d2c1ff 212 sd_id128_t t;
0f0e240c 213 int r;
87d2c1ff 214
1ae464e0 215 assert_return(ret, -EINVAL);
87d2c1ff 216
0f0e240c
LP
217 r = dev_urandom(&t, sizeof(t));
218 if (r < 0)
219 return r;
87d2c1ff
LP
220
221 /* Turn this into a valid v4 UUID, to be nice. Note that we
222 * only guarantee this for newly generated UUIDs, not for
f7340ab2 223 * pre-existing ones. */
87d2c1ff 224
e4bac488 225 *ret = make_v4_uuid(t);
87d2c1ff
LP
226 return 0;
227}