#include <stdlib.h>
#include <fcntl.h>
-#include <yajl/yajl_gen.h>
-#include <yajl/yajl_parse.h>
+#include <json.h>
#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;
+ size_t i;
+ int len;
- 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);
+ 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;
- free(parser->key);
- if (!(parser->key = strndup((char *)stringVal, stringLen)))
- return 0;
+ entry = json_object_array_get_idx(jobj, i);
+ if (!entry)
+ continue;
- return 1;
-}
+ DEBUG("Processing item %zu", i);
+ domain = json_object_object_get(entry, "domain");
+ if (!domain)
+ continue;
-static int
-findMACsParserStartMap(void *ctx)
-{
- findMACsParser *parser = ctx;
+ domainName = json_object_get_string(domain);
+ if (!domainName)
+ continue;
- DEBUG("Parse start map state=%d", parser->state);
+ DEBUG("Processing domain %s", domainName);
- if (parser->state != FIND_MACS_STATE_LIST)
- return 0;
+ if (strcasecmp(domainName, name))
+ continue;
- free(parser->key);
- parser->key = NULL;
- parser->state = FIND_MACS_STATE_ENTRY;
+ macsArray = json_object_object_get(entry, "macs");
+ if (!macsArray)
+ continue;
- return 1;
-}
+ newmacs = json_object_array_length(macsArray);
+ DEBUG("Found %zu MAC addresses", newmacs);
+ tmpMacs = realloc(*macs, sizeof(char *) * (*nmacs + newmacs + 1));
+ if (!tmpMacs)
+ return -1;
-static int
-findMACsParserEndMap(void *ctx)
-{
- findMACsParser *parser = ctx;
- size_t i;
-
- DEBUG("Parse end map state=%d", parser->state);
+ *macs = tmpMacs;
- if (parser->entry.name == NULL)
- return 0;
+ for (j = 0; j < newmacs; j++) {
+ json_object *macobj = NULL;
+ char *macstr;
- 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]);
+ macobj = json_object_array_get_idx(macsArray, j);
+ macstr = strdup(json_object_get_string(macobj));
+ if (!macstr)
+ return -1;
+ (*macs)[(*nmacs)++] = macstr;
+ }
}
- 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;
-
- return 1;
-}
-
-
-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;
+ return 0;
}
{
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 (jerr == json_tokener_continue) {
+ ERROR("Cannot parse %s: incomplete json found", file);
+ goto cleanup;
}
- 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);
cleanup:
+ json_object_put(jobj);
+ json_tokener_free(tok);
if (ret != 0) {
for (i = 0; i < *nmacs; i++) {
char *mac = (*macs)[i];
*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;