blob: fff8c0e3d71768b313cd600bbab1b5868209311d [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
71static int send_dbus_msg(struct mboxctl_context *context,
72 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 */
82 rc = sd_bus_message_new_method_call(context->bus, &m, DBUS_NAME,
83 DOBJ_NAME, DBUS_NAME, "cmd");
84 if (rc < 0) {
85 MSG_ERR("Failed to init method call: %s\n",
86 strerror(-rc));
87 rc = -E_DBUS_INTERNAL;
88 goto out;
89 }
90
91 /* Add the command */
92 rc = sd_bus_message_append(m, "y", msg->cmd);
93 if (rc < 0) {
94 MSG_ERR("Failed to add cmd to message: %s\n",
95 strerror(-rc));
96 rc = -E_DBUS_INTERNAL;
97 goto out;
98 }
99
100 /* Add the args */
101 rc = sd_bus_message_append_array(m, 'y', msg->args, msg->num_args);
102 if (rc < 0) {
103 MSG_ERR("Failed to add args to message: %s\n",
104 strerror(-rc));
105 rc = -E_DBUS_INTERNAL;
106 goto out;
107 }
108
109 /* Send the message */
110 rc = sd_bus_call(context->bus, m, 0, &error, &n);
111 if (rc < 0) {
112 MSG_ERR("Failed to post message: %s\n", strerror(-rc));
113 rc = -E_DBUS_INTERNAL;
114 goto out;
115 }
116
117 /* Read response code */
118 rc = sd_bus_message_read(n, "y", &resp->cmd);
119 if (rc < 0) {
120 MSG_ERR("Failed to read response code: %s\n",
121 strerror(-rc));
122 rc = -E_DBUS_INTERNAL;
123 goto out;
124 }
125
126 /* Read response args */
127 rc = sd_bus_message_read_array(n, 'y', (const void **) &buf, &sz);
128 if (rc < 0) {
129 MSG_ERR("Failed to read response args: %s\n",
130 strerror(-rc));
131 rc = -E_DBUS_INTERNAL;
132 goto out;
133 }
134
135 if (sz < resp->num_args) {
136 MSG_ERR("Command returned insufficient response args\n");
137 rc = -E_DBUS_INTERNAL;
138 goto out;
139 }
140
141 memcpy(resp->args, buf, resp->num_args);
142 rc = 0;
143
144out:
145 sd_bus_error_free(&error);
146 sd_bus_message_unref(m);
147 sd_bus_message_unref(n);
148
149 return rc;
150}
151
152static int handle_cmd_ping(struct mboxctl_context *context)
153{
154 struct mbox_dbus_msg msg = { 0 }, resp = { 0 };
155 int rc;
156
157 msg.cmd = DBUS_C_PING;
158
159 rc = send_dbus_msg(context, &msg, &resp);
160 if (rc < 0) {
161 MSG_ERR("Failed to send ping command\n");
162 return rc;
163 }
164
165 rc = -resp.cmd;
166 MSG_OUT("Ping: %s\n", dbus_err_str[-rc]);
167
168 return rc;
169}
170
171static int handle_cmd_daemon_state(struct mboxctl_context *context)
172{
173 struct mbox_dbus_msg msg = { 0 }, resp = { 0 };
174 int rc;
175
176 msg.cmd = DBUS_C_DAEMON_STATE;
177 resp.num_args = DAEMON_STATE_NUM_ARGS;
178 resp.args = calloc(resp.num_args, sizeof(*resp.args));
179 if (!resp.args) {
180 MSG_ERR("Memory allocation failed\n");
181 return -E_DBUS_NO_MEM;
182 }
183
184 rc = send_dbus_msg(context, &msg, &resp);
185 if (rc < 0) {
186 MSG_ERR("Failed to send daemon state command\n");
187 goto out;
188 }
189
190 rc = -resp.cmd;
191 if (resp.cmd != DBUS_SUCCESS) {
192 MSG_ERR("Daemon state command failed\n");
193 goto out;
194 }
195
196 MSG_OUT("Daemon State: %s\n", resp.args[0] == DAEMON_STATE_ACTIVE ?
197 "Active" : "Suspended");
198
199out:
200 free(resp.args);
201 return rc;
202}
203
204static int handle_cmd_lpc_state(struct mboxctl_context *context)
205{
206 struct mbox_dbus_msg msg = { 0 }, resp = { 0 };
207 int rc;
208
209 msg.cmd = DBUS_C_LPC_STATE;
210 resp.num_args = LPC_STATE_NUM_ARGS;
211 resp.args = calloc(resp.num_args, sizeof(*resp.args));
212 if (!resp.args) {
213 MSG_ERR("Memory allocation failed\n");
214 return -E_DBUS_NO_MEM;
215 }
216
217 rc = send_dbus_msg(context, &msg, &resp);
218 if (rc < 0) {
219 MSG_ERR("Failed to send lpc state command\n");
220 goto out;
221 }
222
223 rc = -resp.cmd;
224 if (resp.cmd != DBUS_SUCCESS) {
225 MSG_ERR("LPC state command failed\n");
226 goto out;
227 }
228
229 MSG_OUT("LPC Bus Maps: %s\n", resp.args[0] == LPC_STATE_MEM ?
230 "BMC Memory" :
231 (resp.args[0] == LPC_STATE_FLASH ?
232 "Flash Device" :
233 "Invalid System State"));
234
235out:
236 free(resp.args);
237 return rc;
238}
239
240static int handle_cmd_kill(struct mboxctl_context *context)
241{
242 struct mbox_dbus_msg msg = { 0 }, resp = { 0 };
243 int rc;
244
245 msg.cmd = DBUS_C_KILL;
246
247 rc = send_dbus_msg(context, &msg, &resp);
248 if (rc < 0) {
249 MSG_ERR("Failed to send kill command\n");
250 return rc;
251 }
252
253 rc = -resp.cmd;
254 MSG_OUT("Kill: %s\n", dbus_err_str[-rc]);
255
256 return rc;
257}
258
259static int handle_cmd_reset(struct mboxctl_context *context)
260{
261 struct mbox_dbus_msg msg = { 0 }, resp = { 0 };
262 int rc;
263
264 msg.cmd = DBUS_C_RESET;
265
266 rc = send_dbus_msg(context, &msg, &resp);
267 if (rc < 0) {
268 MSG_ERR("Failed to send reset command\n");
269 return rc;
270 }
271
272 rc = -resp.cmd;
273 MSG_OUT("Reset: %s\n", dbus_err_str[-rc]);
274
275 return rc;
276}
277
278static int handle_cmd_suspend(struct mboxctl_context *context)
279{
280 struct mbox_dbus_msg msg = { 0 }, resp = { 0 };
281 int rc;
282
283 msg.cmd = DBUS_C_SUSPEND;
284
285 rc = send_dbus_msg(context, &msg, &resp);
286 if (rc < 0) {
287 MSG_ERR("Failed to send suspend command\n");
288 return rc;
289 }
290
291 rc = -resp.cmd;
292 MSG_OUT("Suspend: %s\n", dbus_err_str[-rc]);
293
294 return rc;
295}
296
297static int handle_cmd_resume(struct mboxctl_context *context, char *arg)
298{
299 struct mbox_dbus_msg msg = { 0 }, resp = { 0 };
300 int rc;
301
302 if (!arg) {
303 MSG_ERR("Resume command takes an argument\n");
304 return -E_DBUS_INVAL;
305 }
306
307 msg.cmd = DBUS_C_RESUME;
308 msg.num_args = RESUME_NUM_ARGS;
309 msg.args = calloc(msg.num_args, sizeof(*msg.args));
310 if (!msg.args) {
311 MSG_ERR("Memory allocation failed\n");
312 return -E_DBUS_NO_MEM;
313 }
314
315 if (!strncmp(arg, "clean", strlen("clean"))) {
316 msg.args[0] = RESUME_NOT_MODIFIED;
317 } else if (!strncmp(arg, "modified", strlen("modified"))) {
318 msg.args[0] = RESUME_FLASH_MODIFIED;
319 } else {
320 MSG_ERR("Resume command takes argument < \"clean\" | "
321 "\"modified\" >\n");
322 rc = -E_DBUS_INVAL;
323 goto out;
324 }
325
326 rc = send_dbus_msg(context, &msg, &resp);
327 if (rc < 0) {
328 MSG_ERR("Failed to send resume command\n");
329 goto out;
330 }
331
332 rc = -resp.cmd;
333 MSG_OUT("Resume: %s\n", dbus_err_str[-rc]);
334
335out:
336 free(msg.args);
337 return rc;
338}
339
340static int handle_cmd_modified(struct mboxctl_context *context)
341{
342 struct mbox_dbus_msg msg = { 0 }, resp = { 0 };
343 int rc;
344
345 msg.cmd = DBUS_C_MODIFIED;
346
347 rc = send_dbus_msg(context, &msg, &resp);
348 if (rc < 0) {
349 MSG_ERR("Failed to send flash modified command\n");
350 return rc;
351 }
352
353 rc = -resp.cmd;
354 MSG_OUT("Clear Cache: %s\n", dbus_err_str[-rc]);
355
356 return rc;
357}
358
359static int parse_cmdline(struct mboxctl_context *context, int argc, char **argv)
360{
361 int opt, rc = -1;
362
363 static const struct option long_options[] = {
364 { "silent", no_argument, 0, 's' },
365 { "ping", no_argument, 0, 'p' },
366 { "daemon-state", no_argument, 0, 'd' },
367 { "lpc-state", no_argument, 0, 'l' },
368 { "kill", no_argument, 0, 'k' },
369 { "reset", no_argument, 0, 'r' },
370 { "point-to-flash", no_argument, 0, 'f' },
371 { "suspend", no_argument, 0, 'u' },
372 { "resume", required_argument, 0, 'e' },
373 { "clear-cache", no_argument, 0, 'c' },
374 { "version", no_argument, 0, 'v' },
375 { "help", no_argument, 0, 'h' },
376 { 0, 0, 0, 0 }
377 };
378
379 if (argc <= 1) {
380 usage(argv[0]);
381 return -E_DBUS_INVAL;
382 }
383
384 while ((opt = getopt_long(argc, argv, "spdlkrfue:cvh", long_options,
385 NULL)) != -1) {
386 switch (opt) {
387 case 's':
388 silent = true;
389 continue;
390 case 'p':
391 rc = handle_cmd_ping(context);
392 break;
393 case 'd':
394 rc = handle_cmd_daemon_state(context);
395 break;
396 case 'l':
397 rc = handle_cmd_lpc_state(context);
398 break;
399 case 'k':
400 rc = handle_cmd_kill(context);
401 break;
402 case 'r': /* These are the same for now (reset may change) */
403 case 'f':
404 rc = handle_cmd_reset(context);
405 break;
406 case 'u':
407 rc = handle_cmd_suspend(context);
408 break;
409 case 'e':
410 rc = handle_cmd_resume(context, optarg);
411 break;
412 case 'c':
413 rc = handle_cmd_modified(context);
414 break;
415 case 'v':
Suraj Jitindar Singh8d65bb42017-05-01 16:05:17 +1000416 MSG_OUT("%s V%s\n", NAME, PACKAGE_VERSION);
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100417 rc = 0;
418 break;
419 case 'h':
420 usage(argv[0]);
421 rc = 0;
422 break;
423 default:
424 usage(argv[0]);
425 rc = -E_DBUS_INVAL;
426 break;
427 }
428 }
429
430 return rc;
431}
432
433int main(int argc, char **argv)
434{
435 struct mboxctl_context context;
436 int rc;
437
438 silent = false;
439
440 rc = init_mboxctl_dbus(&context);
441 if (rc < 0) {
442 MSG_ERR("Failed to init dbus\n");
443 return rc;
444 }
445
446 rc = parse_cmdline(&context, argc, argv);
447
448 return rc;
449}