Merge pull request #13096 from keszybz/unit-loading
Preparatory work for the unit loading rework
This commit is contained in:
@@ -10,6 +10,9 @@ void string_hash_func(const char *p, struct siphash *state) {
|
||||
}
|
||||
|
||||
DEFINE_HASH_OPS(string_hash_ops, char, string_hash_func, string_compare_func);
|
||||
DEFINE_HASH_OPS_FULL(string_hash_ops_free_free,
|
||||
char, string_hash_func, string_compare_func, free,
|
||||
char, free);
|
||||
|
||||
void path_hash_func(const char *q, struct siphash *state) {
|
||||
size_t n;
|
||||
|
||||
@@ -76,6 +76,7 @@ struct hash_ops {
|
||||
void string_hash_func(const char *p, struct siphash *state);
|
||||
#define string_compare_func strcmp
|
||||
extern const struct hash_ops string_hash_ops;
|
||||
extern const struct hash_ops string_hash_ops_free_free;
|
||||
|
||||
void path_hash_func(const char *p, struct siphash *state);
|
||||
int path_compare_func(const char *a, const char *b) _pure_;
|
||||
|
||||
+28
-2
@@ -733,8 +733,8 @@ bool internal_hashmap_iterate(HashmapBase *h, Iterator *i, void **value, const v
|
||||
return true;
|
||||
}
|
||||
|
||||
bool set_iterate(Set *s, Iterator *i, void **value) {
|
||||
return internal_hashmap_iterate(HASHMAP_BASE(s), i, value, NULL);
|
||||
bool set_iterate(const Set *s, Iterator *i, void **value) {
|
||||
return internal_hashmap_iterate(HASHMAP_BASE((Set*) s), i, value, NULL);
|
||||
}
|
||||
|
||||
#define HASHMAP_FOREACH_IDX(idx, h, i) \
|
||||
@@ -1768,6 +1768,32 @@ int set_consume(Set *s, void *value) {
|
||||
return r;
|
||||
}
|
||||
|
||||
int hashmap_put_strdup(Hashmap **h, const char *k, const char *v) {
|
||||
int r;
|
||||
|
||||
r = hashmap_ensure_allocated(h, &string_hash_ops_free_free);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
_cleanup_free_ char *kdup = NULL, *vdup = NULL;
|
||||
kdup = strdup(k);
|
||||
vdup = strdup(v);
|
||||
if (!kdup || !vdup)
|
||||
return -ENOMEM;
|
||||
|
||||
r = hashmap_put(*h, kdup, vdup);
|
||||
if (r < 0) {
|
||||
if (r == -EEXIST && streq(v, hashmap_get(*h, kdup)))
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
assert(r > 0); /* 0 would mean vdup is already in the hashmap, which cannot be */
|
||||
kdup = vdup = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int set_put_strdup(Set *s, const char *p) {
|
||||
char *c;
|
||||
|
||||
|
||||
@@ -147,6 +147,8 @@ static inline int ordered_hashmap_put(OrderedHashmap *h, const void *key, void *
|
||||
return hashmap_put(PLAIN_HASHMAP(h), key, value);
|
||||
}
|
||||
|
||||
int hashmap_put_strdup(Hashmap **h, const char *k, const char *v);
|
||||
|
||||
int hashmap_update(Hashmap *h, const void *key, void *value);
|
||||
static inline int ordered_hashmap_update(OrderedHashmap *h, const void *key, void *value) {
|
||||
return hashmap_update(PLAIN_HASHMAP(h), key, value);
|
||||
|
||||
+58
-46
@@ -207,6 +207,18 @@ int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* path_startswith_strv(const char *p, char **set) {
|
||||
char **s, *t;
|
||||
|
||||
STRV_FOREACH(s, set) {
|
||||
t = path_startswith(p, *s);
|
||||
if (t)
|
||||
return t;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int path_strv_make_absolute_cwd(char **l) {
|
||||
char **s;
|
||||
int r;
|
||||
@@ -382,6 +394,52 @@ char *path_simplify(char *path, bool kill_dots) {
|
||||
return path;
|
||||
}
|
||||
|
||||
int path_simplify_and_warn(
|
||||
char *path,
|
||||
unsigned flag,
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *lvalue) {
|
||||
|
||||
bool fatal = flag & PATH_CHECK_FATAL;
|
||||
|
||||
assert(!FLAGS_SET(flag, PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE));
|
||||
|
||||
if (!utf8_is_valid(path))
|
||||
return log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, path);
|
||||
|
||||
if (flag & (PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE)) {
|
||||
bool absolute;
|
||||
|
||||
absolute = path_is_absolute(path);
|
||||
|
||||
if (!absolute && (flag & PATH_CHECK_ABSOLUTE))
|
||||
return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s= path is not absolute%s: %s",
|
||||
lvalue, fatal ? "" : ", ignoring", path);
|
||||
|
||||
if (absolute && (flag & PATH_CHECK_RELATIVE))
|
||||
return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s= path is absolute%s: %s",
|
||||
lvalue, fatal ? "" : ", ignoring", path);
|
||||
}
|
||||
|
||||
path_simplify(path, true);
|
||||
|
||||
if (!path_is_valid(path))
|
||||
return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s= path has invalid length (%zu bytes)%s.",
|
||||
lvalue, strlen(path), fatal ? "" : ", ignoring");
|
||||
|
||||
if (!path_is_normalized(path))
|
||||
return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s= path is not normalized%s: %s",
|
||||
lvalue, fatal ? "" : ", ignoring", path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* path_startswith(const char *path, const char *prefix) {
|
||||
assert(path);
|
||||
assert(prefix);
|
||||
@@ -1058,49 +1116,3 @@ bool empty_or_root(const char *root) {
|
||||
|
||||
return root[strspn(root, "/")] == 0;
|
||||
}
|
||||
|
||||
int path_simplify_and_warn(
|
||||
char *path,
|
||||
unsigned flag,
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *lvalue) {
|
||||
|
||||
bool fatal = flag & PATH_CHECK_FATAL;
|
||||
|
||||
assert(!FLAGS_SET(flag, PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE));
|
||||
|
||||
if (!utf8_is_valid(path))
|
||||
return log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, path);
|
||||
|
||||
if (flag & (PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE)) {
|
||||
bool absolute;
|
||||
|
||||
absolute = path_is_absolute(path);
|
||||
|
||||
if (!absolute && (flag & PATH_CHECK_ABSOLUTE))
|
||||
return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s= path is not absolute%s: %s",
|
||||
lvalue, fatal ? "" : ", ignoring", path);
|
||||
|
||||
if (absolute && (flag & PATH_CHECK_RELATIVE))
|
||||
return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s= path is absolute%s: %s",
|
||||
lvalue, fatal ? "" : ", ignoring", path);
|
||||
}
|
||||
|
||||
path_simplify(path, true);
|
||||
|
||||
if (!path_is_valid(path))
|
||||
return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s= path has invalid length (%zu bytes)%s.",
|
||||
lvalue, strlen(path), fatal ? "" : ", ignoring");
|
||||
|
||||
if (!path_is_normalized(path))
|
||||
return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s= path is not normalized%s: %s",
|
||||
lvalue, fatal ? "" : ", ignoring", path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+10
-19
@@ -54,6 +54,14 @@ char* path_join_internal(const char *first, ...);
|
||||
|
||||
char* path_simplify(char *path, bool kill_dots);
|
||||
|
||||
enum {
|
||||
PATH_CHECK_FATAL = 1 << 0, /* If not set, then error message is appended with 'ignoring'. */
|
||||
PATH_CHECK_ABSOLUTE = 1 << 1,
|
||||
PATH_CHECK_RELATIVE = 1 << 2,
|
||||
};
|
||||
|
||||
int path_simplify_and_warn(char *path, unsigned flag, const char *unit, const char *filename, unsigned line, const char *lvalue);
|
||||
|
||||
static inline bool path_equal_ptr(const char *a, const char *b) {
|
||||
return !!a == !!b && (!a || path_equal(a, b));
|
||||
}
|
||||
@@ -71,17 +79,8 @@ static inline bool path_equal_ptr(const char *a, const char *b) {
|
||||
_found; \
|
||||
})
|
||||
|
||||
#define PATH_STARTSWITH_SET(p, ...) \
|
||||
({ \
|
||||
const char *_p = (p); \
|
||||
char *_found = NULL, **_i; \
|
||||
STRV_FOREACH(_i, STRV_MAKE(__VA_ARGS__)) { \
|
||||
_found = path_startswith(_p, *_i); \
|
||||
if (_found) \
|
||||
break; \
|
||||
} \
|
||||
_found; \
|
||||
})
|
||||
char* path_startswith_strv(const char *p, char **set);
|
||||
#define PATH_STARTSWITH_SET(p, ...) path_startswith_strv(p, STRV_MAKE(__VA_ARGS__))
|
||||
|
||||
int path_strv_make_absolute_cwd(char **l);
|
||||
char** path_strv_resolve(char **l, const char *root);
|
||||
@@ -178,11 +177,3 @@ bool empty_or_root(const char *root);
|
||||
static inline const char *empty_to_root(const char *path) {
|
||||
return isempty(path) ? "/" : path;
|
||||
}
|
||||
|
||||
enum {
|
||||
PATH_CHECK_FATAL = 1 << 0, /* If not set, then error message is appended with 'ignoring'. */
|
||||
PATH_CHECK_ABSOLUTE = 1 << 1,
|
||||
PATH_CHECK_RELATIVE = 1 << 2,
|
||||
};
|
||||
|
||||
int path_simplify_and_warn(char *path, unsigned flag, const char *unit, const char *filename, unsigned line, const char *lvalue);
|
||||
|
||||
+10
-10
@@ -28,13 +28,13 @@ int internal_set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHM
|
||||
int set_put(Set *s, const void *key);
|
||||
/* no set_update */
|
||||
/* no set_replace */
|
||||
static inline void *set_get(Set *s, void *key) {
|
||||
return internal_hashmap_get(HASHMAP_BASE(s), key);
|
||||
static inline void *set_get(const Set *s, void *key) {
|
||||
return internal_hashmap_get(HASHMAP_BASE((Set *) s), key);
|
||||
}
|
||||
/* no set_get2 */
|
||||
|
||||
static inline bool set_contains(Set *s, const void *key) {
|
||||
return internal_hashmap_contains(HASHMAP_BASE(s), key);
|
||||
static inline bool set_contains(const Set *s, const void *key) {
|
||||
return internal_hashmap_contains(HASHMAP_BASE((Set *) s), key);
|
||||
}
|
||||
|
||||
static inline void *set_remove(Set *s, const void *key) {
|
||||
@@ -59,19 +59,19 @@ static inline int set_move_one(Set *s, Set *other, const void *key) {
|
||||
return internal_hashmap_move_one(HASHMAP_BASE(s), HASHMAP_BASE(other), key);
|
||||
}
|
||||
|
||||
static inline unsigned set_size(Set *s) {
|
||||
return internal_hashmap_size(HASHMAP_BASE(s));
|
||||
static inline unsigned set_size(const Set *s) {
|
||||
return internal_hashmap_size(HASHMAP_BASE((Set *) s));
|
||||
}
|
||||
|
||||
static inline bool set_isempty(Set *s) {
|
||||
static inline bool set_isempty(const Set *s) {
|
||||
return set_size(s) == 0;
|
||||
}
|
||||
|
||||
static inline unsigned set_buckets(Set *s) {
|
||||
return internal_hashmap_buckets(HASHMAP_BASE(s));
|
||||
static inline unsigned set_buckets(const Set *s) {
|
||||
return internal_hashmap_buckets(HASHMAP_BASE((Set *) s));
|
||||
}
|
||||
|
||||
bool set_iterate(Set *s, Iterator *i, void **value);
|
||||
bool set_iterate(const Set *s, Iterator *i, void **value);
|
||||
|
||||
static inline void set_clear(Set *s) {
|
||||
internal_hashmap_clear(HASHMAP_BASE(s), NULL, NULL);
|
||||
|
||||
@@ -889,3 +889,63 @@ int fputstrv(FILE *f, char **l, const char *separator, bool *space) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int string_strv_hashmap_put_internal(Hashmap *h, const char *key, const char *value) {
|
||||
char **l;
|
||||
int r;
|
||||
|
||||
l = hashmap_get(h, key);
|
||||
if (l) {
|
||||
/* A list for this key already exists, let's append to it if it is not listed yet */
|
||||
if (strv_contains(l, value))
|
||||
return 0;
|
||||
|
||||
r = strv_extend(&l, value);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
assert_se(hashmap_update(h, key, l) >= 0);
|
||||
} else {
|
||||
/* No list for this key exists yet, create one */
|
||||
_cleanup_strv_free_ char **l2 = NULL;
|
||||
_cleanup_free_ char *t = NULL;
|
||||
|
||||
t = strdup(key);
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
|
||||
r = strv_extend(&l2, value);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = hashmap_put(h, t, l2);
|
||||
if (r < 0)
|
||||
return r;
|
||||
TAKE_PTR(t);
|
||||
TAKE_PTR(l2);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int string_strv_hashmap_put(Hashmap **h, const char *key, const char *value) {
|
||||
int r;
|
||||
|
||||
r = hashmap_ensure_allocated(h, &string_strv_hash_ops);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return string_strv_hashmap_put_internal(*h, key, value);
|
||||
}
|
||||
|
||||
int string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const char *value) {
|
||||
int r;
|
||||
|
||||
r = ordered_hashmap_ensure_allocated(h, &string_strv_hash_ops);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return string_strv_hashmap_put_internal(PLAIN_HASHMAP(*h), key, value);
|
||||
}
|
||||
|
||||
DEFINE_HASH_OPS_FULL(string_strv_hash_ops, char, string_hash_func, string_compare_func, free, char*, strv_free);
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "extract-word.h"
|
||||
#include "hashmap.h"
|
||||
#include "macro.h"
|
||||
#include "string-util.h"
|
||||
|
||||
@@ -188,3 +189,7 @@ int fputstrv(FILE *f, char **l, const char *separator, bool *space);
|
||||
(b) = NULL; \
|
||||
0; \
|
||||
})
|
||||
|
||||
extern const struct hash_ops string_strv_hash_ops;
|
||||
int string_strv_hashmap_put(Hashmap **h, const char *key, const char *value);
|
||||
int string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const char *value);
|
||||
|
||||
+11
-10
@@ -140,12 +140,10 @@ int unit_name_to_prefix(const char *n, char **ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unit_name_to_instance(const char *n, char **instance) {
|
||||
int unit_name_to_instance(const char *n, char **ret) {
|
||||
const char *p, *d;
|
||||
char *i;
|
||||
|
||||
assert(n);
|
||||
assert(instance);
|
||||
|
||||
if (!unit_name_is_valid(n, UNIT_NAME_ANY))
|
||||
return -EINVAL;
|
||||
@@ -153,8 +151,9 @@ int unit_name_to_instance(const char *n, char **instance) {
|
||||
/* Everything past the first @ and before the last . is the instance */
|
||||
p = strchr(n, '@');
|
||||
if (!p) {
|
||||
*instance = NULL;
|
||||
return 0;
|
||||
if (ret)
|
||||
*ret = NULL;
|
||||
return UNIT_NAME_PLAIN;
|
||||
}
|
||||
|
||||
p++;
|
||||
@@ -163,12 +162,14 @@ int unit_name_to_instance(const char *n, char **instance) {
|
||||
if (!d)
|
||||
return -EINVAL;
|
||||
|
||||
i = strndup(p, d-p);
|
||||
if (!i)
|
||||
return -ENOMEM;
|
||||
if (ret) {
|
||||
char *i = strndup(p, d-p);
|
||||
if (!i)
|
||||
return -ENOMEM;
|
||||
|
||||
*instance = i;
|
||||
return 1;
|
||||
*ret = i;
|
||||
}
|
||||
return d > p ? UNIT_NAME_INSTANCE : UNIT_NAME_TEMPLATE;
|
||||
}
|
||||
|
||||
int unit_name_to_prefix_and_instance(const char *n, char **ret) {
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
|
||||
typedef enum UnitNameFlags {
|
||||
UNIT_NAME_PLAIN = 1 << 0, /* Allow foo.service */
|
||||
UNIT_NAME_INSTANCE = 1 << 1, /* Allow foo@bar.service */
|
||||
UNIT_NAME_TEMPLATE = 1 << 2, /* Allow foo@.service */
|
||||
UNIT_NAME_ANY = UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE,
|
||||
UNIT_NAME_TEMPLATE = 1 << 1, /* Allow foo@.service */
|
||||
UNIT_NAME_INSTANCE = 1 << 2, /* Allow foo@bar.service */
|
||||
UNIT_NAME_ANY = UNIT_NAME_PLAIN|UNIT_NAME_TEMPLATE|UNIT_NAME_INSTANCE,
|
||||
} UnitNameFlags;
|
||||
|
||||
bool unit_name_is_valid(const char *n, UnitNameFlags flags) _pure_;
|
||||
@@ -20,13 +20,11 @@ bool unit_prefix_is_valid(const char *p) _pure_;
|
||||
bool unit_instance_is_valid(const char *i) _pure_;
|
||||
bool unit_suffix_is_valid(const char *s) _pure_;
|
||||
|
||||
static inline int unit_prefix_and_instance_is_valid(const char *p) {
|
||||
/* For prefix+instance and instance the same rules apply */
|
||||
return unit_instance_is_valid(p);
|
||||
int unit_name_to_prefix(const char *n, char **ret);
|
||||
int unit_name_to_instance(const char *n, char **ret);
|
||||
static inline int unit_name_classify(const char *n) {
|
||||
return unit_name_to_instance(n, NULL);
|
||||
}
|
||||
|
||||
int unit_name_to_prefix(const char *n, char **prefix);
|
||||
int unit_name_to_instance(const char *n, char **instance);
|
||||
int unit_name_to_prefix_and_instance(const char *n, char **ret);
|
||||
|
||||
UnitType unit_name_to_type(const char *n) _pure_;
|
||||
|
||||
Reference in New Issue
Block a user