| /*****************************************************************************\ | |
| * data.h - data_t parser plugin interface | |
| ****************************************************************************** | |
| * Copyright (C) SchedMD LLC. | |
| * | |
| * This file is part of Slurm, a resource management program. | |
| * For details, see <https://slurm.schedmd.com/>. | |
| * Please also read the included file: DISCLAIMER. | |
| * | |
| * Slurm is free software; you can redistribute it and/or modify it under | |
| * the terms of the GNU General Public License as published by the Free | |
| * Software Foundation; either version 2 of the License, or (at your option) | |
| * any later version. | |
| * | |
| * In addition, as a special exception, the copyright holders give permission | |
| * to link the code of portions of this program with the OpenSSL library under | |
| * certain conditions as described in each individual source file, and | |
| * distribute linked combinations including the two. You must obey the GNU | |
| * General Public License in all respects for all of the code used other than | |
| * OpenSSL. If you modify file(s) with this exception, you may extend this | |
| * exception to your version of the file(s), but you are not obligated to do | |
| * so. If you do not wish to do so, delete this exception statement from your | |
| * version. If you delete this exception statement from all source files in | |
| * the program, then also delete it here. | |
| * | |
| * Slurm is distributed in the hope that it will be useful, but WITHOUT ANY | |
| * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |
| * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | |
| * details. | |
| * | |
| * You should have received a copy of the GNU General Public License along | |
| * with Slurm; if not, write to the Free Software Foundation, Inc., | |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
| \*****************************************************************************/ | |
| #include "config.h" | |
| #include "src/common/data.h" | |
| #include "src/common/fd.h" | |
| #include "src/common/list.h" | |
| #include "src/common/log.h" | |
| #include "src/common/openapi.h" | |
| #include "src/common/read_config.h" | |
| #include "src/common/timers.h" | |
| #include "src/common/xassert.h" | |
| #include "src/common/xmalloc.h" | |
| #include "src/common/xstring.h" | |
| #include "src/interfaces/data_parser.h" | |
| #define PARSE_MAJOR_TYPE "data_parser" | |
| #define PARSE_MAGIC 0x0ea0b1be | |
| #define LATEST_PLUGIN_NAME "latest" | |
| typedef struct data_parser_s { | |
| int magic; | |
| int plugin_offset; | |
| /* opaque context returned by the plugin's new() */ | |
| void *plugin_ctxt; | |
| /* on_error callback arg from _new() - shallow pointer */ | |
| void *error_arg; | |
| /* on_warn callback arg from _new() - shallow pointer */ | |
| void *warn_arg; | |
| const char *plugin_type; /* ptr to plugin plugin_type - do not xfree */ | |
| char *params; /* parameters from _new - must xfree */ | |
| char *plugin_string; /* plugin_type+params - must xfree */ | |
| } data_parser_t; | |
| typedef struct { | |
| int (*parse)(void *arg, data_parser_type_t type, void *dst, | |
| ssize_t dst_bytes, data_t *src, data_t *parent_path); | |
| int (*dump)(void *arg, data_parser_type_t type, void *src, | |
| ssize_t src_bytes, data_t *dst); | |
| /* ptr returned to be handed to commands as arg */ | |
| void *(*new)(data_parser_on_error_t on_parse_error, | |
| data_parser_on_error_t on_dump_error, | |
| data_parser_on_error_t on_query_error, void *error_arg, | |
| data_parser_on_warn_t on_parse_warn, | |
| data_parser_on_warn_t on_dump_warn, | |
| data_parser_on_warn_t on_query_warn, void *warn, | |
| char *params); | |
| void (*free)(void *arg); | |
| int (*assign)(void *arg, data_parser_attr_type_t type, void *obj); | |
| openapi_type_t (*resolve_openapi_type)(void *arg, | |
| data_parser_type_t type, | |
| const char *field); | |
| const char *(*resolve_type_str)(void *arg, data_parser_type_t type); | |
| int (*inc_ref)(void *arg, data_parser_type_t type, | |
| void **references_ptr); | |
| int (*populate_schema)(void *arg, data_parser_type_t type, | |
| void **references_ptr, data_t *dst, data_t *schemas); | |
| int (*populate_parameters)(void *arg, data_parser_type_t parameter_type, | |
| data_parser_type_t query_type, | |
| void **references_ptr, data_t *dst, | |
| data_t *schemas); | |
| void (*release_refs)(void *arg, void **references_ptr); | |
| bool (*is_complex)(void *arg); | |
| bool (*is_deprecated)(void *arg); | |
| int (*dump_flags)(void *arg, data_t *dst); | |
| } parse_funcs_t; | |
| typedef struct { | |
| char *plugin_type; | |
| char *params; | |
| } plugin_param_t; | |
| /* | |
| * Must be synchronized with parse_funcs_t above. | |
| */ | |
| static const char *parse_syms[] = { | |
| "data_parser_p_parse", | |
| "data_parser_p_dump", | |
| "data_parser_p_new", | |
| "data_parser_p_free", | |
| "data_parser_p_assign", | |
| "data_parser_p_resolve_openapi_type", | |
| "data_parser_p_resolve_type_string", | |
| "data_parser_p_increment_reference", | |
| "data_parser_p_populate_schema", | |
| "data_parser_p_populate_parameters", | |
| "data_parser_p_release_references", | |
| "data_parser_p_is_complex", | |
| "data_parser_p_is_deprecated", | |
| "data_parser_p_dump_flags", | |
| }; | |
| static plugins_t *plugins = NULL; | |
| static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER; | |
| static int active_parsers = 0; | |
| static const char *_get_plugin_version(const char *plugin_type); | |
| extern int data_parser_g_parse(data_parser_t *parser, data_parser_type_t type, | |
| void *dst, ssize_t dst_bytes, data_t *src, | |
| data_t *parent_path) | |
| { | |
| const parse_funcs_t *funcs; | |
| DEF_TIMERS; | |
| int rc; | |
| if (!parser) | |
| return ESLURM_DATA_INVALID_PARSER; | |
| funcs = plugins->functions[parser->plugin_offset]; | |
| if (!src || (data_get_type(src) == DATA_TYPE_NONE)) | |
| return ESLURM_DATA_PARSE_NOTHING; | |
| xassert(type > DATA_PARSER_TYPE_INVALID); | |
| xassert(type < DATA_PARSER_TYPE_MAX); | |
| xassert(parser->magic == PARSE_MAGIC); | |
| xassert(data_get_type(parent_path) == DATA_TYPE_LIST); | |
| xassert(plugins && (plugins->magic == PLUGINS_MAGIC)); | |
| xassert(parser->plugin_offset < plugins->count); | |
| xassert(plugins->functions[parser->plugin_offset]); | |
| START_TIMER; | |
| rc = funcs->parse(parser->plugin_ctxt, type, dst, dst_bytes, src, | |
| parent_path); | |
| END_TIMER2(__func__); | |
| return rc; | |
| } | |
| extern int data_parser_g_dump(data_parser_t *parser, data_parser_type_t type, | |
| void *src, ssize_t src_bytes, data_t *dst) | |
| { | |
| DEF_TIMERS; | |
| int rc; | |
| const parse_funcs_t *funcs; | |
| if (!parser) | |
| return ESLURM_DATA_INVALID_PARSER; | |
| funcs = plugins->functions[parser->plugin_offset]; | |
| xassert(data_get_type(dst)); | |
| xassert(type > DATA_PARSER_TYPE_INVALID); | |
| xassert(type < DATA_PARSER_TYPE_MAX); | |
| xassert(parser->magic == PARSE_MAGIC); | |
| xassert(plugins && (plugins->magic == PLUGINS_MAGIC)); | |
| xassert(parser->plugin_offset < plugins->count); | |
| xassert(plugins->functions[parser->plugin_offset]); | |
| START_TIMER; | |
| rc = funcs->dump(parser->plugin_ctxt, type, src, src_bytes, dst); | |
| END_TIMER2(__func__); | |
| return rc; | |
| } | |
| /* takes ownership of params */ | |
| static data_parser_t *_new_parser(data_parser_on_error_t on_parse_error, | |
| data_parser_on_error_t on_dump_error, | |
| data_parser_on_error_t on_query_error, | |
| void *error_arg, | |
| data_parser_on_warn_t on_parse_warn, | |
| data_parser_on_warn_t on_dump_warn, | |
| data_parser_on_warn_t on_query_warn, | |
| void *warn_arg, int plugin_index, | |
| char *params) | |
| { | |
| DEF_TIMERS; | |
| const parse_funcs_t *funcs; | |
| data_parser_t *parser = xmalloc(sizeof(*parser)); | |
| parser->magic = PARSE_MAGIC; | |
| parser->plugin_offset = plugin_index; | |
| parser->plugin_type = plugins->types[plugin_index]; | |
| parser->params = params; | |
| parser->error_arg = error_arg; | |
| parser->warn_arg = warn_arg; | |
| START_TIMER; | |
| funcs = plugins->functions[plugin_index]; | |
| parser->plugin_ctxt = | |
| funcs->new (on_parse_error, on_dump_error, on_query_error, | |
| error_arg, on_parse_warn, on_dump_warn, | |
| on_query_warn, warn_arg, params); | |
| xstrfmtcat(parser->plugin_string, "%s%s", parser->plugin_type, | |
| (parser->params ? parser->params : "")); | |
| END_TIMER2(__func__); | |
| slurm_mutex_lock(&init_mutex); | |
| xassert(active_parsers >= 0); | |
| active_parsers++; | |
| slurm_mutex_unlock(&init_mutex); | |
| return parser; | |
| } | |
| static plugin_param_t *_parse_plugin_type(const char *plugin_type) | |
| { | |
| char *type, *last = NULL, *pl; | |
| plugin_param_t *pparams = NULL; | |
| int count = 0; | |
| if (!plugin_type) | |
| return NULL; | |
| pl = xstrdup(plugin_type); | |
| type = strtok_r(pl, ",", &last); | |
| while (type) { | |
| char *pl; | |
| plugin_param_t *p; | |
| xrecalloc(pparams, (count + 2), sizeof(*pparams)); | |
| p = &pparams[count]; | |
| if ((pl = xstrstr(type, | |
| SLURM_DATA_PARSER_PLUGIN_PARAMS_CHAR))) { | |
| p->plugin_type = xstrndup(type, (pl - type)); | |
| p->params = xstrdup(pl); | |
| } else { | |
| p->plugin_type = xstrdup(type); | |
| } | |
| if (!xstrcasecmp(p->plugin_type, LATEST_PLUGIN_NAME)) { | |
| xfree(p->plugin_type); | |
| p->plugin_type = xstrdup(SLURM_DATA_PARSER_VERSION); | |
| } | |
| log_flag(DATA, "%s: plugin=%s params=%s", | |
| __func__, p->plugin_type, p->params); | |
| count++; | |
| type = strtok_r(NULL, ",", &last); | |
| } | |
| xfree(pl); | |
| return pparams; | |
| } | |
| static int _load_plugins(plugin_param_t *pparams, plugrack_foreach_t listf, | |
| bool skip_loading) | |
| { | |
| int rc = SLURM_SUCCESS; | |
| if (skip_loading) | |
| return rc; | |
| slurm_mutex_lock(&init_mutex); | |
| xassert(sizeof(parse_funcs_t) == | |
| (sizeof(void *) * ARRAY_SIZE(parse_syms))); | |
| if (!pparams) { | |
| rc = load_plugins(&plugins, PARSE_MAJOR_TYPE, NULL, listf, | |
| parse_syms, ARRAY_SIZE(parse_syms)); | |
| } else { | |
| for (int i = 0; !rc && pparams[i].plugin_type; i++) | |
| rc = load_plugins(&plugins, PARSE_MAJOR_TYPE, | |
| pparams[i].plugin_type, listf, | |
| parse_syms, ARRAY_SIZE(parse_syms)); | |
| } | |
| xassert(rc || plugins); | |
| slurm_mutex_unlock(&init_mutex); | |
| return rc; | |
| } | |
| static int _find_plugin_by_type(const char *plugin_type) | |
| { | |
| if (!plugin_type || !plugins) | |
| return -1; | |
| /* quick match by pointer address */ | |
| for (int i = 0; i < plugins->count; i++) { | |
| if (plugin_type == plugins->types[i]) | |
| return i; | |
| } | |
| /* match by full string */ | |
| for (int i = 0; i < plugins->count; i++) { | |
| if (!xstrcasecmp(plugin_type, plugins->types[i])) | |
| return i; | |
| } | |
| /* match by string without "data_parser/" */ | |
| for (int i = 0; i < plugins->count; i++) { | |
| if (!xstrcasecmp(plugin_type, | |
| _get_plugin_version(plugins->types[i]))) | |
| return i; | |
| } | |
| return -1; | |
| } | |
| extern data_parser_t *data_parser_g_new(data_parser_on_error_t on_parse_error, | |
| data_parser_on_error_t on_dump_error, | |
| data_parser_on_error_t on_query_error, | |
| void *error_arg, | |
| data_parser_on_warn_t on_parse_warn, | |
| data_parser_on_warn_t on_dump_warn, | |
| data_parser_on_warn_t on_query_warn, | |
| void *warn_arg, const char *plugin_type, | |
| plugrack_foreach_t listf, | |
| bool skip_loading) | |
| { | |
| int rc, index; | |
| char *params = NULL; | |
| data_parser_t *parser = NULL; | |
| plugin_param_t *pparams; | |
| if (!xstrcasecmp(plugin_type, "list")) { | |
| xassert(listf); | |
| load_plugins(&plugins, PARSE_MAJOR_TYPE, plugin_type, listf, | |
| parse_syms, ARRAY_SIZE(parse_syms)); | |
| return NULL; | |
| } | |
| pparams = _parse_plugin_type(plugin_type); | |
| if (!pparams || !pparams[0].plugin_type) { | |
| error("%s: invalid plugin %s", __func__, plugin_type); | |
| goto cleanup; | |
| } | |
| if (pparams[1].plugin_type) { | |
| error("%s: rejecting ambiguous plugin %s", | |
| __func__, plugin_type); | |
| goto cleanup; | |
| } | |
| if ((rc = _load_plugins(pparams, listf, skip_loading))) { | |
| error("%s: failure loading plugins: %s", | |
| __func__, slurm_strerror(rc)); | |
| goto cleanup; | |
| } | |
| if ((index = _find_plugin_by_type(pparams[0].plugin_type)) < 0) { | |
| error("%s: unable to find plugin %s", __func__, | |
| pparams[0].plugin_type); | |
| goto cleanup; | |
| } | |
| SWAP(params, pparams[0].params); | |
| parser = _new_parser(on_parse_error, on_dump_error, on_query_error, | |
| error_arg, on_parse_warn, on_dump_warn, | |
| on_query_warn, warn_arg, index, params); | |
| cleanup: | |
| if (pparams) { | |
| for (int i = 0; pparams[i].plugin_type; i++) { | |
| xfree(pparams[i].plugin_type); | |
| xfree(pparams[i].params); | |
| } | |
| xfree(pparams); | |
| } | |
| return parser; | |
| } | |
| /* | |
| * Check if a parser was already built from this plugin | |
| * IN parsers - parsers built so far | |
| * IN count - number of populated entries in parsers | |
| * IN plugin_offset - resolved plugin index of the candidate | |
| * RET true if this plugin already has a parser | |
| * | |
| * Parameters are deliberately not compared. Only the version reaches a | |
| * {data_parser} URL, so every parser built from one plugin resolves to the | |
| * same path and only the first can be served. | |
| */ | |
| static bool _duplicate_parser(data_parser_t **parsers, int count, | |
| int plugin_offset) | |
| { | |
| for (int i = 0; i < count; i++) | |
| if (parsers[i]->plugin_offset == plugin_offset) | |
| return true; | |
| return false; | |
| } | |
| extern data_parser_t **data_parser_g_new_array( | |
| data_parser_on_error_t on_parse_error, | |
| data_parser_on_error_t on_dump_error, | |
| data_parser_on_error_t on_query_error, | |
| void *error_arg, | |
| data_parser_on_warn_t on_parse_warn, | |
| data_parser_on_warn_t on_dump_warn, | |
| data_parser_on_warn_t on_query_warn, | |
| void *warn_arg, | |
| const char *plugin_type, | |
| plugrack_foreach_t listf, | |
| bool skip_loading) | |
| { | |
| int rc, i = 0, count = 0; | |
| data_parser_t **parsers = NULL; | |
| plugin_param_t *pparams; | |
| if (!xstrcasecmp(plugin_type, "list")) { | |
| xassert(listf); | |
| load_plugins(&plugins, PARSE_MAJOR_TYPE, plugin_type, listf, | |
| parse_syms, ARRAY_SIZE(parse_syms)); | |
| return NULL; | |
| } | |
| pparams = _parse_plugin_type(plugin_type); | |
| if ((rc = _load_plugins(pparams, listf, skip_loading))) { | |
| error("%s: failure loading plugins: %s", | |
| __func__, slurm_strerror(rc)); | |
| goto cleanup; | |
| } | |
| /* | |
| * Several requested parsers can share one loaded plugin, as a | |
| * version and each of its "+params" variants all resolve to the | |
| * same plugin. Sizing by plugins->count then leaves no room for | |
| * the NULL terminator and every walk of the array reads past its | |
| * end. Size by whichever count is larger. | |
| */ | |
| for (int j = 0; pparams && pparams[j].plugin_type; j++) | |
| count++; | |
| if (!plugins) { | |
| error("%s: no data_parser plugins loaded", __func__); | |
| goto cleanup; | |
| } | |
| if (count < plugins->count) | |
| count = plugins->count; | |
| parsers = xcalloc((count + 1), sizeof(*parsers)); | |
| if (pparams) { | |
| int n = 0; | |
| for (; pparams[i].plugin_type; i++) { | |
| int index = | |
| _find_plugin_by_type(pparams[i].plugin_type); | |
| if (index < 0) { | |
| error("%s: unable to find plugin %s", | |
| __func__, pparams[i].plugin_type); | |
| goto cleanup; | |
| } | |
| /* | |
| * A version and LATEST_PLUGIN_NAME name the same | |
| * parser, so one can be requested twice. Asking for it | |
| * twice is not an error, but building it twice is: | |
| * callers bind one parser per version. | |
| */ | |
| if (_duplicate_parser(parsers, n, index)) { | |
| log_flag(DATA, "%s: skipping repeat request for plugin %s", | |
| __func__, plugins->types[index]); | |
| xfree(pparams[i].params); | |
| xfree(pparams[i].plugin_type); | |
| continue; | |
| } | |
| parsers[n++] = | |
| _new_parser(on_parse_error, on_dump_error, | |
| on_query_error, error_arg, | |
| on_parse_warn, on_dump_warn, | |
| on_query_warn, warn_arg, index, | |
| pparams[i].params); | |
| pparams[i].params = NULL; | |
| xfree(pparams[i].plugin_type); | |
| } | |
| } else { | |
| for (; i < plugins->count; i++) { | |
| parsers[i] = _new_parser(on_parse_error, on_dump_error, | |
| on_query_error, error_arg, | |
| on_parse_warn, on_dump_warn, | |
| on_query_warn, warn_arg, i, | |
| NULL); | |
| } | |
| } | |
| xfree(pparams); | |
| return parsers; | |
| cleanup: | |
| if (pparams) { | |
| for (; pparams[i].plugin_type; i++) { | |
| xfree(pparams[i].plugin_type); | |
| xfree(pparams[i].params); | |
| } | |
| xfree(pparams); | |
| } | |
| if (plugins && parsers) | |
| for (int j = 0; j < count; j++) | |
| FREE_NULL_DATA_PARSER(parsers[j]); | |
| xfree(parsers); | |
| return NULL; | |
| } | |
| extern const char *data_parser_get_plugin(data_parser_t *parser) | |
| { | |
| if (!parser) | |
| return NULL; | |
| xassert(parser->magic == PARSE_MAGIC); | |
| return parser->plugin_string; | |
| } | |
| extern void *data_parser_get_error_arg(data_parser_t *parser) | |
| { | |
| if (!parser) | |
| return NULL; | |
| xassert(parser->magic == PARSE_MAGIC); | |
| return parser->error_arg; | |
| } | |
| extern void *data_parser_get_warn_arg(data_parser_t *parser) | |
| { | |
| if (!parser) | |
| return NULL; | |
| xassert(parser->magic == PARSE_MAGIC); | |
| return parser->warn_arg; | |
| } | |
| static const char *_get_plugin_version(const char *plugin_type) | |
| { | |
| static const char prefix[] = PARSE_MAJOR_TYPE "/"; | |
| #ifndef NDEBUG | |
| /* catch if the prefix ever changes in an unexpected way */ | |
| const char *match; | |
| xassert(plugin_type); | |
| match = xstrstr(plugin_type, prefix); | |
| xassert(match); | |
| #endif | |
| return plugin_type + strlen(prefix); | |
| } | |
| extern const char *data_parser_get_plugin_version(data_parser_t *parser) | |
| { | |
| xassert(!parser || parser->magic == PARSE_MAGIC); | |
| if (!parser) | |
| return NULL; | |
| return _get_plugin_version(parser->plugin_type); | |
| } | |
| extern const char *data_parser_get_plugin_params(data_parser_t *parser) | |
| { | |
| xassert(!parser || parser->magic == PARSE_MAGIC); | |
| if (!parser) | |
| return NULL; | |
| return parser->params; | |
| } | |
| extern void data_parser_g_free(data_parser_t *parser, bool skip_unloading) | |
| { | |
| DEF_TIMERS; | |
| const parse_funcs_t *funcs = NULL; | |
| if (!parser) | |
| return; | |
| if (plugins) { | |
| xassert(plugins->magic == PLUGINS_MAGIC); | |
| xassert(parser->magic == PARSE_MAGIC); | |
| xassert(parser->plugin_offset < plugins->count); | |
| xassert(plugins->functions[parser->plugin_offset]); | |
| funcs = plugins->functions[parser->plugin_offset]; | |
| } | |
| START_TIMER; | |
| if (plugins) | |
| funcs->free(parser->plugin_ctxt); | |
| END_TIMER2(__func__); | |
| xfree(parser->params); | |
| xfree(parser->plugin_string); | |
| parser->plugin_ctxt = NULL; | |
| parser->plugin_offset = -1; | |
| parser->magic = ~PARSE_MAGIC; | |
| xfree(parser); | |
| slurm_mutex_lock(&init_mutex); | |
| xassert(active_parsers >= 0); | |
| active_parsers--; | |
| xassert(active_parsers >= 0); | |
| if (!skip_unloading && !active_parsers) | |
| FREE_NULL_PLUGINS(plugins); | |
| slurm_mutex_unlock(&init_mutex); | |
| } | |
| extern void data_parser_g_array_free(data_parser_t **ptr, bool skip_unloading) | |
| { | |
| if (!ptr) | |
| return; | |
| for (int i = 0; ptr[i]; i++) | |
| data_parser_g_free(ptr[i], skip_unloading); | |
| xfree(ptr); | |
| } | |
| extern int data_parser_g_assign(data_parser_t *parser, | |
| data_parser_attr_type_t type, void *obj) | |
| { | |
| int rc; | |
| DEF_TIMERS; | |
| const parse_funcs_t *funcs; | |
| if (!parser) | |
| return ESLURM_DATA_INVALID_PARSER; | |
| funcs = plugins->functions[parser->plugin_offset]; | |
| xassert(parser); | |
| xassert(plugins); | |
| xassert(parser->magic == PARSE_MAGIC); | |
| xassert(parser->plugin_offset < plugins->count); | |
| xassert(type > DATA_PARSER_ATTR_INVALID); | |
| xassert(type < DATA_PARSER_ATTR_MAX); | |
| START_TIMER; | |
| rc = funcs->assign(parser->plugin_ctxt, type, obj); | |
| END_TIMER2(__func__); | |
| return rc; | |
| } | |
| extern openapi_resp_meta_t *data_parser_cli_meta(int argc, char **argv, | |
| const char *mime_type) | |
| { | |
| openapi_resp_meta_t *meta = xmalloc_nz(sizeof(*meta)); | |
| int tty; | |
| char **argvnt = NULL; | |
| /* need a new array with a NULL terminator */ | |
| if (argc > 0) { | |
| argvnt = xcalloc((argc + 1), sizeof(*argv)); | |
| memcpy(argvnt, argv, (sizeof(*argv) * argc)); | |
| } | |
| if (isatty(STDIN_FILENO)) | |
| tty = STDIN_FILENO; | |
| else if (isatty(STDOUT_FILENO)) | |
| tty = STDOUT_FILENO; | |
| else if (isatty(STDERR_FILENO)) | |
| tty = STDERR_FILENO; | |
| else | |
| tty = -1; | |
| *meta = (openapi_resp_meta_t) { | |
| .plugin = { | |
| .data_parser = NULL, | |
| .accounting_storage = | |
| xstrdup(slurm_conf.accounting_storage_type), | |
| }, | |
| .command = argvnt, | |
| .client = { | |
| .source = ((tty != -1) ? fd_resolve_path(tty) : | |
| NULL), | |
| .uid = getuid(), | |
| .gid = getgid(), | |
| }, | |
| .slurm = { | |
| .version = { | |
| .major = xstrdup(SLURM_MAJOR), | |
| .micro = xstrdup(SLURM_MICRO), | |
| .minor = xstrdup(SLURM_MINOR), | |
| }, | |
| .release = xstrdup(SLURM_VERSION_STRING), | |
| .cluster = xstrdup(slurm_conf.cluster_name), | |
| } | |
| }; | |
| return meta; | |
| } | |
| extern int data_parser_g_resolve_openapi_type(data_parser_t *parser, | |
| data_parser_type_t type, | |
| const char *field) | |
| { | |
| const parse_funcs_t *funcs; | |
| if (!parser) | |
| return OPENAPI_TYPE_INVALID; | |
| funcs = plugins->functions[parser->plugin_offset]; | |
| xassert(parser); | |
| xassert(plugins); | |
| xassert(parser->magic == PARSE_MAGIC); | |
| xassert(parser->plugin_offset < plugins->count); | |
| return funcs->resolve_openapi_type(parser->plugin_ctxt, type, field); | |
| } | |
| extern const char *data_parser_g_resolve_type_string(data_parser_t *parser, | |
| data_parser_type_t type) | |
| { | |
| const parse_funcs_t *funcs; | |
| if (!parser) | |
| return NULL; | |
| funcs = plugins->functions[parser->plugin_offset]; | |
| xassert(plugins); | |
| xassert(parser->magic == PARSE_MAGIC); | |
| xassert(parser->plugin_offset < plugins->count); | |
| return funcs->resolve_type_str(parser->plugin_ctxt, type); | |
| } | |
| extern int data_parser_g_increment_reference(data_parser_t *parser, | |
| data_parser_type_t type, | |
| void **references_ptr) | |
| { | |
| const parse_funcs_t *funcs; | |
| if (!parser) | |
| return EINVAL; | |
| funcs = plugins->functions[parser->plugin_offset]; | |
| xassert(parser->magic == PARSE_MAGIC); | |
| xassert(parser->plugin_offset < plugins->count); | |
| return funcs->inc_ref(parser->plugin_ctxt, type, references_ptr); | |
| } | |
| extern int data_parser_g_populate_schema(data_parser_t *parser, | |
| data_parser_type_t type, | |
| void **references_ptr, data_t *dst, | |
| data_t *schemas) | |
| { | |
| const parse_funcs_t *funcs; | |
| if (!parser) | |
| return EINVAL; | |
| funcs = plugins->functions[parser->plugin_offset]; | |
| xassert(parser->magic == PARSE_MAGIC); | |
| xassert(parser->plugin_offset < plugins->count); | |
| return funcs->populate_schema(parser->plugin_ctxt, type, references_ptr, | |
| dst, schemas); | |
| } | |
| extern int data_parser_g_populate_parameters(data_parser_t *parser, | |
| data_parser_type_t parameter_type, | |
| data_parser_type_t query_type, | |
| void **references_ptr, data_t *dst, | |
| data_t *schemas) | |
| { | |
| const parse_funcs_t *funcs; | |
| if (!parser) | |
| return EINVAL; | |
| funcs = plugins->functions[parser->plugin_offset]; | |
| xassert(parser->magic == PARSE_MAGIC); | |
| xassert(parser->plugin_offset < plugins->count); | |
| return funcs->populate_parameters(parser->plugin_ctxt, parameter_type, | |
| query_type, references_ptr, dst, | |
| schemas); | |
| } | |
| extern void data_parser_g_release_references(data_parser_t *parser, | |
| void **references_ptr) | |
| { | |
| const parse_funcs_t *funcs; | |
| if (!parser) | |
| return; | |
| funcs = plugins->functions[parser->plugin_offset]; | |
| xassert(parser->magic == PARSE_MAGIC); | |
| xassert(parser->plugin_offset < plugins->count); | |
| return funcs->release_refs(parser->plugin_ctxt, references_ptr); | |
| } | |
| extern bool data_parser_g_is_complex(data_parser_t *parser) | |
| { | |
| const parse_funcs_t *funcs; | |
| if (!parser) | |
| return false; | |
| funcs = plugins->functions[parser->plugin_offset]; | |
| xassert(parser->magic == PARSE_MAGIC); | |
| xassert(parser->plugin_offset < plugins->count); | |
| return funcs->is_complex(parser->plugin_ctxt); | |
| } | |
| extern bool data_parser_g_is_deprecated(data_parser_t *parser) | |
| { | |
| const parse_funcs_t *funcs; | |
| if (!parser) | |
| return true; | |
| funcs = plugins->functions[parser->plugin_offset]; | |
| xassert(parser->magic == PARSE_MAGIC); | |
| xassert(parser->plugin_offset < plugins->count); | |
| return funcs->is_deprecated(parser->plugin_ctxt); | |
| } | |
| extern int data_parser_g_dump_flags(data_parser_t *parser, data_t *dst) | |
| { | |
| const parse_funcs_t *funcs; | |
| if (!parser) | |
| return EINVAL; | |
| xassert(data_get_type(dst)); | |
| xassert(parser->magic == PARSE_MAGIC); | |
| xassert(plugins && (plugins->magic == PLUGINS_MAGIC)); | |
| xassert(parser->plugin_offset < plugins->count); | |
| xassert(plugins->functions[parser->plugin_offset]); | |
| funcs = plugins->functions[parser->plugin_offset]; | |
| return funcs->dump_flags(parser->plugin_ctxt, dst); | |
| } |