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