97 lines
4.1 KiB
C
97 lines
4.1 KiB
C
/* SPDX-License-Identifier: LGPL-2.1+ */
|
|
|
|
#include "macro.h"
|
|
#include "string-util.h"
|
|
#include "unit-file.h"
|
|
|
|
bool unit_type_may_alias(UnitType type) {
|
|
return IN_SET(type,
|
|
UNIT_SERVICE,
|
|
UNIT_SOCKET,
|
|
UNIT_TARGET,
|
|
UNIT_DEVICE,
|
|
UNIT_TIMER,
|
|
UNIT_PATH);
|
|
}
|
|
|
|
bool unit_type_may_template(UnitType type) {
|
|
return IN_SET(type,
|
|
UNIT_SERVICE,
|
|
UNIT_SOCKET,
|
|
UNIT_TARGET,
|
|
UNIT_TIMER,
|
|
UNIT_PATH);
|
|
}
|
|
|
|
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;
|
|
UnitType src_unit_type, dst_unit_type;
|
|
int src_name_type, dst_name_type;
|
|
|
|
/* Check if the *alias* symlink is valid. This applies to symlinks like
|
|
* /etc/systemd/system/dbus.service → dbus-broker.service, but not to .wants or .requires symlinks
|
|
* and such. Neither does this apply to symlinks which *link* units, i.e. symlinks to outside of the
|
|
* unit lookup path.
|
|
*
|
|
* -EINVAL is returned if the something is wrong with the source filename or the source unit type is
|
|
* not allowed to symlink,
|
|
* -EXDEV if the target filename is not a valid unit name or doesn't match the source.
|
|
*/
|
|
|
|
src = basename(filename);
|
|
dst = basename(target);
|
|
|
|
/* src checks */
|
|
|
|
src_name_type = unit_name_to_instance(src, &src_instance);
|
|
if (src_name_type < 0)
|
|
return log_notice_errno(src_name_type,
|
|
"%s: not a valid unit name \"%s\": %m", filename, src);
|
|
|
|
src_unit_type = unit_name_to_type(src);
|
|
assert(src_unit_type >= 0); /* unit_name_to_instance() checked the suffix already */
|
|
|
|
if (!unit_type_may_alias(src_unit_type))
|
|
return log_notice_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
"%s: symlinks are not allowed for units of this type, rejecting.",
|
|
filename);
|
|
|
|
if (src_name_type != UNIT_NAME_PLAIN &&
|
|
!unit_type_may_template(src_unit_type))
|
|
return log_notice_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
"%s: templates not allowed for %s units, rejecting.",
|
|
filename, unit_type_to_string(src_unit_type));
|
|
|
|
/* dst checks */
|
|
|
|
dst_name_type = unit_name_to_instance(dst, &dst_instance);
|
|
if (dst_name_type < 0)
|
|
return log_notice_errno(dst_name_type == -EINVAL ? SYNTHETIC_ERRNO(EXDEV) : dst_name_type,
|
|
"%s points to \"%s\" which is not a valid unit name: %m",
|
|
filename, dst);
|
|
|
|
if (!(dst_name_type == src_name_type ||
|
|
(src_name_type == UNIT_NAME_INSTANCE && dst_name_type == UNIT_NAME_TEMPLATE)))
|
|
return log_notice_errno(SYNTHETIC_ERRNO(EXDEV),
|
|
"%s: symlink target name type \"%s\" does not match source, rejecting.",
|
|
filename, dst);
|
|
|
|
if (dst_name_type == UNIT_NAME_INSTANCE) {
|
|
assert(src_instance);
|
|
assert(dst_instance);
|
|
if (!streq(src_instance, dst_instance))
|
|
return log_notice_errno(SYNTHETIC_ERRNO(EXDEV),
|
|
"%s: unit symlink target \"%s\" instance name doesn't match, rejecting.",
|
|
filename, dst);
|
|
}
|
|
|
|
dst_unit_type = unit_name_to_type(dst);
|
|
if (dst_unit_type != src_unit_type)
|
|
return log_notice_errno(SYNTHETIC_ERRNO(EXDEV),
|
|
"%s: symlink target \"%s\" has incompatible suffix, rejecting.",
|
|
filename, dst);
|
|
|
|
return 0;
|
|
}
|