blob: ccb58482bdf019cf055f5b41a74692a111305921 [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
Andrew Jefferya804a732019-04-04 16:52:36 +103095static int mboxctl_getter(struct mboxctl_context *context,
96 const char *property, uint8_t *resp)
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +110097{
98 sd_bus_error error = SD_BUS_ERROR_NULL;
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +110099
Andrew Jefferya804a732019-04-04 16:52:36 +1030100 return sd_bus_get_property_trivial(context->bus, MBOX_DBUS_NAME,
101 MBOX_DBUS_OBJECT,
102 MBOX_DBUS_CONTROL_IFACE,
103 property, &error, 'y', resp);
Andrew Jefferyfbf74542018-08-06 15:58:01 +0930104}
105
106static int handle_cmd_ping(struct mboxctl_context *context)
107{
108 int rc;
109
110 rc = mboxctl_directive(context, "Ping");
111 MSG_OUT("Ping: %s\n", rc ? strerror(-rc) : "Success");
112
113 return rc;
114}
115
116static int handle_cmd_daemon_state(struct mboxctl_context *context)
117{
118 uint8_t resp;
119 int rc;
120
Andrew Jefferya804a732019-04-04 16:52:36 +1030121 rc = mboxctl_getter(context, "DaemonState", &resp);
Andrew Jefferyfbf74542018-08-06 15:58:01 +0930122 if (rc < 0)
123 return rc;
124
125 MSG_OUT("Daemon State: %s\n", resp == DAEMON_STATE_ACTIVE ?
126 "Active" : "Suspended");
127 return 0;
128}
129
130static int handle_cmd_lpc_state(struct mboxctl_context *context)
131{
132 uint8_t resp;
133 int rc;
134
Andrew Jefferya804a732019-04-04 16:52:36 +1030135 rc = mboxctl_getter(context, "LpcState", &resp);
Andrew Jefferyfbf74542018-08-06 15:58:01 +0930136 if (rc < 0)
137 return rc;
138
139 MSG_OUT("LPC Bus Maps: %s\n", resp == LPC_STATE_MEM ?
140 "BMC Memory" :
141 (resp == LPC_STATE_FLASH ?
142 "Flash Device" :
143 "Invalid System State"));
144
145 return 0;
146}
147
148static int handle_cmd_kill(struct mboxctl_context *context)
149{
150 int rc;
151
152 rc = mboxctl_directive(context, "Kill");
153 MSG_OUT("Kill: %s\n", rc ? strerror(-rc) : "Success");
154
155 return rc;
156}
157
158static int handle_cmd_reset(struct mboxctl_context *context)
159{
160 int rc;
161
162 rc = mboxctl_directive(context, "Reset");
163 MSG_OUT("Reset: %s\n", rc ? strerror(-rc) : "Success");
164
165 return rc;
166}
167
168static int handle_cmd_suspend(struct mboxctl_context *context)
169{
170 int rc;
171
172 rc = mboxctl_directive(context, "Suspend");
173 MSG_OUT("Suspend: %s\n", rc ? strerror(-rc) : "Success");
174
175 return rc;
176}
177
178static int handle_cmd_resume(struct mboxctl_context *context, char *sarg)
179{
180 sd_bus_error error = SD_BUS_ERROR_NULL;
181 sd_bus_message *m = NULL, *n = NULL;
182 uint8_t arg;
183 int rc;
184
185 if (!sarg) {
186 MSG_ERR("Resume command takes an argument\n");
187 return -EINVAL;
188 }
189
190 rc = sd_bus_message_new_method_call(context->bus, &m,
191 MBOX_DBUS_NAME,
192 MBOX_DBUS_OBJECT,
193 MBOX_DBUS_CONTROL_IFACE,
194 "Resume");
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100195 if (rc < 0) {
196 MSG_ERR("Failed to init method call: %s\n",
197 strerror(-rc));
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100198 goto out;
199 }
200
Andrew Jefferyfbf74542018-08-06 15:58:01 +0930201 if (!strncmp(sarg, "clean", strlen("clean"))) {
202 arg = RESUME_NOT_MODIFIED;
203 } else if (!strncmp(sarg, "modified", strlen("modified"))) {
204 arg = RESUME_FLASH_MODIFIED;
205 } else {
206 MSG_ERR("Resume command takes argument < \"clean\" | "
207 "\"modified\" >\n");
208 rc = -EINVAL;
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100209 goto out;
210 }
211
Andrew Jeffery6c4d8ba2018-11-01 10:45:35 +1030212 rc = sd_bus_message_append(m, "b", arg);
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100213 if (rc < 0) {
214 MSG_ERR("Failed to add args to message: %s\n",
215 strerror(-rc));
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100216 goto out;
217 }
218
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100219 rc = sd_bus_call(context->bus, m, 0, &error, &n);
220 if (rc < 0) {
221 MSG_ERR("Failed to post message: %s\n", strerror(-rc));
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100222 goto out;
223 }
224
Andrew Jefferyfbf74542018-08-06 15:58:01 +0930225 MSG_OUT("Resume: %s\n", rc < 0 ? strerror(-rc) : "Success");
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100226
227out:
228 sd_bus_error_free(&error);
229 sd_bus_message_unref(m);
230 sd_bus_message_unref(n);
231
Andrew Jefferyfbf74542018-08-06 15:58:01 +0930232 return rc < 0 ? rc : 0;
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100233}
234
235static int handle_cmd_modified(struct mboxctl_context *context)
236{
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100237 int rc;
238
Andrew Jefferyfbf74542018-08-06 15:58:01 +0930239 rc = mboxctl_directive(context, "MarkFlashModified");
240 MSG_OUT("Clear Cache: %s\n", rc ? strerror(-rc) : "Success");
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100241
242 return rc;
243}
244
Andrew Jeffery5320f6e2019-03-15 12:40:41 +1030245static int handle_cmd_backend(struct mboxctl_context *context, char *sarg)
246{
247 sd_bus_error error = SD_BUS_ERROR_NULL;
248 sd_bus_message *m = NULL, *n = NULL;
249 char *delim = NULL;
250 char *strv[2];
251 int rc;
252
253 if (!sarg) {
254 MSG_ERR("Backend command takes an argument\n");
255 return -EINVAL;
256 }
257
258 rc = sd_bus_message_new_method_call(context->bus, &m,
259 MBOX_DBUS_NAME,
260 MBOX_DBUS_OBJECT,
261 MBOX_DBUS_CONTROL_IFACE,
262 "SetBackend");
263 if (rc < 0) {
264 MSG_ERR("Failed to init method call: %s\n",
265 strerror(-rc));
266 goto out;
267 }
268
269 if (!strncmp(sarg, "vpnor", strlen("vpnor"))) {
270 if (strchr(sarg, ':')) {
271 MSG_ERR("Path parameter not supported for vpnor\n");
272 rc = -EINVAL;
273 goto out;
274 }
275
276 rc = sd_bus_message_append(m, "s", "vpnor");
277 if (rc < 0)
278 goto out;
279 } else if (!strncmp(sarg, "mtd", strlen("mtd"))) {
280 rc = sd_bus_message_append(m, "s", "mtd");
281 if (rc < 0)
282 goto out;
283 } else if (!strncmp(sarg, "file", strlen("file"))) {
284 rc = sd_bus_message_append(m, "s", "file");
285 if (rc < 0)
286 goto out;
287 } else {
288 rc = -EINVAL;
289 goto out;
290 }
291
292 delim = strchr(sarg, ':');
293 if (delim) {
294 char *path;
295
296 path = realpath(delim + 1, NULL);
297 if (!path) {
298 MSG_ERR("Failed to resolve path: %s\n",
299 strerror(errno));
300 rc = -errno;
301 goto out;
302 }
303
304 strv[0] = path;
305 strv[1] = NULL;
306
307 rc = sd_bus_message_append_strv(m, &strv[0]);
308 free(path);
309 if (rc < 0)
310 goto out;
311 } else {
312 strv[0] = NULL;
313 strv[1] = NULL;
314 rc = sd_bus_message_append_strv(m, &strv[0]);
315 if (rc < 0)
316 goto out;
317 }
318
319 rc = sd_bus_call(context->bus, m, 0, &error, &n);
320 if (rc < 0) {
321 MSG_ERR("Failed to post message: %s\n", strerror(-rc));
322 goto out;
323 }
324
325 MSG_OUT("SetBackend: %s\n", rc < 0 ? strerror(-rc) : "Success");
326
327out:
328 sd_bus_error_free(&error);
329 sd_bus_message_unref(m);
330
331 return rc < 0 ? rc : 0;
332}
333
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100334static int parse_cmdline(struct mboxctl_context *context, int argc, char **argv)
335{
336 int opt, rc = -1;
337
338 static const struct option long_options[] = {
339 { "silent", no_argument, 0, 's' },
340 { "ping", no_argument, 0, 'p' },
341 { "daemon-state", no_argument, 0, 'd' },
342 { "lpc-state", no_argument, 0, 'l' },
343 { "kill", no_argument, 0, 'k' },
344 { "reset", no_argument, 0, 'r' },
345 { "point-to-flash", no_argument, 0, 'f' },
346 { "suspend", no_argument, 0, 'u' },
347 { "resume", required_argument, 0, 'e' },
348 { "clear-cache", no_argument, 0, 'c' },
Andrew Jeffery5320f6e2019-03-15 12:40:41 +1030349 { "backend", required_argument, 0, 'b' },
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100350 { "version", no_argument, 0, 'v' },
351 { "help", no_argument, 0, 'h' },
352 { 0, 0, 0, 0 }
353 };
354
355 if (argc <= 1) {
356 usage(argv[0]);
Andrew Jefferyfbf74542018-08-06 15:58:01 +0930357 return -EINVAL;
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100358 }
359
360 while ((opt = getopt_long(argc, argv, "spdlkrfue:cvh", long_options,
361 NULL)) != -1) {
362 switch (opt) {
363 case 's':
364 silent = true;
365 continue;
366 case 'p':
367 rc = handle_cmd_ping(context);
368 break;
369 case 'd':
370 rc = handle_cmd_daemon_state(context);
371 break;
372 case 'l':
373 rc = handle_cmd_lpc_state(context);
374 break;
375 case 'k':
376 rc = handle_cmd_kill(context);
377 break;
378 case 'r': /* These are the same for now (reset may change) */
379 case 'f':
380 rc = handle_cmd_reset(context);
381 break;
382 case 'u':
383 rc = handle_cmd_suspend(context);
384 break;
385 case 'e':
386 rc = handle_cmd_resume(context, optarg);
387 break;
388 case 'c':
389 rc = handle_cmd_modified(context);
390 break;
Andrew Jeffery5320f6e2019-03-15 12:40:41 +1030391 case 'b':
392 rc = handle_cmd_backend(context, optarg);
393 break;
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100394 case 'v':
Suraj Jitindar Singh8d65bb42017-05-01 16:05:17 +1000395 MSG_OUT("%s V%s\n", NAME, PACKAGE_VERSION);
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100396 rc = 0;
397 break;
398 case 'h':
399 usage(argv[0]);
400 rc = 0;
401 break;
402 default:
403 usage(argv[0]);
Andrew Jefferyfbf74542018-08-06 15:58:01 +0930404 rc = -EINVAL;
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100405 break;
406 }
407 }
408
409 return rc;
410}
411
412int main(int argc, char **argv)
413{
414 struct mboxctl_context context;
415 int rc;
416
417 silent = false;
418
419 rc = init_mboxctl_dbus(&context);
420 if (rc < 0) {
421 MSG_ERR("Failed to init dbus\n");
422 return rc;
423 }
424
425 rc = parse_cmdline(&context, argc, argv);
426
427 return rc;
428}