blob: 7455bc89162def2fc47b61bff47beee8a0586384 [file] [log] [blame]
Andrew Jeffery4fe996c2018-02-27 12:16:48 +10301// SPDX-License-Identifier: Apache-2.0
2// Copyright (C) 2018 IBM Corp.
Andrew Jeffery939bd382018-08-06 12:34:26 +09303#include "config.h"
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +11004
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +11005#include <getopt.h>
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +11006#include <stdbool.h>
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +11007#include <stdio.h>
8#include <stdlib.h>
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +11009#include <systemd/sd-bus.h>
10
11#include "dbus.h"
12
13#define USAGE \
14"\nUsage: %s [--silent | -s] <command> [args]\n\n" \
15"\t\t--silent\t\t- no output on the command line\n\n" \
16"\tCommands: (num args)\n" \
17"\t\t--ping\t\t\t- ping the daemon (0)\n" \
18"\t\t--daemon-state\t\t- check state of the daemon (0)\n" \
19"\t\t--lpc-state\t\t- check the state of the lpc mapping (0)\n" \
20"\t\t--kill\t\t\t- stop the daemon [no flush] (0)\n" \
21"\t\t--reset\t\t\t- hard reset the daemon state (0)\n" \
22"\t\t--point-to-flash\t- point the lpc mapping back to flash (0)\n" \
23"\t\t--suspend\t\t- suspend the daemon to inhibit flash accesses (0)\n" \
24"\t\t--resume\t\t- resume the daemon (1)\n" \
25"\t\t\targ[0]: < \"clean\" | \"modified\" >\n" \
26"\t\t--clear-cache\t- tell the daemon to discard any caches (0)\n"
27
Suraj Jitindar Singh8d65bb42017-05-01 16:05:17 +100028#define NAME "Mailbox Control"
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +110029
30static bool silent;
31
32#define MSG_OUT(...) do { if (!silent) { \
33 fprintf(stdout, __VA_ARGS__); } \
34 } while (0)
35#define MSG_ERR(...) do { if (!silent) { \
36 fprintf(stderr, __VA_ARGS__); } \
37 } while (0)
38
39struct mboxctl_context {
40 sd_bus *bus;
41};
42
43static void usage(char *name)
44{
45 MSG_OUT(USAGE, name);
46 exit(0);
47}
48
49static const char *dbus_err_str[] = {
50 "Success",
51 "Failed - Internal Error",
52 "Failed - Invalid Command or Request",
53 "Failed - Request Rejected by Daemon",
54 "Failed - BMC Hardware Error",
55 "Failed - Insufficient Memory for Allocation Request"
56};
57
58static int init_mboxctl_dbus(struct mboxctl_context *context)
59{
60 int rc;
61
62 rc = sd_bus_default_system(&context->bus);
63 if (rc < 0) {
64 MSG_ERR("Failed to connect to the system bus: %s\n",
65 strerror(-rc));
66 }
67
68 return rc;
69}
70
Andrew Jeffery68023072018-08-06 10:08:11 +093071static int send_dbus_msg_legacy(struct mboxctl_context *context,
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +110072 struct mbox_dbus_msg *msg,
73 struct mbox_dbus_msg *resp)
74{
75 sd_bus_error error = SD_BUS_ERROR_NULL;
76 sd_bus_message *m = NULL, *n = NULL;
77 uint8_t *buf;
78 size_t sz;
79 int rc;
80
81 /* Generate the bus message */
Andrew Jeffery68023072018-08-06 10:08:11 +093082 rc = sd_bus_message_new_method_call(context->bus, &m,
83 MBOX_DBUS_LEGACY_NAME,
84 MBOX_DBUS_LEGACY_OBJECT,
85 MBOX_DBUS_LEGACY_NAME, "cmd");
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +110086 if (rc < 0) {
87 MSG_ERR("Failed to init method call: %s\n",
88 strerror(-rc));
89 rc = -E_DBUS_INTERNAL;
90 goto out;
91 }
92
93 /* Add the command */
94 rc = sd_bus_message_append(m, "y", msg->cmd);
95 if (rc < 0) {
96 MSG_ERR("Failed to add cmd to message: %s\n",
97 strerror(-rc));
98 rc = -E_DBUS_INTERNAL;
99 goto out;
100 }
101
102 /* Add the args */
103 rc = sd_bus_message_append_array(m, 'y', msg->args, msg->num_args);
104 if (rc < 0) {
105 MSG_ERR("Failed to add args to message: %s\n",
106 strerror(-rc));
107 rc = -E_DBUS_INTERNAL;
108 goto out;
109 }
110
111 /* Send the message */
112 rc = sd_bus_call(context->bus, m, 0, &error, &n);
113 if (rc < 0) {
114 MSG_ERR("Failed to post message: %s\n", strerror(-rc));
115 rc = -E_DBUS_INTERNAL;
116 goto out;
117 }
118
119 /* Read response code */
120 rc = sd_bus_message_read(n, "y", &resp->cmd);
121 if (rc < 0) {
122 MSG_ERR("Failed to read response code: %s\n",
123 strerror(-rc));
124 rc = -E_DBUS_INTERNAL;
125 goto out;
126 }
127
128 /* Read response args */
129 rc = sd_bus_message_read_array(n, 'y', (const void **) &buf, &sz);
130 if (rc < 0) {
131 MSG_ERR("Failed to read response args: %s\n",
132 strerror(-rc));
133 rc = -E_DBUS_INTERNAL;
134 goto out;
135 }
136
137 if (sz < resp->num_args) {
138 MSG_ERR("Command returned insufficient response args\n");
139 rc = -E_DBUS_INTERNAL;
140 goto out;
141 }
142
143 memcpy(resp->args, buf, resp->num_args);
144 rc = 0;
145
146out:
147 sd_bus_error_free(&error);
148 sd_bus_message_unref(m);
149 sd_bus_message_unref(n);
150
151 return rc;
152}
153
154static int handle_cmd_ping(struct mboxctl_context *context)
155{
156 struct mbox_dbus_msg msg = { 0 }, resp = { 0 };
157 int rc;
158
159 msg.cmd = DBUS_C_PING;
160
Andrew Jeffery68023072018-08-06 10:08:11 +0930161 rc = send_dbus_msg_legacy(context, &msg, &resp);
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100162 if (rc < 0) {
163 MSG_ERR("Failed to send ping command\n");
164 return rc;
165 }
166
167 rc = -resp.cmd;
168 MSG_OUT("Ping: %s\n", dbus_err_str[-rc]);
169
170 return rc;
171}
172
173static int handle_cmd_daemon_state(struct mboxctl_context *context)
174{
175 struct mbox_dbus_msg msg = { 0 }, resp = { 0 };
176 int rc;
177
178 msg.cmd = DBUS_C_DAEMON_STATE;
179 resp.num_args = DAEMON_STATE_NUM_ARGS;
180 resp.args = calloc(resp.num_args, sizeof(*resp.args));
181 if (!resp.args) {
182 MSG_ERR("Memory allocation failed\n");
183 return -E_DBUS_NO_MEM;
184 }
185
Andrew Jeffery68023072018-08-06 10:08:11 +0930186 rc = send_dbus_msg_legacy(context, &msg, &resp);
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100187 if (rc < 0) {
188 MSG_ERR("Failed to send daemon state command\n");
189 goto out;
190 }
191
192 rc = -resp.cmd;
193 if (resp.cmd != DBUS_SUCCESS) {
194 MSG_ERR("Daemon state command failed\n");
195 goto out;
196 }
197
198 MSG_OUT("Daemon State: %s\n", resp.args[0] == DAEMON_STATE_ACTIVE ?
199 "Active" : "Suspended");
200
201out:
202 free(resp.args);
203 return rc;
204}
205
206static int handle_cmd_lpc_state(struct mboxctl_context *context)
207{
208 struct mbox_dbus_msg msg = { 0 }, resp = { 0 };
209 int rc;
210
211 msg.cmd = DBUS_C_LPC_STATE;
212 resp.num_args = LPC_STATE_NUM_ARGS;
213 resp.args = calloc(resp.num_args, sizeof(*resp.args));
214 if (!resp.args) {
215 MSG_ERR("Memory allocation failed\n");
216 return -E_DBUS_NO_MEM;
217 }
218
Andrew Jeffery68023072018-08-06 10:08:11 +0930219 rc = send_dbus_msg_legacy(context, &msg, &resp);
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100220 if (rc < 0) {
221 MSG_ERR("Failed to send lpc state command\n");
222 goto out;
223 }
224
225 rc = -resp.cmd;
226 if (resp.cmd != DBUS_SUCCESS) {
227 MSG_ERR("LPC state command failed\n");
228 goto out;
229 }
230
231 MSG_OUT("LPC Bus Maps: %s\n", resp.args[0] == LPC_STATE_MEM ?
232 "BMC Memory" :
233 (resp.args[0] == LPC_STATE_FLASH ?
234 "Flash Device" :
235 "Invalid System State"));
236
237out:
238 free(resp.args);
239 return rc;
240}
241
242static int handle_cmd_kill(struct mboxctl_context *context)
243{
244 struct mbox_dbus_msg msg = { 0 }, resp = { 0 };
245 int rc;
246
247 msg.cmd = DBUS_C_KILL;
248
Andrew Jeffery68023072018-08-06 10:08:11 +0930249 rc = send_dbus_msg_legacy(context, &msg, &resp);
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100250 if (rc < 0) {
251 MSG_ERR("Failed to send kill command\n");
252 return rc;
253 }
254
255 rc = -resp.cmd;
256 MSG_OUT("Kill: %s\n", dbus_err_str[-rc]);
257
258 return rc;
259}
260
261static int handle_cmd_reset(struct mboxctl_context *context)
262{
263 struct mbox_dbus_msg msg = { 0 }, resp = { 0 };
264 int rc;
265
266 msg.cmd = DBUS_C_RESET;
267
Andrew Jeffery68023072018-08-06 10:08:11 +0930268 rc = send_dbus_msg_legacy(context, &msg, &resp);
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100269 if (rc < 0) {
270 MSG_ERR("Failed to send reset command\n");
271 return rc;
272 }
273
274 rc = -resp.cmd;
275 MSG_OUT("Reset: %s\n", dbus_err_str[-rc]);
276
277 return rc;
278}
279
280static int handle_cmd_suspend(struct mboxctl_context *context)
281{
282 struct mbox_dbus_msg msg = { 0 }, resp = { 0 };
283 int rc;
284
285 msg.cmd = DBUS_C_SUSPEND;
286
Andrew Jeffery68023072018-08-06 10:08:11 +0930287 rc = send_dbus_msg_legacy(context, &msg, &resp);
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100288 if (rc < 0) {
289 MSG_ERR("Failed to send suspend command\n");
290 return rc;
291 }
292
293 rc = -resp.cmd;
294 MSG_OUT("Suspend: %s\n", dbus_err_str[-rc]);
295
296 return rc;
297}
298
299static int handle_cmd_resume(struct mboxctl_context *context, char *arg)
300{
301 struct mbox_dbus_msg msg = { 0 }, resp = { 0 };
302 int rc;
303
304 if (!arg) {
305 MSG_ERR("Resume command takes an argument\n");
306 return -E_DBUS_INVAL;
307 }
308
309 msg.cmd = DBUS_C_RESUME;
310 msg.num_args = RESUME_NUM_ARGS;
311 msg.args = calloc(msg.num_args, sizeof(*msg.args));
312 if (!msg.args) {
313 MSG_ERR("Memory allocation failed\n");
314 return -E_DBUS_NO_MEM;
315 }
316
317 if (!strncmp(arg, "clean", strlen("clean"))) {
318 msg.args[0] = RESUME_NOT_MODIFIED;
319 } else if (!strncmp(arg, "modified", strlen("modified"))) {
320 msg.args[0] = RESUME_FLASH_MODIFIED;
321 } else {
322 MSG_ERR("Resume command takes argument < \"clean\" | "
323 "\"modified\" >\n");
324 rc = -E_DBUS_INVAL;
325 goto out;
326 }
327
Andrew Jeffery68023072018-08-06 10:08:11 +0930328 rc = send_dbus_msg_legacy(context, &msg, &resp);
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100329 if (rc < 0) {
330 MSG_ERR("Failed to send resume command\n");
331 goto out;
332 }
333
334 rc = -resp.cmd;
335 MSG_OUT("Resume: %s\n", dbus_err_str[-rc]);
336
337out:
338 free(msg.args);
339 return rc;
340}
341
342static int handle_cmd_modified(struct mboxctl_context *context)
343{
344 struct mbox_dbus_msg msg = { 0 }, resp = { 0 };
345 int rc;
346
347 msg.cmd = DBUS_C_MODIFIED;
348
Andrew Jeffery68023072018-08-06 10:08:11 +0930349 rc = send_dbus_msg_legacy(context, &msg, &resp);
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100350 if (rc < 0) {
351 MSG_ERR("Failed to send flash modified command\n");
352 return rc;
353 }
354
355 rc = -resp.cmd;
356 MSG_OUT("Clear Cache: %s\n", dbus_err_str[-rc]);
357
358 return rc;
359}
360
361static int parse_cmdline(struct mboxctl_context *context, int argc, char **argv)
362{
363 int opt, rc = -1;
364
365 static const struct option long_options[] = {
366 { "silent", no_argument, 0, 's' },
367 { "ping", no_argument, 0, 'p' },
368 { "daemon-state", no_argument, 0, 'd' },
369 { "lpc-state", no_argument, 0, 'l' },
370 { "kill", no_argument, 0, 'k' },
371 { "reset", no_argument, 0, 'r' },
372 { "point-to-flash", no_argument, 0, 'f' },
373 { "suspend", no_argument, 0, 'u' },
374 { "resume", required_argument, 0, 'e' },
375 { "clear-cache", no_argument, 0, 'c' },
376 { "version", no_argument, 0, 'v' },
377 { "help", no_argument, 0, 'h' },
378 { 0, 0, 0, 0 }
379 };
380
381 if (argc <= 1) {
382 usage(argv[0]);
383 return -E_DBUS_INVAL;
384 }
385
386 while ((opt = getopt_long(argc, argv, "spdlkrfue:cvh", long_options,
387 NULL)) != -1) {
388 switch (opt) {
389 case 's':
390 silent = true;
391 continue;
392 case 'p':
393 rc = handle_cmd_ping(context);
394 break;
395 case 'd':
396 rc = handle_cmd_daemon_state(context);
397 break;
398 case 'l':
399 rc = handle_cmd_lpc_state(context);
400 break;
401 case 'k':
402 rc = handle_cmd_kill(context);
403 break;
404 case 'r': /* These are the same for now (reset may change) */
405 case 'f':
406 rc = handle_cmd_reset(context);
407 break;
408 case 'u':
409 rc = handle_cmd_suspend(context);
410 break;
411 case 'e':
412 rc = handle_cmd_resume(context, optarg);
413 break;
414 case 'c':
415 rc = handle_cmd_modified(context);
416 break;
417 case 'v':
Suraj Jitindar Singh8d65bb42017-05-01 16:05:17 +1000418 MSG_OUT("%s V%s\n", NAME, PACKAGE_VERSION);
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100419 rc = 0;
420 break;
421 case 'h':
422 usage(argv[0]);
423 rc = 0;
424 break;
425 default:
426 usage(argv[0]);
427 rc = -E_DBUS_INVAL;
428 break;
429 }
430 }
431
432 return rc;
433}
434
435int main(int argc, char **argv)
436{
437 struct mboxctl_context context;
438 int rc;
439
440 silent = false;
441
442 rc = init_mboxctl_dbus(&context);
443 if (rc < 0) {
444 MSG_ERR("Failed to init dbus\n");
445 return rc;
446 }
447
448 rc = parse_cmdline(&context, argc, argv);
449
450 return rc;
451}