On Wed, Aug 14, 2024 at 23:40:26 +0200, Ján Tomko wrote: > While the parsing is still done by 1K buffers, the results > are no longer filtered during the parsing, but the whole JSON > has to live in memory at once, which was also the case before > the NSS plugin dropped its dependency on libvirt_util. > > Also, the new parser might be more forgiving of missing elements. > > Signed-off-by: Ján Tomko <jtomko@xxxxxxxxxx> > --- > tools/nss/libvirt_nss_macs.c | 263 +++++++++-------------------------- > 1 file changed, 68 insertions(+), 195 deletions(-) > > diff --git a/tools/nss/libvirt_nss_macs.c b/tools/nss/libvirt_nss_macs.c > index f45d149793..dbc0790945 100644 > --- a/tools/nss/libvirt_nss_macs.c > +++ b/tools/nss/libvirt_nss_macs.c > @@ -25,179 +25,78 @@ > #include <stdlib.h> > #include <fcntl.h> > > -#include <yajl/yajl_gen.h> > -#include <yajl/yajl_parse.h> > +#include <json.h> Same issue with linking as outlined in previous patch. > > #include "libvirt_nss_macs.h" > #include "libvirt_nss.h" > > -enum { > - FIND_MACS_STATE_START, > - FIND_MACS_STATE_LIST, > - FIND_MACS_STATE_ENTRY, > - FIND_MACS_STATE_ENTRY_MACS, > -}; > - > -typedef struct { > - const char *name; > - char ***macs; > - size_t *nmacs; > - int state; > - > - char *key; > - struct { > - char *name; > - char **macs; > - size_t nmacs; > - } entry; > -} findMACsParser; > - > > static int > -findMACsParserString(void *ctx, > - const unsigned char *stringVal, > - size_t stringLen) As before please document this. > +findMACsFromJSON(json_object *jobj, > + const char *name, > + char ***macs, > + size_t *nmacs) > { > - findMACsParser *parser = ctx; > - > - DEBUG("Parse string state=%d '%.*s' (map key '%s')", > - parser->state, (int)stringLen, (const char *)stringVal, > - NULLSTR(parser->key)); > - if (!parser->key) > - return 0; > - > - if (parser->state == FIND_MACS_STATE_ENTRY) { > - if (strcmp(parser->key, "domain")) > - return 1; > - > - free(parser->entry.name); > - if (!(parser->entry.name = strndup((char *)stringVal, stringLen))) > - return 0; > - } else if (parser->state == FIND_MACS_STATE_ENTRY_MACS) { > - char **macs; > - if (strcmp(parser->key, "macs")) > - return 1; > + size_t i, j; One per line. > + int len; > > - if (!(macs = realloc(parser->entry.macs, > - sizeof(char *) * (parser->entry.nmacs + 1)))) > - return 0; > - > - parser->entry.macs = macs; > - if (!(macs[parser->entry.nmacs++] = strndup((char *)stringVal, stringLen))) > - return 0; > - } else { > - return 0; > + if (!json_object_is_type(jobj, json_type_array)) { > + ERROR("parsed JSON does not contain the leases array"); > + return -1; > } > - return 1; > -} > - > - > -static int > -findMACsParserMapKey(void *ctx, > - const unsigned char *stringVal, > - size_t stringLen) > -{ > - findMACsParser *parser = ctx; > - > - DEBUG("Parse map key state=%d '%.*s'", > - parser->state, (int)stringLen, (const char *)stringVal); > - > - free(parser->key); > - if (!(parser->key = strndup((char *)stringVal, stringLen))) > - return 0; > - > - return 1; > -} > - > - > -static int > -findMACsParserStartMap(void *ctx) > -{ > - findMACsParser *parser = ctx; > > - DEBUG("Parse start map state=%d", parser->state); > + len = json_object_array_length(jobj); > + DEBUG("Found an array of length: %zu", len); > + for (i = 0; i < len; i++) { > + json_object *entry = NULL; > + json_object *domain = NULL; > + const char *domainName; > + char **tmpMacs = NULL; > + size_t newmacs = 0; > + json_object *macsArray = NULL; > > - if (parser->state != FIND_MACS_STATE_LIST) > - return 0; > + entry = json_object_array_get_idx(jobj, i); > + if (!entry) > + return -1; > > - free(parser->key); > - parser->key = NULL; > - parser->state = FIND_MACS_STATE_ENTRY; > + DEBUG("Processing item %zu", i); > > - return 1; > -} > + domain = json_object_object_get(entry, "domain"); > + if (!domain) > + return -1; > > + domainName = json_object_get_string(domain); > + if (!domainName) > + return -1; No error reporting in any of these? If no shouldn't this continue processing the loop? (also below) > > -static int > -findMACsParserEndMap(void *ctx) > -{ > - findMACsParser *parser = ctx; > - size_t i; > + DEBUG("Processing domain %s", domainName); > > - DEBUG("Parse end map state=%d", parser->state); > + if (strcasecmp(domainName, name)) > + continue; > > - if (parser->entry.name == NULL) > - return 0; > + macsArray = json_object_object_get(entry, "macs"); > + if (!macsArray) > + return -1; > > - if (parser->state != FIND_MACS_STATE_ENTRY) > - return 0; > + newmacs = json_object_array_length(macsArray); > + DEBUG("Found %zu MAC addresses", newmacs); > > - if (!strcasecmp(parser->entry.name, parser->name)) { > - char **macs = realloc(*parser->macs, > - sizeof(char *) * ((*parser->nmacs) + parser->entry.nmacs)); > - if (!macs) > + tmpMacs = realloc(*macs, sizeof(char *) * (*nmacs + newmacs + 1)); > + if (!tmpMacs) > return 0; So allocation failure is success? > > - *parser->macs = macs; > - for (i = 0; i < parser->entry.nmacs; i++) > - (*parser->macs)[(*parser->nmacs)++] = parser->entry.macs[i]; > - } else { > - for (i = 0; i < parser->entry.nmacs; i++) > - free(parser->entry.macs[i]); > - } > - free(parser->entry.macs); > - parser->entry.macs = NULL; > - parser->entry.nmacs = 0; > - > - parser->state = FIND_MACS_STATE_LIST; > - > - return 1; > -} > - > - > -static int > -findMACsParserStartArray(void *ctx) > -{ > - findMACsParser *parser = ctx; > - > - DEBUG("Parse start array state=%d", parser->state); > - > - if (parser->state == FIND_MACS_STATE_START) > - parser->state = FIND_MACS_STATE_LIST; > - else if (parser->state == FIND_MACS_STATE_ENTRY) > - parser->state = FIND_MACS_STATE_ENTRY_MACS; > - else > - return 0; > + *macs = tmpMacs; > > - return 1; > -} > + for (j = 0; j < newmacs; j++) { > + json_object *macobj = NULL; > > + DEBUG("j: %zu", j); This doesn't sound very useful. > > -static int > -findMACsParserEndArray(void *ctx) > -{ > - findMACsParser *parser = ctx; > - > - DEBUG("Parse end array state=%d", parser->state); > - > - if (parser->state == FIND_MACS_STATE_LIST) > - parser->state = FIND_MACS_STATE_START; > - else if (parser->state == FIND_MACS_STATE_ENTRY_MACS) > - parser->state = FIND_MACS_STATE_ENTRY; > - else > - return 0; > - > - return 1; > + macobj = json_object_array_get_idx(macsArray, j); > + (*macs)[(*nmacs)++] = strdup(json_object_get_string(macobj)); No return value check from strdup (since you are checking realloc). > + } > + } > + return 0; > } > > > @@ -209,66 +108,47 @@ findMACs(const char *file, > { > int fd = -1; > int ret = -1; > - const yajl_callbacks parserCallbacks = { > - NULL, /* null */ > - NULL, /* bool */ > - NULL, /* integer */ > - NULL, /* double */ > - NULL, /* number */ > - findMACsParserString, > - findMACsParserStartMap, > - findMACsParserMapKey, > - findMACsParserEndMap, > - findMACsParserStartArray, > - findMACsParserEndArray, > - }; > - findMACsParser parserState = { > - .name = name, > - .macs = macs, > - .nmacs = nmacs, > - }; > - yajl_handle parser = NULL; > char line[1024]; > - size_t i; > + json_object *jobj = NULL; > + json_tokener *tok = NULL; > + enum json_tokener_error jerr = json_tokener_success; > + int jsonflags = JSON_TOKENER_STRICT | JSON_TOKENER_VALIDATE_UTF8; > + ssize_t nreadTotal = 0; > int rv; > + size_t i; > > if ((fd = open(file, O_RDONLY)) < 0) { > ERROR("Cannot open %s", file); > goto cleanup; > } > > - parser = yajl_alloc(&parserCallbacks, NULL, &parserState); > - if (!parser) { > - ERROR("Unable to create JSON parser"); > - goto cleanup; > - } > + tok = json_tokener_new(); > + json_tokener_set_flags(tok, jsonflags); > > - while (1) { > - rv = read(fd, line, sizeof(line)); > + while (jerr != json_tokener_continue) { > + rv = read(fd, line, sizeof(line) - 1); > if (rv < 0) > goto cleanup; > if (rv == 0) > break; > + nreadTotal += rv; > > - if (yajl_parse(parser, (const unsigned char *)line, rv) != > - yajl_status_ok) { > - unsigned char *err = yajl_get_error(parser, 1, > - (const unsigned char*)line, rv); > - ERROR("Parse failed %s", (const char *) err); > - yajl_free_error(parser, err); > - goto cleanup; > - } > + line[rv] = 0; > + > + jobj = json_tokener_parse_ex(tok, line, rv); > + jerr = json_tokener_get_error(tok); > } > > - if (yajl_complete_parse(parser) != yajl_status_ok) { > - ERROR("Parse failed %s", > - yajl_get_error(parser, 1, NULL, 0)); > + if (nreadTotal > 0 && jerr != json_tokener_success) { > + ERROR("Cannot parse %s: %s", file, json_tokener_error_desc(jerr)); > goto cleanup; > } > > - ret = 0; > + ret = findMACsFromJSON(jobj, name, macs, nmacs); Same issues with the parser as in patch before.