]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-id128/id128-util.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
10 #include "id128-util.h"
12 #include "stdio-util.h"
13 #include "string-util.h"
14 #include "sync-util.h"
16 bool id128_is_valid(const char *s
) {
23 if (l
== SD_ID128_STRING_MAX
- 1)
24 /* Plain formatted 128bit hex string */
25 return in_charset(s
, HEXDIGITS
);
27 if (l
== SD_ID128_UUID_STRING_MAX
- 1) {
29 for (size_t i
= 0; i
< l
; i
++) {
32 if (IN_SET(i
, 8, 13, 18, 23)) {
35 } else if (!ascii_ishex(c
))
44 int id128_read_fd(int fd
, Id128Flag f
, sd_id128_t
*ret
) {
45 char buffer
[SD_ID128_UUID_STRING_MAX
+ 1]; /* +1 is for trailing newline */
52 /* Reads an 128bit ID from a file, which may either be in plain format (32 hex digits), or in UUID format, both
53 * optionally followed by a newline and nothing else. ID files should really be newline terminated, but if they
54 * aren't that's OK too, following the rule of "Be conservative in what you send, be liberal in what you
57 * This returns the following:
58 * -ENOMEDIUM: an empty string,
59 * -ENOPKG: "uninitialized" or "uninitialized\n",
60 * -EUCLEAN: other invalid strings. */
62 l
= loop_read(fd
, buffer
, sizeof(buffer
), false); /* we expect a short read of either 32/33 or 36/37 chars */
65 if (l
== 0) /* empty? */
70 case STRLEN("uninitialized"):
71 case STRLEN("uninitialized\n"):
72 return strneq(buffer
, "uninitialized\n", l
) ? -ENOPKG
: -EINVAL
;
74 case SD_ID128_STRING_MAX
: /* plain UUID with trailing newline */
75 if (buffer
[SD_ID128_STRING_MAX
-1] != '\n')
79 case SD_ID128_STRING_MAX
-1: /* plain UUID without trailing newline */
80 if (!FLAGS_SET(f
, ID128_FORMAT_PLAIN
))
83 buffer
[SD_ID128_STRING_MAX
-1] = 0;
86 case SD_ID128_UUID_STRING_MAX
: /* RFC UUID with trailing newline */
87 if (buffer
[SD_ID128_UUID_STRING_MAX
-1] != '\n')
91 case SD_ID128_UUID_STRING_MAX
-1: /* RFC UUID without trailing newline */
92 if (!FLAGS_SET(f
, ID128_FORMAT_UUID
))
95 buffer
[SD_ID128_UUID_STRING_MAX
-1] = 0;
102 r
= sd_id128_from_string(buffer
, &id
);
108 if (FLAGS_SET(f
, ID128_REFUSE_NULL
) && sd_id128_is_null(id
))
116 int id128_read_at(int dir_fd
, const char *path
, Id128Flag f
, sd_id128_t
*ret
) {
117 _cleanup_close_
int fd
= -EBADF
;
119 assert(dir_fd
>= 0 || dir_fd
== AT_FDCWD
);
122 fd
= xopenat(dir_fd
, path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
, /* xopen_flags = */ 0, /* mode = */ 0);
126 return id128_read_fd(fd
, f
, ret
);
129 int id128_write_fd(int fd
, Id128Flag f
, sd_id128_t id
) {
130 char buffer
[SD_ID128_UUID_STRING_MAX
+ 1]; /* +1 is for trailing newline */
135 assert(IN_SET((f
& ID128_FORMAT_ANY
), ID128_FORMAT_PLAIN
, ID128_FORMAT_UUID
));
137 if (FLAGS_SET(f
, ID128_REFUSE_NULL
) && sd_id128_is_null(id
))
140 if (FLAGS_SET(f
, ID128_FORMAT_PLAIN
)) {
141 assert_se(sd_id128_to_string(id
, buffer
));
142 sz
= SD_ID128_STRING_MAX
;
144 assert_se(sd_id128_to_uuid_string(id
, buffer
));
145 sz
= SD_ID128_UUID_STRING_MAX
;
148 buffer
[sz
- 1] = '\n';
149 r
= loop_write(fd
, buffer
, sz
, false);
153 if (FLAGS_SET(f
, ID128_SYNC_ON_WRITE
)) {
162 int id128_write_at(int dir_fd
, const char *path
, Id128Flag f
, sd_id128_t id
) {
163 _cleanup_close_
int fd
= -EBADF
;
165 assert(dir_fd
>= 0 || dir_fd
== AT_FDCWD
);
168 fd
= xopenat(dir_fd
, path
, O_WRONLY
|O_CREAT
|O_CLOEXEC
|O_NOCTTY
|O_TRUNC
, /* xopen_flags = */ 0, 0444);
172 return id128_write_fd(fd
, f
, id
);
175 void id128_hash_func(const sd_id128_t
*p
, struct siphash
*state
) {
176 siphash24_compress(p
, sizeof(sd_id128_t
), state
);
179 int id128_compare_func(const sd_id128_t
*a
, const sd_id128_t
*b
) {
180 return memcmp(a
, b
, 16);
183 sd_id128_t
id128_make_v4_uuid(sd_id128_t id
) {
184 /* Stolen from generate_random_uuid() of drivers/char/random.c
185 * in the kernel sources */
187 /* Set UUID version to 4 --- truly random generation */
188 id
.bytes
[6] = (id
.bytes
[6] & 0x0F) | 0x40;
190 /* Set the UUID variant to DCE */
191 id
.bytes
[8] = (id
.bytes
[8] & 0x3F) | 0x80;
196 DEFINE_HASH_OPS(id128_hash_ops
, sd_id128_t
, id128_hash_func
, id128_compare_func
);
197 DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(id128_hash_ops_free
, sd_id128_t
, id128_hash_func
, id128_compare_func
, free
);
199 int id128_get_product(sd_id128_t
*ret
) {
205 /* Reads the systems product UUID from DMI or devicetree (where it is located on POWER). This is
206 * particularly relevant in VM environments, where VM managers typically place a VM uuid there. */
208 r
= id128_read("/sys/class/dmi/id/product_uuid", ID128_FORMAT_UUID
, &uuid
);
210 r
= id128_read("/proc/device-tree/vm,uuid", ID128_FORMAT_UUID
, &uuid
);
214 if (sd_id128_is_null(uuid
) || sd_id128_is_allf(uuid
))
215 return -EADDRNOTAVAIL
; /* Recognizable error */