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