Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/armbru/tags/pull-block-2017-02-…
Browse files Browse the repository at this point in the history
…28-v4' into staging

block: Command line option -blockdev

# gpg: Signature made Tue 07 Mar 2017 15:07:59 GMT
# gpg:                using RSA key 0x3870B400EB918653
# gpg: Good signature from "Markus Armbruster <[email protected]>"
# gpg:                 aka "Markus Armbruster <[email protected]>"
# Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867  4E5F 3870 B400 EB91 8653

* remotes/armbru/tags/pull-block-2017-02-28-v4: (24 commits)
  keyval: Support lists
  docs/qapi-code-gen.txt: Clarify naming rules
  qapi: Improve how keyval input visitor reports unexpected dicts
  block: Initial implementation of -blockdev
  qapi: New qobject_input_visitor_new_str() for convenience
  keyval: Restrict key components to valid QAPI names
  qapi: New parse_qapi_name()
  test-qapi-util: New, covering qapi/qapi-util.c
  monitor: Assert qmp_schema_json[] is sane
  test-visitor-serialization: Pass &error_abort to qobject_from_json()
  check-qjson: Test errors from qobject_from_json()
  block: More detailed syntax error reporting for JSON filenames
  qobject: Propagate parse errors through qobject_from_json()
  test-qobject-input-visitor: Abort earlier on bad test input
  qjson: Abort earlier on qobject_from_jsonf() misuse
  libqtest: Fix qmp() & friends to abort on JSON parse errors
  qobject: Propagate parse errors through qobject_from_jsonv()
  qapi: Factor out common qobject_input_get_keyval()
  qapi: Factor out common part of qobject input visitor creation
  test-keyval: Cover use with qobject input visitor
  ...

Signed-off-by: Peter Maydell <[email protected]>
  • Loading branch information
pm215 committed Mar 7, 2017
2 parents 43c227f + 0b2c1be commit 8746709
Show file tree
Hide file tree
Showing 23 changed files with 1,746 additions and 82 deletions.
9 changes: 7 additions & 2 deletions block.c
Original file line number Diff line number Diff line change
Expand Up @@ -1262,9 +1262,14 @@ static QDict *parse_json_filename(const char *filename, Error **errp)
ret = strstart(filename, "json:", &filename);
assert(ret);

options_obj = qobject_from_json(filename);
options_obj = qobject_from_json(filename, errp);
if (!options_obj) {
error_setg(errp, "Could not parse the JSON options");
/* Work around qobject_from_json() lossage TODO fix that */
if (errp && !*errp) {
error_setg(errp, "Could not parse the JSON options");
return NULL;
}
error_prepend(errp, "Could not parse the JSON options: ");
return NULL;
}

Expand Down
61 changes: 39 additions & 22 deletions docs/qapi-code-gen.txt
Original file line number Diff line number Diff line change
Expand Up @@ -216,33 +216,38 @@ single-dimension array of that type; multi-dimension arrays are not
directly supported (although an array of a complex struct that
contains an array member is possible).

All names must begin with a letter, and contain only ASCII letters,
digits, hyphen, and underscore. There are two exceptions: enum values
may start with a digit, and names that are downstream extensions (see
section Downstream extensions) start with underscore.

Names beginning with 'q_' are reserved for the generator, which uses
them for munging QMP names that resemble C keywords or other
problematic strings. For example, a member named "default" in qapi
becomes "q_default" in the generated C code.

Types, commands, and events share a common namespace. Therefore,
generally speaking, type definitions should always use CamelCase for
user-defined type names, while built-in types are lowercase. Type
definitions should not end in 'Kind', as this namespace is used for
creating implicit C enums for visiting union types, or in 'List', as
this namespace is used for creating array types. Command names,
and member names within a type, should be all lower case with words
separated by a hyphen. However, some existing older commands and
complex types use underscore; when extending such expressions,
consistency is preferred over blindly avoiding underscore. Event
names should be ALL_CAPS with words separated by underscore. Member
names cannot start with 'has-' or 'has_', as this is reserved for
tracking optional members.
user-defined type names, while built-in types are lowercase.

Type names ending with 'Kind' or 'List' are reserved for the
generator, which uses them for implicit union enums and array types,
respectively.

Command names, and member names within a type, should be all lower
case with words separated by a hyphen. However, some existing older
commands and complex types use underscore; when extending such
expressions, consistency is preferred over blindly avoiding
underscore.

Event names should be ALL_CAPS with words separated by underscore.

Member names starting with 'has-' or 'has_' are reserved for the
generator, which uses them for tracking optional members.

Any name (command, event, type, member, or enum value) beginning with
"x-" is marked experimental, and may be withdrawn or changed
incompatibly in a future release. All names must begin with a letter,
and contain only ASCII letters, digits, dash, and underscore. There
are two exceptions: enum values may start with a digit, and any
extensions added by downstream vendors should start with a prefix
matching "__RFQDN_" (for the reverse-fully-qualified-domain-name of
the vendor), even if the rest of the name uses dash (example:
__com.redhat_drive-mirror). Names beginning with 'q_' are reserved
for the generator: QMP names that resemble C keywords or other
problematic strings will be munged in C to use this prefix. For
example, a member named "default" in qapi becomes "q_default" in the
generated C code.
incompatibly in a future release.

