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