]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-id128/id128-util.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
9 #include "id128-util.h"
11 #include "stdio-util.h"
12 #include "string-util.h"
13 #include "sync-util.h"
15 bool id128_is_valid(const char *s
) {
23 /* Plain formatted 128bit hex string */
25 for (i
= 0; i
< l
; i
++) {
28 if (!ascii_isdigit(c
) &&
29 !(c
>= 'a' && c
<= 'f') &&
30 !(c
>= 'A' && c
<= 'F'))
38 for (i
= 0; i
< l
; i
++) {
41 if (IN_SET(i
, 8, 13, 18, 23)) {
45 if (!ascii_isdigit(c
) &&
46 !(c
>= 'a' && c
<= 'f') &&
47 !(c
>= 'A' && c
<= 'F'))
58 int id128_read_fd(int fd
, Id128Format f
, sd_id128_t
*ret
) {
63 assert(f
< _ID128_FORMAT_MAX
);
65 /* Reads an 128bit ID from a file, which may either be in plain format (32 hex digits), or in UUID format, both
66 * optionally followed by a newline and nothing else. ID files should really be newline terminated, but if they
67 * aren't that's OK too, following the rule of "Be conservative in what you send, be liberal in what you
70 l
= loop_read(fd
, buffer
, sizeof(buffer
), false); /* we expect a short read of either 32/33 or 36/37 chars */
73 if (l
== 0) /* empty? */
80 /* Treat an "uninitialized" id file like an empty one */
81 return f
== ID128_PLAIN_OR_UNINIT
&& strneq(buffer
, "uninitialized\n", l
) ? -ENOMEDIUM
: -EINVAL
;
83 case 33: /* plain UUID with trailing newline */
84 if (buffer
[32] != '\n')
88 case 32: /* plain UUID without trailing newline */
95 case 37: /* RFC UUID with trailing newline */
96 if (buffer
[36] != '\n')
100 case 36: /* RFC UUID without trailing newline */
101 if (IN_SET(f
, ID128_PLAIN
, ID128_PLAIN_OR_UNINIT
))
111 return sd_id128_from_string(buffer
, ret
);
114 int id128_read(const char *p
, Id128Format f
, sd_id128_t
*ret
) {
115 _cleanup_close_
int fd
= -1;
117 fd
= open(p
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
121 return id128_read_fd(fd
, f
, ret
);
124 int id128_write_fd(int fd
, Id128Format f
, sd_id128_t id
, bool do_sync
) {
130 assert(f
< _ID128_FORMAT_MAX
);
132 if (f
!= ID128_UUID
) {
133 assert_se(sd_id128_to_string(id
, buffer
));
134 buffer
[SD_ID128_STRING_MAX
- 1] = '\n';
135 sz
= SD_ID128_STRING_MAX
;
137 assert_se(sd_id128_to_uuid_string(id
, buffer
));
138 buffer
[SD_ID128_UUID_STRING_MAX
- 1] = '\n';
139 sz
= SD_ID128_UUID_STRING_MAX
;
142 r
= loop_write(fd
, buffer
, sz
, false);
155 int id128_write(const char *p
, Id128Format f
, sd_id128_t id
, bool do_sync
) {
156 _cleanup_close_
int fd
= -1;
158 fd
= open(p
, O_WRONLY
|O_CREAT
|O_CLOEXEC
|O_NOCTTY
|O_TRUNC
, 0444);
162 return id128_write_fd(fd
, f
, id
, do_sync
);
165 void id128_hash_func(const sd_id128_t
*p
, struct siphash
*state
) {
166 siphash24_compress(p
, sizeof(sd_id128_t
), state
);
169 int id128_compare_func(const sd_id128_t
*a
, const sd_id128_t
*b
) {
170 return memcmp(a
, b
, 16);
173 sd_id128_t
id128_make_v4_uuid(sd_id128_t id
) {
174 /* Stolen from generate_random_uuid() of drivers/char/random.c
175 * in the kernel sources */
177 /* Set UUID version to 4 --- truly random generation */
178 id
.bytes
[6] = (id
.bytes
[6] & 0x0F) | 0x40;
180 /* Set the UUID variant to DCE */
181 id
.bytes
[8] = (id
.bytes
[8] & 0x3F) | 0x80;
186 DEFINE_HASH_OPS(id128_hash_ops
, sd_id128_t
, id128_hash_func
, id128_compare_func
);
188 int id128_get_product(sd_id128_t
*ret
) {
194 /* Reads the systems product UUID from DMI or devicetree (where it is located on POWER). This is
195 * particularly relevant in VM environments, where VM managers typically place a VM uuid there. */
197 r
= id128_read("/sys/class/dmi/id/product_uuid", ID128_UUID
, &uuid
);
199 r
= id128_read("/proc/device-tree/vm,uuid", ID128_UUID
, &uuid
);
203 if (sd_id128_is_null(uuid
) || sd_id128_is_allf(uuid
))
204 return -EADDRNOTAVAIL
; /* Recognizable error */