X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/7bc8401712d70dc12f230fb69cdb38511fd021b1..5b4448d27d7c6ff6e18a1edc8245cb1db783e37c:/qerror.c diff --git a/qerror.c b/qerror.c index 9fb817e7cb..3d95383940 100644 --- a/qerror.c +++ b/qerror.c @@ -1,5 +1,5 @@ /* - * QError: QEMU Error data-type. + * QError Module * * Copyright (C) 2009 Red Hat Inc. * @@ -40,22 +40,33 @@ static const QType qerror_type = { * "running out of foo: %(foo)%%" * * Please keep the entries in alphabetical order. - * Use "sed -n '/^static.*qerror_table\[\]/,/^};/s/QERR_/&/gp' qerror.c | sort -c" - * to check. + * Use scripts/check-qerror.sh to check. */ static const QErrorStringTable qerror_table[] = { + { + .error_fmt = QERR_ADD_CLIENT_FAILED, + .desc = "Could not add client", + }, { .error_fmt = QERR_BAD_BUS_FOR_DEVICE, .desc = "Device '%(device)' can't go on a %(bad_bus_type) bus", }, { - .error_fmt = QERR_BUS_NOT_FOUND, - .desc = "Bus '%(bus)' not found", + .error_fmt = QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED, + .desc = "Block format '%(format)' used by device '%(name)' does not support feature '%(feature)'", }, { .error_fmt = QERR_BUS_NO_HOTPLUG, .desc = "Bus '%(bus)' does not support hotplugging", }, + { + .error_fmt = QERR_BUS_NOT_FOUND, + .desc = "Bus '%(bus)' not found", + }, + { + .error_fmt = QERR_COMMAND_DISABLED, + .desc = "The command %(name) has been disabled for this instance", + }, { .error_fmt = QERR_COMMAND_NOT_FOUND, .desc = "The command %(name) has not been found", @@ -64,10 +75,26 @@ static const QErrorStringTable qerror_table[] = { .error_fmt = QERR_DEVICE_ENCRYPTED, .desc = "Device '%(device)' is encrypted", }, + { + .error_fmt = QERR_DEVICE_FEATURE_BLOCKS_MIGRATION, + .desc = "Migration is disabled when using feature '%(feature)' in device '%(device)'", + }, + { + .error_fmt = QERR_DEVICE_HAS_NO_MEDIUM, + .desc = "Device '%(device)' has no medium", + }, { .error_fmt = QERR_DEVICE_INIT_FAILED, .desc = "Device '%(device)' could not be initialized", }, + { + .error_fmt = QERR_DEVICE_IN_USE, + .desc = "Device '%(device)' is in use", + }, + { + .error_fmt = QERR_DEVICE_IS_READ_ONLY, + .desc = "Device '%(device)' is read only", + }, { .error_fmt = QERR_DEVICE_LOCKED, .desc = "Device '%(device)' is locked", @@ -76,9 +103,17 @@ static const QErrorStringTable qerror_table[] = { .error_fmt = QERR_DEVICE_MULTIPLE_BUSSES, .desc = "Device '%(device)' has multiple child busses", }, + { + .error_fmt = QERR_DEVICE_NO_BUS, + .desc = "Device '%(device)' has no child bus", + }, + { + .error_fmt = QERR_DEVICE_NO_HOTPLUG, + .desc = "Device '%(device)' does not support hotplugging", + }, { .error_fmt = QERR_DEVICE_NOT_ACTIVE, - .desc = "Device '%(device)' has not been activated by the guest", + .desc = "Device '%(device)' has not been activated", }, { .error_fmt = QERR_DEVICE_NOT_ENCRYPTED, @@ -92,10 +127,6 @@ static const QErrorStringTable qerror_table[] = { .error_fmt = QERR_DEVICE_NOT_REMOVABLE, .desc = "Device '%(device)' is not removable", }, - { - .error_fmt = QERR_DEVICE_NO_BUS, - .desc = "Device '%(device)' has no child bus", - }, { .error_fmt = QERR_DUPLICATE_ID, .desc = "Duplicate ID '%(id)' for %(object)", @@ -108,6 +139,10 @@ static const QErrorStringTable qerror_table[] = { .error_fmt = QERR_FD_NOT_SUPPLIED, .desc = "No file descriptor supplied via SCM_RIGHTS", }, + { + .error_fmt = QERR_FEATURE_DISABLED, + .desc = "The feature '%(name)' is not enabled", + }, { .error_fmt = QERR_INVALID_BLOCK_FORMAT, .desc = "Invalid block format '%(name)'", @@ -116,14 +151,31 @@ static const QErrorStringTable qerror_table[] = { .error_fmt = QERR_INVALID_PARAMETER, .desc = "Invalid parameter '%(name)'", }, + { + .error_fmt = QERR_INVALID_PARAMETER_COMBINATION, + .desc = "Invalid parameter combination", + }, { .error_fmt = QERR_INVALID_PARAMETER_TYPE, .desc = "Invalid parameter type, expected: %(expected)", }, + { + .error_fmt = QERR_INVALID_PARAMETER_VALUE, + .desc = "Parameter '%(name)' expects %(expected)", + }, { .error_fmt = QERR_INVALID_PASSWORD, .desc = "Password incorrect", }, + { + .error_fmt = QERR_IO_ERROR, + .desc = "An IO error has occurred", + }, + { + .error_fmt = QERR_JSON_PARSE_ERROR, + .desc = "JSON parse error, %(message)", + + }, { .error_fmt = QERR_JSON_PARSING, .desc = "Invalid JSON syntax", @@ -132,6 +184,10 @@ static const QErrorStringTable qerror_table[] = { .error_fmt = QERR_KVM_MISSING_CAP, .desc = "Using KVM without %(capability), %(feature) unavailable", }, + { + .error_fmt = QERR_MIGRATION_EXPECTED, + .desc = "An incoming migration is expected before this command can be executed", + }, { .error_fmt = QERR_MISSING_PARAMETER, .desc = "Parameter '%(name)' is missing", @@ -144,6 +200,10 @@ static const QErrorStringTable qerror_table[] = { .error_fmt = QERR_OPEN_FILE_FAILED, .desc = "Could not open '%(filename)'", }, + { + .error_fmt = QERR_PERMISSION_DENIED, + .desc = "Insufficient permission to perform this operation", + }, { .error_fmt = QERR_PROPERTY_NOT_FOUND, .desc = "Property '%(device).%(property)' not found", @@ -160,9 +220,34 @@ static const QErrorStringTable qerror_table[] = { .error_fmt = QERR_PROPERTY_VALUE_NOT_FOUND, .desc = "Property '%(device).%(property)' can't find value '%(value)'", }, + { + .error_fmt = QERR_PROPERTY_VALUE_OUT_OF_RANGE, + .desc = "Property '%(device).%(property)' doesn't take " + "value %(value) (minimum: %(min), maximum: %(max)'", + }, + { + .error_fmt = QERR_QGA_COMMAND_FAILED, + .desc = "Guest agent command failed, error was '%(message)'", + }, + { + .error_fmt = QERR_QGA_LOGGING_FAILED, + .desc = "Guest agent failed to log non-optional log statement", + }, { .error_fmt = QERR_QMP_BAD_INPUT_OBJECT, - .desc = "Bad QMP input object", + .desc = "Expected '%(expected)' in QMP input", + }, + { + .error_fmt = QERR_QMP_BAD_INPUT_OBJECT_MEMBER, + .desc = "QMP input object member '%(member)' expects '%(expected)'", + }, + { + .error_fmt = QERR_QMP_EXTRA_MEMBER, + .desc = "QMP input object member '%(member)' is unexpected", + }, + { + .error_fmt = QERR_RESET_REQUIRED, + .desc = "Resetting the Virtual Machine is required", }, { .error_fmt = QERR_SET_PASSWD_FAILED, @@ -174,7 +259,21 @@ static const QErrorStringTable qerror_table[] = { }, { .error_fmt = QERR_UNDEFINED_ERROR, - .desc = "An undefined error has ocurred", + .desc = "An undefined error has occurred", + }, + { + .error_fmt = QERR_UNKNOWN_BLOCK_FORMAT_FEATURE, + .desc = "'%(device)' uses a %(format) feature which is not " + "supported by this qemu version: %(feature)", + }, + { + .error_fmt = QERR_UNSUPPORTED, + .desc = "this feature or command is not currently supported", + }, + { + .error_fmt = QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION, + .desc = "Migration is disabled when VirtFS export path '%(path)' " + "is mounted in the guest using mount_tag '%(tag)'", }, { .error_fmt = QERR_VNC_SERVER_FAILED, @@ -192,13 +291,14 @@ QError *qerror_new(void) { QError *qerr; - qerr = qemu_mallocz(sizeof(*qerr)); + qerr = g_malloc0(sizeof(*qerr)); QOBJECT_INIT(qerr, &qerror_type); return qerr; } -static void qerror_abort(const QError *qerr, const char *fmt, ...) +static void GCC_FMT_ATTR(2, 3) qerror_abort(const QError *qerr, + const char *fmt, ...) { va_list ap; @@ -213,7 +313,8 @@ static void qerror_abort(const QError *qerr, const char *fmt, ...) abort(); } -static void qerror_set_data(QError *qerr, const char *fmt, va_list *va) +static void GCC_FMT_ATTR(2, 0) qerror_set_data(QError *qerr, + const char *fmt, va_list *va) { QObject *obj; @@ -295,12 +396,14 @@ QError *qerror_from_info(const char *file, int linenr, const char *func, return qerr; } -static void parse_error(const QError *qerror, int c) +static void parse_error(const QErrorStringTable *entry, int c) { - qerror_abort(qerror, "expected '%c' in '%s'", c, qerror->entry->desc); + fprintf(stderr, "expected '%c' in '%s'", c, entry->desc); + abort(); } -static const char *append_field(QString *outstr, const QError *qerror, +static const char *append_field(QDict *error, QString *outstr, + const QErrorStringTable *entry, const char *start) { QObject *obj; @@ -309,23 +412,23 @@ static const char *append_field(QString *outstr, const QError *qerror, const char *end, *key; if (*start != '%') - parse_error(qerror, '%'); + parse_error(entry, '%'); start++; if (*start != '(') - parse_error(qerror, '('); + parse_error(entry, '('); start++; end = strchr(start, ')'); if (!end) - parse_error(qerror, ')'); + parse_error(entry, ')'); key_qs = qstring_from_substr(start, 0, end - start - 1); key = qstring_get_str(key_qs); - qdict = qobject_to_qdict(qdict_get(qerror->error, "data")); + qdict = qobject_to_qdict(qdict_get(error, "data")); obj = qdict_get(qdict, key); if (!obj) { - qerror_abort(qerror, "key '%s' not found in QDict", key); + abort(); } switch (qobject_type(obj)) { @@ -336,41 +439,60 @@ static const char *append_field(QString *outstr, const QError *qerror, qstring_append_int(outstr, qdict_get_int(qdict, key)); break; default: - qerror_abort(qerror, "invalid type '%c'", qobject_type(obj)); + abort(); } QDECREF(key_qs); return ++end; } -/** - * qerror_human(): Format QError data into human-readable string. - * - * Formats according to member 'desc' of the specified QError object. - */ -QString *qerror_human(const QError *qerror) +static QString *qerror_format_desc(QDict *error, + const QErrorStringTable *entry) { - const char *p; QString *qstring; + const char *p; - assert(qerror->entry != NULL); + assert(entry != NULL); qstring = qstring_new(); - for (p = qerror->entry->desc; *p != '\0';) { + for (p = entry->desc; *p != '\0';) { if (*p != '%') { qstring_append_chr(qstring, *p++); } else if (*(p + 1) == '%') { qstring_append_chr(qstring, '%'); p += 2; } else { - p = append_field(qstring, qerror, p); + p = append_field(error, qstring, entry, p); } } return qstring; } +QString *qerror_format(const char *fmt, QDict *error) +{ + const QErrorStringTable *entry = NULL; + int i; + + for (i = 0; qerror_table[i].error_fmt; i++) { + if (strcmp(qerror_table[i].error_fmt, fmt) == 0) { + entry = &qerror_table[i]; + break; + } + } + + return qerror_format_desc(error, entry); +} + +/** + * qerror_human(): Format QError data into human-readable string. + */ +QString *qerror_human(const QError *qerror) +{ + return qerror_format_desc(qerror->error, qerror->entry); +} + /** * qerror_print(): Print QError data * @@ -405,6 +527,39 @@ void qerror_report_internal(const char *file, int linenr, const char *func, } } +/* Evil... */ +struct Error +{ + QDict *obj; + const char *fmt; + char *msg; +}; + +void qerror_report_err(Error *err) +{ + QError *qerr; + int i; + + qerr = qerror_new(); + loc_save(&qerr->loc); + QINCREF(err->obj); + qerr->error = err->obj; + + for (i = 0; qerror_table[i].error_fmt; i++) { + if (strcmp(qerror_table[i].error_fmt, err->fmt) == 0) { + qerr->entry = &qerror_table[i]; + break; + } + } + + if (monitor_cur_is_qmp()) { + monitor_set_error(cur_mon, qerr); + } else { + qerror_print(qerr); + QDECREF(qerr); + } +} + /** * qobject_to_qerror(): Convert a QObject into a QError */ @@ -428,5 +583,5 @@ static void qerror_destroy_obj(QObject *obj) qerr = qobject_to_qerror(obj); QDECREF(qerr->error); - qemu_free(qerr); + g_free(qerr); }