xref: /openbmc/hiomapd/mboxctl.c (revision fd4fa34d)
1 // SPDX-License-Identifier: Apache-2.0
2 // Copyright (C) 2018 IBM Corp.
3 #include "config.h"
4 
5 #include <errno.h>
6 #include <getopt.h>
7 #include <stdbool.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #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 
30 #define NAME		"Mailbox Control"
31 
32 static 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 
41 struct mboxctl_context {
42 	sd_bus *bus;
43 };
44 
45 static void usage(char *name)
46 {
47 	MSG_OUT(USAGE, name);
48 	exit(0);
49 }
50 
51 static 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 
64 static 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 
86 out:
87 	sd_bus_error_free(&error);
88 	sd_bus_message_unref(m);
89 
90 	return rc < 0 ? rc : 0;
91 }
92 
93 static int mboxctl_getter(struct mboxctl_context *context, const char *cmd,
94 			  uint8_t *resp)
95 {
96 	sd_bus_error error = SD_BUS_ERROR_NULL;
97 	sd_bus_message *m = NULL, *n = NULL;
98 	int rc;
99 
100 	rc = sd_bus_message_new_method_call(context->bus, &m,
101 					    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 
124 out:
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 
133 static 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 
143 static 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 
157 static 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 
175 static 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 
185 static 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 
195 static 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 
205 static 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");
222 	if (rc < 0) {
223 		MSG_ERR("Failed to init method call: %s\n",
224 			strerror(-rc));
225 		goto out;
226 	}
227 
228 	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;
236 		goto out;
237 	}
238 
239 	rc = sd_bus_message_append(m, "b", arg);
240 	if (rc < 0) {
241 		MSG_ERR("Failed to add args to message: %s\n",
242 			strerror(-rc));
243 		goto out;
244 	}
245 
246 	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));
249 		goto out;
250 	}
251 
252 	MSG_OUT("Resume: %s\n", rc < 0 ? strerror(-rc) : "Success");
253 
254 out:
255 	sd_bus_error_free(&error);
256 	sd_bus_message_unref(m);
257 	sd_bus_message_unref(n);
258 
259 	return rc < 0 ? rc : 0;
260 }
261 
262 static int handle_cmd_modified(struct mboxctl_context *context)
263 {
264 	int rc;
265 
266 	rc = mboxctl_directive(context, "MarkFlashModified");
267 	MSG_OUT("Clear Cache: %s\n", rc ? strerror(-rc) : "Success");
268 
269 	return rc;
270 }
271 
272 static 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]);
294 		return -EINVAL;
295 	}
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':
329 			MSG_OUT("%s V%s\n", NAME, PACKAGE_VERSION);
330 			rc = 0;
331 			break;
332 		case 'h':
333 			usage(argv[0]);
334 			rc = 0;
335 			break;
336 		default:
337 			usage(argv[0]);
338 			rc = -EINVAL;
339 			break;
340 		}
341 	}
342 
343 	return rc;
344 }
345 
346 int 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 }
363