#include #include #include #include #include "main.h" #include "server.h" #include "systemd.h" #include "config.h" void systemd_delete() { assert_return_silent(cfg->sd_bus); sd_bus_unref(cfg->sd_bus); cfg->sd_bus = NULL; } static sd_bus *get_bus() { int r; if (cfg->sd_bus_failed) return NULL; if (!cfg->sd_bus) { r = sd_bus_open_user(&cfg->sd_bus); if (r < 0) { error("failed to connect to user system bus: %s", strerror(-r)); cfg->sd_bus_failed = true; return NULL; } } return cfg->sd_bus; } /* * Check if a systemd service is running. * * This is equivalent to (assuming service mc@world1): * gdbus call --session * --dest org.freedesktop.systemd1 * --object-path /org/freedesktop/systemd1/unit/mc_40world1_2eservice * --method org.freedesktop.DBus.Properties.Get * "org.freedesktop.systemd1.Unit" * "ActiveState" */ bool systemd_service_running(struct server *server) { sd_bus *bus = get_bus(); sd_bus_error error = SD_BUS_ERROR_NULL; char *status = NULL; bool running = false; int r; assert_return(server && bus && server->scfg.systemd_service && server->scfg.systemd_obj, false); again: r = sd_bus_get_property_string(bus, SYSTEMD_DBUS_SERVICE, server->scfg.systemd_obj, SYSTEMD_DBUS_INTERFACE, "ActiveState", &error, &status); if (r < 0) { if (sd_bus_error_get_errno(&error) == EINTR) goto again; error("failed to get status for service %s (%s): %s", server->scfg.systemd_service, server->scfg.systemd_obj, error.message); goto out; } if (streq(status, "active")) { running = true; debug(DBG_SYSD, "systemd service %s (%s) is active", server->scfg.systemd_service, server->scfg.systemd_obj); } else debug(DBG_SYSD, "systemd service %s (%s) is not active", server->scfg.systemd_service, server->scfg.systemd_obj); out: free(status); sd_bus_error_free(&error); return running; } static bool systemd_service_action(struct server *server, const char *action) { sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus_message *m = NULL; sd_bus *bus = get_bus(); const char *path; bool performed = false; int r; assert_return(server && bus && server->scfg.systemd_service && server->scfg.systemd_obj && action, false); again: r = sd_bus_call_method(bus, SYSTEMD_DBUS_SERVICE, server->scfg.systemd_obj, SYSTEMD_DBUS_INTERFACE, action, &error, &m, "s", "fail"); if (r < 0) { if (sd_bus_error_get_errno(&error) == EINTR) goto again; error("failed to perform action %s on systemd service %s: %s", action, server->scfg.systemd_service, error.message); goto out; } r = sd_bus_message_read(m, "o", &path); if (r < 0) { error("failed to parse response message: %s", strerror(-r)); goto out; } verbose("action %s queued for service %s", action, server->scfg.systemd_service); performed = true; out: sd_bus_error_free(&error); sd_bus_message_unref(m); return performed; } /* * Stop systemd service. * * This is equivalent to (assuming service mc@world1): * gdbus call --session * --dest org.freedesktop.systemd1 * --object-path /org/freedesktop/systemd1/unit/mc_40world1_2eservice * --method org.freedesktop.systemd1.Unit.Stop "fail" */ bool systemd_service_stop(struct server *server) { assert_return(server, false); return systemd_service_action(server, "Stop"); } /* * Start systemd service. * * This is equivalent to (assuming service mc@world1): * gdbus call --session * --dest org.freedesktop.systemd1 * --object-path /org/freedesktop/systemd1/unit/mc_40world1_2eservice * --method org.freedesktop.systemd1.Unit.Start "fail" */ bool systemd_service_start(struct server *server) { assert_return(server, false); return systemd_service_action(server, "Start"); }