1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright (C) 2018 IBM Corp. 3 #include "config.h" 4 5 #include <errno.h> 6 #include <getopt.h> 7 #include <stdbool.h> 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <string.h> 11 #include <systemd/sd-bus.h> 12 13 #include "dbus.h" 14 15 #define USAGE \ 16 "\nUsage: %s [--silent | -s] <command> [args]\n\n" \ 17 "\t\t--silent\t\t- no output on the command line\n\n" \ 18 "\tCommands: (num args)\n" \ 19 "\t\t--ping\t\t\t- ping the daemon (0)\n" \ 20 "\t\t--daemon-state\t\t- check state of the daemon (0)\n" \ 21 "\t\t--lpc-state\t\t- check the state of the lpc mapping (0)\n" \ 22 "\t\t--kill\t\t\t- stop the daemon [no flush] (0)\n" \ 23 "\t\t--reset\t\t\t- hard reset the daemon state (0)\n" \ 24 "\t\t--point-to-flash\t- point the lpc mapping back to flash (0)\n" \ 25 "\t\t--suspend\t\t- suspend the daemon to inhibit flash accesses (0)\n" \ 26 "\t\t--resume\t\t- resume the daemon (1)\n" \ 27 "\t\t\targ[0]: < \"clean\" | \"modified\" >\n" \ 28 "\t\t--clear-cache\t- tell the daemon to discard any caches (0)\n" 29 30 #define NAME "Mailbox Control" 31 32 static bool silent; 33 34 #define MSG_OUT(...) do { if (!silent) { \ 35 fprintf(stdout, __VA_ARGS__); } \ 36 } while (0) 37 #define MSG_ERR(...) do { if (!silent) { \ 38 fprintf(stderr, __VA_ARGS__); } \ 39 } while (0) 40 41 struct mboxctl_context { 42 sd_bus *bus; 43 }; 44 45 static void usage(char *name) 46 { 47 MSG_OUT(USAGE, name); 48 exit(0); 49 } 50 51 static int init_mboxctl_dbus(struct mboxctl_context *context) 52 { 53 int rc; 54 55 rc = sd_bus_default_system(&context->bus); 56 if (rc < 0) { 57 MSG_ERR("Failed to connect to the system bus: %s\n", 58 strerror(-rc)); 59 } 60 61 return rc; 62 } 63 64 static int mboxctl_directive(struct mboxctl_context *context, const char *cmd) 65 { 66 sd_bus_error error = SD_BUS_ERROR_NULL; 67 sd_bus_message *m = NULL; 68 int rc; 69 70 rc = sd_bus_message_new_method_call(context->bus, &m, 71 MBOX_DBUS_NAME, 72 MBOX_DBUS_OBJECT, 73 MBOX_DBUS_CONTROL_IFACE, 74 cmd); 75 if (rc < 0) { 76 MSG_ERR("Failed to init method call: %s\n", 77 strerror(-rc)); 78 goto out; 79 } 80 81 rc = sd_bus_call(context->bus, m, 0, &error, NULL); 82 if (rc < 0) { 83 MSG_ERR("Failed to post message: %s\n", strerror(-rc)); 84 } 85 86 out: 87 sd_bus_error_free(&error); 88 sd_bus_message_unref(m); 89 90 return rc < 0 ? rc : 0; 91 } 92 93 static int mboxctl_getter(struct mboxctl_context *context, const char *cmd, 94 uint8_t *resp) 95 { 96 sd_bus_error error = SD_BUS_ERROR_NULL; 97 sd_bus_message *m = NULL, *n = NULL; 98 int rc; 99 100 rc = sd_bus_message_new_method_call(context->bus, &m, 101 MBOX_DBUS_NAME, 102 MBOX_DBUS_OBJECT, 103 MBOX_DBUS_CONTROL_IFACE, 104 cmd); 105 if (rc < 0) { 106 MSG_ERR("Failed to init method call: %s\n", 107 strerror(-rc)); 108 goto out; 109 } 110 111 rc = sd_bus_call(context->bus, m, 0, &error, &n); 112 if (rc < 0) { 113 MSG_ERR("Failed to post message: %s\n", strerror(-rc)); 114 goto out; 115 } 116 117 rc = sd_bus_message_read_basic(n, 'y', resp); 118 if (rc < 0) { 119 MSG_ERR("Failed to read response args: %s\n", 120 strerror(-rc)); 121 goto out; 122 } 123 124 out: 125 sd_bus_error_free(&error); 126 sd_bus_message_unref(m); 127 sd_bus_message_unref(n); 128 129 return rc < 0 ? rc : 0; 130 131 } 132 133 static int handle_cmd_ping(struct mboxctl_context *context) 134 { 135 int rc; 136 137 rc = mboxctl_directive(context, "Ping"); 138 MSG_OUT("Ping: %s\n", rc ? strerror(-rc) : "Success"); 139 140 return rc; 141 } 142 143 static int handle_cmd_daemon_state(struct mboxctl_context *context) 144 { 145 uint8_t resp; 146 int rc; 147 148 rc = mboxctl_getter(context, "GetDaemonState", &resp); 149 if (rc < 0) 150 return rc; 151 152 MSG_OUT("Daemon State: %s\n", resp == DAEMON_STATE_ACTIVE ? 153 "Active" : "Suspended"); 154 return 0; 155 } 156 157 static int handle_cmd_lpc_state(struct mboxctl_context *context) 158 { 159 uint8_t resp; 160 int rc; 161 162 rc = mboxctl_getter(context, "GetLpcState", &resp); 163 if (rc < 0) 164 return rc; 165 166 MSG_OUT("LPC Bus Maps: %s\n", resp == LPC_STATE_MEM ? 167 "BMC Memory" : 168 (resp == LPC_STATE_FLASH ? 169 "Flash Device" : 170 "Invalid System State")); 171 172 return 0; 173 } 174 175 static int handle_cmd_kill(struct mboxctl_context *context) 176 { 177 int rc; 178 179 rc = mboxctl_directive(context, "Kill"); 180 MSG_OUT("Kill: %s\n", rc ? strerror(-rc) : "Success"); 181 182 return rc; 183 } 184 185 static int handle_cmd_reset(struct mboxctl_context *context) 186 { 187 int rc; 188 189 rc = mboxctl_directive(context, "Reset"); 190 MSG_OUT("Reset: %s\n", rc ? strerror(-rc) : "Success"); 191 192 return rc; 193 } 194 195 static int handle_cmd_suspend(struct mboxctl_context *context) 196 { 197 int rc; 198 199 rc = mboxctl_directive(context, "Suspend"); 200 MSG_OUT("Suspend: %s\n", rc ? strerror(-rc) : "Success"); 201 202 return rc; 203 } 204 205 static int handle_cmd_resume(struct mboxctl_context *context, char *sarg) 206 { 207 sd_bus_error error = SD_BUS_ERROR_NULL; 208 sd_bus_message *m = NULL, *n = NULL; 209 uint8_t arg; 210 int rc; 211 212 if (!sarg) { 213 MSG_ERR("Resume command takes an argument\n"); 214 return -EINVAL; 215 } 216 217 rc = sd_bus_message_new_method_call(context->bus, &m, 218 MBOX_DBUS_NAME, 219 MBOX_DBUS_OBJECT, 220 MBOX_DBUS_CONTROL_IFACE, 221 "Resume"); 222 if (rc < 0) { 223 MSG_ERR("Failed to init method call: %s\n", 224 strerror(-rc)); 225 goto out; 226 } 227 228 if (!strncmp(sarg, "clean", strlen("clean"))) { 229 arg = RESUME_NOT_MODIFIED; 230 } else if (!strncmp(sarg, "modified", strlen("modified"))) { 231 arg = RESUME_FLASH_MODIFIED; 232 } else { 233 MSG_ERR("Resume command takes argument < \"clean\" | " 234 "\"modified\" >\n"); 235 rc = -EINVAL; 236 goto out; 237 } 238 239 rc = sd_bus_message_append(m, "b", arg); 240 if (rc < 0) { 241 MSG_ERR("Failed to add args to message: %s\n", 242 strerror(-rc)); 243 goto out; 244 } 245 246 rc = sd_bus_call(context->bus, m, 0, &error, &n); 247 if (rc < 0) { 248 MSG_ERR("Failed to post message: %s\n", strerror(-rc)); 249 goto out; 250 } 251 252 MSG_OUT("Resume: %s\n", rc < 0 ? strerror(-rc) : "Success"); 253 254 out: 255 sd_bus_error_free(&error); 256 sd_bus_message_unref(m); 257 sd_bus_message_unref(n); 258 259 return rc < 0 ? rc : 0; 260 } 261 262 static int handle_cmd_modified(struct mboxctl_context *context) 263 { 264 int rc; 265 266 rc = mboxctl_directive(context, "MarkFlashModified"); 267 MSG_OUT("Clear Cache: %s\n", rc ? strerror(-rc) : "Success"); 268 269 return rc; 270 } 271 272 static int parse_cmdline(struct mboxctl_context *context, int argc, char **argv) 273 { 274 int opt, rc = -1; 275 276 static const struct option long_options[] = { 277 { "silent", no_argument, 0, 's' }, 278 { "ping", no_argument, 0, 'p' }, 279 { "daemon-state", no_argument, 0, 'd' }, 280 { "lpc-state", no_argument, 0, 'l' }, 281 { "kill", no_argument, 0, 'k' }, 282 { "reset", no_argument, 0, 'r' }, 283 { "point-to-flash", no_argument, 0, 'f' }, 284 { "suspend", no_argument, 0, 'u' }, 285 { "resume", required_argument, 0, 'e' }, 286 { "clear-cache", no_argument, 0, 'c' }, 287 { "version", no_argument, 0, 'v' }, 288 { "help", no_argument, 0, 'h' }, 289 { 0, 0, 0, 0 } 290 }; 291 292 if (argc <= 1) { 293 usage(argv[0]); 294 return -EINVAL; 295 } 296 297 while ((opt = getopt_long(argc, argv, "spdlkrfue:cvh", long_options, 298 NULL)) != -1) { 299 switch (opt) { 300 case 's': 301 silent = true; 302 continue; 303 case 'p': 304 rc = handle_cmd_ping(context); 305 break; 306 case 'd': 307 rc = handle_cmd_daemon_state(context); 308 break; 309 case 'l': 310 rc = handle_cmd_lpc_state(context); 311 break; 312 case 'k': 313 rc = handle_cmd_kill(context); 314 break; 315 case 'r': /* These are the same for now (reset may change) */ 316 case 'f': 317 rc = handle_cmd_reset(context); 318 break; 319 case 'u': 320 rc = handle_cmd_suspend(context); 321 break; 322 case 'e': 323 rc = handle_cmd_resume(context, optarg); 324 break; 325 case 'c': 326 rc = handle_cmd_modified(context); 327 break; 328 case 'v': 329 MSG_OUT("%s V%s\n", NAME, PACKAGE_VERSION); 330 rc = 0; 331 break; 332 case 'h': 333 usage(argv[0]); 334 rc = 0; 335 break; 336 default: 337 usage(argv[0]); 338 rc = -EINVAL; 339 break; 340 } 341 } 342 343 return rc; 344 } 345 346 int main(int argc, char **argv) 347 { 348 struct mboxctl_context context; 349 int rc; 350 351 silent = false; 352 353 rc = init_mboxctl_dbus(&context); 354 if (rc < 0) { 355 MSG_ERR("Failed to init dbus\n"); 356 return rc; 357 } 358 359 rc = parse_cmdline(&context, argc, argv); 360 361 return rc; 362 } 363