diff options
Diffstat (limited to 'lib/ipmi_cfgp.c')
-rw-r--r-- | lib/ipmi_cfgp.c | 542 |
1 files changed, 542 insertions, 0 deletions
diff --git a/lib/ipmi_cfgp.c b/lib/ipmi_cfgp.c new file mode 100644 index 0000000..b8af80d --- /dev/null +++ b/lib/ipmi_cfgp.c @@ -0,0 +1,542 @@ +/* + * Copyright (c) 2016 Pentair Technical Products. All right reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Pentair Technical Products or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * PENTAIR TECHNICAL SOLUTIONS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <malloc.h> +#include <string.h> + +#include <ipmitool/helper.h> +#include <ipmitool/ipmi_cfgp.h> +#include <ipmitool/log.h> + +/* ipmi_cfgp_init initialize configuration parameter context + * @param ctx context to initialize + * @param set array of parameter descriptors + * @param count amount of descriptors supplied + * @param handler function to do real job on parameters from the set + * @param priv private data for the handler + */ +int +ipmi_cfgp_init(struct ipmi_cfgp_ctx *ctx, const struct ipmi_cfgp *set, + unsigned int count, const char *cmdname, + ipmi_cfgp_handler_t handler, void *priv) +{ + if (ctx == NULL || set == NULL || handler == NULL || !cmdname) { + return -1; + } + + memset(ctx, 0, sizeof(struct ipmi_cfgp_ctx)); + + ctx->set = set; + ctx->count = count; + ctx->cmdname = cmdname; + ctx->handler = handler; + ctx->priv = priv; + + return 0; +} + +/* ipmi_cfgp_uninit destroy data list attached to context + * @param ctx parameter context to clear + * @returns 0 -- list destroyed + * -1 -- ctx is NULL + */ +int +ipmi_cfgp_uninit(struct ipmi_cfgp_ctx *ctx) +{ + struct ipmi_cfgp_data *d; + + if (ctx == NULL) { + return -1; + } + + while (ctx->v) { + d = ctx->v; + ctx->v = d->next; + free(d); + d = NULL; + } + + return 0; +} + +/* lookup_cfgp -- find a parameter in a set*/ +static const struct ipmi_cfgp * +lookup_cfgp(const struct ipmi_cfgp_ctx *ctx, const char *name) +{ + const struct ipmi_cfgp *p; + int i; + + for (i = 0; i < ctx->count; i++) { + p = &ctx->set[i]; + + if (p->name && !strcasecmp(p->name, name)) { + return p; + } + } + + return NULL; +} + +/* ipmi_cfgp_parse_sel parse parameter selector + * (parameter ID, set selector, block selector) from cmdline. + * + * @param ctx configuration parameter context to use + * @param argc elements left in argv + * @param argv array of arguments + * @param sel where to store parsed selector + * + * @returns >=0 number of argv elements used + * <0 error + */ +int +ipmi_cfgp_parse_sel(struct ipmi_cfgp_ctx *ctx, + int argc, const char **argv, struct ipmi_cfgp_sel *sel) +{ + const struct ipmi_cfgp *p; + + if (ctx == NULL || argv == NULL || sel == NULL) { + return -1; + } + + sel->param = -1; + sel->set = -1; + sel->block = -1; + + if (argc == 0) { + /* no parameter specified, good for print, save */ + return 0; + } + + p = lookup_cfgp(ctx, argv[0]); + if (p == NULL) { + lprintf(LOG_ERR, "invalid parameter"); + return -1; + } + + sel->param = p - ctx->set; + sel->set = p->is_set ? -1 : 0; + sel->block = p->has_blocks ? -1 : 0; + + if (argc == 1 || !p->is_set) { + /* No set and block selector applicable or specified */ + return 1; + } + + if (str2int(argv[1], &sel->set) + || sel->set < 0 + || (sel->set == 0 && p->first_set)) { + lprintf(LOG_ERR, "invalid set selector"); + return -1; + } + + if (argc == 2 || !p->has_blocks) { + /* No block selector applicable or specified */ + return 2; + } + + if (str2int(argv[2], &sel->block) + || sel->block < 0 + || (sel->block == 0 && p->first_block)) { + lprintf(LOG_ERR, "invalid block selector"); + return -1; + } + + return 3; +} + +/* cfgp_add_data adds block of data to list in the configuration + * parameter context + * + * @param ctx context to add data to + * @param data parameter data + */ +static void +cfgp_add_data(struct ipmi_cfgp_ctx *ctx, struct ipmi_cfgp_data *data) +{ + struct ipmi_cfgp_data **pprev = &ctx->v; + + data->next = NULL; + + while (*pprev) { + pprev = &(*pprev)->next; + } + + *pprev = data; +} + +/* cfgp_usage prints format for configuration parameter + * + * @param p configuration parameter descriptor + * @param write 0 if no value is expected, !=0 otherwise + */ +static void +cfgp_usage(const struct ipmi_cfgp *p, int write) +{ + if (p->name == NULL) { + return; + } + + if (write && p->format == NULL) { + return; + } + + printf(" %s%s%s %s\n", + p->name, p->is_set ? " <set_sel>" : "", + p->has_blocks ? " <block_sel>" : "", + write ? p->format : ""); +} + +/* ipmi_cfgp_usage prints format for configuration parameter set + * + * @param set configuration parameter descriptor array + * @param count number of elements in set + * @param write 0 if no value is expected, !=0 otherwise + */ +void +ipmi_cfgp_usage(const struct ipmi_cfgp *set, int count, int write) +{ + const struct ipmi_cfgp *p; + int i; + + if (set == NULL) { + return; + } + + for (i = 0; i < count; i++) { + p = &set[i]; + + if (write && p->access == CFGP_RDONLY) { + continue; + } + + if (!write && p->access == CFGP_WRONLY) { + continue; + } + + cfgp_usage(p, write); + } +} + +/* ipmi_cfgp_parse_data parse parameter data from command line into context + * @param ctx context to add data + * @param sel parameter selector + * @param argc number of elements in argv + * @param argv array of unparsed arguments + * + * @returns 0 on success + * <0 on error + */ +int +ipmi_cfgp_parse_data(struct ipmi_cfgp_ctx *ctx, + const struct ipmi_cfgp_sel *sel, int argc, const char **argv) +{ + const struct ipmi_cfgp *p; + struct ipmi_cfgp_data *data; + struct ipmi_cfgp_action action; + + if (ctx == NULL || sel == NULL || argv == NULL) { + return -1; + } + + if (sel->param == -1 || sel->param >= ctx->count) { + lprintf(LOG_ERR, "invalid parameter, must be one of:"); + ipmi_cfgp_usage(ctx->set, ctx->count, 1); + return -1; + } + + if (sel->set == -1) { + lprintf(LOG_ERR, "set selector is not specified"); + return -1; + } + + if (sel->block == -1) { + lprintf(LOG_ERR, "block selector is not specified"); + return -1; + } + + p = &ctx->set[sel->param]; + + if (p->size == 0) { + return -1; + } + + data = malloc(sizeof(struct ipmi_cfgp_data) + p->size); + if (data == NULL) { + return -1; + } + + memset(data, 0, sizeof(struct ipmi_cfgp_data) + p->size); + + action.type = CFGP_PARSE; + action.set = sel->set; + action.block = sel->block; + action.argc = argc; + action.argv = argv; + action.file = NULL; + + if (ctx->handler(ctx->priv, p, &action, data->data) != 0) { + ipmi_cfgp_usage(p, 1, 1); + free(data); + data = NULL; + return -1; + } + + data->sel = *sel; + + cfgp_add_data(ctx, data); + return 0; +} + +/* cfgp_get_param -- get parameter data from MC into data list within context + * + * @param ctx context + * @param p parameter descriptor + * @param set parameter set selector, can be -1 to scan all set selectors + * @param block parameter block selector, can be -1 to get all blocks + * @param quiet set to non-zero to continue on errors + * (required for -1 to work) + * @returns 0 on success, non-zero otherwise + */ +static int +cfgp_get_param(struct ipmi_cfgp_ctx *ctx, const struct ipmi_cfgp *p, + int set, int block, int quiet) +{ + struct ipmi_cfgp_data *data; + struct ipmi_cfgp_action action; + int cset; + int cblock; + int ret; + + if (p->size == 0) { + return -1; + } + + action.type = CFGP_GET; + action.argc = 0; + action.argv = NULL; + action.file = NULL; + + if (set == -1 && !p->is_set) { + set = 0; + } + + if (block == -1 && !p->has_blocks) { + block = 0; + } + + if (set == -1) { + cset = p->first_set; + } else { + cset = set; + } + + action.quiet = quiet; + + do { + if (block == -1) { + cblock = p->first_block; + } else { + cblock = block; + } + + do { + data = malloc(sizeof(struct ipmi_cfgp_data) + p->size); + if (data == NULL) { + return -1; + } + + memset(data, 0, sizeof(struct ipmi_cfgp_data) + p->size); + + action.set = cset; + action.block = cblock; + + ret = ctx->handler(ctx->priv, p, &action, data->data); + if (ret != 0) { + free(data); + data = NULL; + + if (!action.quiet) { + return ret; + } + break; + } + + data->sel.param = p - ctx->set; + data->sel.set = cset; + data->sel.block = cblock; + + cfgp_add_data(ctx, data); + + cblock++; + action.quiet = 1; + } while (block == -1); + + if (ret != 0 && cblock == p->first_block) { + break; + } + + cset++; + } while (set == -1); + + return 0; +} + +/* ipmi_cfgp_get -- get parameters data from MC into data list within context + * + * @param ctx context + * @param sel parameter selector + * @returns 0 on success, non-zero otherwise + */ +int +ipmi_cfgp_get(struct ipmi_cfgp_ctx *ctx, const struct ipmi_cfgp_sel *sel) +{ + int i; + int ret; + + if (ctx == NULL || sel == NULL) { + return -1; + } + + if (sel->param != -1) { + if (sel->param >= ctx->count) { + return -1; + } + + ret = cfgp_get_param(ctx, &ctx->set[sel->param], + sel->set, sel->block, 0); + if (ret) { + return -1; + } + return 0; + } + + for (i = 0; i < ctx->count; i++) { + if (ctx->set[i].access == CFGP_WRONLY) { + continue; + } + + if (cfgp_get_param(ctx, &ctx->set[i], sel->set, sel->block, 1)) { + return -1; + } + } + + return 0; +} + +static int +cfgp_do_action(struct ipmi_cfgp_ctx *ctx, int action_type, + const struct ipmi_cfgp_sel *sel, FILE *file, int filter) +{ + const struct ipmi_cfgp *p; + struct ipmi_cfgp_data *data; + struct ipmi_cfgp_action action; + int ret; + + if (ctx == NULL || sel == NULL) { + return -1; + } + + action.type = action_type; + action.argc = 0; + action.argv = NULL; + action.file = file; + + for (data = ctx->v; data != NULL; data = data->next) { + if (sel->param != -1 && sel->param != data->sel.param) { + continue; + } + if (sel->set != -1 && sel->set != data->sel.set) { + continue; + } + if (sel->block != -1 && sel->block != data->sel.block) { + continue; + } + if (ctx->set[data->sel.param].access == filter) { + continue; + } + + p = &ctx->set[data->sel.param]; + + action.set = data->sel.set; + action.block = data->sel.block; + + if (action_type == CFGP_SAVE) { + fprintf(file, "%s %s ", ctx->cmdname, p->name); + if (p->is_set) { + fprintf(file, "%d ", data->sel.set); + } + if (p->has_blocks) { + fprintf(file, "%d ", data->sel.block); + } + } + + ret = ctx->handler(ctx->priv, p, &action, data->data); + + if (action_type == CFGP_SAVE) { + fputc('\n', file); + } + + if (ret != 0) { + return -1; + } + } + + return 0; +} + +int +ipmi_cfgp_set(struct ipmi_cfgp_ctx *ctx, const struct ipmi_cfgp_sel *sel) +{ + return cfgp_do_action(ctx, CFGP_SET, sel, NULL, CFGP_RDONLY); +} + +int +ipmi_cfgp_save(struct ipmi_cfgp_ctx *ctx, + const struct ipmi_cfgp_sel *sel, FILE *file) +{ + if (file == NULL) { + return -1; + } + + return cfgp_do_action(ctx, CFGP_SAVE, sel, file, CFGP_RDONLY); +} + +int +ipmi_cfgp_print(struct ipmi_cfgp_ctx *ctx, + const struct ipmi_cfgp_sel *sel, FILE *file) +{ + if (file == NULL) { + return -1; + } + + return cfgp_do_action(ctx, CFGP_PRINT, sel, file, CFGP_RESERVED); +} |