summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/basic/unit-name.c41
-rw-r--r--src/basic/unit-name.h9
2 files changed, 34 insertions, 16 deletions
diff --git a/src/basic/unit-name.c b/src/basic/unit-name.c
index 8bf28ba749..06ed9054d0 100644
--- a/src/basic/unit-name.c
+++ b/src/basic/unit-name.c
@@ -454,34 +454,45 @@ int unit_name_path_unescape(const char *f, char **ret) {
return 0;
}
-int unit_name_replace_instance(const char *f, const char *i, char **ret) {
+int unit_name_replace_instance_full(
+ const char *original,
+ const char *instance,
+ bool accept_glob,
+ char **ret) {
+
_cleanup_free_ char *s = NULL;
- const char *p, *e;
- size_t a, b;
+ const char *prefix, *suffix;
+ size_t pl;
- assert(f);
- assert(i);
+ assert(original);
+ assert(instance);
assert(ret);
- if (!unit_name_is_valid(f, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE))
+ if (!unit_name_is_valid(original, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE))
return -EINVAL;
- if (!unit_instance_is_valid(i))
+ if (!unit_instance_is_valid(instance) && !(accept_glob && in_charset(instance, VALID_CHARS_GLOB)))
return -EINVAL;
- assert_se(p = strchr(f, '@'));
- assert_se(e = strrchr(f, '.'));
+ prefix = ASSERT_PTR(strchr(original, '@'));
+ suffix = ASSERT_PTR(strrchr(original, '.'));
+ assert(prefix < suffix);
- a = p - f;
- b = strlen(i);
+ pl = prefix - original + 1; /* include '@' */
- s = new(char, a + 1 + b + strlen(e) + 1);
+ s = new(char, pl + strlen(instance) + strlen(suffix) + 1);
if (!s)
return -ENOMEM;
- strcpy(mempcpy(mempcpy(s, f, a + 1), i, b), e);
+#if HAS_FEATURE_MEMORY_SANITIZER
+ /* MSan doesn't like stpncpy... See also https://github.com/google/sanitizers/issues/926 */
+ memzero(s, pl + strlen(instance) + strlen(suffix) + 1);
+#endif
- /* Make sure the resulting name still is valid, i.e. didn't grow too large */
- if (!unit_name_is_valid(s, UNIT_NAME_INSTANCE))
+ strcpy(stpcpy(stpncpy(s, original, pl), instance), suffix);
+
+ /* Make sure the resulting name still is valid, i.e. didn't grow too large. Globs will be expanded
+ * by clients when used, so the check is pointless. */
+ if (!accept_glob && !unit_name_is_valid(s, UNIT_NAME_INSTANCE))
return -EINVAL;
*ret = TAKE_PTR(s);
diff --git a/src/basic/unit-name.h b/src/basic/unit-name.h
index d22d824fbe..fa7295e250 100644
--- a/src/basic/unit-name.h
+++ b/src/basic/unit-name.h
@@ -40,7 +40,14 @@ int unit_name_unescape(const char *f, char **ret);
int unit_name_path_escape(const char *f, char **ret);
int unit_name_path_unescape(const char *f, char **ret);
-int unit_name_replace_instance(const char *f, const char *i, char **ret);
+int unit_name_replace_instance_full(
+ const char *original,
+ const char *instance,
+ bool accept_glob,
+ char **ret);
+static inline int unit_name_replace_instance(const char *original, const char *instance, char **ret) {
+ return unit_name_replace_instance_full(original, instance, false, ret);
+}
int unit_name_template(const char *f, char **ret);