]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/libsystemd/sd-id128/id128-util.c
tree-wide: "<n>bit" → "<n>-bit"
[thirdparty/systemd.git] / src / libsystemd / sd-id128 / id128-util.c
index e4a3bbd3ebe5b73085ea3c34b1f91da058a309da..ee9e91c58d5f9e927dd9570008abc5abca440f7a 100644 (file)
@@ -5,6 +5,7 @@
 #include <unistd.h>
 
 #include "fd-util.h"
+#include "fs-util.h"
 #include "hexdecoct.h"
 #include "id128-util.h"
 #include "io-util.h"
 #include "sync-util.h"
 
 bool id128_is_valid(const char *s) {
-        size_t i, l;
+        size_t l;
 
         assert(s);
 
         l = strlen(s);
-        if (l == 32) {
 
-                /* Plain formatted 128bit hex string */
-
-                for (i = 0; i < l; i++) {
-                        char c = s[i];
-
-                        if (!(c >= '0' && c <= '9') &&
-                            !(c >= 'a' && c <= 'z') &&
-                            !(c >= 'A' && c <= 'Z'))
-                                return false;
-                }
-
-        } else if (l == 36) {
+        if (l == SD_ID128_STRING_MAX - 1)
+                /* Plain formatted 128-bit hex string */
+                return in_charset(s, HEXDIGITS);
 
+        if (l == SD_ID128_UUID_STRING_MAX - 1) {
                 /* Formatted UUID */
-
-                for (i = 0; i < l; i++) {
+                for (size_t i = 0; i < l; i++) {
                         char c = s[i];
 
                         if (IN_SET(i, 8, 13, 18, 23)) {
                                 if (c != '-')
                                         return false;
-                        } else {
-                                if (!(c >= '0' && c <= '9') &&
-                                    !(c >= 'a' && c <= 'z') &&
-                                    !(c >= 'A' && c <= 'Z'))
-                                        return false;
-                        }
+                        } else if (!ascii_ishex(c))
+                                return false;
                 }
+                return true;
+        }
 
-        } else
-                return false;
-
-        return true;
+        return false;
 }
 