In the rest of this document, usage lines are given for each
expression type, with literal strings written in lower case and
Expand Down Expand Up @@ -643,6 +648,18 @@ any non-empty complex type (struct, union, or alternate), and a
pointer to that QAPI type is passed as a single argument.


=== Downstream extensions ===

QAPI schema names that are externally visible, say in the Client JSON
Protocol, need to be managed with care. Names starting with a
downstream prefix of the form __RFQDN_ are reserved for the downstream
who controls the valid, reverse fully qualified domain name RFQDN.
RFQDN may only contain ASCII letters, digits, hyphen and period.

Example: Red Hat, Inc. controls redhat.com, and may therefore add a
downstream command __com.redhat_drive-mirror.


== Client JSON Protocol introspection ==

Clients of a Client JSON Protocol commonly need to figure out what
Expand Down
5 changes: 3 additions & 2 deletions include/qapi/qmp/qjson.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@
#include "qapi/qmp/qobject.h"
#include "qapi/qmp/qstring.h"

QObject *qobject_from_json(const char *string);
QObject *qobject_from_json(const char *string, Error **errp);
QObject *qobject_from_jsonf(const char *string, ...) GCC_FMT_ATTR(1, 2);
QObject *qobject_from_jsonv(const char *string, va_list *ap) GCC_FMT_ATTR(1, 0);
QObject *qobject_from_jsonv(const char *string, va_list *ap, Error **errp)
GCC_FMT_ATTR(1, 0);

QString *qobject_to_json(const QObject *obj);
QString *qobject_to_json_pretty(const QObject *obj);
Expand Down
21 changes: 21 additions & 0 deletions include/qapi/qobject-input-visitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,25 @@ typedef struct QObjectInputVisitor QObjectInputVisitor;
*/
Visitor *qobject_input_visitor_new(QObject *obj);

/*
* Create a QObject input visitor for @obj for use with keyval_parse()
*
* This is like qobject_input_visitor_new(), except scalars are all
* QString, and error messages refer to parts of @obj in the syntax
* keyval_parse() uses for KEYs.
*/
Visitor *qobject_input_visitor_new_keyval(QObject *obj);

/*
* Create a QObject input visitor for parsing @str.
*
* If @str looks like JSON, parse it as JSON, else as KEY=VALUE,...
* @implied_key applies to KEY=VALUE, and works as in keyval_parse().
* On failure, store an error through @errp and return NULL.
* On success, return a new QObject input visitor for the parse.
*/
Visitor *qobject_input_visitor_new_str(const char *str,
const char *implied_key,
Error **errp);

#endif
2 changes: 2 additions & 0 deletions include/qapi/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@
int qapi_enum_parse(const char * const lookup[], const char *buf,
int max, int def, Error **errp);

int parse_qapi_name(const char *name, bool complete);

#endif
3 changes: 3 additions & 0 deletions include/qemu/option.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,4 +141,7 @@ void qemu_opts_print_help(QemuOptsList *list);
void qemu_opts_free(QemuOptsList *list);
QemuOptsList *qemu_opts_append(QemuOptsList *dst, QemuOptsList *list);

QDict *keyval_parse(const char *params, const char *implied_key,
Error **errp);

#endif
2 changes: 1 addition & 1 deletion monitor.c
Original file line number Diff line number Diff line change
Expand Up @@ -953,7 +953,7 @@ EventInfoList *qmp_query_events(Error **errp)
static void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data,
Error **errp)
{
*ret_data = qobject_from_json(qmp_schema_json);
*ret_data = qobject_from_json(qmp_schema_json, &error_abort);
}

/*
Expand Down
47 changes: 47 additions & 0 deletions qapi/qapi-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,50 @@ int qapi_enum_parse(const char * const lookup[], const char *buf,
error_setg(errp, "invalid parameter value: %s", buf);
return def;
}

/*
* Parse a valid QAPI name from @str.
* A valid name consists of letters, digits, hyphen and underscore.
* It may be prefixed by __RFQDN_ (downstream extension), where RFQDN
* may contain only letters, digits, hyphen and period.
* The special exception for enumeration names is not implemented.
* See docs/qapi-code-gen.txt for more on QAPI naming rules.
* Keep this consistent with scripts/qapi.py!
* If @complete, the parse fails unless it consumes @str completely.
* Return its length on success, -1 on failure.
*/
int parse_qapi_name(const char *str, bool complete)
{
const char *p = str;

if (*p == '_') { /* Downstream __RFQDN_ */
p++;
if (*p != '_') {
return -1;
}
while (*++p) {
if (!qemu_isalnum(*p) && *p != '-' && *p != '.') {
break;
}
}

if (*p != '_') {
return -1;
}
p++;
}

if (!qemu_isalpha(*p)) {
return -1;
}
while (*++p) {
if (!qemu_isalnum(*p) && *p != '-' && *p != '_') {
break;
}
}

if (complete && *p) {
return -1;
}
return p - str;
}
Loading

0 comments on commit 8746709

Please sign in to comment.