Annotation of qemu/qerror.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * QError: QEMU Error data-type.
        !             3:  *
        !             4:  * Copyright (C) 2009 Red Hat Inc.
        !             5:  *
        !             6:  * Authors:
        !             7:  *  Luiz Capitulino <lcapitulino@redhat.com>
        !             8:  *
        !             9:  * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
        !            10:  * See the COPYING.LIB file in the top-level directory.
        !            11:  */
        !            12: #include "qjson.h"
        !            13: #include "qerror.h"
        !            14: #include "qstring.h"
        !            15: #include "sysemu.h"
        !            16: #include "qemu-common.h"
        !            17: 
        !            18: static void qerror_destroy_obj(QObject *obj);
        !            19: 
        !            20: static const QType qerror_type = {
        !            21:     .code = QTYPE_QERROR,
        !            22:     .destroy = qerror_destroy_obj,
        !            23: };
        !            24: 
        !            25: /**
        !            26:  * The 'desc' parameter is a printf-like string, the format of the format
        !            27:  * string is:
        !            28:  *
        !            29:  * %(KEY)
        !            30:  *
        !            31:  * Where KEY is a QDict key, which has to be passed to qerror_from_info().
        !            32:  *
        !            33:  * Example:
        !            34:  *
        !            35:  * "foo error on device: %(device) slot: %(slot_nr)"
        !            36:  *
        !            37:  * A single percent sign can be printed if followed by a second one,
        !            38:  * for example:
        !            39:  *
        !            40:  * "running out of foo: %(foo)%%"
        !            41:  */
        !            42: static const QErrorStringTable qerror_table[] = {
        !            43:     {
        !            44:         .error_fmt = QERR_COMMAND_NOT_FOUND,
        !            45:         .desc      = "The command %(name) has not been found",
        !            46:     },
        !            47:     {
        !            48:         .error_fmt = QERR_DEVICE_ENCRYPTED,
        !            49:         .desc      = "The %(device) is encrypted",
        !            50:     },
        !            51:     {
        !            52:         .error_fmt = QERR_DEVICE_LOCKED,
        !            53:         .desc      = "Device %(device) is locked",
        !            54:     },
        !            55:     {
        !            56:         .error_fmt = QERR_DEVICE_NOT_ACTIVE,
        !            57:         .desc      = "The %(device) device has not been activated by the guest",
        !            58:     },
        !            59:     {
        !            60:         .error_fmt = QERR_DEVICE_NOT_FOUND,
        !            61:         .desc      = "The %(device) device has not been found",
        !            62:     },
        !            63:     {
        !            64:         .error_fmt = QERR_DEVICE_NOT_REMOVABLE,
        !            65:         .desc      = "Device %(device) is not removable",
        !            66:     },
        !            67:     {
        !            68:         .error_fmt = QERR_FD_NOT_FOUND,
        !            69:         .desc      = "Failed to find file descriptor named %(name)",
        !            70:     },
        !            71:     {
        !            72:         .error_fmt = QERR_FD_NOT_SUPPLIED,
        !            73:         .desc      = "No file descriptor supplied via SCM_RIGHTS",
        !            74:     },
        !            75:     {
        !            76:         .error_fmt = QERR_INVALID_BLOCK_FORMAT,
        !            77:         .desc      = "Invalid block format %(name)",
        !            78:     },
        !            79:     {
        !            80:         .error_fmt = QERR_INVALID_PARAMETER,
        !            81:         .desc      = "Invalid parameter %(name)",
        !            82:     },
        !            83:     {
        !            84:         .error_fmt = QERR_INVALID_PARAMETER_TYPE,
        !            85:         .desc      = "Invalid parameter type, expected: %(expected)",
        !            86:     },
        !            87:     {
        !            88:         .error_fmt = QERR_INVALID_PASSWORD,
        !            89:         .desc      = "The entered password is invalid",
        !            90:     },
        !            91:     {
        !            92:         .error_fmt = QERR_JSON_PARSING,
        !            93:         .desc      = "Invalid JSON syntax",
        !            94:     },
        !            95:     {
        !            96:         .error_fmt = QERR_KVM_MISSING_CAP,
        !            97:         .desc      = "Using KVM without %(capability), %(feature) unavailable",
        !            98:     },
        !            99:     {
        !           100:         .error_fmt = QERR_MISSING_PARAMETER,
        !           101:         .desc      = "Parameter %(name) is missing",
        !           102:     },
        !           103:     {
        !           104:         .error_fmt = QERR_QMP_BAD_INPUT_OBJECT,
        !           105:         .desc      = "Bad QMP input object",
        !           106:     },
        !           107:     {
        !           108:         .error_fmt = QERR_SET_PASSWD_FAILED,
        !           109:         .desc      = "Could not set password",
        !           110:     },
        !           111:     {
        !           112:         .error_fmt = QERR_TOO_MANY_FILES,
        !           113:         .desc      = "Too many open files",
        !           114:     },
        !           115:     {
        !           116:         .error_fmt = QERR_UNDEFINED_ERROR,
        !           117:         .desc      = "An undefined error has ocurred",
        !           118:     },
        !           119:     {
        !           120:         .error_fmt = QERR_VNC_SERVER_FAILED,
        !           121:         .desc      = "Could not start VNC server on %(target)",
        !           122:     },
        !           123:     {}
        !           124: };
        !           125: 
        !           126: /**
        !           127:  * qerror_new(): Create a new QError
        !           128:  *
        !           129:  * Return strong reference.
        !           130:  */
        !           131: QError *qerror_new(void)
        !           132: {
        !           133:     QError *qerr;
        !           134: 
        !           135:     qerr = qemu_mallocz(sizeof(*qerr));
        !           136:     QOBJECT_INIT(qerr, &qerror_type);
        !           137: 
        !           138:     return qerr;
        !           139: }
        !           140: 
        !           141: static void qerror_abort(const QError *qerr, const char *fmt, ...)
        !           142: {
        !           143:     va_list ap;
        !           144: 
        !           145:     fprintf(stderr, "qerror: bad call in function '%s':\n", qerr->func);
        !           146:     fprintf(stderr, "qerror: -> ");
        !           147: 
        !           148:     va_start(ap, fmt);
        !           149:     vfprintf(stderr, fmt, ap);
        !           150:     va_end(ap);
        !           151: 
        !           152:     fprintf(stderr, "\nqerror: call at %s:%d\n", qerr->file, qerr->linenr);
        !           153:     abort();
        !           154: }
        !           155: 
        !           156: static void qerror_set_data(QError *qerr, const char *fmt, va_list *va)
        !           157: {
        !           158:     QObject *obj;
        !           159: 
        !           160:     obj = qobject_from_jsonv(fmt, va);
        !           161:     if (!obj) {
        !           162:         qerror_abort(qerr, "invalid format '%s'", fmt);
        !           163:     }
        !           164:     if (qobject_type(obj) != QTYPE_QDICT) {
        !           165:         qerror_abort(qerr, "error format is not a QDict '%s'", fmt);
        !           166:     }
        !           167: 
        !           168:     qerr->error = qobject_to_qdict(obj);
        !           169: 
        !           170:     obj = qdict_get(qerr->error, "class");
        !           171:     if (!obj) {
        !           172:         qerror_abort(qerr, "missing 'class' key in '%s'", fmt);
        !           173:     }
        !           174:     if (qobject_type(obj) != QTYPE_QSTRING) {
        !           175:         qerror_abort(qerr, "'class' key value should be a QString");
        !           176:     }
        !           177:     
        !           178:     obj = qdict_get(qerr->error, "data");
        !           179:     if (!obj) {
        !           180:         qerror_abort(qerr, "missing 'data' key in '%s'", fmt);
        !           181:     }
        !           182:     if (qobject_type(obj) != QTYPE_QDICT) {
        !           183:         qerror_abort(qerr, "'data' key value should be a QDICT");
        !           184:     }
        !           185: }
        !           186: 
        !           187: static void qerror_set_desc(QError *qerr, const char *fmt)
        !           188: {
        !           189:     int i;
        !           190: 
        !           191:     // FIXME: inefficient loop
        !           192: 
        !           193:     for (i = 0; qerror_table[i].error_fmt; i++) {
        !           194:         if (strcmp(qerror_table[i].error_fmt, fmt) == 0) {
        !           195:             qerr->entry = &qerror_table[i];
        !           196:             return;
        !           197:         }
        !           198:     }
        !           199: 
        !           200:     qerror_abort(qerr, "error format '%s' not found", fmt);
        !           201: }
        !           202: 
        !           203: /**
        !           204:  * qerror_from_info(): Create a new QError from error information
        !           205:  *
        !           206:  * The information consists of:
        !           207:  *
        !           208:  * - file   the file name of where the error occurred
        !           209:  * - linenr the line number of where the error occurred
        !           210:  * - func   the function name of where the error occurred
        !           211:  * - fmt    JSON printf-like dictionary, there must exist keys 'class' and
        !           212:  *          'data'
        !           213:  * - va     va_list of all arguments specified by fmt
        !           214:  *
        !           215:  * Return strong reference.
        !           216:  */
        !           217: QError *qerror_from_info(const char *file, int linenr, const char *func,
        !           218:                          const char *fmt, va_list *va)
        !           219: {
        !           220:     QError *qerr;
        !           221: 
        !           222:     qerr = qerror_new();
        !           223:     qerr->linenr = linenr;
        !           224:     qerr->file = file;
        !           225:     qerr->func = func;
        !           226: 
        !           227:     if (!fmt) {
        !           228:         qerror_abort(qerr, "QDict not specified");
        !           229:     }
        !           230: 
        !           231:     qerror_set_data(qerr, fmt, va);
        !           232:     qerror_set_desc(qerr, fmt);
        !           233: 
        !           234:     return qerr;
        !           235: }
        !           236: 
        !           237: static void parse_error(const QError *qerror, int c)
        !           238: {
        !           239:     qerror_abort(qerror, "expected '%c' in '%s'", c, qerror->entry->desc);
        !           240: }
        !           241: 
        !           242: static const char *append_field(QString *outstr, const QError *qerror,
        !           243:                                 const char *start)
        !           244: {
        !           245:     QObject *obj;
        !           246:     QDict *qdict;
        !           247:     QString *key_qs;
        !           248:     const char *end, *key;
        !           249: 
        !           250:     if (*start != '%')
        !           251:         parse_error(qerror, '%');
        !           252:     start++;
        !           253:     if (*start != '(')
        !           254:         parse_error(qerror, '(');
        !           255:     start++;
        !           256: 
        !           257:     end = strchr(start, ')');
        !           258:     if (!end)
        !           259:         parse_error(qerror, ')');
        !           260: 
        !           261:     key_qs = qstring_from_substr(start, 0, end - start - 1);
        !           262:     key = qstring_get_str(key_qs);
        !           263: 
        !           264:     qdict = qobject_to_qdict(qdict_get(qerror->error, "data"));
        !           265:     obj = qdict_get(qdict, key);
        !           266:     if (!obj) {
        !           267:         qerror_abort(qerror, "key '%s' not found in QDict", key);
        !           268:     }
        !           269: 
        !           270:     switch (qobject_type(obj)) {
        !           271:         case QTYPE_QSTRING:
        !           272:             qstring_append(outstr, qdict_get_str(qdict, key));
        !           273:             break;
        !           274:         case QTYPE_QINT:
        !           275:             qstring_append_int(outstr, qdict_get_int(qdict, key));
        !           276:             break;
        !           277:         default:
        !           278:             qerror_abort(qerror, "invalid type '%c'", qobject_type(obj));
        !           279:     }
        !           280: 
        !           281:     QDECREF(key_qs);
        !           282:     return ++end;
        !           283: }
        !           284: 
        !           285: /**
        !           286:  * qerror_human(): Format QError data into human-readable string.
        !           287:  *
        !           288:  * Formats according to member 'desc' of the specified QError object.
        !           289:  */
        !           290: QString *qerror_human(const QError *qerror)
        !           291: {
        !           292:     const char *p;
        !           293:     QString *qstring;
        !           294: 
        !           295:     assert(qerror->entry != NULL);
        !           296: 
        !           297:     qstring = qstring_new();
        !           298: 
        !           299:     for (p = qerror->entry->desc; *p != '\0';) {
        !           300:         if (*p != '%') {
        !           301:             qstring_append_chr(qstring, *p++);
        !           302:         } else if (*(p + 1) == '%') {
        !           303:             qstring_append_chr(qstring, '%');
        !           304:             p += 2;
        !           305:         } else {
        !           306:             p = append_field(qstring, qerror, p);
        !           307:         }
        !           308:     }
        !           309: 
        !           310:     return qstring;
        !           311: }
        !           312: 
        !           313: /**
        !           314:  * qerror_print(): Print QError data
        !           315:  *
        !           316:  * This function will print the member 'desc' of the specified QError object,
        !           317:  * it uses qemu_error() for this, so that the output is routed to the right
        !           318:  * place (ie. stderr or Monitor's device).
        !           319:  */
        !           320: void qerror_print(const QError *qerror)
        !           321: {
        !           322:     QString *qstring = qerror_human(qerror);
        !           323:     qemu_error("%s\n", qstring_get_str(qstring));
        !           324:     QDECREF(qstring);
        !           325: }
        !           326: 
        !           327: /**
        !           328:  * qobject_to_qerror(): Convert a QObject into a QError
        !           329:  */
        !           330: QError *qobject_to_qerror(const QObject *obj)
        !           331: {
        !           332:     if (qobject_type(obj) != QTYPE_QERROR) {
        !           333:         return NULL;
        !           334:     }
        !           335: 
        !           336:     return container_of(obj, QError, base);
        !           337: }
        !           338: 
        !           339: /**
        !           340:  * qerror_destroy_obj(): Free all memory allocated by a QError
        !           341:  */
        !           342: static void qerror_destroy_obj(QObject *obj)
        !           343: {
        !           344:     QError *qerr;
        !           345: 
        !           346:     assert(obj != NULL);
        !           347:     qerr = qobject_to_qerror(obj);
        !           348: 
        !           349:     QDECREF(qerr->error);
        !           350:     qemu_free(qerr);
        !           351: }

unix.superglobalmegacorp.com