chiark / gitweb /
util: never follow symlinks in rm_rf_children()
[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
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 }