1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright (C) 2018 IBM Corp. 3 #include <assert.h> 4 #include <errno.h> 5 #include <stdlib.h> 6 #include <systemd/sd-bus.h> 7 8 #include "common.h" 9 #include "dbus.h" 10 #include "control_dbus.h" 11 #include "mboxd.h" 12 #include "vpnor/mboxd_pnor_partition_table.h" 13 14 typedef int (*control_action)(struct mbox_context *context); 15 16 static int control_dbus_directive(sd_bus_message *m, void *userdata, 17 sd_bus_error *ret_error, 18 control_action action) 19 { 20 struct mbox_context *context; 21 sd_bus_message *n; 22 int rc; 23 24 if (!action) { 25 MSG_ERR("No action provided\n"); 26 return -EINVAL; 27 } 28 29 context = (struct mbox_context *) userdata; 30 if (!context) { 31 MSG_ERR("DBUS Internal Error\n"); 32 return -EINVAL; 33 } 34 35 rc = action(context); 36 if (rc < 0) { 37 MSG_ERR("Action failed: %d\n", rc); 38 return rc; 39 } 40 41 rc = sd_bus_message_new_method_return(m, &n); 42 if (rc < 0) { 43 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc); 44 return rc; 45 } 46 47 return sd_bus_send(NULL, n, NULL); 48 } 49 50 static int control_dbus_ping(sd_bus_message *m, void *userdata, 51 sd_bus_error *ret_error) 52 { 53 return control_dbus_directive(m, userdata, ret_error, control_ping); 54 } 55 56 static int control_dbus_reset(sd_bus_message *m, void *userdata, 57 sd_bus_error *ret_error) 58 { 59 return control_dbus_directive(m, userdata, ret_error, control_reset); 60 } 61 62 static int control_dbus_kill(sd_bus_message *m, void *userdata, 63 sd_bus_error *ret_error) 64 { 65 return control_dbus_directive(m, userdata, ret_error, control_kill); 66 } 67 68 static int control_dbus_modified(sd_bus_message *m, void *userdata, 69 sd_bus_error *ret_error) 70 { 71 return control_dbus_directive(m, userdata, ret_error, control_modified); 72 } 73 74 static int control_dbus_suspend(sd_bus_message *m, void *userdata, 75 sd_bus_error *ret_error) 76 { 77 return control_dbus_directive(m, userdata, ret_error, control_suspend); 78 } 79 80 static int control_dbus_resume(sd_bus_message *m, void *userdata, 81 sd_bus_error *ret_error) 82 { 83 struct mbox_context *context; 84 sd_bus_message *n; 85 bool modified; 86 int rc; 87 88 context = (struct mbox_context *) userdata; 89 if (!context) { 90 MSG_ERR("DBUS Internal Error\n"); 91 return -EINVAL; 92 } 93 94 rc = sd_bus_message_read_basic(m, 'b', &modified); 95 if (rc < 0) { 96 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc)); 97 return rc; 98 } 99 100 rc = control_resume(context, modified); 101 if (rc < 0) 102 return rc; 103 104 rc = sd_bus_message_new_method_return(m, &n); 105 if (rc < 0) { 106 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc); 107 return rc; 108 } 109 110 return sd_bus_send(NULL, n, NULL); 111 } 112 113 static int control_dbus_set_backend(sd_bus_message *m, void *userdata, 114 sd_bus_error *ret_error) 115 { 116 struct mbox_context *context; 117 struct backend backend; 118 sd_bus_message *n; 119 const char *name; 120 int rc; 121 122 context = (struct mbox_context *) userdata; 123 if (!context) { 124 MSG_ERR("DBUS Internal Error\n"); 125 return -EINVAL; 126 } 127 128 rc = sd_bus_message_read_basic(m, 's', &name); 129 if (rc < 0) { 130 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc)); 131 return rc; 132 } 133 134 if (!strcmp(name, "vpnor")) { 135 struct vpnor_partition_paths paths; 136 137 vpnor_default_paths(&paths); 138 backend = backend_get_vpnor(); 139 rc = control_set_backend(context, &backend, &paths); 140 if (rc < 0) 141 return rc; 142 } else if (!strcmp(name, "mtd")) { 143 char **paths = NULL; 144 char *path = NULL; 145 146 rc = sd_bus_message_read_strv(m, &paths); 147 if (rc < 0) 148 return rc; 149 150 if (paths && *paths) 151 path = *paths; 152 else 153 path = get_dev_mtd(); 154 155 backend = backend_get_mtd(); 156 157 rc = control_set_backend(context, &backend, path); 158 if (rc < 0) 159 return rc; 160 161 free(path); 162 free(paths); 163 } else if (!strcmp(name, "file")) { 164 char **paths = NULL; 165 char *path = NULL; 166 167 rc = sd_bus_message_read_strv(m, &paths); 168 if (rc < 0) 169 return rc; 170 171 if (!(paths && *paths)) 172 return -EINVAL; 173 174 path = *paths; 175 176 backend = backend_get_file(); 177 178 rc = control_set_backend(context, &backend, path); 179 if (rc < 0) 180 return rc; 181 182 free(path); 183 free(paths); 184 } else { 185 return -EINVAL; 186 } 187 188 rc = sd_bus_message_new_method_return(m, &n); 189 if (rc < 0) { 190 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc); 191 return rc; 192 } 193 194 return sd_bus_send(NULL, n, NULL); 195 } 196 197 static int control_dbus_get_u8(sd_bus *bus, const char *path, 198 const char *interface, const char *property, 199 sd_bus_message *reply, void *userdata, 200 sd_bus_error *ret_error) 201 { 202 struct mbox_context *context = userdata; 203 uint8_t value; 204 205 assert(!strcmp(MBOX_DBUS_OBJECT, path)); 206 207 if (!strcmp("DaemonState", property)) { 208 value = control_daemon_state(context); 209 } else if (!strcmp("LpcState", property)) { 210 value = control_lpc_state(context); 211 } else { 212 MSG_ERR("Unknown DBus property: %s\n", property); 213 return -EINVAL; 214 } 215 216 return sd_bus_message_append(reply, "y", value); 217 } 218 219 static const sd_bus_vtable mboxd_vtable[] = { 220 SD_BUS_VTABLE_START(0), 221 SD_BUS_METHOD("Ping", NULL, NULL, &control_dbus_ping, 222 SD_BUS_VTABLE_UNPRIVILEGED), 223 SD_BUS_METHOD("Reset", NULL, NULL, &control_dbus_reset, 224 SD_BUS_VTABLE_UNPRIVILEGED), 225 SD_BUS_METHOD("Kill", NULL, NULL, &control_dbus_kill, 226 SD_BUS_VTABLE_UNPRIVILEGED), 227 SD_BUS_METHOD("MarkFlashModified", NULL, NULL, &control_dbus_modified, 228 SD_BUS_VTABLE_UNPRIVILEGED), 229 SD_BUS_METHOD("Suspend", NULL, NULL, &control_dbus_suspend, 230 SD_BUS_VTABLE_UNPRIVILEGED), 231 SD_BUS_METHOD("Resume", "b", NULL, &control_dbus_resume, 232 SD_BUS_VTABLE_UNPRIVILEGED), 233 SD_BUS_METHOD("SetBackend", "sas", NULL, &control_dbus_set_backend, 234 SD_BUS_VTABLE_UNPRIVILEGED), 235 SD_BUS_PROPERTY("DaemonState", "y", &control_dbus_get_u8, 0, 236 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), 237 SD_BUS_PROPERTY("LpcState", "y", &control_dbus_get_u8, 0, 238 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), 239 SD_BUS_VTABLE_END 240 }; 241 242 int control_dbus_init(struct mbox_context *context) 243 { 244 return sd_bus_add_object_vtable(context->bus, NULL, 245 MBOX_DBUS_OBJECT, 246 MBOX_DBUS_CONTROL_IFACE, 247 mboxd_vtable, context); 248 } 249 250 #define __unused __attribute__((unused)) 251 void control_dbus_free(struct mbox_context *context __unused) 252 { 253 return; 254 } 255