summaryrefslogtreecommitdiffstats
path: root/src/basic/unit-name.c
diff options
context:
space:
mode:
authorMichal Sekletar <msekleta@redhat.com>2022-03-15 19:02:05 +0100
committerMichal Sekletar <msekleta@redhat.com>2022-04-08 15:18:24 +0200
commit1d0727e76fd5e9a07cc9991ec9a10ea1d78a99c7 (patch)
tree210e5a04fccf5b7ececb91916d64502578d31cba /src/basic/unit-name.c
parentMerge pull request #22803 from medhefgo/boot-cflags (diff)
downloadsystemd-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.c86
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);
}