#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <systemd/sd-bus.h>
static const char *const systemd_service = "org.freedesktop.systemd1";
static bool prv_systemd_get_service_state(sd_bus *bus, const char *service_name, char **state) {
static const char *const unit_interface = "org.freedesktop.systemd1.Unit";
char *unit_path = NULL;
bool result = true;
if (sd_bus_path_encode("/org/freedesktop/systemd1/unit", service_name, &unit_path) < 0) {
fprintf(stderr, "memfaultd:: Failed to generate SystemD unit path\n");
return false;
}
sd_bus_error error = SD_BUS_ERROR_NULL;
if (sd_bus_get_property_string(bus, systemd_service, unit_path, unit_interface, "ActiveState",
&error, state) < 0) {
fprintf(stderr, "memfaultd:: Failed to get state of %s: %s\n", service_name, error.name);
sd_bus_error_free(&error);
result = false;
}
if (unit_path) {
free(unit_path);
}
return result;
}
static bool prv_systemd_restart_service(sd_bus *bus, const char *service_name) {
const char *manager_path = "/org/freedesktop/systemd1";
const char *manager_interface = "org.freedesktop.systemd1.Manager";
sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus_message *msg = NULL;
if (sd_bus_call_method(bus, systemd_service, manager_path, manager_interface, "RestartUnit",
&error, &msg, "ss", service_name, "replace") < 0) {
fprintf(stderr, "memfaultd:: Failed to restart %s: %s\n", service_name, error.name);
sd_bus_error_free(&error);
return false;
}
sd_bus_message_unref(msg);
return true;
}
static bool prv_systemd_kill_service(sd_bus *bus, const char *service_name, int signal) {
const char *manager_path = "/org/freedesktop/systemd1";
const char *manager_interface = "org.freedesktop.systemd1.Manager";
sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus_message *msg = NULL;
if (sd_bus_call_method(bus, systemd_service, manager_path, manager_interface, "KillUnit", &error,
&msg, "ssi", service_name, "all", signal) < 0) {
fprintf(stderr, "memfaultd:: Failed to kill %s: %s\n", service_name, error.name);
sd_bus_error_free(&error);
return false;
}
sd_bus_message_unref(msg);
return true;
}
bool memfaultd_restart_systemd_service_if_running(const char *service_name) {
bool result = true;
sd_bus *bus;
if (sd_bus_default_system(&bus) < 0) {
fprintf(stderr, "memfaultd:: Failed to find systemd system bus\n");
return false;
}
char *state = NULL;
if (!prv_systemd_get_service_state(bus, service_name, &state)) {
result = false;
goto cleanup;
}
if (strcmp("active", state) != 0 && strcmp("activating", state) != 0) {
fprintf(stderr, "memfaultd:: %s is not active (%s). Not starting.\n", service_name, state);
result = true;
goto cleanup;
}
if (!prv_systemd_restart_service(bus, service_name)) {
result = false;
goto cleanup;
}
cleanup:
if (state != NULL) {
free(state);
}
sd_bus_unref(bus);
return result;
}
bool memfaultd_kill_systemd_service(const char *service_name, int signal) {
bool result = true;
sd_bus *bus;
if (sd_bus_default_system(&bus) < 0) {
fprintf(stderr, "memfaultd:: Failed to find systemd system bus\n");
return false;
}
if (!prv_systemd_kill_service(bus, service_name, signal)) {
result = false;
goto cleanup;
}
cleanup:
sd_bus_unref(bus);
return result;
}
char *memfaultd_get_systemd_bus_state() {
sd_bus *bus = NULL;
sd_bus_error error = SD_BUS_ERROR_NULL;
char *cur_state = NULL;
const char *service = "org.freedesktop.systemd1";
const char *path = "/org/freedesktop/systemd1";
const char *interface = "org.freedesktop.systemd1.Manager";
const char *system_state = "SystemState";
const int bus_result = sd_bus_default_system(&bus);
if (bus_result < 0) {
fprintf(stderr, "reboot:: Failed to find systemd system bus: %s\n", strerror(-bus_result));
goto cleanup;
}
if (sd_bus_get_property_string(bus, service, path, interface, system_state, &error, &cur_state) <
0) {
fprintf(stderr, "reboot:: Failed to get system state: %s\n", error.name);
goto cleanup;
}
cleanup:
sd_bus_error_free(&error);
sd_bus_unref(bus);
return cur_state;
}