diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index bdbaa9b58c..633873da27 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -2171,6 +2171,11 @@ static int install_error( "Unit %s is transient or generated.", changes[i].path); goto found; + case -ETXTBSY: + r = sd_bus_error_setf(error, BUS_ERROR_UNIT_BAD_PATH, + "File %s is under the systemd unit hierarchy already.", changes[i].path); + goto found; + case -EUCLEAN: r = sd_bus_error_setf(error, BUS_ERROR_BAD_UNIT_SETTING, "\"%s\" is not a valid unit name.", diff --git a/src/libsystemd/sd-bus/bus-common-errors.h b/src/libsystemd/sd-bus/bus-common-errors.h index c3c25d69c3..d4a1fb689e 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.h +++ b/src/libsystemd/sd-bus/bus-common-errors.h @@ -20,6 +20,7 @@ #define BUS_ERROR_UNIT_MASKED "org.freedesktop.systemd1.UnitMasked" #define BUS_ERROR_UNIT_GENERATED "org.freedesktop.systemd1.UnitGenerated" #define BUS_ERROR_UNIT_LINKED "org.freedesktop.systemd1.UnitLinked" +#define BUS_ERROR_UNIT_BAD_PATH "org.freedesktop.systemd1.UnitBadPath" #define BUS_ERROR_JOB_TYPE_NOT_APPLICABLE "org.freedesktop.systemd1.JobTypeNotApplicable" #define BUS_ERROR_NO_ISOLATION "org.freedesktop.systemd1.NoIsolation" #define BUS_ERROR_SHUTTING_DOWN "org.freedesktop.systemd1.ShuttingDown" diff --git a/src/shared/install.c b/src/shared/install.c index cca8b0b0c8..6d91a02f11 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -104,13 +104,19 @@ static int in_search_path(const LookupPaths *lp, const char *path) { _cleanup_free_ char *parent = NULL; int r; - assert(path); + /* Check if 'path' is in lp->search_path. */ - r = path_extract_directory(path, &parent); + r = path_extract_directory(ASSERT_PTR(path), &parent); if (r < 0) return r; - return path_strv_contains(lp->search_path, parent); + return path_strv_contains(ASSERT_PTR(lp)->search_path, parent); +} + +static int underneath_search_path(const LookupPaths *lp, const char *path) { + /* Check if 'path' is underneath lp->search_path. */ + + return !!path_startswith_strv(ASSERT_PTR(path), ASSERT_PTR(lp)->search_path); } static const char* skip_root(const char *root_dir, const char *path) { @@ -390,6 +396,10 @@ void install_changes_dump(int r, const char *verb, const InstallChange *changes, err = log_error_errno(changes[i].type, "Failed to %s unit, unit %s is transient or generated.", verb, changes[i].path); break; + case -ETXTBSY: + err = log_error_errno(changes[i].type, "Failed to %s unit, file %s is under the systemd unit hierarchy already.", + verb, changes[i].path); + break; case -EBADSLT: err = log_error_errno(changes[i].type, "Failed to %s unit, invalid specifier in \"%s\".", verb, changes[i].path); @@ -2425,8 +2435,15 @@ int unit_file_link( if (r < 0) return install_changes_add(changes, n_changes, r, *file, NULL); if (r > 0) + /* A silent noop if the file is already in the search path. */ continue; + r = underneath_search_path(&lp, *file); + if (r > 0) + r = -ETXTBSY; + if (r < 0) + return install_changes_add(changes, n_changes, r, *file, NULL); + if (!GREEDY_REALLOC0(todo, n_todo + 2)) return -ENOMEM;