// SPDX-License-Identifier: Apache-2.0 // Copyright (C) 2018 IBM Corp. #include #include #include #include #include "common.h" #include "dbus.h" #include "control_dbus.h" #include "mboxd.h" typedef int (*control_action)(struct mbox_context *context); static int control_dbus_directive(sd_bus_message *m, void *userdata, sd_bus_error *ret_error, control_action action) { struct mbox_context *context; sd_bus_message *n; int rc; if (!action) { MSG_ERR("No action provided\n"); return -EINVAL; } context = (struct mbox_context *) userdata; if (!context) { MSG_ERR("DBUS Internal Error\n"); return -EINVAL; } rc = action(context); if (rc < 0) { MSG_ERR("Action failed: %d\n", rc); return rc; } rc = sd_bus_message_new_method_return(m, &n); if (rc < 0) { MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc); return rc; } return sd_bus_send(NULL, n, NULL); } static int control_dbus_ping(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { return control_dbus_directive(m, userdata, ret_error, control_ping); } static int control_dbus_reset(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { return control_dbus_directive(m, userdata, ret_error, control_reset); } static int control_dbus_kill(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { return control_dbus_directive(m, userdata, ret_error, control_kill); } static int control_dbus_modified(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { return control_dbus_directive(m, userdata, ret_error, control_modified); } static int control_dbus_suspend(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { return control_dbus_directive(m, userdata, ret_error, control_suspend); } static int control_dbus_resume(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { struct mbox_context *context; sd_bus_message *n; bool modified; int rc; context = (struct mbox_context *) userdata; if (!context) { MSG_ERR("DBUS Internal Error\n"); return -EINVAL; } rc = sd_bus_message_read_basic(m, 'b', &modified); if (rc < 0) { MSG_ERR("DBUS error reading message: %s\n", strerror(-rc)); return rc; } rc = control_resume(context, modified); if (rc < 0) return rc; rc = sd_bus_message_new_method_return(m, &n); if (rc < 0) { MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc); return rc; } return sd_bus_send(NULL, n, NULL); } static int control_dbus_set_backend(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { struct mbox_context *context; struct backend backend; sd_bus_message *n; const char *name; int rc; context = (struct mbox_context *) userdata; if (!context) { MSG_ERR("DBUS Internal Error\n"); return -EINVAL; } rc = sd_bus_message_read_basic(m, 's', &name); if (rc < 0) { MSG_ERR("DBUS error reading message: %s\n", strerror(-rc)); return rc; } if (!strcmp(name, "vpnor")) { struct vpnor_partition_paths paths; vpnor_default_paths(&paths); backend = backend_get_vpnor(); rc = control_set_backend(context, &backend, &paths); if (rc < 0) return rc; } else if (!strcmp(name, "mtd")) { char **paths = NULL; char *path = NULL; rc = sd_bus_message_read_strv(m, &paths); if (rc < 0) return rc; if (paths && *paths) path = *paths; else path = get_dev_mtd(); backend = backend_get_mtd(); rc = control_set_backend(context, &backend, path); if (rc < 0) return rc; free(path); free(paths); } else if (!strcmp(name, "file")) { char **paths = NULL; char *path = NULL; rc = sd_bus_message_read_strv(m, &paths); if (rc < 0) return rc; if (!(paths && *paths)) return -EINVAL; path = *paths; backend = backend_get_file(); rc = control_set_backend(context, &backend, path); if (rc < 0) return rc; free(path); free(paths); } else { return -EINVAL; } rc = sd_bus_message_new_method_return(m, &n); if (rc < 0) { MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc); return rc; } return sd_bus_send(NULL, n, NULL); } static int control_dbus_get_u8(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *ret_error) { struct mbox_context *context = userdata; uint8_t value; assert(!strcmp(MBOX_DBUS_OBJECT, path)); if (!strcmp("DaemonState", property)) { value = control_daemon_state(context); } else if (!strcmp("LpcState", property)) { value = control_lpc_state(context); } else { MSG_ERR("Unknown DBus property: %s\n", property); return -EINVAL; } return sd_bus_message_append(reply, "y", value); } static const sd_bus_vtable mboxd_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_METHOD("Ping", NULL, NULL, &control_dbus_ping, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("Reset", NULL, NULL, &control_dbus_reset, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("Kill", NULL, NULL, &control_dbus_kill, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("MarkFlashModified", NULL, NULL, &control_dbus_modified, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("Suspend", NULL, NULL, &control_dbus_suspend, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("Resume", "b", NULL, &control_dbus_resume, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetBackend", "sas", NULL, &control_dbus_set_backend, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_PROPERTY("DaemonState", "y", &control_dbus_get_u8, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("LpcState", "y", &control_dbus_get_u8, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_VTABLE_END }; int control_dbus_init(struct mbox_context *context) { return sd_bus_add_object_vtable(context->bus, NULL, MBOX_DBUS_OBJECT, MBOX_DBUS_CONTROL_IFACE, mboxd_vtable, context); } #define __unused __attribute__((unused)) void control_dbus_free(struct mbox_context *context __unused) { return; }