diff --git a/tools/nss/libvirt_nss_macs.c b/tools/nss/libvirt_nss_macs.c index f45d149793..430023abec 100644 --- a/tools/nss/libvirt_nss_macs.c +++ b/tools/nss/libvirt_nss_macs.c @@ -25,179 +25,89 @@ #include #include -#include -#include +#include #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; - +/** + * findMACsFromJSON + * + * @jobj: JSON object containing the leases + * @name: requested hostname + * @macs: returned array of MAC addresses leased to the hostname + * @nmacs: size of the returned array + */ static int -findMACsParserString(void *ctx, - const unsigned char *stringVal, - size_t stringLen) +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; - - 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; - } - 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); - - if (parser->state != FIND_MACS_STATE_LIST) - return 0; - - free(parser->key); - parser->key = NULL; - parser->state = FIND_MACS_STATE_ENTRY; - - return 1; -} - - -static int -findMACsParserEndMap(void *ctx) -{ - findMACsParser *parser = ctx; size_t i; + int len; - DEBUG("Parse end map state=%d", parser->state); - - if (parser->entry.name == NULL) - return 0; - - if (parser->state != FIND_MACS_STATE_ENTRY) - return 0; - - if (!strcasecmp(parser->entry.name, parser->name)) { - char **macs = realloc(*parser->macs, - sizeof(char *) * ((*parser->nmacs) + parser->entry.nmacs)); - if (!macs) - return 0; - - *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]); + if (!json_object_is_type(jobj, json_type_array)) { + ERROR("parsed JSON does not contain the leases array"); + return -1; } - free(parser->entry.macs); - parser->entry.macs = NULL; - parser->entry.nmacs = 0; - parser->state = FIND_MACS_STATE_LIST; + 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; + size_t j; - return 1; -} + entry = json_object_array_get_idx(jobj, i); + if (!entry) + continue; + DEBUG("Processing item %zu", i); -static int -findMACsParserStartArray(void *ctx) -{ - findMACsParser *parser = ctx; + domain = json_object_object_get(entry, "domain"); + if (!domain) + continue; - DEBUG("Parse start array state=%d", parser->state); + domainName = json_object_get_string(domain); + if (!domainName) + continue; - 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; + DEBUG("Processing domain %s", domainName); - return 1; -} + if (strcasecmp(domainName, name)) + continue; + macsArray = json_object_object_get(entry, "macs"); + if (!macsArray) + continue; -static int -findMACsParserEndArray(void *ctx) -{ - findMACsParser *parser = ctx; + newmacs = json_object_array_length(macsArray); + DEBUG("Found %zu MAC addresses", newmacs); - DEBUG("Parse end array state=%d", parser->state); + tmpMacs = realloc(*macs, sizeof(char *) * (*nmacs + newmacs + 1)); + if (!tmpMacs) + return -1; - 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; + *macs = tmpMacs; - return 1; + for (j = 0; j < newmacs; j++) { + json_object *macobj = NULL; + char *macstr; + + macobj = json_object_array_get_idx(macsArray, j); + macstr = strdup(json_object_get_string(macobj)); + if (!macstr) + return -1; + (*macs)[(*nmacs)++] = macstr; + } + } + return 0; } @@ -209,66 +119,50 @@ 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; + 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) { + do { rv = read(fd, line, sizeof(line)); 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; - } - } + jobj = json_tokener_parse_ex(tok, line, rv); + jerr = json_tokener_get_error(tok); + } while (jerr == json_tokener_continue); - if (yajl_complete_parse(parser) != yajl_status_ok) { - ERROR("Parse failed %s", - yajl_get_error(parser, 1, NULL, 0)); + if (jerr == json_tokener_continue) { + ERROR("Cannot parse %s: incomplete json found", file); goto cleanup; } - ret = 0; + if (nreadTotal > 0 && jerr != json_tokener_success) { + ERROR("Cannot parse %s: %s", file, json_tokener_error_desc(jerr)); + goto cleanup; + } + + ret = findMACsFromJSON(jobj, name, macs, nmacs); cleanup: + json_object_put(jobj); + json_tokener_free(tok); if (ret != 0) { for (i = 0; i < *nmacs; i++) { char *mac = (*macs)[i]; @@ -278,13 +172,6 @@ findMACs(const char *file, *macs = NULL; *nmacs = 0; } - if (parser) - yajl_free(parser); - for (i = 0; i < parserState.entry.nmacs; i++) - free(parserState.entry.macs[i]); - free(parserState.entry.macs); - free(parserState.entry.name); - free(parserState.key); if (fd != -1) close(fd); return ret;