chiark / gitweb /
bus: make sd_bus_request_name() and sd_bus_release_name() behave more like other...
[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         assert_return(s, NULL);
35
36         for (n = 0; n < 16; n++) {
37                 s[n*2] = hexchar(id.bytes[n] >> 4);
38                 s[n*2+1] = hexchar(id.bytes[n] & 0xF);
39         }
40
41         s[32] = 0;
42
43         return s;
44 }
45
46 _public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) {
47         unsigned n, i;
48         sd_id128_t t;
49         bool is_guid = false;
50
51         assert_return(s, -EINVAL);
52         assert_return(ret, -EINVAL);
53
54         for (n = 0, i = 0; n < 16;) {
55                 int a, b;
56
57                 if (s[i] == '-') {
58                         /* Is this a GUID? Then be nice, and skip over
59                          * the dashes */
60
61                         if (i == 8)
62                                 is_guid = true;
63                         else if (i == 13 || i == 18 || i == 23) {
64                                 if (!is_guid)
65                                         return -EINVAL;
66                         } else
67                                 return -EINVAL;
68
69                         i++;
70                         continue;
71                 }
72
73                 a = unhexchar(s[i++]);
74                 if (a < 0)
75                         return -EINVAL;
76
77                 b = unhexchar(s[i++]);
78                 if (b < 0)
79                         return -EINVAL;
80
81                 t.bytes[n++] = (a << 4) | b;
82         }
83
84         if (i != (is_guid ? 36 : 32))
85                 return -EINVAL;
86
87         if (s[i] != 0)
88                 return -EINVAL;
89
90         *ret = t;
91         return 0;
92 }
93
94 static sd_id128_t make_v4_uuid(sd_id128_t id) {
95         /* Stolen from generate_random_uuid() of drivers/char/random.c
96          * in the kernel sources */
97
98         /* Set UUID version to 4 --- truly random generation */
99         id.bytes[6] = (id.bytes[6] & 0x0F) | 0x40;
100
101         /* Set the UUID variant to DCE */
102         id.bytes[8] = (id.bytes[8] & 0x3F) | 0x80;
103
104         return id;
105 }
106
107 _public_ int sd_id128_get_machine(sd_id128_t *ret) {
108         static __thread sd_id128_t saved_machine_id;
109         static __thread bool saved_machine_id_valid = false;
110         _cleanup_close_ int fd = -1;
111         char buf[33];
112         ssize_t k;
113         unsigned j;
114         sd_id128_t t;
115
116         assert_return(ret, -EINVAL);
117
118         if (saved_machine_id_valid) {
119                 *ret = saved_machine_id;
120                 return 0;
121         }
122
123         fd = open("/etc/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
124         if (fd < 0)
125                 return -errno;
126
127         k = loop_read(fd, buf, 33, false);
128         if (k < 0)
129                 return (int) k;
130
131         if (k != 33)
132                 return -EIO;
133
134         if (buf[32] !='\n')
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
156 _public_ int sd_id128_get_boot(sd_id128_t *ret) {
157         static __thread sd_id128_t saved_boot_id;
158         static __thread bool saved_boot_id_valid = false;
159         _cleanup_close_ int fd = -1;
160         char buf[36];
161         ssize_t k;
162         unsigned j;
163         sd_id128_t t;
164         char *p;
165
166         assert_return(ret, -EINVAL);
167
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
177         k = loop_read(fd, buf, 36, false);
178         if (k < 0)
179                 return (int) k;
180
181         if (k != 36)
182                 return -EIO;
183
184         for (j = 0, p = buf; j < 16; j++) {
185                 int a, b;
186
187                 if (p >= buf + k)
188                         return -EIO;
189
190                 if (*p == '-')
191                         p++;
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
211 _public_ int sd_id128_randomize(sd_id128_t *ret) {
212         _cleanup_close_ int fd = -1;
213         sd_id128_t t;
214         ssize_t k;
215
216         assert_return(ret, -EINVAL);
217
218         fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
219         if (fd < 0)
220                 return -errno;
221
222         k = loop_read(fd, &t, 16, false);
223         if (k < 0)
224                 return (int) k;
225
226         if (k != 16)
227                 return -EIO;
228
229         /* Turn this into a valid v4 UUID, to be nice. Note that we
230          * only guarantee this for newly generated UUIDs, not for
231          * pre-existing ones.*/
232
233         *ret = make_v4_uuid(t);
234         return 0;
235 }