-int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) {
-        char buffer[36 + 2];
+int id128_read_fd(int fd, Id128Flag f, sd_id128_t *ret) {
+        char buffer[SD_ID128_UUID_STRING_MAX + 1]; /* +1 is for trailing newline */
+        sd_id128_t id;
         ssize_t l;
+        int r;
 
         assert(fd >= 0);
-        assert(f < _ID128_FORMAT_MAX);
 
-        /* Reads an 128bit ID from a file, which may either be in plain format (32 hex digits), or in UUID format, both
+        /* Reads an 128-bit ID from a file, which may either be in plain format (32 hex digits), or in UUID format, both
          * optionally followed by a newline and nothing else. ID files should really be newline terminated, but if they
          * aren't that's OK too, following the rule of "Be conservative in what you send, be liberal in what you
-         * accept". */
+         * accept".
+         *
+         * This returns the following:
+         *     -ENOMEDIUM: an empty string,
+         *     -ENOPKG:    "uninitialized" or "uninitialized\n",
+         *     -EUCLEAN:   other invalid strings. */
 
         l = loop_read(fd, buffer, sizeof(buffer), false); /* we expect a short read of either 32/33 or 36/37 chars */
         if (l < 0)
@@ -75,75 +67,90 @@ int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) {
 
         switch (l) {
 
-        case 13:
-        case 14:
-                /* Treat an "uninitialized" id file like an empty one */
-                return f == ID128_PLAIN_OR_UNINIT && strneq(buffer, "uninitialized\n", l) ? -ENOMEDIUM : -EINVAL;
+        case STRLEN("uninitialized"):
+        case STRLEN("uninitialized\n"):
+                return strneq(buffer, "uninitialized\n", l) ? -ENOPKG : -EINVAL;
 
-        case 33: /* plain UUID with trailing newline */
-                if (buffer[32] != '\n')
-                        return -EINVAL;
+        case SD_ID128_STRING_MAX: /* plain UUID with trailing newline */
+                if (buffer[SD_ID128_STRING_MAX-1] != '\n')
+                        return -EUCLEAN;
 
                 _fallthrough_;
-        case 32: /* plain UUID without trailing newline */
-                if (f == ID128_UUID)
-                        return -EINVAL;
+        case SD_ID128_STRING_MAX-1: /* plain UUID without trailing newline */
+                if (!FLAGS_SET(f, ID128_FORMAT_PLAIN))
+                        return -EUCLEAN;
 
-                buffer[32] = 0;
+                buffer[SD_ID128_STRING_MAX-1] = 0;
                 break;
 
-        case 37: /* RFC UUID with trailing newline */
-                if (buffer[36] != '\n')
-                        return -EINVAL;
+        case SD_ID128_UUID_STRING_MAX: /* RFC UUID with trailing newline */
+                if (buffer[SD_ID128_UUID_STRING_MAX-1] != '\n')
+                        return -EUCLEAN;
 
                 _fallthrough_;
-        case 36: /* RFC UUID without trailing newline */
-                if (IN_SET(f, ID128_PLAIN, ID128_PLAIN_OR_UNINIT))
-                        return -EINVAL;
+        case SD_ID128_UUID_STRING_MAX-1: /* RFC UUID without trailing newline */
+                if (!FLAGS_SET(f, ID128_FORMAT_UUID))
+                        return -EUCLEAN;
 
-                buffer[36] = 0;
+                buffer[SD_ID128_UUID_STRING_MAX-1] = 0;
                 break;
 
         default:
-                return -EINVAL;
+                return -EUCLEAN;
         }
 
-        return sd_id128_from_string(buffer, ret);
+        r = sd_id128_from_string(buffer, &id);
+        if (r == -EINVAL)
+                return -EUCLEAN;
+        if (r < 0)
+                return r;
+
+        if (FLAGS_SET(f, ID128_REFUSE_NULL) && sd_id128_is_null(id))
+                return -ENOMEDIUM;
+
+        if (ret)
+                *ret = id;
+        return 0;
 }
 
-int id128_read(const char *p, Id128Format f, sd_id128_t *ret) {
-        _cleanup_close_ int fd = -1;
+int id128_read_at(int dir_fd, const char *path, Id128Flag f, sd_id128_t *ret) {
+        _cleanup_close_ int fd = -EBADF;
 
-        fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY);
+        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
+        assert(path);
+
+        fd = xopenat(dir_fd, path, O_RDONLY|O_CLOEXEC|O_NOCTTY, /* xopen_flags = */ 0, /* mode = */ 0);
         if (fd < 0)
-                return -errno;
+                return fd;
 
         return id128_read_fd(fd, f, ret);
 }
 
-int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync) {
-        char buffer[36 + 2];
+int id128_write_fd(int fd, Id128Flag f, sd_id128_t id) {
+        char buffer[SD_ID128_UUID_STRING_MAX + 1]; /* +1 is for trailing newline */
         size_t sz;
         int r;
 
         assert(fd >= 0);
-        assert(f < _ID128_FORMAT_MAX);
+        assert(IN_SET((f & ID128_FORMAT_ANY), ID128_FORMAT_PLAIN, ID128_FORMAT_UUID));
+
+        if (FLAGS_SET(f, ID128_REFUSE_NULL) && sd_id128_is_null(id))
+                return -ENOMEDIUM;
 
-        if (f != ID128_UUID) {
+        if (FLAGS_SET(f, ID128_FORMAT_PLAIN)) {
                 assert_se(sd_id128_to_string(id, buffer));
-                buffer[SD_ID128_STRING_MAX - 1] = '\n';
                 sz = SD_ID128_STRING_MAX;
         } else {
                 assert_se(sd_id128_to_uuid_string(id, buffer));
-                buffer[SD_ID128_UUID_STRING_MAX - 1] = '\n';
                 sz = SD_ID128_UUID_STRING_MAX;
         }
 
+        buffer[sz - 1] = '\n';
         r = loop_write(fd, buffer, sz, false);
         if (r < 0)
                 return r;
 
-        if (do_sync) {
+        if (FLAGS_SET(f, ID128_SYNC_ON_WRITE)) {
                 r = fsync_full(fd);
                 if (r < 0)
                         return r;
@@ -152,14 +159,17 @@ int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync) {
         return 0;
 }
 
-int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync) {
-        _cleanup_close_ int fd = -1;
+int id128_write_at(int dir_fd, const char *path, Id128Flag f, sd_id128_t id) {
+        _cleanup_close_ int fd = -EBADF;
+
+        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
+        assert(path);
 
-        fd = open(p, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_TRUNC, 0444);
+        fd = xopenat(dir_fd, path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_TRUNC, /* xopen_flags = */ 0, 0444);
         if (fd < 0)
-                return -errno;
+                return fd;
 
-        return id128_write_fd(fd, f, id, do_sync);
+        return id128_write_fd(fd, f, id);
 }
 
 void id128_hash_func(const sd_id128_t *p, struct siphash *state) {
@@ -184,6 +194,7 @@ sd_id128_t id128_make_v4_uuid(sd_id128_t id) {
 }
 
 DEFINE_HASH_OPS(id128_hash_ops, sd_id128_t, id128_hash_func, id128_compare_func);
+DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(id128_hash_ops_free, sd_id128_t, id128_hash_func, id128_compare_func, free);
 
 int id128_get_product(sd_id128_t *ret) {
         sd_id128_t uuid;
@@ -194,9 +205,9 @@ int id128_get_product(sd_id128_t *ret) {
         /* Reads the systems product UUID from DMI or devicetree (where it is located on POWER). This is
          * particularly relevant in VM environments, where VM managers typically place a VM uuid there. */
 
-        r = id128_read("/sys/class/dmi/id/product_uuid", ID128_UUID, &uuid);
+        r = id128_read("/sys/class/dmi/id/product_uuid", ID128_FORMAT_UUID, &uuid);
         if (r == -ENOENT)
-                r = id128_read("/proc/device-tree/vm,uuid", ID128_UUID, &uuid);
+                r = id128_read("/proc/device-tree/vm,uuid", ID128_FORMAT_UUID, &uuid);
         if (r < 0)
                 return r;
 
@@ -206,19 +217,3 @@ int id128_get_product(sd_id128_t *ret) {
         *ret = uuid;
         return 0;
 }
-
-int id128_equal_string(const char *s, sd_id128_t id) {
-        sd_id128_t parsed;
-        int r;
-
-        if (!s)
-                return false;
-
-        /* Checks if the specified string matches a valid string representation of the specified 128 bit ID/uuid */
-
-        r = sd_id128_from_string(s, &parsed);
-        if (r < 0)
-                return r;
-
-        return sd_id128_equal(parsed, id);
-}