chiark / gitweb /
udev: declare some symbols static
[elogind.git] / src / libsystemd-id128 / 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 Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 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   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser 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[], sd_id128_t *ret) {
48         unsigned n, i;
49         sd_id128_t t;
50         bool is_guid = false;
51
52         if (!s)
53                 return -EINVAL;
54         if (!ret)
55                 return -EINVAL;
56
57         for (n = 0, i = 0; n < 16;) {
58                 int a, b;
59
60                 if (s[i] == '-') {
61                         /* Is this a GUID? Then be nice, and skip over
62                          * the dashes */
63
64                         if (i == 8)
65                                 is_guid = true;
66                         else if (i == 13 || i == 18 || i == 23) {
67                                 if (!is_guid)
68                                         return -EINVAL;
69                         } else
70                                 return -EINVAL;
71
72                         i++;
73                         continue;
74                 }
75
76                 a = unhexchar(s[i++]);
77                 if (a < 0)
78                         return -EINVAL;
79
80                 b = unhexchar(s[i++]);
81                 if (b < 0)
82                         return -EINVAL;
83
84                 t.bytes[n++] = (a << 4) | b;
85         }
86
87         if (i != (is_guid ? 36 : 32))
88                 return -EINVAL;
89
90         if (s[i] != 0)
91                 return -EINVAL;
92
93         *ret = t;
94         return 0;
95 }
96
97 static sd_id128_t make_v4_uuid(sd_id128_t id) {
98         /* Stolen from generate_random_uuid() of drivers/char/random.c
99          * in the kernel sources */
100
101         /* Set UUID version to 4 --- truly random generation */
102         id.bytes[6] = (id.bytes[6] & 0x0F) | 0x40;
103
104         /* Set the UUID variant to DCE */
105         id.bytes[8] = (id.bytes[8] & 0x3F) | 0x80;
106
107         return id;
108 }
109
110 _public_ int sd_id128_get_machine(sd_id128_t *ret) {
111         static __thread sd_id128_t saved_machine_id;
112         static __thread bool saved_machine_id_valid = false;
113         _cleanup_close_ int fd = -1;
114         char buf[33];
115         ssize_t k;
116         unsigned j;
117         sd_id128_t t;
118
119         if (!ret)
120                 return -EINVAL;
121
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
131         k = loop_read(fd, buf, 33, false);
132         if (k < 0)
133                 return (int) k;
134
135         if (k != 33)
136                 return -EIO;
137
138         if (buf[32] !='\n')
139                 return -EIO;
140
141         for (j = 0; j < 16; j++) {
142                 int a, b;
143
144                 a = unhexchar(buf[j*2]);
145                 b = unhexchar(buf[j*2+1]);
146
147                 if (a < 0 || b < 0)
148                         return -EIO;
149
150                 t.bytes[j] = a << 4 | b;
151         }
152
153         saved_machine_id = t;
154         saved_machine_id_valid = true;
155
156         *ret = t;
157         return 0;
158 }
159
160 _public_ int sd_id128_get_boot(sd_id128_t *ret) {
161         static __thread sd_id128_t saved_boot_id;
162         static __thread bool saved_boot_id_valid = false;
163         _cleanup_close_ int fd = -1;
164         char buf[36];
165         ssize_t k;
166         unsigned j;
167         sd_id128_t t;
168         char *p;
169
170         if (!ret)
171                 return -EINVAL;
172
173         if (saved_boot_id_valid) {
174                 *ret = saved_boot_id;
175                 return 0;
176         }
177
178         fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
179         if (fd < 0)
180                 return -errno;
181
182         k = loop_read(fd, buf, 36, false);
183         if (k < 0)
184                 return (int) k;
185
186         if (k != 36)
187                 return -EIO;
188
189         for (j = 0, p = buf; j < 16; j++) {
190                 int a, b;
191
192                 if (p >= buf + k)
193                         return -EIO;
194
195                 if (*p == '-')
196                         p++;
197
198                 a = unhexchar(p[0]);
199                 b = unhexchar(p[1]);
200
201                 if (a < 0 || b < 0)
202                         return -EIO;
203
204                 t.bytes[j] = a << 4 | b;
205
206                 p += 2;
207         }
208
209         saved_boot_id = t;
210         saved_boot_id_valid = true;
211
212         *ret = t;
213         return 0;
214 }
215
216 _public_ int sd_id128_randomize(sd_id128_t *ret) {
217         _cleanup_close_ int fd = -1;
218         sd_id128_t t;
219         ssize_t k;
220
221         if (!ret)
222                 return -EINVAL;
223
224         fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
225         if (fd < 0)
226                 return -errno;
227
228         k = loop_read(fd, &t, 16, false);
229         if (k < 0)
230                 return (int) k;
231
232         if (k != 16)
233                 return -EIO;
234
235         /* Turn this into a valid v4 UUID, to be nice. Note that we
236          * only guarantee this for newly generated UUIDs, not for
237          * pre-existing ones.*/
238
239         *ret = make_v4_uuid(t);
240         return 0;
241 }