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