2009-11-03 18:59:18 +00:00
|
|
|
/*
|
2012-12-12 17:53:50 +00:00
|
|
|
* virjson.c: JSON object parsing/formatting
|
2009-11-03 18:59:18 +00:00
|
|
|
*
|
2013-04-26 14:59:02 +00:00
|
|
|
* Copyright (C) 2009-2010, 2012-2013 Red Hat, Inc.
|
2010-03-01 23:38:28 +00:00
|
|
|
* Copyright (C) 2009 Daniel P. Berrange
|
2009-11-03 18:59:18 +00:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library 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
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-07-21 10:06:23 +00:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
2009-11-03 18:59:18 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
2012-12-12 17:53:50 +00:00
|
|
|
#include "virjson.h"
|
2012-12-12 18:06:53 +00:00
|
|
|
#include "viralloc.h"
|
2012-12-13 18:21:53 +00:00
|
|
|
#include "virerror.h"
|
2012-12-12 17:59:27 +00:00
|
|
|
#include "virlog.h"
|
2013-04-03 10:36:23 +00:00
|
|
|
#include "virstring.h"
|
2012-12-13 17:44:57 +00:00
|
|
|
#include "virutil.h"
|
2009-11-03 18:59:18 +00:00
|
|
|
|
2012-09-20 11:57:13 +00:00
|
|
|
#if WITH_YAJL
|
2010-03-09 18:22:22 +00:00
|
|
|
# include <yajl/yajl_gen.h>
|
|
|
|
# include <yajl/yajl_parse.h>
|
2011-05-03 16:50:58 +00:00
|
|
|
|
2012-09-20 11:57:13 +00:00
|
|
|
# ifdef WITH_YAJL2
|
2011-05-03 16:50:58 +00:00
|
|
|
# define yajl_size_t size_t
|
|
|
|
# else
|
|
|
|
# define yajl_size_t unsigned int
|
|
|
|
# endif
|
|
|
|
|
2009-12-08 10:08:17 +00:00
|
|
|
#endif
|
2009-11-03 18:59:18 +00:00
|
|
|
|
|
|
|
/* XXX fixme */
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_NONE
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct _virJSONParserState virJSONParserState;
|
|
|
|
typedef virJSONParserState *virJSONParserStatePtr;
|
|
|
|
struct _virJSONParserState {
|
|
|
|
virJSONValuePtr value;
|
|
|
|
char *key;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct _virJSONParser virJSONParser;
|
|
|
|
typedef virJSONParser *virJSONParserPtr;
|
|
|
|
struct _virJSONParser {
|
|
|
|
virJSONValuePtr head;
|
|
|
|
virJSONParserStatePtr state;
|
|
|
|
unsigned int nstate;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
void virJSONValueFree(virJSONValuePtr value)
|
|
|
|
{
|
|
|
|
int i;
|
2012-04-05 19:15:03 +00:00
|
|
|
if (!value || value->protect)
|
2009-11-03 18:59:18 +00:00
|
|
|
return;
|
|
|
|
|
2012-04-05 19:15:03 +00:00
|
|
|
switch ((virJSONType) value->type) {
|
2009-11-03 18:59:18 +00:00
|
|
|
case VIR_JSON_TYPE_OBJECT:
|
2013-05-21 07:58:16 +00:00
|
|
|
for (i = 0; i < value->data.object.npairs; i++) {
|
2009-11-03 18:59:18 +00:00
|
|
|
VIR_FREE(value->data.object.pairs[i].key);
|
|
|
|
virJSONValueFree(value->data.object.pairs[i].value);
|
|
|
|
}
|
|
|
|
VIR_FREE(value->data.object.pairs);
|
|
|
|
break;
|
|
|
|
case VIR_JSON_TYPE_ARRAY:
|
2013-05-21 07:58:16 +00:00
|
|
|
for (i = 0; i < value->data.array.nvalues; i++)
|
2009-11-03 18:59:18 +00:00
|
|
|
virJSONValueFree(value->data.array.values[i]);
|
|
|
|
VIR_FREE(value->data.array.values);
|
|
|
|
break;
|
|
|
|
case VIR_JSON_TYPE_STRING:
|
|
|
|
VIR_FREE(value->data.string);
|
|
|
|
break;
|
|
|
|
case VIR_JSON_TYPE_NUMBER:
|
|
|
|
VIR_FREE(value->data.number);
|
|
|
|
break;
|
2012-04-05 19:15:03 +00:00
|
|
|
case VIR_JSON_TYPE_BOOLEAN:
|
|
|
|
case VIR_JSON_TYPE_NULL:
|
|
|
|
break;
|
2009-11-03 18:59:18 +00:00
|
|
|
}
|
2010-01-27 08:58:12 +00:00
|
|
|
|
|
|
|
VIR_FREE(value);
|
2009-11-03 18:59:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virJSONValuePtr virJSONValueNewString(const char *data)
|
|
|
|
{
|
|
|
|
virJSONValuePtr val;
|
|
|
|
|
|
|
|
if (!data)
|
|
|
|
return virJSONValueNewNull();
|
|
|
|
|
|
|
|
if (VIR_ALLOC(val) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
val->type = VIR_JSON_TYPE_STRING;
|
2013-05-24 07:19:51 +00:00
|
|
|
if (VIR_STRDUP(val->data.string, data) < 0) {
|
2009-11-03 18:59:18 +00:00
|
|
|
VIR_FREE(val);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
virJSONValuePtr virJSONValueNewStringLen(const char *data, size_t length)
|
|
|
|
{
|
|
|
|
virJSONValuePtr val;
|
|
|
|
|
|
|
|
if (!data)
|
|
|
|
return virJSONValueNewNull();
|
|
|
|
|
|
|
|
if (VIR_ALLOC(val) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
val->type = VIR_JSON_TYPE_STRING;
|
2013-05-24 07:19:51 +00:00
|
|
|
if (VIR_STRNDUP(val->data.string, data, length) < 0) {
|
2009-11-03 18:59:18 +00:00
|
|
|
VIR_FREE(val);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
static virJSONValuePtr virJSONValueNewNumber(const char *data)
|
|
|
|
{
|
|
|
|
virJSONValuePtr val;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(val) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
val->type = VIR_JSON_TYPE_NUMBER;
|
2013-05-24 07:19:51 +00:00
|
|
|
if (VIR_STRDUP(val->data.number, data) < 0) {
|
2009-11-03 18:59:18 +00:00
|
|
|
VIR_FREE(val);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
virJSONValuePtr virJSONValueNewNumberInt(int data)
|
|
|
|
{
|
|
|
|
virJSONValuePtr val = NULL;
|
|
|
|
char *str;
|
|
|
|
if (virAsprintf(&str, "%i", data) < 0)
|
|
|
|
return NULL;
|
|
|
|
val = virJSONValueNewNumber(str);
|
|
|
|
VIR_FREE(str);
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virJSONValuePtr virJSONValueNewNumberUint(unsigned int data)
|
|
|
|
{
|
|
|
|
virJSONValuePtr val = NULL;
|
|
|
|
char *str;
|
|
|
|
if (virAsprintf(&str, "%u", data) < 0)
|
|
|
|
return NULL;
|
|
|
|
val = virJSONValueNewNumber(str);
|
|
|
|
VIR_FREE(str);
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virJSONValuePtr virJSONValueNewNumberLong(long long data)
|
|
|
|
{
|
|
|
|
virJSONValuePtr val = NULL;
|
|
|
|
char *str;
|
|
|
|
if (virAsprintf(&str, "%lld", data) < 0)
|
|
|
|
return NULL;
|
|
|
|
val = virJSONValueNewNumber(str);
|
|
|
|
VIR_FREE(str);
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virJSONValuePtr virJSONValueNewNumberUlong(unsigned long long data)
|
|
|
|
{
|
|
|
|
virJSONValuePtr val = NULL;
|
|
|
|
char *str;
|
|
|
|
if (virAsprintf(&str, "%llu", data) < 0)
|
|
|
|
return NULL;
|
|
|
|
val = virJSONValueNewNumber(str);
|
|
|
|
VIR_FREE(str);
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virJSONValuePtr virJSONValueNewNumberDouble(double data)
|
|
|
|
{
|
|
|
|
virJSONValuePtr val = NULL;
|
|
|
|
char *str;
|
2012-08-11 19:13:00 +00:00
|
|
|
if (virDoubleToStr(&str, data) < 0)
|
2009-11-03 18:59:18 +00:00
|
|
|
return NULL;
|
|
|
|
val = virJSONValueNewNumber(str);
|
|
|
|
VIR_FREE(str);
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-23 03:02:26 +00:00
|
|
|
virJSONValuePtr virJSONValueNewBoolean(int boolean_)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
virJSONValuePtr val;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(val) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
val->type = VIR_JSON_TYPE_BOOLEAN;
|
2009-12-23 03:02:26 +00:00
|
|
|
val->data.boolean = boolean_;
|
2009-11-03 18:59:18 +00:00
|
|
|
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
virJSONValuePtr virJSONValueNewNull(void)
|
|
|
|
{
|
|
|
|
virJSONValuePtr val;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(val) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
val->type = VIR_JSON_TYPE_NULL;
|
|
|
|
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
virJSONValuePtr virJSONValueNewArray(void)
|
|
|
|
{
|
|
|
|
virJSONValuePtr val;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(val) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
val->type = VIR_JSON_TYPE_ARRAY;
|
|
|
|
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
virJSONValuePtr virJSONValueNewObject(void)
|
|
|
|
{
|
|
|
|
virJSONValuePtr val;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(val) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
val->type = VIR_JSON_TYPE_OBJECT;
|
|
|
|
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
int virJSONValueObjectAppend(virJSONValuePtr object, const char *key, virJSONValuePtr value)
|
|
|
|
{
|
|
|
|
char *newkey;
|
|
|
|
|
|
|
|
if (object->type != VIR_JSON_TYPE_OBJECT)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virJSONValueObjectHasKey(object, key))
|
|
|
|
return -1;
|
|
|
|
|
2013-05-24 07:19:51 +00:00
|
|
|
if (VIR_STRDUP(newkey, key) < 0)
|
2009-11-03 18:59:18 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (VIR_REALLOC_N(object->data.object.pairs,
|
|
|
|
object->data.object.npairs + 1) < 0) {
|
|
|
|
VIR_FREE(newkey);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
object->data.object.pairs[object->data.object.npairs].key = newkey;
|
|
|
|
object->data.object.pairs[object->data.object.npairs].value = value;
|
|
|
|
object->data.object.npairs++;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int virJSONValueObjectAppendString(virJSONValuePtr object, const char *key, const char *value)
|
|
|
|
{
|
|
|
|
virJSONValuePtr jvalue = virJSONValueNewString(value);
|
|
|
|
if (!jvalue)
|
|
|
|
return -1;
|
|
|
|
if (virJSONValueObjectAppend(object, key, jvalue) < 0) {
|
|
|
|
virJSONValueFree(jvalue);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int virJSONValueObjectAppendNumberInt(virJSONValuePtr object, const char *key, int number)
|
|
|
|
{
|
|
|
|
virJSONValuePtr jvalue = virJSONValueNewNumberInt(number);
|
|
|
|
if (!jvalue)
|
|
|
|
return -1;
|
|
|
|
if (virJSONValueObjectAppend(object, key, jvalue) < 0) {
|
|
|
|
virJSONValueFree(jvalue);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int virJSONValueObjectAppendNumberUint(virJSONValuePtr object, const char *key, unsigned int number)
|
|
|
|
{
|
|
|
|
virJSONValuePtr jvalue = virJSONValueNewNumberUint(number);
|
|
|
|
if (!jvalue)
|
|
|
|
return -1;
|
|
|
|
if (virJSONValueObjectAppend(object, key, jvalue) < 0) {
|
|
|
|
virJSONValueFree(jvalue);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int virJSONValueObjectAppendNumberLong(virJSONValuePtr object, const char *key, long long number)
|
|
|
|
{
|
|
|
|
virJSONValuePtr jvalue = virJSONValueNewNumberLong(number);
|
|
|
|
if (!jvalue)
|
|
|
|
return -1;
|
|
|
|
if (virJSONValueObjectAppend(object, key, jvalue) < 0) {
|
|
|
|
virJSONValueFree(jvalue);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int virJSONValueObjectAppendNumberUlong(virJSONValuePtr object, const char *key, unsigned long long number)
|
|
|
|
{
|
|
|
|
virJSONValuePtr jvalue = virJSONValueNewNumberUlong(number);
|
|
|
|
if (!jvalue)
|
|
|
|
return -1;
|
|
|
|
if (virJSONValueObjectAppend(object, key, jvalue) < 0) {
|
|
|
|
virJSONValueFree(jvalue);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int virJSONValueObjectAppendNumberDouble(virJSONValuePtr object, const char *key, double number)
|
|
|
|
{
|
|
|
|
virJSONValuePtr jvalue = virJSONValueNewNumberDouble(number);
|
|
|
|
if (!jvalue)
|
|
|
|
return -1;
|
|
|
|
if (virJSONValueObjectAppend(object, key, jvalue) < 0) {
|
|
|
|
virJSONValueFree(jvalue);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-12-23 03:02:26 +00:00
|
|
|
int virJSONValueObjectAppendBoolean(virJSONValuePtr object, const char *key, int boolean_)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
2009-12-23 03:02:26 +00:00
|
|
|
virJSONValuePtr jvalue = virJSONValueNewBoolean(boolean_);
|
2009-11-03 18:59:18 +00:00
|
|
|
if (!jvalue)
|
|
|
|
return -1;
|
|
|
|
if (virJSONValueObjectAppend(object, key, jvalue) < 0) {
|
|
|
|
virJSONValueFree(jvalue);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int virJSONValueObjectAppendNull(virJSONValuePtr object, const char *key)
|
|
|
|
{
|
|
|
|
virJSONValuePtr jvalue = virJSONValueNewNull();
|
|
|
|
if (!jvalue)
|
|
|
|
return -1;
|
|
|
|
if (virJSONValueObjectAppend(object, key, jvalue) < 0) {
|
|
|
|
virJSONValueFree(jvalue);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int virJSONValueArrayAppend(virJSONValuePtr array, virJSONValuePtr value)
|
|
|
|
{
|
|
|
|
if (array->type != VIR_JSON_TYPE_ARRAY)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (VIR_REALLOC_N(array->data.array.values,
|
|
|
|
array->data.array.nvalues + 1) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
array->data.array.values[array->data.array.nvalues] = value;
|
|
|
|
array->data.array.nvalues++;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int virJSONValueObjectHasKey(virJSONValuePtr object, const char *key)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (object->type != VIR_JSON_TYPE_OBJECT)
|
|
|
|
return -1;
|
|
|
|
|
2013-05-21 07:58:16 +00:00
|
|
|
for (i = 0; i < object->data.object.npairs; i++) {
|
2009-11-03 18:59:18 +00:00
|
|
|
if (STREQ(object->data.object.pairs[i].key, key))
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
virJSONValuePtr virJSONValueObjectGet(virJSONValuePtr object, const char *key)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (object->type != VIR_JSON_TYPE_OBJECT)
|
|
|
|
return NULL;
|
|
|
|
|
2013-05-21 07:58:16 +00:00
|
|
|
for (i = 0; i < object->data.object.npairs; i++) {
|
2009-11-03 18:59:18 +00:00
|
|
|
if (STREQ(object->data.object.pairs[i].key, key))
|
|
|
|
return object->data.object.pairs[i].value;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-05-02 18:32:37 +00:00
|
|
|
int virJSONValueObjectKeysNumber(virJSONValuePtr object)
|
|
|
|
{
|
|
|
|
if (object->type != VIR_JSON_TYPE_OBJECT)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return object->data.object.npairs;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *virJSONValueObjectGetKey(virJSONValuePtr object, unsigned int n)
|
|
|
|
{
|
|
|
|
if (object->type != VIR_JSON_TYPE_OBJECT)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (n >= object->data.object.npairs)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return object->data.object.pairs[n].key;
|
|
|
|
}
|
|
|
|
|
2013-04-26 14:59:02 +00:00
|
|
|
/* Remove the key-value pair tied to @key out of @object. If @value is
|
|
|
|
* not NULL, the dropped value object is returned instead of freed.
|
|
|
|
* Returns 1 on success, 0 if no key was found, and -1 on error. */
|
|
|
|
int
|
|
|
|
virJSONValueObjectRemoveKey(virJSONValuePtr object, const char *key,
|
|
|
|
virJSONValuePtr *value)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (value)
|
|
|
|
*value = NULL;
|
|
|
|
|
|
|
|
if (object->type != VIR_JSON_TYPE_OBJECT)
|
|
|
|
return -1;
|
|
|
|
|
2013-05-21 07:58:16 +00:00
|
|
|
for (i = 0; i < object->data.object.npairs; i++) {
|
2013-04-26 14:59:02 +00:00
|
|
|
if (STREQ(object->data.object.pairs[i].key, key)) {
|
|
|
|
if (value) {
|
|
|
|
*value = object->data.object.pairs[i].value;
|
|
|
|
object->data.object.pairs[i].value = NULL;
|
|
|
|
}
|
|
|
|
VIR_FREE(object->data.object.pairs[i].key);
|
|
|
|
virJSONValueFree(object->data.object.pairs[i].value);
|
|
|
|
VIR_DELETE_ELEMENT(object->data.object.pairs, i,
|
|
|
|
object->data.object.npairs);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-05-02 18:32:37 +00:00
|
|
|
virJSONValuePtr virJSONValueObjectGetValue(virJSONValuePtr object, unsigned int n)
|
|
|
|
{
|
|
|
|
if (object->type != VIR_JSON_TYPE_OBJECT)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (n >= object->data.object.npairs)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return object->data.object.pairs[n].value;
|
|
|
|
}
|
|
|
|
|
2009-11-03 18:59:18 +00:00
|
|
|
int virJSONValueArraySize(virJSONValuePtr array)
|
|
|
|
{
|
|
|
|
if (array->type != VIR_JSON_TYPE_ARRAY)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return array->data.array.nvalues;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virJSONValuePtr virJSONValueArrayGet(virJSONValuePtr array, unsigned int element)
|
|
|
|
{
|
|
|
|
if (array->type != VIR_JSON_TYPE_ARRAY)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (element >= array->data.array.nvalues)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return array->data.array.values[element];
|
|
|
|
}
|
|
|
|
|
2010-01-22 13:22:53 +00:00
|
|
|
const char *virJSONValueGetString(virJSONValuePtr string)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
if (string->type != VIR_JSON_TYPE_STRING)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return string->data.string;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int virJSONValueGetNumberInt(virJSONValuePtr number, int *value)
|
|
|
|
{
|
|
|
|
if (number->type != VIR_JSON_TYPE_NUMBER)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return virStrToLong_i(number->data.number, NULL, 10, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
int virJSONValueGetNumberUint(virJSONValuePtr number, unsigned int *value)
|
|
|
|
{
|
|
|
|
if (number->type != VIR_JSON_TYPE_NUMBER)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return virStrToLong_ui(number->data.number, NULL, 10, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
int virJSONValueGetNumberLong(virJSONValuePtr number, long long *value)
|
|
|
|
{
|
|
|
|
if (number->type != VIR_JSON_TYPE_NUMBER)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return virStrToLong_ll(number->data.number, NULL, 10, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
int virJSONValueGetNumberUlong(virJSONValuePtr number, unsigned long long *value)
|
|
|
|
{
|
|
|
|
if (number->type != VIR_JSON_TYPE_NUMBER)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return virStrToLong_ull(number->data.number, NULL, 10, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
int virJSONValueGetNumberDouble(virJSONValuePtr number, double *value)
|
|
|
|
{
|
|
|
|
if (number->type != VIR_JSON_TYPE_NUMBER)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return virStrToDouble(number->data.number, NULL, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-05-05 11:48:31 +00:00
|
|
|
int virJSONValueGetBoolean(virJSONValuePtr val, bool *value)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
2011-05-05 11:48:31 +00:00
|
|
|
if (val->type != VIR_JSON_TYPE_BOOLEAN)
|
2009-11-03 18:59:18 +00:00
|
|
|
return -1;
|
|
|
|
|
2011-05-05 11:48:31 +00:00
|
|
|
*value = val->data.boolean;
|
|
|
|
return 0;
|
2009-11-03 18:59:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int virJSONValueIsNull(virJSONValuePtr val)
|
|
|
|
{
|
|
|
|
if (val->type != VIR_JSON_TYPE_NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-22 13:22:53 +00:00
|
|
|
const char *virJSONValueObjectGetString(virJSONValuePtr object, const char *key)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
virJSONValuePtr val;
|
|
|
|
if (object->type != VIR_JSON_TYPE_OBJECT)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
val = virJSONValueObjectGet(object, key);
|
|
|
|
if (!val)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return virJSONValueGetString(val);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int virJSONValueObjectGetNumberInt(virJSONValuePtr object, const char *key, int *value)
|
|
|
|
{
|
|
|
|
virJSONValuePtr val;
|
|
|
|
if (object->type != VIR_JSON_TYPE_OBJECT)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
val = virJSONValueObjectGet(object, key);
|
|
|
|
if (!val)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return virJSONValueGetNumberInt(val, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int virJSONValueObjectGetNumberUint(virJSONValuePtr object, const char *key, unsigned int *value)
|
|
|
|
{
|
|
|
|
virJSONValuePtr val;
|
|
|
|
if (object->type != VIR_JSON_TYPE_OBJECT)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
val = virJSONValueObjectGet(object, key);
|
|
|
|
if (!val)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return virJSONValueGetNumberUint(val, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int virJSONValueObjectGetNumberLong(virJSONValuePtr object, const char *key, long long *value)
|
|
|
|
{
|
|
|
|
virJSONValuePtr val;
|
|
|
|
if (object->type != VIR_JSON_TYPE_OBJECT)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
val = virJSONValueObjectGet(object, key);
|
|
|
|
if (!val)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return virJSONValueGetNumberLong(val, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int virJSONValueObjectGetNumberUlong(virJSONValuePtr object, const char *key, unsigned long long *value)
|
|
|
|
{
|
|
|
|
virJSONValuePtr val;
|
|
|
|
if (object->type != VIR_JSON_TYPE_OBJECT)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
val = virJSONValueObjectGet(object, key);
|
|
|
|
if (!val)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return virJSONValueGetNumberUlong(val, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int virJSONValueObjectGetNumberDouble(virJSONValuePtr object, const char *key, double *value)
|
|
|
|
{
|
|
|
|
virJSONValuePtr val;
|
|
|
|
if (object->type != VIR_JSON_TYPE_OBJECT)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
val = virJSONValueObjectGet(object, key);
|
|
|
|
if (!val)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return virJSONValueGetNumberDouble(val, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-05-05 11:48:31 +00:00
|
|
|
int virJSONValueObjectGetBoolean(virJSONValuePtr object, const char *key, bool *value)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
virJSONValuePtr val;
|
|
|
|
if (object->type != VIR_JSON_TYPE_OBJECT)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
val = virJSONValueObjectGet(object, key);
|
|
|
|
if (!val)
|
|
|
|
return -1;
|
|
|
|
|
2011-05-05 11:48:31 +00:00
|
|
|
return virJSONValueGetBoolean(val, value);
|
2009-11-03 18:59:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int virJSONValueObjectIsNull(virJSONValuePtr object, const char *key)
|
|
|
|
{
|
|
|
|
virJSONValuePtr val;
|
|
|
|
if (object->type != VIR_JSON_TYPE_OBJECT)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
val = virJSONValueObjectGet(object, key);
|
|
|
|
if (!val)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return virJSONValueIsNull(val);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-20 11:57:13 +00:00
|
|
|
#if WITH_YAJL
|
2009-11-03 18:59:18 +00:00
|
|
|
static int virJSONParserInsertValue(virJSONParserPtr parser,
|
|
|
|
virJSONValuePtr value)
|
|
|
|
{
|
|
|
|
if (!parser->head) {
|
|
|
|
parser->head = value;
|
|
|
|
} else {
|
|
|
|
virJSONParserStatePtr state;
|
|
|
|
if (!parser->nstate) {
|
2011-05-09 09:24:09 +00:00
|
|
|
VIR_DEBUG("got a value to insert without a container");
|
2009-11-03 18:59:18 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
state = &parser->state[parser->nstate-1];
|
|
|
|
|
|
|
|
switch (state->value->type) {
|
|
|
|
case VIR_JSON_TYPE_OBJECT: {
|
|
|
|
if (!state->key) {
|
2011-05-09 09:24:09 +00:00
|
|
|
VIR_DEBUG("missing key when inserting object value");
|
2009-11-03 18:59:18 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virJSONValueObjectAppend(state->value,
|
|
|
|
state->key,
|
|
|
|
value) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
VIR_FREE(state->key);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case VIR_JSON_TYPE_ARRAY: {
|
|
|
|
if (state->key) {
|
2011-05-09 09:24:09 +00:00
|
|
|
VIR_DEBUG("unexpected key when inserting array value");
|
2009-11-03 18:59:18 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virJSONValueArrayAppend(state->value,
|
|
|
|
value) < 0)
|
|
|
|
return -1;
|
|
|
|
} break;
|
|
|
|
|
|
|
|
default:
|
2011-05-09 09:24:09 +00:00
|
|
|
VIR_DEBUG("unexpected value type, not a container");
|
2009-11-03 18:59:18 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-05-03 16:50:58 +00:00
|
|
|
static int virJSONParserHandleNull(void *ctx)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
virJSONParserPtr parser = ctx;
|
|
|
|
virJSONValuePtr value = virJSONValueNewNull();
|
|
|
|
|
|
|
|
VIR_DEBUG("parser=%p", parser);
|
|
|
|
|
|
|
|
if (!value)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (virJSONParserInsertValue(parser, value) < 0) {
|
|
|
|
virJSONValueFree(value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-05-03 16:50:58 +00:00
|
|
|
static int virJSONParserHandleBoolean(void *ctx, int boolean_)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
virJSONParserPtr parser = ctx;
|
2009-12-23 03:02:26 +00:00
|
|
|
virJSONValuePtr value = virJSONValueNewBoolean(boolean_);
|
2009-11-03 18:59:18 +00:00
|
|
|
|
2009-12-23 03:02:26 +00:00
|
|
|
VIR_DEBUG("parser=%p boolean=%d", parser, boolean_);
|
2009-11-03 18:59:18 +00:00
|
|
|
|
|
|
|
if (!value)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (virJSONParserInsertValue(parser, value) < 0) {
|
|
|
|
virJSONValueFree(value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-05-03 16:50:58 +00:00
|
|
|
static int virJSONParserHandleNumber(void *ctx,
|
|
|
|
const char *s,
|
|
|
|
yajl_size_t l)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
virJSONParserPtr parser = ctx;
|
2013-05-24 07:19:51 +00:00
|
|
|
char *str;
|
2009-11-03 18:59:18 +00:00
|
|
|
virJSONValuePtr value;
|
|
|
|
|
2013-05-24 07:19:51 +00:00
|
|
|
if (VIR_STRNDUP(str, s, l) < 0)
|
2009-11-03 18:59:18 +00:00
|
|
|
return -1;
|
|
|
|
value = virJSONValueNewNumber(str);
|
|
|
|
VIR_FREE(str);
|
|
|
|
|
|
|
|
VIR_DEBUG("parser=%p str=%s", parser, str);
|
|
|
|
|
|
|
|
if (!value)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (virJSONParserInsertValue(parser, value) < 0) {
|
|
|
|
virJSONValueFree(value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-05-03 16:50:58 +00:00
|
|
|
static int virJSONParserHandleString(void *ctx,
|
|
|
|
const unsigned char *stringVal,
|
|
|
|
yajl_size_t stringLen)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
virJSONParserPtr parser = ctx;
|
|
|
|
virJSONValuePtr value = virJSONValueNewStringLen((const char *)stringVal,
|
|
|
|
stringLen);
|
|
|
|
|
|
|
|
VIR_DEBUG("parser=%p str=%p", parser, (const char *)stringVal);
|
|
|
|
|
|
|
|
if (!value)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (virJSONParserInsertValue(parser, value) < 0) {
|
|
|
|
virJSONValueFree(value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-05-03 16:50:58 +00:00
|
|
|
static int virJSONParserHandleMapKey(void *ctx,
|
|
|
|
const unsigned char *stringVal,
|
|
|
|
yajl_size_t stringLen)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
virJSONParserPtr parser = ctx;
|
|
|
|
virJSONParserStatePtr state;
|
|
|
|
|
|
|
|
VIR_DEBUG("parser=%p key=%p", parser, (const char *)stringVal);
|
|
|
|
|
|
|
|
if (!parser->nstate)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
state = &parser->state[parser->nstate-1];
|
|
|
|
if (state->key)
|
|
|
|
return 0;
|
2013-05-24 07:19:51 +00:00
|
|
|
if (VIR_STRNDUP(state->key, (const char *)stringVal, stringLen) < 0)
|
2009-11-03 18:59:18 +00:00
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-05-03 16:50:58 +00:00
|
|
|
static int virJSONParserHandleStartMap(void *ctx)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
virJSONParserPtr parser = ctx;
|
|
|
|
virJSONValuePtr value = virJSONValueNewObject();
|
|
|
|
|
|
|
|
VIR_DEBUG("parser=%p", parser);
|
|
|
|
|
|
|
|
if (!value)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (virJSONParserInsertValue(parser, value) < 0) {
|
|
|
|
virJSONValueFree(value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_REALLOC_N(parser->state,
|
2011-06-23 10:16:31 +00:00
|
|
|
parser->nstate + 1) < 0) {
|
|
|
|
virJSONValueFree(value);
|
2009-11-03 18:59:18 +00:00
|
|
|
return 0;
|
2011-06-23 10:16:31 +00:00
|
|
|
}
|
2009-11-03 18:59:18 +00:00
|
|
|
|
|
|
|
parser->state[parser->nstate].value = value;
|
|
|
|
parser->state[parser->nstate].key = NULL;
|
|
|
|
parser->nstate++;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-05-03 16:50:58 +00:00
|
|
|
static int virJSONParserHandleEndMap(void *ctx)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
virJSONParserPtr parser = ctx;
|
|
|
|
virJSONParserStatePtr state;
|
|
|
|
|
|
|
|
VIR_DEBUG("parser=%p", parser);
|
|
|
|
|
|
|
|
if (!parser->nstate)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
state = &(parser->state[parser->nstate-1]);
|
|
|
|
if (state->key) {
|
|
|
|
VIR_FREE(state->key);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_REALLOC_N(parser->state,
|
|
|
|
parser->nstate - 1) < 0)
|
|
|
|
return 0;
|
|
|
|
parser->nstate--;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-05-03 16:50:58 +00:00
|
|
|
static int virJSONParserHandleStartArray(void *ctx)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
virJSONParserPtr parser = ctx;
|
|
|
|
virJSONValuePtr value = virJSONValueNewArray();
|
|
|
|
|
|
|
|
VIR_DEBUG("parser=%p", parser);
|
|
|
|
|
|
|
|
if (!value)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (virJSONParserInsertValue(parser, value) < 0) {
|
|
|
|
virJSONValueFree(value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_REALLOC_N(parser->state,
|
|
|
|
parser->nstate + 1) < 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
parser->state[parser->nstate].value = value;
|
|
|
|
parser->state[parser->nstate].key = NULL;
|
|
|
|
parser->nstate++;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-05-03 16:50:58 +00:00
|
|
|
static int virJSONParserHandleEndArray(void *ctx)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
virJSONParserPtr parser = ctx;
|
|
|
|
virJSONParserStatePtr state;
|
|
|
|
|
|
|
|
VIR_DEBUG("parser=%p", parser);
|
|
|
|
|
|
|
|
if (!parser->nstate)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
state = &(parser->state[parser->nstate-1]);
|
|
|
|
if (state->key) {
|
|
|
|
VIR_FREE(state->key);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_REALLOC_N(parser->state,
|
|
|
|
parser->nstate - 1) < 0)
|
|
|
|
return 0;
|
|
|
|
parser->nstate--;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const yajl_callbacks parserCallbacks = {
|
|
|
|
virJSONParserHandleNull,
|
|
|
|
virJSONParserHandleBoolean,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
virJSONParserHandleNumber,
|
|
|
|
virJSONParserHandleString,
|
|
|
|
virJSONParserHandleStartMap,
|
|
|
|
virJSONParserHandleMapKey,
|
|
|
|
virJSONParserHandleEndMap,
|
|
|
|
virJSONParserHandleStartArray,
|
|
|
|
virJSONParserHandleEndArray
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/* XXX add an incremental streaming parser - yajl trivially supports it */
|
|
|
|
virJSONValuePtr virJSONValueFromString(const char *jsonstring)
|
|
|
|
{
|
|
|
|
yajl_handle hand;
|
|
|
|
virJSONParser parser = { NULL, NULL, 0 };
|
util: Fix return value for virJSONValueFromString if it fails
Problem:
"parser.head" is not NULL even if it's free'ed by "virJSONValueFree",
returning "parser.head" when "virJSONValueFromString" fails will cause
unexpected errors (libvirtd will crash sometimes), e.g.
In function "qemuMonitorJSONArbitraryCommand":
if (!(cmd = virJSONValueFromString(cmd_str)))
goto cleanup;
if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
goto cleanup;
......
cleanup:
virJSONValueFree(cmd);
It will continues to send command to monitor even if "virJSONValueFromString"
is failed, and more worse, it trys to free "cmd" again.
Crash example:
{"error":{"class":"QMPBadInputObject","desc":"Expected 'execute' in QMP input","data":{"expected":"execute"}}}
{"error":{"class":"QMPBadInputObject","desc":"Expected 'execute' in QMP input","data":{"expected":"execute"}}}
error: server closed connection:
error: unable to connect to '/var/run/libvirt/libvirt-sock', libvirtd may need to be started: Connection refused
error: failed to connect to the hypervisor
This fix is to:
1) return NULL for failure of "virJSONValueFromString",
2) and it seems "virJSONValueFree" uses incorrect loop index for type
of "VIR_JSON_TYPE_OBJECT", fix it together.
* src/util/json.c
2011-03-23 14:57:44 +00:00
|
|
|
virJSONValuePtr ret = NULL;
|
2012-09-20 11:57:13 +00:00
|
|
|
# ifndef WITH_YAJL2
|
2011-05-03 16:50:58 +00:00
|
|
|
yajl_parser_config cfg = { 1, 1 };
|
|
|
|
# endif
|
2009-11-03 18:59:18 +00:00
|
|
|
|
|
|
|
VIR_DEBUG("string=%s", jsonstring);
|
|
|
|
|
2012-09-20 11:57:13 +00:00
|
|
|
# ifdef WITH_YAJL2
|
2011-05-03 16:50:58 +00:00
|
|
|
hand = yajl_alloc(&parserCallbacks, NULL, &parser);
|
|
|
|
if (hand) {
|
|
|
|
yajl_config(hand, yajl_allow_comments, 1);
|
|
|
|
yajl_config(hand, yajl_dont_validate_strings, 0);
|
|
|
|
}
|
|
|
|
# else
|
2009-11-03 18:59:18 +00:00
|
|
|
hand = yajl_alloc(&parserCallbacks, &cfg, NULL, &parser);
|
2011-05-03 16:50:58 +00:00
|
|
|
# endif
|
|
|
|
if (!hand) {
|
2012-07-18 10:26:24 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Unable to create JSON parser"));
|
2011-05-03 16:50:58 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2009-11-03 18:59:18 +00:00
|
|
|
|
|
|
|
if (yajl_parse(hand,
|
|
|
|
(const unsigned char *)jsonstring,
|
|
|
|
strlen(jsonstring)) != yajl_status_ok) {
|
|
|
|
unsigned char *errstr = yajl_get_error(hand, 1,
|
|
|
|
(const unsigned char*)jsonstring,
|
|
|
|
strlen(jsonstring));
|
|
|
|
|
2012-07-18 10:26:24 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse json %s: %s"),
|
|
|
|
jsonstring, (const char*) errstr);
|
2009-11-03 18:59:18 +00:00
|
|
|
VIR_FREE(errstr);
|
|
|
|
virJSONValueFree(parser.head);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
util: Fix return value for virJSONValueFromString if it fails
Problem:
"parser.head" is not NULL even if it's free'ed by "virJSONValueFree",
returning "parser.head" when "virJSONValueFromString" fails will cause
unexpected errors (libvirtd will crash sometimes), e.g.
In function "qemuMonitorJSONArbitraryCommand":
if (!(cmd = virJSONValueFromString(cmd_str)))
goto cleanup;
if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
goto cleanup;
......
cleanup:
virJSONValueFree(cmd);
It will continues to send command to monitor even if "virJSONValueFromString"
is failed, and more worse, it trys to free "cmd" again.
Crash example:
{"error":{"class":"QMPBadInputObject","desc":"Expected 'execute' in QMP input","data":{"expected":"execute"}}}
{"error":{"class":"QMPBadInputObject","desc":"Expected 'execute' in QMP input","data":{"expected":"execute"}}}
error: server closed connection:
error: unable to connect to '/var/run/libvirt/libvirt-sock', libvirtd may need to be started: Connection refused
error: failed to connect to the hypervisor
This fix is to:
1) return NULL for failure of "virJSONValueFromString",
2) and it seems "virJSONValueFree" uses incorrect loop index for type
of "VIR_JSON_TYPE_OBJECT", fix it together.
* src/util/json.c
2011-03-23 14:57:44 +00:00
|
|
|
ret = parser.head;
|
|
|
|
|
2009-11-03 18:59:18 +00:00
|
|
|
cleanup:
|
|
|
|
yajl_free(hand);
|
|
|
|
|
|
|
|
if (parser.nstate) {
|
|
|
|
int i;
|
2013-05-21 07:58:16 +00:00
|
|
|
for (i = 0; i < parser.nstate; i++) {
|
2009-11-03 18:59:18 +00:00
|
|
|
VIR_FREE(parser.state[i].key);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_DEBUG("result=%p", parser.head);
|
|
|
|
|
util: Fix return value for virJSONValueFromString if it fails
Problem:
"parser.head" is not NULL even if it's free'ed by "virJSONValueFree",
returning "parser.head" when "virJSONValueFromString" fails will cause
unexpected errors (libvirtd will crash sometimes), e.g.
In function "qemuMonitorJSONArbitraryCommand":
if (!(cmd = virJSONValueFromString(cmd_str)))
goto cleanup;
if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
goto cleanup;
......
cleanup:
virJSONValueFree(cmd);
It will continues to send command to monitor even if "virJSONValueFromString"
is failed, and more worse, it trys to free "cmd" again.
Crash example:
{"error":{"class":"QMPBadInputObject","desc":"Expected 'execute' in QMP input","data":{"expected":"execute"}}}
{"error":{"class":"QMPBadInputObject","desc":"Expected 'execute' in QMP input","data":{"expected":"execute"}}}
error: server closed connection:
error: unable to connect to '/var/run/libvirt/libvirt-sock', libvirtd may need to be started: Connection refused
error: failed to connect to the hypervisor
This fix is to:
1) return NULL for failure of "virJSONValueFromString",
2) and it seems "virJSONValueFree" uses incorrect loop index for type
of "VIR_JSON_TYPE_OBJECT", fix it together.
* src/util/json.c
2011-03-23 14:57:44 +00:00
|
|
|
return ret;
|
2009-11-03 18:59:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int virJSONValueToStringOne(virJSONValuePtr object,
|
|
|
|
yajl_gen g)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
VIR_DEBUG("object=%p type=%d gen=%p", object, object->type, g);
|
|
|
|
|
|
|
|
switch (object->type) {
|
|
|
|
case VIR_JSON_TYPE_OBJECT:
|
|
|
|
if (yajl_gen_map_open(g) != yajl_gen_status_ok)
|
|
|
|
return -1;
|
2013-05-21 07:58:16 +00:00
|
|
|
for (i = 0; i < object->data.object.npairs; i++) {
|
2009-11-03 18:59:18 +00:00
|
|
|
if (yajl_gen_string(g,
|
|
|
|
(unsigned char *)object->data.object.pairs[i].key,
|
|
|
|
strlen(object->data.object.pairs[i].key))
|
|
|
|
!= yajl_gen_status_ok)
|
|
|
|
return -1;
|
|
|
|
if (virJSONValueToStringOne(object->data.object.pairs[i].value, g) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (yajl_gen_map_close(g) != yajl_gen_status_ok)
|
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
case VIR_JSON_TYPE_ARRAY:
|
|
|
|
if (yajl_gen_array_open(g) != yajl_gen_status_ok)
|
|
|
|
return -1;
|
2013-05-21 07:58:16 +00:00
|
|
|
for (i = 0; i < object->data.array.nvalues; i++) {
|
2009-11-03 18:59:18 +00:00
|
|
|
if (virJSONValueToStringOne(object->data.array.values[i], g) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (yajl_gen_array_close(g) != yajl_gen_status_ok)
|
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_JSON_TYPE_STRING:
|
|
|
|
if (yajl_gen_string(g, (unsigned char *)object->data.string,
|
|
|
|
strlen(object->data.string)) != yajl_gen_status_ok)
|
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_JSON_TYPE_NUMBER:
|
|
|
|
if (yajl_gen_number(g, object->data.number,
|
|
|
|
strlen(object->data.number)) != yajl_gen_status_ok)
|
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_JSON_TYPE_BOOLEAN:
|
|
|
|
if (yajl_gen_bool(g, object->data.boolean) != yajl_gen_status_ok)
|
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_JSON_TYPE_NULL:
|
|
|
|
if (yajl_gen_null(g) != yajl_gen_status_ok)
|
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-09 10:46:29 +00:00
|
|
|
char *virJSONValueToString(virJSONValuePtr object,
|
|
|
|
bool pretty)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
yajl_gen g;
|
|
|
|
const unsigned char *str;
|
|
|
|
char *ret = NULL;
|
2011-05-03 16:50:58 +00:00
|
|
|
yajl_size_t len;
|
2012-09-20 11:57:13 +00:00
|
|
|
# ifndef WITH_YAJL2
|
2012-08-09 10:46:29 +00:00
|
|
|
yajl_gen_config conf = { pretty ? 1 : 0, pretty ? " " : " "};
|
2011-05-03 16:50:58 +00:00
|
|
|
# endif
|
2009-11-03 18:59:18 +00:00
|
|
|
|
|
|
|
VIR_DEBUG("object=%p", object);
|
|
|
|
|
2012-09-20 11:57:13 +00:00
|
|
|
# ifdef WITH_YAJL2
|
2011-05-03 16:50:58 +00:00
|
|
|
g = yajl_gen_alloc(NULL);
|
|
|
|
if (g) {
|
2012-08-09 10:46:29 +00:00
|
|
|
yajl_gen_config(g, yajl_gen_beautify, pretty ? 1 : 0);
|
|
|
|
yajl_gen_config(g, yajl_gen_indent_string, pretty ? " " : " ");
|
2011-05-03 16:50:58 +00:00
|
|
|
yajl_gen_config(g, yajl_gen_validate_utf8, 1);
|
|
|
|
}
|
|
|
|
# else
|
2009-11-03 18:59:18 +00:00
|
|
|
g = yajl_gen_alloc(&conf, NULL);
|
2011-05-03 16:50:58 +00:00
|
|
|
# endif
|
|
|
|
if (!g) {
|
2012-07-18 10:26:24 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Unable to create JSON formatter"));
|
2011-05-03 16:50:58 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2009-11-03 18:59:18 +00:00
|
|
|
|
|
|
|
if (virJSONValueToStringOne(object, g) < 0) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-11-03 18:59:18 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (yajl_gen_get_buf(g, &str, &len) != yajl_gen_status_ok) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-11-03 18:59:18 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-05-24 07:19:51 +00:00
|
|
|
ignore_value(VIR_STRDUP(ret, (const char *)str));
|
2009-11-03 18:59:18 +00:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
yajl_gen_free(g);
|
|
|
|
|
|
|
|
VIR_DEBUG("result=%s", NULLSTR(ret));
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
virJSONValuePtr virJSONValueFromString(const char *jsonstring ATTRIBUTE_UNUSED)
|
|
|
|
{
|
2012-07-18 10:26:24 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("No JSON parser implementation is available"));
|
2009-11-03 18:59:18 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2012-08-15 14:51:46 +00:00
|
|
|
char *virJSONValueToString(virJSONValuePtr object ATTRIBUTE_UNUSED,
|
|
|
|
bool pretty ATTRIBUTE_UNUSED)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
2012-07-18 10:26:24 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("No JSON parser implementation is available"));
|
2009-11-03 18:59:18 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#endif
|