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