+82
-2
@@ -1703,6 +1703,82 @@ static int install_info_discover_and_check(
|
||||
return install_info_may_process(ret ? *ret : NULL, paths, changes, n_changes);
|
||||
}
|
||||
|
||||
int unit_file_verify_alias(const UnitFileInstallInfo *i, const char *dst, char **ret_dst) {
|
||||
_cleanup_free_ char *dst_updated = NULL;
|
||||
int r;
|
||||
|
||||
/* Verify that dst is a valid either a valid alias or a valid .wants/.requires symlink for the target
|
||||
* unit *i. Return negative on error or if not compatible, zero on success.
|
||||
*
|
||||
* ret_dst is set in cases where "instance propagation" happens, i.e. when the instance part is
|
||||
* inserted into dst. It is not normally set, even on success, so that the caller can easily
|
||||
* distinguish the case where instance propagation occured.
|
||||
*/
|
||||
|
||||
const char *path_alias = strrchr(dst, '/');
|
||||
if (path_alias) {
|
||||
/* This branch covers legacy Alias= function of creating .wants and .requires symlinks. */
|
||||
_cleanup_free_ char *dir = NULL;
|
||||
char *p;
|
||||
|
||||
path_alias ++; /* skip over slash */
|
||||
|
||||
dir = dirname_malloc(dst);
|
||||
if (!dir)
|
||||
return log_oom();
|
||||
|
||||
p = endswith(dir, ".wants");
|
||||
if (!p)
|
||||
p = endswith(dir, ".requires");
|
||||
if (!p)
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EXDEV),
|
||||
"Invalid path \"%s\" in alias.", dir);
|
||||
*p = '\0'; /* dir should now be a unit name */
|
||||
|
||||
r = unit_name_classify(dir);
|
||||
if (r < 0)
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EXDEV),
|
||||
"Invalid unit name component \"%s\" in alias.", dir);
|
||||
|
||||
const bool instance_propagation = r == UNIT_NAME_TEMPLATE;
|
||||
|
||||
/* That's the name we want to use for verification. */
|
||||
r = unit_symlink_name_compatible(path_alias, i->name, instance_propagation);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to verify alias validity: %m");
|
||||
if (r == 0)
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EXDEV),
|
||||
"Invalid unit %s symlink %s.",
|
||||
i->name, dst);
|
||||
|
||||
} else {
|
||||
/* If the symlink target has an instance set and the symlink source doesn't, we "propagate
|
||||
* the instance", i.e. instantiate the symlink source with the target instance. */
|
||||
if (unit_name_is_valid(dst, UNIT_NAME_TEMPLATE)) {
|
||||
_cleanup_free_ char *inst = NULL;
|
||||
|
||||
r = unit_name_to_instance(i->name, &inst);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to extract instance name from %s: %m", i->name);
|
||||
|
||||
if (r == UNIT_NAME_INSTANCE) {
|
||||
r = unit_name_replace_instance(dst, inst, &dst_updated);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to build unit name from %s+%s: %m",
|
||||
dst, inst);
|
||||
}
|
||||
}
|
||||
|
||||
r = unit_validate_alias_symlink_and_warn(dst_updated ?: dst, i->name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
*ret_dst = TAKE_PTR(dst_updated);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int install_info_symlink_alias(
|
||||
UnitFileInstallInfo *i,
|
||||
const LookupPaths *paths,
|
||||
@@ -1719,13 +1795,17 @@ static int install_info_symlink_alias(
|
||||
assert(config_path);
|
||||
|
||||
STRV_FOREACH(s, i->aliases) {
|
||||
_cleanup_free_ char *alias_path = NULL, *dst = NULL;
|
||||
_cleanup_free_ char *alias_path = NULL, *dst = NULL, *dst_updated = NULL;
|
||||
|
||||
q = install_full_printf(i, *s, &dst);
|
||||
if (q < 0)
|
||||
return q;
|
||||
|
||||
alias_path = path_make_absolute(dst, config_path);
|
||||
q = unit_file_verify_alias(i, dst, &dst_updated);
|
||||
if (q < 0)
|
||||
continue;
|
||||
|
||||
alias_path = path_make_absolute(dst_updated ?: dst, config_path);
|
||||
if (!alias_path)
|
||||
return -ENOMEM;
|
||||
|
||||
|
||||
@@ -187,6 +187,8 @@ int unit_file_changes_add(UnitFileChange **changes, size_t *n_changes, UnitFileC
|
||||
void unit_file_changes_free(UnitFileChange *changes, size_t n_changes);
|
||||
void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *changes, size_t n_changes, bool quiet);
|
||||
|
||||
int unit_file_verify_alias(const UnitFileInstallInfo *i, const char *dst, char **ret_dst);
|
||||
|
||||
int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name);
|
||||
|
||||
const char *unit_file_state_to_string(UnitFileState s) _const_;
|
||||
|
||||
@@ -31,6 +31,41 @@ bool unit_type_may_template(UnitType type) {
|
||||
UNIT_PATH);
|
||||
}
|
||||
|
||||
int unit_symlink_name_compatible(const char *symlink, const char *target, bool instance_propagation) {
|
||||
_cleanup_free_ char *template = NULL;
|
||||
int r, un_type1, un_type2;
|
||||
|
||||
un_type1 = unit_name_classify(symlink);
|
||||
|
||||
/* The straightforward case: the symlink name matches the target and we have a valid unit */
|
||||
if (streq(symlink, target) &&
|
||||
(un_type1 & (UNIT_NAME_PLAIN | UNIT_NAME_INSTANCE)))
|
||||
return 1;
|
||||
|
||||
r = unit_name_template(symlink, &template);
|
||||
if (r == -EINVAL)
|
||||
return 0; /* Not a template */
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
un_type2 = unit_name_classify(target);
|
||||
|
||||
/* An instance name points to a target that is just the template name */
|
||||
if (un_type1 == UNIT_NAME_INSTANCE &&
|
||||
un_type2 == UNIT_NAME_TEMPLATE &&
|
||||
streq(template, target))
|
||||
return 1;
|
||||
|
||||
/* foo@.target.requires/bar@.service: instance will be propagated */
|
||||
if (instance_propagation &&
|
||||
un_type1 == UNIT_NAME_TEMPLATE &&
|
||||
un_type2 == UNIT_NAME_TEMPLATE &&
|
||||
streq(template, target))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unit_validate_alias_symlink_and_warn(const char *filename, const char *target) {
|
||||
const char *src, *dst;
|
||||
_cleanup_free_ char *src_instance = NULL, *dst_instance = NULL;
|
||||
|
||||
@@ -39,6 +39,7 @@ enum UnitFileScope {
|
||||
bool unit_type_may_alias(UnitType type) _const_;
|
||||
bool unit_type_may_template(UnitType type) _const_;
|
||||
|
||||
int unit_symlink_name_compatible(const char *symlink, const char *target, bool instance_propagation);
|
||||
int unit_validate_alias_symlink_and_warn(const char *filename, const char *target);
|
||||
|
||||
int unit_file_build_name_map(
|
||||
|
||||
Reference in New Issue
Block a user