]> Git Repo - qemu.git/blob - qerror.c
net: clean up includes in net.c
[qemu.git] / qerror.c
1 /*
2  * QError: QEMU Error data-type.
3  *
4  * Copyright (C) 2009 Red Hat Inc.
5  *
6  * Authors:
7  *  Luiz Capitulino <[email protected]>
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 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_NOT_FOUND,
49         .desc      = "The %(device) device has not been found",
50     },
51     {
52         .error_fmt = QERR_DEVICE_NOT_ACTIVE,
53         .desc      = "The %(device) device has not been activated by the guest",
54     },
55     {
56         .error_fmt   = QERR_INVALID_PARAMETER_TYPE,
57         .desc        = "Invalid parameter type, expected: %(expected)",
58     },
59     {
60         .error_fmt = QERR_KVM_MISSING_CAP,
61         .desc      = "Using KVM without %(capability), %(feature) unavailable",
62     },
63     {
64         .error_fmt = QERR_MISSING_PARAMETER,
65         .desc      = "Parameter %(name) is missing",
66     },
67     {
68         .error_fmt = QERR_QMP_BAD_INPUT_OBJECT,
69         .desc      = "Bad QMP input object",
70     },
71     {
72         .error_fmt = QERR_JSON_PARSING,
73         .desc      = "Invalid JSON synaxt",
74     },
75     {
76         .error_fmt   = QERR_UNDEFINED_ERROR,
77         .desc        = "An undefined error has ocurred",
78     },
79     {}
80 };
81
82 /**
83  * qerror_new(): Create a new QError
84  *
85  * Return strong reference.
86  */
87 QError *qerror_new(void)
88 {
89     QError *qerr;
90
91     qerr = qemu_mallocz(sizeof(*qerr));
92     QOBJECT_INIT(qerr, &qerror_type);
93
94     return qerr;
95 }
96
97 static void qerror_abort(const QError *qerr, const char *fmt, ...)
98 {
99     va_list ap;
100
101     fprintf(stderr, "qerror: bad call in function '%s':\n", qerr->func);
102     fprintf(stderr, "qerror: -> ");
103
104     va_start(ap, fmt);
105     vfprintf(stderr, fmt, ap);
106     va_end(ap);
107
108     fprintf(stderr, "\nqerror: call at %s:%d\n", qerr->file, qerr->linenr);
109     abort();
110 }
111
112 static void qerror_set_data(QError *qerr, const char *fmt, va_list *va)
113 {
114     QObject *obj;
115
116     obj = qobject_from_jsonv(fmt, va);
117     if (!obj) {
118         qerror_abort(qerr, "invalid format '%s'", fmt);
119     }
120     if (qobject_type(obj) != QTYPE_QDICT) {
121         qerror_abort(qerr, "error format is not a QDict '%s'", fmt);
122     }
123
124     qerr->error = qobject_to_qdict(obj);
125
126     obj = qdict_get(qerr->error, "class");
127     if (!obj) {
128         qerror_abort(qerr, "missing 'class' key in '%s'", fmt);
129     }
130     if (qobject_type(obj) != QTYPE_QSTRING) {
131         qerror_abort(qerr, "'class' key value should be a QString");
132     }
133     
134     obj = qdict_get(qerr->error, "data");
135     if (!obj) {
136         qerror_abort(qerr, "missing 'data' key in '%s'", fmt);
137     }
138     if (qobject_type(obj) != QTYPE_QDICT) {
139         qerror_abort(qerr, "'data' key value should be a QDICT");
140     }
141 }
142
143 static void qerror_set_desc(QError *qerr, const char *fmt)
144 {
145     int i;
146
147     // FIXME: inefficient loop
148
149     for (i = 0; qerror_table[i].error_fmt; i++) {
150         if (strcmp(qerror_table[i].error_fmt, fmt) == 0) {
151             qerr->entry = &qerror_table[i];
152             return;
153         }
154     }
155
156     qerror_abort(qerr, "error format '%s' not found", fmt);
157 }
158
159 /**
160  * qerror_from_info(): Create a new QError from error information
161  *
162  * The information consists of:
163  *
164  * - file   the file name of where the error occurred
165  * - linenr the line number of where the error occurred
166  * - func   the function name of where the error occurred
167  * - fmt    JSON printf-like dictionary, there must exist keys 'class' and
168  *          'data'
169  * - va     va_list of all arguments specified by fmt
170  *
171  * Return strong reference.
172  */
173 QError *qerror_from_info(const char *file, int linenr, const char *func,
174                          const char *fmt, va_list *va)
175 {
176     QError *qerr;
177
178     qerr = qerror_new();
179     qerr->linenr = linenr;
180     qerr->file = file;
181     qerr->func = func;
182
183     if (!fmt) {
184         qerror_abort(qerr, "QDict not specified");
185     }
186
187     qerror_set_data(qerr, fmt, va);
188     qerror_set_desc(qerr, fmt);
189
190     return qerr;
191 }
192
193 static void parse_error(const QError *qerror, int c)
194 {
195     qerror_abort(qerror, "expected '%c' in '%s'", c, qerror->entry->desc);
196 }
197
198 static const char *append_field(QString *outstr, const QError *qerror,
199                                 const char *start)
200 {
201     QObject *obj;
202     QDict *qdict;
203     QString *key_qs;
204     const char *end, *key;
205
206     if (*start != '%')
207         parse_error(qerror, '%');
208     start++;
209     if (*start != '(')
210         parse_error(qerror, '(');
211     start++;
212
213     end = strchr(start, ')');
214     if (!end)
215         parse_error(qerror, ')');
216
217     key_qs = qstring_from_substr(start, 0, end - start - 1);
218     key = qstring_get_str(key_qs);
219
220     qdict = qobject_to_qdict(qdict_get(qerror->error, "data"));
221     obj = qdict_get(qdict, key);
222     if (!obj) {
223         qerror_abort(qerror, "key '%s' not found in QDict", key);
224     }
225
226     switch (qobject_type(obj)) {
227         case QTYPE_QSTRING:
228             qstring_append(outstr, qdict_get_str(qdict, key));
229             break;
230         case QTYPE_QINT:
231             qstring_append_int(outstr, qdict_get_int(qdict, key));
232             break;
233         default:
234             qerror_abort(qerror, "invalid type '%c'", qobject_type(obj));
235     }
236
237     QDECREF(key_qs);
238     return ++end;
239 }
240
241 /**
242  * qerror_print(): Print QError data
243  *
244  * This function will print the member 'desc' of the specified QError object,
245  * it uses qemu_error() for this, so that the output is routed to the right
246  * place (ie. stderr or Monitor's device).
247  */
248 void qerror_print(const QError *qerror)
249 {
250     const char *p;
251     QString *qstring;
252
253     assert(qerror->entry != NULL);
254
255     qstring = qstring_new();
256
257     for (p = qerror->entry->desc; *p != '\0';) {
258         if (*p != '%') {
259             qstring_append_chr(qstring, *p++);
260         } else if (*(p + 1) == '%') {
261             qstring_append_chr(qstring, '%');
262             p += 2;
263         } else {
264             p = append_field(qstring, qerror, p);
265         }
266     }
267
268     qemu_error("%s\n", qstring_get_str(qstring));
269     QDECREF(qstring);
270 }
271
272 /**
273  * qobject_to_qerror(): Convert a QObject into a QError
274  */
275 QError *qobject_to_qerror(const QObject *obj)
276 {
277     if (qobject_type(obj) != QTYPE_QERROR) {
278         return NULL;
279     }
280
281     return container_of(obj, QError, base);
282 }
283
284 /**
285  * qerror_destroy_obj(): Free all memory allocated by a QError
286  */
287 static void qerror_destroy_obj(QObject *obj)
288 {
289     QError *qerr;
290
291     assert(obj != NULL);
292     qerr = qobject_to_qerror(obj);
293
294     QDECREF(qerr->error);
295     qemu_free(qerr);
296 }
This page took 0.040637 seconds and 4 git commands to generate.