]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-id128/id128-util.c
pkgconfig: define variables relative to ${prefix}/${rootprefix}/${sysconfdir}
[thirdparty/systemd.git] / src / libsystemd / sd-id128 / id128-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <unistd.h>
6
7 #include "fd-util.h"
8 #include "fs-util.h"
9 #include "hexdecoct.h"
10 #include "id128-util.h"
11 #include "io-util.h"
12 #include "stdio-util.h"
13
14 char *id128_to_uuid_string(sd_id128_t id, char s[37]) {
15 unsigned n, k = 0;
16
17 assert(s);
18
19 /* Similar to sd_id128_to_string() but formats the result as UUID instead of plain hex chars */
20
21 for (n = 0; n < 16; n++) {
22
23 if (IN_SET(n, 4, 6, 8, 10))
24 s[k++] = '-';
25
26 s[k++] = hexchar(id.bytes[n] >> 4);
27 s[k++] = hexchar(id.bytes[n] & 0xF);
28 }
29
30 assert(k == 36);
31
32 s[k] = 0;
33
34 return s;
35 }
36
37 bool id128_is_valid(const char *s) {
38 size_t i, l;
39
40 assert(s);
41
42 l = strlen(s);
43 if (l == 32) {
44
45 /* Plain formatted 128bit hex string */
46
47 for (i = 0; i < l; i++) {
48 char c = s[i];
49
50 if (!(c >= '0' && c <= '9') &&
51 !(c >= 'a' && c <= 'z') &&
52 !(c >= 'A' && c <= 'Z'))
53 return false;
54 }
55
56 } else if (l == 36) {
57
58 /* Formatted UUID */
59
60 for (i = 0; i < l; i++) {
61 char c = s[i];
62
63 if (IN_SET(i, 8, 13, 18, 23)) {
64 if (c != '-')
65 return false;
66 } else {
67 if (!(c >= '0' && c <= '9') &&
68 !(c >= 'a' && c <= 'z') &&
69 !(c >= 'A' && c <= 'Z'))
70 return false;
71 }
72 }
73
74 } else
75 return false;
76
77 return true;
78 }
79
80 int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) {
81 char buffer[36 + 2];
82 ssize_t l;
83
84 assert(fd >= 0);
85 assert(f < _ID128_FORMAT_MAX);
86
87 /* Reads an 128bit ID from a file, which may either be in plain format (32 hex digits), or in UUID format, both
88 * optionally followed by a newline and nothing else. ID files should really be newline terminated, but if they
89 * aren't that's OK too, following the rule of "Be conservative in what you send, be liberal in what you
90 * accept". */
91
92 l = loop_read(fd, buffer, sizeof(buffer), false); /* we expect a short read of either 32/33 or 36/37 chars */
93 if (l < 0)
94 return (int) l;
95 if (l == 0) /* empty? */
96 return -ENOMEDIUM;
97
98 switch (l) {
99
100 case 33: /* plain UUID with trailing newline */
101 if (buffer[32] != '\n')
102 return -EINVAL;
103
104 _fallthrough_;
105 case 32: /* plain UUID without trailing newline */
106 if (f == ID128_UUID)
107 return -EINVAL;
108
109 buffer[32] = 0;
110 break;
111
112 case 37: /* RFC UUID with trailing newline */
113 if (buffer[36] != '\n')
114 return -EINVAL;
115
116 _fallthrough_;
117 case 36: /* RFC UUID without trailing newline */
118 if (f == ID128_PLAIN)
119 return -EINVAL;
120
121 buffer[36] = 0;
122 break;
123
124 default:
125 return -EINVAL;
126 }
127
128 return sd_id128_from_string(buffer, ret);
129 }
130
131 int id128_read(const char *p, Id128Format f, sd_id128_t *ret) {
132 _cleanup_close_ int fd = -1;
133
134 fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY);
135 if (fd < 0)
136 return -errno;
137
138 return id128_read_fd(fd, f, ret);
139 }
140
141 int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync) {
142 char buffer[36 + 2];
143 size_t sz;
144 int r;
145
146 assert(fd >= 0);
147 assert(f < _ID128_FORMAT_MAX);
148
149 if (f != ID128_UUID) {
150 sd_id128_to_string(id, buffer);
151 buffer[32] = '\n';
152 sz = 33;
153 } else {
154 id128_to_uuid_string(id, buffer);
155 buffer[36] = '\n';
156 sz = 37;
157 }
158
159 r = loop_write(fd, buffer, sz, false);
160 if (r < 0)
161 return r;
162
163 if (do_sync) {
164 if (fsync(fd) < 0)
165 return -errno;
166
167 r = fsync_directory_of_file(fd);
168 if (r < 0)
169 return r;
170 }
171
172 return 0;
173 }
174
175 int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync) {
176 _cleanup_close_ int fd = -1;
177
178 fd = open(p, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_TRUNC, 0444);
179 if (fd < 0)
180 return -errno;
181
182 return id128_write_fd(fd, f, id, do_sync);
183 }
184
185 void id128_hash_func(const void *p, struct siphash *state) {
186 siphash24_compress(p, 16, state);
187 }
188
189 int id128_compare_func(const void *a, const void *b) {
190 return memcmp(a, b, 16);
191 }
192
193 const struct hash_ops id128_hash_ops = {
194 .hash = id128_hash_func,
195 .compare = id128_compare_func,
196 };