blob: d2e590e59da91a8a8a45071f9a8d6eaa2c4b48c0 [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>
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +11007#include <stdbool.h>
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +11008#include <stdio.h>
9#include <stdlib.h>
Andrew Jefferyfbf74542018-08-06 15:58:01 +093010#include <string.h>
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +110011#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
Suraj Jitindar Singh8d65bb42017-05-01 16:05:17 +100030#define NAME "Mailbox Control"
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +110031
32static 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
41struct mboxctl_context {
42 sd_bus *bus;
43};
44
45static void usage(char *name)
46{
47 MSG_OUT(USAGE, name);
48 exit(0);
49}
50
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +110051static 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
Andrew Jefferyfbf74542018-08-06 15:58:01 +093064static 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
86out:
87 sd_bus_error_free(&error);
88 sd_bus_message_unref(m);
89
90 return rc < 0 ? rc : 0;
91}
92
93static int mboxctl_getter(struct mboxctl_context *context, const char *cmd,
94 uint8_t *resp)
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +110095{
96 sd_bus_error error = SD_BUS_ERROR_NULL;
97 sd_bus_message *m = NULL, *n = NULL;
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +110098 int rc;
99
Andrew Jeffery68023072018-08-06 10:08:11 +0930100 rc = sd_bus_message_new_method_call(context->bus, &m,
Andrew Jefferyfbf74542018-08-06 15:58:01 +0930101 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
124out:
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
133static 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
143static 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
157static 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
175static 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
185static 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
195static 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
205static 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");
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100222 if (rc < 0) {
223 MSG_ERR("Failed to init method call: %s\n",
224 strerror(-rc));
225 rc = -E_DBUS_INTERNAL;
226 goto out;
227 }
228
Andrew Jefferyfbf74542018-08-06 15:58:01 +0930229 if (!strncmp(sarg, "clean", strlen("clean"))) {
230 arg = RESUME_NOT_MODIFIED;
231 } else if (!strncmp(sarg, "modified", strlen("modified"))) {
232 arg = RESUME_FLASH_MODIFIED;
233 } else {
234 MSG_ERR("Resume command takes argument < \"clean\" | "
235 "\"modified\" >\n");
236 rc = -EINVAL;
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100237 goto out;
238 }
239
Andrew Jefferyfbf74542018-08-06 15:58:01 +0930240 rc = sd_bus_message_append(m, "y", arg);
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100241 if (rc < 0) {
242 MSG_ERR("Failed to add args to message: %s\n",
243 strerror(-rc));
244 rc = -E_DBUS_INTERNAL;
245 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));
251 rc = -E_DBUS_INTERNAL;
252 goto out;
253 }
254
Andrew Jefferyfbf74542018-08-06 15:58:01 +0930255 MSG_OUT("Resume: %s\n", rc < 0 ? strerror(-rc) : "Success");
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100256
257out:
258 sd_bus_error_free(&error);
259 sd_bus_message_unref(m);
260 sd_bus_message_unref(n);
261
Andrew Jefferyfbf74542018-08-06 15:58:01 +0930262 return rc < 0 ? rc : 0;
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100263}
264
265static int handle_cmd_modified(struct mboxctl_context *context)
266{
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100267 int rc;
268
Andrew Jefferyfbf74542018-08-06 15:58:01 +0930269 rc = mboxctl_directive(context, "MarkFlashModified");
270 MSG_OUT("Clear Cache: %s\n", rc ? strerror(-rc) : "Success");
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100271
272 return rc;
273}
274
275static int parse_cmdline(struct mboxctl_context *context, int argc, char **argv)
276{
277 int opt, rc = -1;
278
279 static const struct option long_options[] = {
280 { "silent", no_argument, 0, 's' },
281 { "ping", no_argument, 0, 'p' },
282 { "daemon-state", no_argument, 0, 'd' },
283 { "lpc-state", no_argument, 0, 'l' },
284 { "kill", no_argument, 0, 'k' },
285 { "reset", no_argument, 0, 'r' },
286 { "point-to-flash", no_argument, 0, 'f' },
287 { "suspend", no_argument, 0, 'u' },
288 { "resume", required_argument, 0, 'e' },
289 { "clear-cache", no_argument, 0, 'c' },
290 { "version", no_argument, 0, 'v' },
291 { "help", no_argument, 0, 'h' },
292 { 0, 0, 0, 0 }
293 };
294
295 if (argc <= 1) {
296 usage(argv[0]);
Andrew Jefferyfbf74542018-08-06 15:58:01 +0930297 return -EINVAL;
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100298 }
299
300 while ((opt = getopt_long(argc, argv, "spdlkrfue:cvh", long_options,
301 NULL)) != -1) {
302 switch (opt) {
303 case 's':
304 silent = true;
305 continue;
306 case 'p':
307 rc = handle_cmd_ping(context);
308 break;
309 case 'd':
310 rc = handle_cmd_daemon_state(context);
311 break;
312 case 'l':
313 rc = handle_cmd_lpc_state(context);
314 break;
315 case 'k':
316 rc = handle_cmd_kill(context);
317 break;
318 case 'r': /* These are the same for now (reset may change) */
319 case 'f':
320 rc = handle_cmd_reset(context);
321 break;
322 case 'u':
323 rc = handle_cmd_suspend(context);
324 break;
325 case 'e':
326 rc = handle_cmd_resume(context, optarg);
327 break;
328 case 'c':
329 rc = handle_cmd_modified(context);
330 break;
331 case 'v':
Suraj Jitindar Singh8d65bb42017-05-01 16:05:17 +1000332 MSG_OUT("%s V%s\n", NAME, PACKAGE_VERSION);
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100333 rc = 0;
334 break;
335 case 'h':
336 usage(argv[0]);
337 rc = 0;
338 break;
339 default:
340 usage(argv[0]);
Andrew Jefferyfbf74542018-08-06 15:58:01 +0930341 rc = -EINVAL;
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100342 break;
343 }
344 }
345
346 return rc;
347}
348
349int main(int argc, char **argv)
350{
351 struct mboxctl_context context;
352 int rc;
353
354 silent = false;
355
356 rc = init_mboxctl_dbus(&context);
357 if (rc < 0) {
358 MSG_ERR("Failed to init dbus\n");
359 return rc;
360 }
361
362 rc = parse_cmdline(&context, argc, argv);
363
364 return rc;
365}