diff options
author | Andrew Jeffery <andrew@aj.id.au> | 2019-03-15 12:40:41 +1030 |
---|---|---|
committer | Andrew Jeffery <andrew@aj.id.au> | 2019-03-19 16:40:59 +1030 |
commit | 5320f6e02453261e6c75d3bef101ad1bef6de82e (patch) | |
tree | 28d3df48b8fb56021a2bda3b3a7f460a3f5a46a4 | |
parent | a042978b03c91ca3a716e99f313ef5cda42820ba (diff) | |
download | phosphor-mboxbridge-5320f6e02453261e6c75d3bef101ad1bef6de82e.tar.gz phosphor-mboxbridge-5320f6e02453261e6c75d3bef101ad1bef6de82e.zip |
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 <andrew@aj.id.au>
-rw-r--r-- | backend.h | 29 | ||||
-rw-r--r-- | control.c | 32 | ||||
-rw-r--r-- | control_dbus.c | 88 | ||||
-rw-r--r-- | control_dbus.h | 2 | ||||
-rw-r--r-- | mboxctl.c | 97 | ||||
-rw-r--r-- | mboxd.c | 52 | ||||
-rw-r--r-- | mboxd.h | 2 | ||||
-rw-r--r-- | test/Makefile.am.include | 2 | ||||
-rw-r--r-- | test/backend.c | 11 | ||||
-rw-r--r-- | vpnor/mboxd_pnor_partition_table.h | 10 |
10 files changed, 284 insertions, 41 deletions
@@ -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); +} diff --git a/control_dbus.c b/control_dbus.c index c8c6463..e22d736 100644 --- a/control_dbus.c +++ b/control_dbus.c @@ -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, diff --git a/control_dbus.h b/control_dbus.h index 17e4dec..16661c9 100644 --- a/control_dbus.h +++ b/control_dbus.h @@ -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; diff --git a/test/Makefile.am.include b/test/Makefile.am.include index 2b7ba75..addf2f9 100644 --- a/test/Makefile.am.include +++ b/test/Makefile.am.include @@ -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) diff --git a/test/backend.c b/test/backend.c deleted file mode 100644 index 7b9fec8..0000000 --- a/test/backend.c +++ /dev/null @@ -1,11 +0,0 @@ -#include "backend.h" -#include "mboxd.h" - -#include <errno.h> - -struct backend backend_get_vpnor(void) -{ - struct backend be = {0}; - - return be; -} diff --git a/vpnor/mboxd_pnor_partition_table.h b/vpnor/mboxd_pnor_partition_table.h index e325775..b76aa98 100644 --- a/vpnor/mboxd_pnor_partition_table.h +++ b/vpnor/mboxd_pnor_partition_table.h @@ -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 |