]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-id128/id128-util.c
Merge pull request #11827 from keszybz/pkgconfig-variables
[thirdparty/systemd.git] / src / libsystemd / sd-id128 / id128-util.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
910fd145 2
dccca82b 3#include <errno.h>
910fd145 4#include <fcntl.h>
15b1248a 5#include <unistd.h>
910fd145
LP
6
7#include "fd-util.h"
8ac2f74f 8#include "fs-util.h"
910fd145
LP
9#include "hexdecoct.h"
10#include "id128-util.h"
11#include "io-util.h"
12#include "stdio-util.h"
13
14char *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
37bool 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
945c2931 63 if (IN_SET(i, 8, 13, 18, 23)) {
910fd145
LP
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
80int 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
65548c58
LP
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". */
910fd145 91
65548c58 92 l = loop_read(fd, buffer, sizeof(buffer), false); /* we expect a short read of either 32/33 or 36/37 chars */
910fd145
LP
93 if (l < 0)
94 return (int) l;
95 if (l == 0) /* empty? */
96 return -ENOMEDIUM;
97
65548c58 98 switch (l) {
910fd145 99
65548c58 100 case 33: /* plain UUID with trailing newline */
910fd145
LP
101 if (buffer[32] != '\n')
102 return -EINVAL;
103
4831981d 104 _fallthrough_;
65548c58
LP
105 case 32: /* plain UUID without trailing newline */
106 if (f == ID128_UUID)
107 return -EINVAL;
108
910fd145 109 buffer[32] = 0;
65548c58 110 break;
910fd145 111
65548c58
LP
112 case 37: /* RFC UUID with trailing newline */
113 if (buffer[36] != '\n')
910fd145
LP
114 return -EINVAL;
115
4831981d 116 _fallthrough_;
65548c58
LP
117 case 36: /* RFC UUID without trailing newline */
118 if (f == ID128_PLAIN)
910fd145
LP
119 return -EINVAL;
120
121 buffer[36] = 0;
65548c58
LP
122 break;
123
124 default:
910fd145 125 return -EINVAL;
65548c58 126 }
910fd145
LP
127
128 return sd_id128_from_string(buffer, ret);
129}
130
131int 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
15b1248a 141int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync) {
910fd145
LP
142 char buffer[36 + 2];
143 size_t sz;
15b1248a 144 int r;
910fd145
LP
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
15b1248a
LP
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;
8ac2f74f
LP
166
167 r = fsync_directory_of_file(fd);
168 if (r < 0)
169 return r;
15b1248a
LP
170 }
171
8ac2f74f 172 return 0;
910fd145
LP
173}
174
15b1248a 175int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync) {
910fd145
LP
176 _cleanup_close_ int fd = -1;
177
da2d1421 178 fd = open(p, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_TRUNC, 0444);
910fd145
LP
179 if (fd < 0)
180 return -errno;
181
15b1248a 182 return id128_write_fd(fd, f, id, do_sync);
910fd145 183}
4b58153d 184
7a08d314
YW
185void id128_hash_func(const sd_id128_t *p, struct siphash *state) {
186 siphash24_compress(p, sizeof(sd_id128_t), state);
4b58153d
LP
187}
188
7a08d314 189int id128_compare_func(const sd_id128_t *a, const sd_id128_t *b) {
4b58153d
LP
190 return memcmp(a, b, 16);
191}
192
7a08d314 193DEFINE_HASH_OPS(id128_hash_ops, sd_id128_t, id128_hash_func, id128_compare_func);