blob: 9dbc149d64560991623d54592f185fce95c3ea19 [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));
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100225 goto out;
226 }
227
Andrew Jefferyfbf74542018-08-06 15:58:01 +0930228 if (!strncmp(sarg, "clean", strlen("clean"))) {
229 arg = RESUME_NOT_MODIFIED;
230 } else if (!strncmp(sarg, "modified", strlen("modified"))) {
231 arg = RESUME_FLASH_MODIFIED;
232 } else {
233 MSG_ERR("Resume command takes argument < \"clean\" | "
234 "\"modified\" >\n");
235 rc = -EINVAL;
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100236 goto out;
237 }
238
Andrew Jeffery6c4d8ba2018-11-01 10:45:35 +1030239 rc = sd_bus_message_append(m, "b", arg);
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100240 if (rc < 0) {
241 MSG_ERR("Failed to add args to message: %s\n",
242 strerror(-rc));
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100243 goto out;
244 }
245
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100246 rc = sd_bus_call(context->bus, m, 0, &error, &n);
247 if (rc < 0) {
248 MSG_ERR("Failed to post message: %s\n", strerror(-rc));
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100249 goto out;
250 }
251
Andrew Jefferyfbf74542018-08-06 15:58:01 +0930252 MSG_OUT("Resume: %s\n", rc < 0 ? strerror(-rc) : "Success");
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100253
254out:
255 sd_bus_error_free(&error);
256 sd_bus_message_unref(m);
257 sd_bus_message_unref(n);
258
Andrew Jefferyfbf74542018-08-06 15:58:01 +0930259 return rc < 0 ? rc : 0;
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100260}
261
262static int handle_cmd_modified(struct mboxctl_context *context)
263{
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100264 int rc;
265
Andrew Jefferyfbf74542018-08-06 15:58:01 +0930266 rc = mboxctl_directive(context, "MarkFlashModified");
267 MSG_OUT("Clear Cache: %s\n", rc ? strerror(-rc) : "Success");
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100268
269 return rc;
270}
271
272static int parse_cmdline(struct mboxctl_context *context, int argc, char **argv)
273{
274 int opt, rc = -1;
275
276 static const struct option long_options[] = {
277 { "silent", no_argument, 0, 's' },
278 { "ping", no_argument, 0, 'p' },
279 { "daemon-state", no_argument, 0, 'd' },
280 { "lpc-state", no_argument, 0, 'l' },
281 { "kill", no_argument, 0, 'k' },
282 { "reset", no_argument, 0, 'r' },
283 { "point-to-flash", no_argument, 0, 'f' },
284 { "suspend", no_argument, 0, 'u' },
285 { "resume", required_argument, 0, 'e' },
286 { "clear-cache", no_argument, 0, 'c' },
287 { "version", no_argument, 0, 'v' },
288 { "help", no_argument, 0, 'h' },
289 { 0, 0, 0, 0 }
290 };
291
292 if (argc <= 1) {
293 usage(argv[0]);
Andrew Jefferyfbf74542018-08-06 15:58:01 +0930294 return -EINVAL;
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100295 }
296
297 while ((opt = getopt_long(argc, argv, "spdlkrfue:cvh", long_options,
298 NULL)) != -1) {
299 switch (opt) {
300 case 's':
301 silent = true;
302 continue;
303 case 'p':
304 rc = handle_cmd_ping(context);
305 break;
306 case 'd':
307 rc = handle_cmd_daemon_state(context);
308 break;
309 case 'l':
310 rc = handle_cmd_lpc_state(context);
311 break;
312 case 'k':
313 rc = handle_cmd_kill(context);
314 break;
315 case 'r': /* These are the same for now (reset may change) */
316 case 'f':
317 rc = handle_cmd_reset(context);
318 break;
319 case 'u':
320 rc = handle_cmd_suspend(context);
321 break;
322 case 'e':
323 rc = handle_cmd_resume(context, optarg);
324 break;
325 case 'c':
326 rc = handle_cmd_modified(context);
327 break;
328 case 'v':
Suraj Jitindar Singh8d65bb42017-05-01 16:05:17 +1000329 MSG_OUT("%s V%s\n", NAME, PACKAGE_VERSION);
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100330 rc = 0;
331 break;
332 case 'h':
333 usage(argv[0]);
334 rc = 0;
335 break;
336 default:
337 usage(argv[0]);
Andrew Jefferyfbf74542018-08-06 15:58:01 +0930338 rc = -EINVAL;
Suraj Jitindar Singhddf0edb2017-03-28 10:50:40 +1100339 break;
340 }
341 }
342
343 return rc;
344}
345
346int main(int argc, char **argv)
347{
348 struct mboxctl_context context;
349 int rc;
350
351 silent = false;
352
353 rc = init_mboxctl_dbus(&context);
354 if (rc < 0) {
355 MSG_ERR("Failed to init dbus\n");
356 return rc;
357 }
358
359 rc = parse_cmdline(&context, argc, argv);
360
361 return rc;
362}