Commit 5320f6e0 authored by Andrew Jeffery's avatar Andrew Jeffery

mboxd: Add backend DBus interface and commandline options

Also implement a backend commandline option to mboxctl: `mboxctl
--backend ...`, to allow easy run-time switching of the backend from the
commandline.

Switching between VPNOR and file backends via mboxctl was tested on
Witherspoon, and MTD and file backends on Romulus.

Change-Id: Iaf0e27ecf1d5cdd9e3a31729fb179096bbc37408
Signed-off-by: Andrew Jeffery's avatarAndrew Jeffery <andrew@aj.id.au>
parent a042978b
......@@ -6,6 +6,7 @@
#define BACKEND_H
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include <mtd/mtd-abi.h>
......@@ -16,10 +17,6 @@
/* Estimate as to how long (milliseconds) it takes to access a MB from flash */
#define FLASH_ACCESS_MS_PER_MB 8000
struct backend backend_get_mtd(void);
struct backend backend_get_file(void);
struct backend backend_get_vpnor(void);
enum backend_reset_mode { reset_lpc_flash, reset_lpc_memory };
struct backend_ops;
......@@ -146,7 +143,8 @@ static inline int backend_init(struct backend *master, struct backend *with,
master->block_size_shift = 34;
#endif
assert(master->ops->init);
if (!master->ops->init)
return -ENOTSUP;
rc = master->ops->init(master, data);
if (rc < 0)
......@@ -224,11 +222,32 @@ static inline int backend_reset(struct backend *backend, void *buf,
return backend->ops->reset(backend, buf, count);
}
struct backend backend_get_mtd(void);
int backend_probe_mtd(struct backend *master, const char *path);
struct backend backend_get_file(void);
int backend_probe_file(struct backend *master, const char *path);
/* Avoid dependency on vpnor/mboxd_pnor_partition_table.h */
struct vpnor_partition_paths;
#ifdef VIRTUAL_PNOR_ENABLED
struct backend backend_get_vpnor(void);
int backend_probe_vpnor(struct backend *master,
const struct vpnor_partition_paths *paths);
#else
static inline struct backend backend_get_vpnor(void)
{
struct backend be = { 0 };
return be;
}
static inline int backend_probe_vpnor(struct backend *master,
const struct vpnor_partition_paths *paths)
{
return -ENOTSUP;
}
#endif
#endif /* BACKEND_H */
......@@ -3,12 +3,12 @@
#include <errno.h>
#include <stdlib.h>
#include "backend.h"
#include "common.h"
#include "dbus.h"
#include "mboxd.h"
#include "backend.h"
#include "lpc.h"
#include "transport_mbox.h"
#include "mboxd.h"
#include "protocol.h"
#include "windows.h"
int control_ping(struct mbox_context *context)
......@@ -116,3 +116,29 @@ int control_resume(struct mbox_context *context, bool modified)
return rc;
}
int control_set_backend(struct mbox_context *context, struct backend *backend,
void *data)
{
int rc;
if (context->state & STATE_SUSPENDED)
return -EINVAL;
rc = protocol_events_clear(context, BMC_EVENT_DAEMON_READY);
if (rc < 0)
return rc;
backend_free(&context->backend);
rc = backend_init(&context->backend, backend, data);
if (rc < 0)
return rc;
rc = __protocol_reset(context);
if (rc < 0)
return rc;
return protocol_events_set(context,
BMC_EVENT_DAEMON_READY | BMC_EVENT_PROTOCOL_RESET);
}
......@@ -2,12 +2,14 @@
// Copyright (C) 2018 IBM Corp.
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <systemd/sd-bus.h>
#include "common.h"
#include "dbus.h"
#include "control_dbus.h"
#include "mboxd.h"
#include "vpnor/mboxd_pnor_partition_table.h"
typedef int (*control_action)(struct mbox_context *context);
......@@ -108,6 +110,90 @@ static int control_dbus_resume(sd_bus_message *m, void *userdata,
return sd_bus_send(NULL, n, NULL);
}
static int control_dbus_set_backend(sd_bus_message *m, void *userdata,
sd_bus_error *ret_error)
{
struct mbox_context *context;
struct backend backend;
sd_bus_message *n;
const char *name;
int rc;
context = (struct mbox_context *) userdata;
if (!context) {
MSG_ERR("DBUS Internal Error\n");
return -EINVAL;
}
rc = sd_bus_message_read_basic(m, 's', &name);
if (rc < 0) {
MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
return rc;
}
if (!strcmp(name, "vpnor")) {
struct vpnor_partition_paths paths;
vpnor_default_paths(&paths);
backend = backend_get_vpnor();
rc = control_set_backend(context, &backend, &paths);
if (rc < 0)
return rc;
} else if (!strcmp(name, "mtd")) {
char **paths = NULL;
char *path = NULL;
rc = sd_bus_message_read_strv(m, &paths);
if (rc < 0)
return rc;
if (paths && *paths)
path = *paths;
else
path = get_dev_mtd();
backend = backend_get_mtd();
rc = control_set_backend(context, &backend, path);
if (rc < 0)
return rc;
free(path);
free(paths);
} else if (!strcmp(name, "file")) {
char **paths = NULL;
char *path = NULL;
rc = sd_bus_message_read_strv(m, &paths);
if (rc < 0)
return rc;
if (!(paths && *paths))
return -EINVAL;
path = *paths;
backend = backend_get_file();
rc = control_set_backend(context, &backend, path);
if (rc < 0)
return rc;
free(path);
free(paths);
} else {
return -EINVAL;
}
rc = sd_bus_message_new_method_return(m, &n);
if (rc < 0) {
MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
return rc;
}
return sd_bus_send(NULL, n, NULL);
}
static int control_dbus_get_u8(sd_bus *bus, const char *path,
const char *interface, const char *property,
sd_bus_message *reply, void *userdata,
......@@ -144,6 +230,8 @@ static const sd_bus_vtable mboxd_vtable[] = {
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Resume", "b", NULL, &control_dbus_resume,
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetBackend", "sas", NULL, &control_dbus_set_backend,
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_PROPERTY("DaemonState", "y", &control_dbus_get_u8, 0,
SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("LpcState", "y", &control_dbus_get_u8, 0,
......
......@@ -2,6 +2,7 @@
#define DBUS_CONTROL_H
struct mbox_context;
struct backend;
int control_dbus_init(struct mbox_context *context);
void control_dbus_free(struct mbox_context *context);
......@@ -18,5 +19,6 @@ int control_kill(struct mbox_context *context);
int control_modified(struct mbox_context *context);
int control_suspend(struct mbox_context *context);
int control_resume(struct mbox_context *context, bool modified);
int control_set_backend(struct mbox_context *context, struct backend *backend, void *data);
#endif
......@@ -4,6 +4,7 @@
#include <errno.h>
#include <getopt.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
......@@ -25,7 +26,8 @@
"\t\t--suspend\t\t- suspend the daemon to inhibit flash accesses (0)\n" \
"\t\t--resume\t\t- resume the daemon (1)\n" \
"\t\t\targ[0]: < \"clean\" | \"modified\" >\n" \
"\t\t--clear-cache\t- tell the daemon to discard any caches (0)\n"
"\t\t--clear-cache\t- tell the daemon to discard any caches (0)\n" \
"\t\t--backend <vpnor|mtd[:PATH]|file:PATH>\n"
#define NAME "Mailbox Control"
......@@ -269,6 +271,95 @@ static int handle_cmd_modified(struct mboxctl_context *context)
return rc;
}
static int handle_cmd_backend(struct mboxctl_context *context, char *sarg)
{
sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus_message *m = NULL, *n = NULL;
char *delim = NULL;
char *strv[2];
int rc;
if (!sarg) {
MSG_ERR("Backend command takes an argument\n");
return -EINVAL;
}
rc = sd_bus_message_new_method_call(context->bus, &m,
MBOX_DBUS_NAME,
MBOX_DBUS_OBJECT,
MBOX_DBUS_CONTROL_IFACE,
"SetBackend");
if (rc < 0) {
MSG_ERR("Failed to init method call: %s\n",
strerror(-rc));
goto out;
}
if (!strncmp(sarg, "vpnor", strlen("vpnor"))) {
if (strchr(sarg, ':')) {
MSG_ERR("Path parameter not supported for vpnor\n");
rc = -EINVAL;
goto out;
}
rc = sd_bus_message_append(m, "s", "vpnor");
if (rc < 0)
goto out;
} else if (!strncmp(sarg, "mtd", strlen("mtd"))) {
rc = sd_bus_message_append(m, "s", "mtd");
if (rc < 0)
goto out;
} else if (!strncmp(sarg, "file", strlen("file"))) {
rc = sd_bus_message_append(m, "s", "file");
if (rc < 0)
goto out;
} else {
rc = -EINVAL;
goto out;
}
delim = strchr(sarg, ':');
if (delim) {
char *path;
path = realpath(delim + 1, NULL);
if (!path) {
MSG_ERR("Failed to resolve path: %s\n",
strerror(errno));
rc = -errno;
goto out;
}
strv[0] = path;
strv[1] = NULL;
rc = sd_bus_message_append_strv(m, &strv[0]);
free(path);
if (rc < 0)
goto out;
} else {
strv[0] = NULL;
strv[1] = NULL;
rc = sd_bus_message_append_strv(m, &strv[0]);
if (rc < 0)
goto out;
}
rc = sd_bus_call(context->bus, m, 0, &error, &n);
if (rc < 0) {
MSG_ERR("Failed to post message: %s\n", strerror(-rc));
goto out;
}
MSG_OUT("SetBackend: %s\n", rc < 0 ? strerror(-rc) : "Success");
out:
sd_bus_error_free(&error);
sd_bus_message_unref(m);
return rc < 0 ? rc : 0;
}
static int parse_cmdline(struct mboxctl_context *context, int argc, char **argv)
{
int opt, rc = -1;
......@@ -284,6 +375,7 @@ static int parse_cmdline(struct mboxctl_context *context, int argc, char **argv)
{ "suspend", no_argument, 0, 'u' },
{ "resume", required_argument, 0, 'e' },
{ "clear-cache", no_argument, 0, 'c' },
{ "backend", required_argument, 0, 'b' },
{ "version", no_argument, 0, 'v' },
{ "help", no_argument, 0, 'h' },
{ 0, 0, 0, 0 }
......@@ -325,6 +417,9 @@ static int parse_cmdline(struct mboxctl_context *context, int argc, char **argv)
case 'c':
rc = handle_cmd_modified(context);
break;
case 'b':
rc = handle_cmd_backend(context, optarg);
break;
case 'v':
MSG_OUT("%s V%s\n", NAME, PACKAGE_VERSION);
rc = 0;
......
......@@ -44,9 +44,9 @@ const char* USAGE =
"\t\t[-w | --window-size <size>M]\n"
"\t\t-f | --flash <size>[K|M]\n"
#ifdef VIRTUAL_PNOR_ENABLED
"\t\t-s | --source <vpnor|path>\n\n"
"\t\t-b | --backend <vpnor|mtd[:PATH]|file:PATH>\n"
#else
"\t\t-s | --source <path>\n\n"
"\t\t-b | --backend <mtd[:PATH]|file:PATH>\n"
#endif
"\t-v | --verbose\t\tBe [more] verbose\n"
"\t-s | --syslog\t\tLog output to syslog (pointless without -v)\n"
......@@ -272,7 +272,7 @@ static bool parse_cmdline(int argc, char **argv,
}
break;
case 'b':
context->path = optarg;
context->source = optarg;
break;
case 'n':
context->windows.num = strtol(argv[optind], &endptr,
......@@ -316,9 +316,6 @@ static bool parse_cmdline(int argc, char **argv,
}
}
if (!context->path) {
context->path = get_dev_mtd();
}
if (!context->backend.flash_size) {
fprintf(stderr, "Must specify a non-zero flash size\n");
return false;
......@@ -336,23 +333,44 @@ static bool parse_cmdline(int argc, char **argv,
static int mboxd_backend_init(struct mbox_context *context)
{
const char *delim;
const char *path;
int rc;
#ifdef VIRTUAL_PNOR_ENABLED
struct vpnor_partition_paths paths;
vpnor_default_paths(&paths);
if (!context->source) {
struct vpnor_partition_paths paths;
vpnor_default_paths(&paths);
rc = backend_probe_vpnor(&context->backend, &paths);
if(rc)
#endif
{
rc = backend_probe_mtd(&context->backend, context->path);
if (rc) {
rc = backend_probe_file(&context->backend,
context->path);
rc = backend_probe_vpnor(&context->backend, &paths);
if(rc < 0)
rc = backend_probe_mtd(&context->backend, NULL);
return rc;
}
delim = strchr(context->source, ':');
path = delim ? delim + 1 : NULL;
if (!strncmp(context->source, "vpnor", strlen("vpnor"))) {
struct vpnor_partition_paths paths;
if (path) {
rc = -EINVAL;
} else {
vpnor_default_paths(&paths);
rc = backend_probe_vpnor(&context->backend, &paths);
}
} else if (!strncmp(context->source, "mtd", strlen("mtd"))) {
rc = backend_probe_mtd(&context->backend, path);
} else if (!strncmp(context->source, "file", strlen("file"))) {
rc = backend_probe_file(&context->backend, path);
} else {
rc = -EINVAL;
}
if (rc < 0)
MSG_ERR("Invalid backend argument: %s\n", context->source);
return rc;
}
......
......@@ -76,7 +76,7 @@ struct mbox_context {
struct backend backend;
/* Commandline parameters */
const char *path;
const char *source;
/* System State */
enum mbox_state state;
......
......@@ -35,7 +35,7 @@ TEST_MOCK_CORE = \
%reldir%/mbox.c \
%reldir%/system.c
TEST_MOCK_SRCS = %reldir%/backend.c $(TEST_MOCK_CORE)
TEST_MOCK_SRCS = $(TEST_MOCK_CORE)
test_get_mbox_info_v2_SOURCES = %reldir%/get_mbox_info_v2.c \
$(TEST_MBOX_SRCS) $(TEST_MOCK_SRCS)
......
#include "backend.h"
#include "mboxd.h"
#include <errno.h>
struct backend backend_get_vpnor(void)
{
struct backend be = {0};
return be;
}
......@@ -2,8 +2,6 @@
/* Copyright (C) 2018 IBM Corp. */
#pragma once
#ifdef VIRTUAL_PNOR_ENABLED
#include <limits.h>
#include "pnor_partition_defs.h"
#include "backend.h"
......@@ -34,8 +32,16 @@ extern "C" {
*
* Returns 0 if the call succeeds, else a negative error code.
*/
#ifdef VIRTUAL_PNOR_ENABLED
void vpnor_default_paths(struct vpnor_partition_paths *paths);
#else
static inline void vpnor_default_paths(struct vpnor_partition_paths *paths)
{
memset(paths, 0, sizeof(*paths));
}
#endif
#ifdef VIRTUAL_PNOR_ENABLED
/** @brief Create a virtual PNOR partition table.
*
* @param[in] backend - The backend context pointer
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment