diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 783ce31b3d..2f485f810d 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -10,6 +10,7 @@ #include "cgroup-setup.h" #include "cgroup-util.h" #include "condition.h" +#include "constants.h" #include "coredump-util.h" #include "cpu-set-util.h" #include "dissect-image.h" @@ -2937,3 +2938,89 @@ int bus_service_manager_reload(sd_bus *bus) { return 0; } + +int unit_freezer_new(const char *name, UnitFreezer *ret) { + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + _cleanup_free_ char *namedup = NULL; + int r; + + assert(name); + assert(ret); + + namedup = strdup(name); + if (!namedup) + return log_oom_debug(); + + r = bus_connect_system_systemd(&bus); + if (r < 0) + return log_debug_errno(r, "Failed to open connection to systemd: %m"); + + (void) sd_bus_set_method_call_timeout(bus, FREEZE_TIMEOUT); + + *ret = (UnitFreezer) { + .name = TAKE_PTR(namedup), + .bus = TAKE_PTR(bus), + }; + return 0; +} + +static int unit_freezer_action(bool freeze, UnitFreezer *f) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + assert(f); + assert(f->bus); + assert(f->name); + + r = bus_call_method(f->bus, bus_systemd_mgr, freeze ? "FreezeUnit" : "ThawUnit", + &error, NULL, "s", f->name); + if (r < 0) + return log_debug_errno(r, "Failed to %s unit %s: %s", freeze ? "freeze" : "thaw", + f->name, bus_error_message(&error, r)); + + return 0; +} + +int unit_freezer_freeze(UnitFreezer *f) { + return unit_freezer_action(true, f); +} + +int unit_freezer_thaw(UnitFreezer *f) { + return unit_freezer_action(false, f); +} + +void unit_freezer_done(UnitFreezer *f) { + assert(f); + + f->name = mfree(f->name); + f->bus = sd_bus_flush_close_unref(f->bus); +} + +int unit_freezer_new_freeze(const char *name, UnitFreezer *ret) { + _cleanup_(unit_freezer_done) UnitFreezer f = {}; + int r; + + assert(name); + assert(ret); + + r = unit_freezer_new(name, &f); + if (r < 0) + return r; + + r = unit_freezer_freeze(&f); + if (r < 0) + return r; + + *ret = TAKE_STRUCT(f); + return 0; +} + +void unit_freezer_done_thaw(UnitFreezer *f) { + assert(f); + + if (!f->name) + return; + + (void) unit_freezer_thaw(f); + unit_freezer_done(f); +} diff --git a/src/shared/bus-unit-util.h b/src/shared/bus-unit-util.h index d52c8475ca..3c6a001069 100644 --- a/src/shared/bus-unit-util.h +++ b/src/shared/bus-unit-util.h @@ -35,3 +35,20 @@ int unit_load_state(sd_bus *bus, const char *name, char **load_state); int unit_info_compare(const UnitInfo *a, const UnitInfo *b); int bus_service_manager_reload(sd_bus *bus); + +typedef struct UnitFreezer { + char *name; + sd_bus *bus; +} UnitFreezer; + +int unit_freezer_new(const char *name, UnitFreezer *ret); + +int unit_freezer_freeze(UnitFreezer *freezer); + +int unit_freezer_thaw(UnitFreezer *freezer); + +void unit_freezer_done(UnitFreezer *freezer); + +int unit_freezer_new_freeze(const char *name, UnitFreezer *ret); + +void unit_freezer_done_thaw(UnitFreezer *freezer);