]>
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
) {
22 if (l
== SD_ID128_STRING_MAX
- 1)
23 /* Plain formatted 128bit hex string */
24 return in_charset(s
, HEXDIGITS
);
26 if (l
== SD_ID128_UUID_STRING_MAX
- 1) {
28 for (size_t i
= 0; i
< l
; i
++) {
31 if (IN_SET(i
, 8, 13, 18, 23)) {
34 } else if (!ascii_ishex(c
))
43 int id128_read_fd(int fd
, Id128FormatFlag f
, sd_id128_t
*ret
) {
44 char buffer
[SD_ID128_UUID_STRING_MAX
+ 1]; /* +1 is for trailing newline */
50 /* Reads an 128bit ID from a file, which may either be in plain format (32 hex digits), or in UUID format, both
51 * optionally followed by a newline and nothing else. ID files should really be newline terminated, but if they
52 * aren't that's OK too, following the rule of "Be conservative in what you send, be liberal in what you
55 * This returns the following:
56 * -ENOMEDIUM: an empty string,
57 * -ENOPKG: "uninitialized" or "uninitialized\n",
58 * -EUCLEAN: other invalid strings. */
60 l
= loop_read(fd
, buffer
, sizeof(buffer
), false); /* we expect a short read of either 32/33 or 36/37 chars */
63 if (l
== 0) /* empty? */
68 case STRLEN("uninitialized"):
69 case STRLEN("uninitialized\n"):
70 return strneq(buffer
, "uninitialized\n", l
) ? -ENOPKG
: -EINVAL
;
72 case SD_ID128_STRING_MAX
: /* plain UUID with trailing newline */
73 if (buffer
[SD_ID128_STRING_MAX
-1] != '\n')
77 case SD_ID128_STRING_MAX
-1: /* plain UUID without trailing newline */
78 if (!FLAGS_SET(f
, ID128_FORMAT_PLAIN
))
81 buffer
[SD_ID128_STRING_MAX
-1] = 0;
84 case SD_ID128_UUID_STRING_MAX
: /* RFC UUID with trailing newline */
85 if (buffer
[SD_ID128_UUID_STRING_MAX
-1] != '\n')
89 case SD_ID128_UUID_STRING_MAX
-1: /* RFC UUID without trailing newline */
90 if (!FLAGS_SET(f
, ID128_FORMAT_UUID
))
93 buffer
[SD_ID128_UUID_STRING_MAX
-1] = 0;
100 r
= sd_id128_from_string(buffer
, ret
);
101 return r
== -EINVAL
? -EUCLEAN
: r
;
104 int id128_read(const char *p
, Id128FormatFlag f
, sd_id128_t
*ret
) {
105 _cleanup_close_
int fd
= -EBADF
;
107 fd
= open(p
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
111 return id128_read_fd(fd
, f
, ret
);
114 int id128_write_fd(int fd
, Id128FormatFlag f
, sd_id128_t id
) {
115 char buffer
[SD_ID128_UUID_STRING_MAX
+ 1]; /* +1 is for trailing newline */
120 assert(IN_SET((f
& ID128_FORMAT_ANY
), ID128_FORMAT_PLAIN
, ID128_FORMAT_UUID
));
122 if (FLAGS_SET(f
, ID128_FORMAT_PLAIN
)) {
123 assert_se(sd_id128_to_string(id
, buffer
));
124 sz
= SD_ID128_STRING_MAX
;
126 assert_se(sd_id128_to_uuid_string(id
, buffer
));
127 sz
= SD_ID128_UUID_STRING_MAX
;
130 buffer
[sz
- 1] = '\n';
131 r
= loop_write(fd
, buffer
, sz
, false);
135 if (FLAGS_SET(f
, ID128_SYNC_ON_WRITE
)) {
144 int id128_write(const char *p
, Id128FormatFlag f
, sd_id128_t id
) {
145 _cleanup_close_
int fd
= -EBADF
;
147 fd
= open(p
, O_WRONLY
|O_CREAT
|O_CLOEXEC
|O_NOCTTY
|O_TRUNC
, 0444);
151 return id128_write_fd(fd
, f
, id
);
154 void id128_hash_func(const sd_id128_t
*p
, struct siphash
*state
) {
155 siphash24_compress(p
, sizeof(sd_id128_t
), state
);
158 int id128_compare_func(const sd_id128_t
*a
, const sd_id128_t
*b
) {
159 return memcmp(a
, b
, 16);
162 sd_id128_t
id128_make_v4_uuid(sd_id128_t id
) {
163 /* Stolen from generate_random_uuid() of drivers/char/random.c
164 * in the kernel sources */
166 /* Set UUID version to 4 --- truly random generation */
167 id
.bytes
[6] = (id
.bytes
[6] & 0x0F) | 0x40;
169 /* Set the UUID variant to DCE */
170 id
.bytes
[8] = (id
.bytes
[8] & 0x3F) | 0x80;
175 DEFINE_HASH_OPS(id128_hash_ops
, sd_id128_t
, id128_hash_func
, id128_compare_func
);
177 int id128_get_product(sd_id128_t
*ret
) {
183 /* Reads the systems product UUID from DMI or devicetree (where it is located on POWER). This is
184 * particularly relevant in VM environments, where VM managers typically place a VM uuid there. */
186 r
= id128_read("/sys/class/dmi/id/product_uuid", ID128_FORMAT_UUID
, &uuid
);
188 r
= id128_read("/proc/device-tree/vm,uuid", ID128_FORMAT_UUID
, &uuid
);
192 if (sd_id128_is_null(uuid
) || sd_id128_is_allf(uuid
))
193 return -EADDRNOTAVAIL
; /* Recognizable error */