blob: b001fb9e665f63eeebfb86abe760917d90d17d0f [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
Andrew Jefferyfbf74542018-08-06 15:58:01 +09305#include <errno.h>
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +11006#include <getopt.h>
Andrew Jeffery5320f6e2019-03-15 12:40:41 +10307#include <limits.h>
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +11008#include <stdbool.h>
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +11009#include <stdio.h>
10#include <stdlib.h>
Andrew Jefferyfbf74542018-08-06 15:58:01 +093011#include <string.h>
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +110012#include <systemd/sd-bus.h>
13
14#include "dbus.h"
15
16#define USAGE \
17"\nUsage: %s [--silent | -s] <command> [args]\n\n" \
18"\t\t--silent\t\t- no output on the command line\n\n" \
19"\tCommands: (num args)\n" \
20"\t\t--ping\t\t\t- ping the daemon (0)\n" \
21"\t\t--daemon-state\t\t- check state of the daemon (0)\n" \
22"\t\t--lpc-state\t\t- check the state of the lpc mapping (0)\n" \
23"\t\t--kill\t\t\t- stop the daemon [no flush] (0)\n" \
24"\t\t--reset\t\t\t- hard reset the daemon state (0)\n" \
25"\t\t--point-to-flash\t- point the lpc mapping back to flash (0)\n" \
26"\t\t--suspend\t\t- suspend the daemon to inhibit flash accesses (0)\n" \
27"\t\t--resume\t\t- resume the daemon (1)\n" \
28"\t\t\targ[0]: < \"clean\" | \"modified\" >\n" \
Andrew Jeffery5320f6e2019-03-15 12:40:41 +103029"\t\t--clear-cache\t- tell the daemon to discard any caches (0)\n" \
30"\t\t--backend <vpnor|mtd[:PATH]|file:PATH>\n"
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +110031
Suraj Jitindar Singh8d65bb42017-05-01 16:05:17 +100032#define NAME "Mailbox Control"
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +110033
34static bool silent;
35
36#define MSG_OUT(...) do { if (!silent) { \
37 fprintf(stdout, __VA_ARGS__); } \
38 } while (0)
39#define MSG_ERR(...) do { if (!silent) { \
40 fprintf(stderr, __VA_ARGS__); } \
41 } while (0)
42
43struct mboxctl_context {
44 sd_bus *bus;
45};
46
47static void usage(char *name)
48{
49 MSG_OUT(USAGE, name);
50 exit(0);
51}
52
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +110053static int init_mboxctl_dbus(struct mboxctl_context *context)
54{
55 int rc;
56
57 rc = sd_bus_default_system(&context->bus);
58 if (rc < 0) {
59 MSG_ERR("Failed to connect to the system bus: %s\n",
60 strerror(-rc));
61 }
62
63 return rc;
64}
65
Andrew Jefferyfbf74542018-08-06 15:58:01 +093066static int mboxctl_directive(struct mboxctl_context *context, const char *cmd)
67{
68 sd_bus_error error = SD_BUS_ERROR_NULL;
69 sd_bus_message *m = NULL;
70 int rc;
71
72 rc = sd_bus_message_new_method_call(context->bus, &m,
73 MBOX_DBUS_NAME,
74 MBOX_DBUS_OBJECT,
75 MBOX_DBUS_CONTROL_IFACE,
76 cmd);
77 if (rc < 0) {
78 MSG_ERR("Failed to init method call: %s\n",
79 strerror(-rc));
80 goto out;
81 }
82
83 rc = sd_bus_call(context->bus, m, 0, &error, NULL);
84 if (rc < 0) {
85 MSG_ERR("Failed to post message: %s\n", strerror(-rc));
86 }
87
88out:
89 sd_bus_error_free(&error);
90 sd_bus_message_unref(m);
91
92 return rc < 0 ? rc : 0;
93}
94
95static int mboxctl_getter(struct mboxctl_context *context, const char *cmd,
96 uint8_t *resp)
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +110097{
98 sd_bus_error error = SD_BUS_ERROR_NULL;
99 sd_bus_message *m = NULL, *n = NULL;
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100100 int rc;
101
Andrew Jeffery68023072018-08-06 10:08:11 +0930102 rc = sd_bus_message_new_method_call(context->bus, &m,
Andrew Jefferyfbf74542018-08-06 15:58:01 +0930103 MBOX_DBUS_NAME,
104 MBOX_DBUS_OBJECT,
105 MBOX_DBUS_CONTROL_IFACE,
106 cmd);
107 if (rc < 0) {
108 MSG_ERR("Failed to init method call: %s\n",
109 strerror(-rc));
110 goto out;
111 }
112
113 rc = sd_bus_call(context->bus, m, 0, &error, &n);
114 if (rc < 0) {
115 MSG_ERR("Failed to post message: %s\n", strerror(-rc));
116 goto out;
117 }
118
119 rc = sd_bus_message_read_basic(n, 'y', resp);
120 if (rc < 0) {
121 MSG_ERR("Failed to read response args: %s\n",
122 strerror(-rc));
123 goto out;
124 }
125
126out:
127 sd_bus_error_free(&error);
128 sd_bus_message_unref(m);
129 sd_bus_message_unref(n);
130
131 return rc < 0 ? rc : 0;
132
133}
134
135static int handle_cmd_ping(struct mboxctl_context *context)
136{
137 int rc;
138
139 rc = mboxctl_directive(context, "Ping");
140 MSG_OUT("Ping: %s\n", rc ? strerror(-rc) : "Success");
141
142 return rc;
143}
144
145static int handle_cmd_daemon_state(struct mboxctl_context *context)
146{
147 uint8_t resp;
148 int rc;
149
150 rc = mboxctl_getter(context, "GetDaemonState", &resp);
151 if (rc < 0)
152 return rc;
153
154 MSG_OUT("Daemon State: %s\n", resp == DAEMON_STATE_ACTIVE ?
155 "Active" : "Suspended");
156 return 0;
157}
158
159static int handle_cmd_lpc_state(struct mboxctl_context *context)
160{
161 uint8_t resp;
162 int rc;
163
164 rc = mboxctl_getter(context, "GetLpcState", &resp);
165 if (rc < 0)
166 return rc;
167
168 MSG_OUT("LPC Bus Maps: %s\n", resp == LPC_STATE_MEM ?
169 "BMC Memory" :
170 (resp == LPC_STATE_FLASH ?
171 "Flash Device" :
172 "Invalid System State"));
173
174 return 0;
175}
176
177static int handle_cmd_kill(struct mboxctl_context *context)
178{
179 int rc;
180
181 rc = mboxctl_directive(context, "Kill");
182 MSG_OUT("Kill: %s\n", rc ? strerror(-rc) : "Success");
183
184 return rc;
185}
186
187static int handle_cmd_reset(struct mboxctl_context *context)
188{
189 int rc;
190
191 rc = mboxctl_directive(context, "Reset");
192 MSG_OUT("Reset: %s\n", rc ? strerror(-rc) : "Success");
193
194 return rc;
195}
196
197static int handle_cmd_suspend(struct mboxctl_context *context)
198{
199 int rc;
200
201 rc = mboxctl_directive(context, "Suspend");
202 MSG_OUT("Suspend: %s\n", rc ? strerror(-rc) : "Success");
203
204 return rc;
205}
206
207static int handle_cmd_resume(struct mboxctl_context *context, char *sarg)
208{
209 sd_bus_error error = SD_BUS_ERROR_NULL;
210 sd_bus_message *m = NULL, *n = NULL;
211 uint8_t arg;
212 int rc;
213
214 if (!sarg) {
215 MSG_ERR("Resume command takes an argument\n");
216 return -EINVAL;
217 }
218
219 rc = sd_bus_message_new_method_call(context->bus, &m,
220 MBOX_DBUS_NAME,
221 MBOX_DBUS_OBJECT,
222 MBOX_DBUS_CONTROL_IFACE,
223 "Resume");
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100224 if (rc < 0) {
225 MSG_ERR("Failed to init method call: %s\n",
226 strerror(-rc));
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100227 goto out;
228 }
229
Andrew Jefferyfbf74542018-08-06 15:58:01 +0930230 if (!strncmp(sarg, "clean", strlen("clean"))) {
231 arg = RESUME_NOT_MODIFIED;
232 } else if (!strncmp(sarg, "modified", strlen("modified"))) {
233 arg = RESUME_FLASH_MODIFIED;
234 } else {
235 MSG_ERR("Resume command takes argument < \"clean\" | "
236 "\"modified\" >\n");
237 rc = -EINVAL;
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100238 goto out;
239 }
240
Andrew Jeffery6c4d8ba2018-11-01 10:45:35 +1030241 rc = sd_bus_message_append(m, "b", arg);
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100242 if (rc < 0) {
243 MSG_ERR("Failed to add args to message: %s\n",
244 strerror(-rc));
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100245 goto out;
246 }
247
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100248 rc = sd_bus_call(context->bus, m, 0, &error, &n);
249 if (rc < 0) {
250 MSG_ERR("Failed to post message: %s\n", strerror(-rc));
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100251 goto out;
252 }
253
Andrew Jefferyfbf74542018-08-06 15:58:01 +0930254 MSG_OUT("Resume: %s\n", rc < 0 ? strerror(-rc) : "Success");
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100255
256out:
257 sd_bus_error_free(&error);
258 sd_bus_message_unref(m);
259 sd_bus_message_unref(n);
260
Andrew Jefferyfbf74542018-08-06 15:58:01 +0930261 return rc < 0 ? rc : 0;
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100262}
263
264static int handle_cmd_modified(struct mboxctl_context *context)
265{
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100266 int rc;
267
Andrew Jefferyfbf74542018-08-06 15:58:01 +0930268 rc = mboxctl_directive(context, "MarkFlashModified");
269 MSG_OUT("Clear Cache: %s\n", rc ? strerror(-rc) : "Success");
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100270
271 return rc;
272}
273
Andrew Jeffery5320f6e2019-03-15 12:40:41 +1030274static int handle_cmd_backend(struct mboxctl_context *context, char *sarg)
275{
276 sd_bus_error error = SD_BUS_ERROR_NULL;
277 sd_bus_message *m = NULL, *n = NULL;
278 char *delim = NULL;
279 char *strv[2];
280 int rc;
281
282 if (!sarg) {
283 MSG_ERR("Backend command takes an argument\n");
284 return -EINVAL;
285 }
286
287 rc = sd_bus_message_new_method_call(context->bus, &m,
288 MBOX_DBUS_NAME,
289 MBOX_DBUS_OBJECT,
290 MBOX_DBUS_CONTROL_IFACE,
291 "SetBackend");
292 if (rc < 0) {
293 MSG_ERR("Failed to init method call: %s\n",
294 strerror(-rc));
295 goto out;
296 }
297
298 if (!strncmp(sarg, "vpnor", strlen("vpnor"))) {
299 if (strchr(sarg, ':')) {
300 MSG_ERR("Path parameter not supported for vpnor\n");
301 rc = -EINVAL;
302 goto out;
303 }
304
305 rc = sd_bus_message_append(m, "s", "vpnor");
306 if (rc < 0)
307 goto out;
308 } else if (!strncmp(sarg, "mtd", strlen("mtd"))) {
309 rc = sd_bus_message_append(m, "s", "mtd");
310 if (rc < 0)
311 goto out;
312 } else if (!strncmp(sarg, "file", strlen("file"))) {
313 rc = sd_bus_message_append(m, "s", "file");
314 if (rc < 0)
315 goto out;
316 } else {
317 rc = -EINVAL;
318 goto out;
319 }
320
321 delim = strchr(sarg, ':');
322 if (delim) {
323 char *path;
324
325 path = realpath(delim + 1, NULL);
326 if (!path) {
327 MSG_ERR("Failed to resolve path: %s\n",
328 strerror(errno));
329 rc = -errno;
330 goto out;
331 }
332
333 strv[0] = path;
334 strv[1] = NULL;
335
336 rc = sd_bus_message_append_strv(m, &strv[0]);
337 free(path);
338 if (rc < 0)
339 goto out;
340 } else {
341 strv[0] = NULL;
342 strv[1] = NULL;
343 rc = sd_bus_message_append_strv(m, &strv[0]);
344 if (rc < 0)
345 goto out;
346 }
347
348 rc = sd_bus_call(context->bus, m, 0, &error, &n);
349 if (rc < 0) {
350 MSG_ERR("Failed to post message: %s\n", strerror(-rc));
351 goto out;
352 }
353
354 MSG_OUT("SetBackend: %s\n", rc < 0 ? strerror(-rc) : "Success");
355
356out:
357 sd_bus_error_free(&error);
358 sd_bus_message_unref(m);
359
360 return rc < 0 ? rc : 0;
361}
362
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100363static int parse_cmdline(struct mboxctl_context *context, int argc, char **argv)
364{
365 int opt, rc = -1;
366
367 static const struct option long_options[] = {
368 { "silent", no_argument, 0, 's' },
369 { "ping", no_argument, 0, 'p' },
370 { "daemon-state", no_argument, 0, 'd' },
371 { "lpc-state", no_argument, 0, 'l' },
372 { "kill", no_argument, 0, 'k' },
373 { "reset", no_argument, 0, 'r' },
374 { "point-to-flash", no_argument, 0, 'f' },
375 { "suspend", no_argument, 0, 'u' },
376 { "resume", required_argument, 0, 'e' },
377 { "clear-cache", no_argument, 0, 'c' },
Andrew Jeffery5320f6e2019-03-15 12:40:41 +1030378 { "backend", required_argument, 0, 'b' },
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100379 { "version", no_argument, 0, 'v' },
380 { "help", no_argument, 0, 'h' },
381 { 0, 0, 0, 0 }
382 };
383
384 if (argc <= 1) {
385 usage(argv[0]);
Andrew Jefferyfbf74542018-08-06 15:58:01 +0930386 return -EINVAL;
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100387 }
388
389 while ((opt = getopt_long(argc, argv, "spdlkrfue:cvh", long_options,
390 NULL)) != -1) {
391 switch (opt) {
392 case 's':
393 silent = true;
394 continue;
395 case 'p':
396 rc = handle_cmd_ping(context);
397 break;
398 case 'd':
399 rc = handle_cmd_daemon_state(context);
400 break;
401 case 'l':
402 rc = handle_cmd_lpc_state(context);
403 break;
404 case 'k':
405 rc = handle_cmd_kill(context);
406 break;
407 case 'r': /* These are the same for now (reset may change) */
408 case 'f':
409 rc = handle_cmd_reset(context);
410 break;
411 case 'u':
412 rc = handle_cmd_suspend(context);
413 break;
414 case 'e':
415 rc = handle_cmd_resume(context, optarg);
416 break;
417 case 'c':
418 rc = handle_cmd_modified(context);
419 break;
Andrew Jeffery5320f6e2019-03-15 12:40:41 +1030420 case 'b':
421 rc = handle_cmd_backend(context, optarg);
422 break;
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100423 case 'v':
Suraj Jitindar Singh8d65bb42017-05-01 16:05:17 +1000424 MSG_OUT("%s V%s\n", NAME, PACKAGE_VERSION);
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100425 rc = 0;
426 break;
427 case 'h':
428 usage(argv[0]);
429 rc = 0;
430 break;
431 default:
432 usage(argv[0]);
Andrew Jefferyfbf74542018-08-06 15:58:01 +0930433 rc = -EINVAL;
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100434 break;
435 }
436 }
437
438 return rc;
439}
440
441int main(int argc, char **argv)
442{
443 struct mboxctl_context context;
444 int rc;
445
446 silent = false;
447
448 rc = init_mboxctl_dbus(&context);
449 if (rc < 0) {
450 MSG_ERR("Failed to init dbus\n");
451 return rc;
452 }
453
454 rc = parse_cmdline(&context, argc, argv);
455
456 return rc;
457}