diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 8d3758ac7e..c2067c099a 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -1598,11 +1598,13 @@ static int reply_unit_file_changes_and_free( unsigned i; int r; - if (n_changes > 0) { - r = bus_foreach_bus(m, NULL, send_unit_files_changed, NULL); - if (r < 0) - log_debug_errno(r, "Failed to send UnitFilesChanged signal: %m"); - } + for (i = 0; i < n_changes; i++) + if (unit_file_change_is_modification(changes[i].type)) { + r = bus_foreach_bus(m, NULL, send_unit_files_changed, NULL); + if (r < 0) + log_debug_errno(r, "Failed to send UnitFilesChanged signal: %m"); + break; + } r = sd_bus_message_new_method_return(message, &reply); if (r < 0) diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c index 9d70798cda..d357760870 100644 --- a/src/libsystemd/sd-bus/bus-util.c +++ b/src/libsystemd/sd-bus/bus-util.c @@ -1893,11 +1893,19 @@ int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, Un if (!quiet) { if (streq(type, "symlink")) log_info("Created symlink from %s to %s.", path, source); - else + else if (streq(type, "unlink")) log_info("Removed symlink %s.", path); + else if (streq(type, "masked")) + log_info("Unit %s is masked, ignoring.", path); + else if (streq(type, "dangling")) + log_info("Unit %s is an alias to a unit that is not present, ignoring.", path); + else + log_notice("Manager reported unknown change type \"%s\" for %s.", type, path); } - r = unit_file_changes_add(changes, n_changes, streq(type, "symlink") ? UNIT_FILE_SYMLINK : UNIT_FILE_UNLINK, path, source); + r = unit_file_changes_add(changes, n_changes, + unit_file_change_type_from_string(type), + path, source); if (r < 0) return r; } diff --git a/src/shared/install.c b/src/shared/install.c index ab86cd1453..f01a212620 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -1253,12 +1253,15 @@ static int install_info_traverse( if (r < 0) return r; + /* Try again, with the new target we found. */ r = unit_file_search(c, i, paths, root_dir, flags); - if (r < 0) - return r; + if (r == -ENOENT) + /* Translate error code to highlight this specific case */ + return -ENOLINK; } - /* Try again, with the new target we found. */ + if (r < 0) + return r; } if (ret) @@ -1528,7 +1531,9 @@ static int install_context_mark_for_removal( return r; r = install_info_traverse(scope, c, root_dir, paths, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL); - if (r < 0) + if (r == -ENOLINK) + return 0; + else if (r < 0) return r; if (i->type != UNIT_FILE_TYPE_REGULAR) @@ -2265,12 +2270,20 @@ static int preset_prepare_one( const char *name) { InstallInfo *i; + _cleanup_(install_context_done) InstallContext tmp = {}; int r; - if (install_info_find(plus, name) || - install_info_find(minus, name)) + if (install_info_find(plus, name) || install_info_find(minus, name)) return 0; + r = install_info_discover(scope, &tmp, root_dir, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); + if (r < 0) + return r; + if (!streq(name, i->name)) { + log_debug("Skipping %s because is an alias for %s", name, i->name); + return 0; + } + r = unit_file_query_preset(scope, root_dir, name); if (r < 0) return r; @@ -2402,6 +2415,12 @@ int unit_file_preset_all( continue; r = preset_prepare_one(scope, &plus, &minus, &paths, root_dir, mode, de->d_name); + if (r == -ESHUTDOWN) + r = unit_file_changes_add(changes, n_changes, + UNIT_FILE_IS_MASKED, de->d_name, NULL); + else if (r == -ENOLINK) + r = unit_file_changes_add(changes, n_changes, + UNIT_FILE_IS_DANGLING, de->d_name, NULL); if (r < 0) return r; } @@ -2535,6 +2554,8 @@ DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState); static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = { [UNIT_FILE_SYMLINK] = "symlink", [UNIT_FILE_UNLINK] = "unlink", + [UNIT_FILE_IS_MASKED] = "masked", + [UNIT_FILE_IS_DANGLING] = "dangling", }; DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType); diff --git a/src/shared/install.h b/src/shared/install.h index 87a40b67c1..7e40445d36 100644 --- a/src/shared/install.h +++ b/src/shared/install.h @@ -60,10 +60,16 @@ typedef enum UnitFilePresetMode { typedef enum UnitFileChangeType { UNIT_FILE_SYMLINK, UNIT_FILE_UNLINK, + UNIT_FILE_IS_MASKED, + UNIT_FILE_IS_DANGLING, _UNIT_FILE_CHANGE_TYPE_MAX, _UNIT_FILE_CHANGE_TYPE_INVALID = -1 } UnitFileChangeType; +static inline bool unit_file_change_is_modification(UnitFileChangeType type) { + return IN_SET(type, UNIT_FILE_SYMLINK, UNIT_FILE_UNLINK); +} + typedef struct UnitFileChange { UnitFileChangeType type; char *path; diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index e854508d9d..0644784a55 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -1944,12 +1944,23 @@ static void dump_unit_file_changes(const UnitFileChange *changes, unsigned n_cha assert(changes || n_changes == 0); - for (i = 0; i < n_changes; i++) { - if (changes[i].type == UNIT_FILE_SYMLINK) - log_info("Created symlink from %s to %s.", changes[i].path, changes[i].source); - else - log_info("Removed symlink %s.", changes[i].path); - } + for (i = 0; i < n_changes; i++) + switch(changes[i].type) { + case UNIT_FILE_SYMLINK: + log_info("Created symlink %s, pointing to %s.", changes[i].path, changes[i].source); + break; + case UNIT_FILE_UNLINK: + log_info("Removed %s.", changes[i].path); + break; + case UNIT_FILE_IS_MASKED: + log_info("Unit %s is masked, ignoring.", changes[i].path); + break; + case UNIT_FILE_IS_DANGLING: + log_info("Unit %s is an alias to a unit that is not present, ignoring.", changes[i].path); + break; + default: + assert_not_reached("bad change type"); + } } static int set_default(sd_bus *bus, char **args) {