diff options
author | Michal Sekletar <msekleta@redhat.com> | 2022-03-15 19:02:05 +0100 |
---|---|---|
committer | Michal Sekletar <msekleta@redhat.com> | 2022-04-08 15:18:24 +0200 |
commit | 1d0727e76fd5e9a07cc9991ec9a10ea1d78a99c7 (patch) | |
tree | 210e5a04fccf5b7ececb91916d64502578d31cba /src/basic/unit-name.c | |
parent | Merge pull request #22803 from medhefgo/boot-cflags (diff) | |
download | systemd-1d0727e76fd5e9a07cc9991ec9a10ea1d78a99c7.tar.xz systemd-1d0727e76fd5e9a07cc9991ec9a10ea1d78a99c7.zip |
core: shorten long unit names that are based on paths and append path hash at the end
Fixes #18077
Diffstat (limited to 'src/basic/unit-name.c')
-rw-r--r-- | src/basic/unit-name.c | 86 |
1 files changed, 84 insertions, 2 deletions
diff --git a/src/basic/unit-name.c b/src/basic/unit-name.c index 0a4843f458..3b739c758a 100644 --- a/src/basic/unit-name.c +++ b/src/basic/unit-name.c @@ -5,12 +5,17 @@ #include <stdint.h> #include <stdlib.h> +#include "sd-id128.h" + #include "alloc-util.h" #include "glob-util.h" #include "hexdecoct.h" #include "memory-util.h" #include "path-util.h" +#include "random-util.h" +#include "sparse-endian.h" #include "special.h" +#include "stdio-util.h" #include "string-util.h" #include "strv.h" #include "unit-name.h" @@ -31,6 +36,9 @@ VALID_CHARS_WITH_AT \ "[]!-*?" +#define LONG_UNIT_NAME_HASH_KEY SD_ID128_MAKE(ec,f2,37,fb,58,32,4a,32,84,9f,06,9b,0d,21,eb,9a) +#define UNIT_NAME_HASH_LENGTH_CHARS 16 + bool unit_name_is_valid(const char *n, UnitNameFlags flags) { const char *e, *i, *at; @@ -507,6 +515,68 @@ int unit_name_template(const char *f, char **ret) { return 0; } +bool unit_name_is_hashed(const char *name) { + char *s; + + if (!unit_name_is_valid(name, UNIT_NAME_PLAIN)) + return false; + + assert_se(s = strrchr(name, '.')); + + if (s - name < UNIT_NAME_HASH_LENGTH_CHARS + 1) + return false; + + s -= UNIT_NAME_HASH_LENGTH_CHARS; + if (s[-1] != '_') + return false; + + for (size_t i = 0; i < UNIT_NAME_HASH_LENGTH_CHARS; i++) + if (!strchr(LOWERCASE_HEXDIGITS, s[i])) + return false; + + return true; +} + +int unit_name_hash_long(const char *name, char **ret) { + _cleanup_free_ char *n = NULL, *hash = NULL; + char *suffix; + le64_t h; + size_t len; + + if (strlen(name) < UNIT_NAME_MAX) + return -EMSGSIZE; + + suffix = strrchr(name, '.'); + if (!suffix) + return -EINVAL; + + if (unit_type_from_string(suffix+1) < 0) + return -EINVAL; + + h = htole64(siphash24_string(name, LONG_UNIT_NAME_HASH_KEY.bytes)); + + hash = hexmem(&h, sizeof(h)); + if (!hash) + return -ENOMEM; + + assert_se(strlen(hash) == UNIT_NAME_HASH_LENGTH_CHARS); + + len = UNIT_NAME_MAX - 1 - strlen(suffix+1) - UNIT_NAME_HASH_LENGTH_CHARS - 2; + assert(len > 0 && len < UNIT_NAME_MAX); + + n = strndup(name, len); + if (!n) + return -ENOMEM; + + if (!strextend(&n, "_", hash, suffix)) + return -ENOMEM; + assert_se(unit_name_is_valid(n, UNIT_NAME_PLAIN)); + + *ret = TAKE_PTR(n); + + return 0; +} + int unit_name_from_path(const char *path, const char *suffix, char **ret) { _cleanup_free_ char *p = NULL, *s = NULL; int r; @@ -526,8 +596,17 @@ int unit_name_from_path(const char *path, const char *suffix, char **ret) { if (!s) return -ENOMEM; - if (strlen(s) >= UNIT_NAME_MAX) /* Return a slightly more descriptive error for this specific condition */ - return -ENAMETOOLONG; + if (strlen(s) >= UNIT_NAME_MAX) { + _cleanup_free_ char *n = NULL; + + log_debug("Unit name \"%s\" too long, falling back to hashed unit name.", s); + + r = unit_name_hash_long(s, &n); + if (r < 0) + return r; + + free_and_replace(s, n); + } /* Refuse if this for some other reason didn't result in a valid name */ if (!unit_name_is_valid(s, UNIT_NAME_PLAIN)) @@ -581,6 +660,9 @@ int unit_name_to_path(const char *name, char **ret) { if (r < 0) return r; + if (unit_name_is_hashed(name)) + return -ENAMETOOLONG; + return unit_name_path_unescape(prefix, ret); } |