Statistics
| Branch: | Revision:

root / qerror.c @ df1e608a

History | View | Annotate | Download (12.8 kB)

1
/*
2
 * QError Module
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

    
13
#include "monitor.h"
14
#include "qjson.h"
15
#include "qerror.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
 * Please keep the entries in alphabetical order.
43
 * Use scripts/check-qerror.sh to check.
44
 */
45
static const QErrorStringTable qerror_table[] = {
46
    {
47
         QERR_ADD_CLIENT_FAILED,
48
         "Could not add client",
49
    },
50
    {
51
         QERR_AMBIGUOUS_PATH,
52
         "Path '%(path)' does not uniquely identify an object"
53
    },
54
    {
55
         QERR_BAD_BUS_FOR_DEVICE,
56
         "Device '%(device)' can't go on a %(bad_bus_type) bus",
57
    },
58
    {
59
         QERR_BASE_NOT_FOUND,
60
         "Base '%(base)' not found",
61
    },
62
    {
63
         QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
64
         "Block format '%(format)' used by device '%(name)' does not support feature '%(feature)'",
65
    },
66
    {
67
         QERR_BUS_NO_HOTPLUG,
68
         "Bus '%(bus)' does not support hotplugging",
69
    },
70
    {
71
         QERR_BUS_NOT_FOUND,
72
         "Bus '%(bus)' not found",
73
    },
74
    {
75
         QERR_COMMAND_DISABLED,
76
         "The command %(name) has been disabled for this instance",
77
    },
78
    {
79
         QERR_COMMAND_NOT_FOUND,
80
         "The command %(name) has not been found",
81
    },
82
    {
83
         QERR_DEVICE_ENCRYPTED,
84
         "'%(device)' (%(filename)) is encrypted",
85
    },
86
    {
87
         QERR_DEVICE_FEATURE_BLOCKS_MIGRATION,
88
         "Migration is disabled when using feature '%(feature)' in device '%(device)'",
89
    },
90
    {
91
         QERR_DEVICE_HAS_NO_MEDIUM,
92
         "Device '%(device)' has no medium",
93
    },
94
    {
95
         QERR_DEVICE_INIT_FAILED,
96
         "Device '%(device)' could not be initialized",
97
    },
98
    {
99
         QERR_DEVICE_IN_USE,
100
         "Device '%(device)' is in use",
101
    },
102
    {
103
         QERR_DEVICE_IS_READ_ONLY,
104
         "Device '%(device)' is read only",
105
    },
106
    {
107
         QERR_DEVICE_LOCKED,
108
         "Device '%(device)' is locked",
109
    },
110
    {
111
         QERR_DEVICE_MULTIPLE_BUSSES,
112
         "Device '%(device)' has multiple child busses",
113
    },
114
    {
115
         QERR_DEVICE_NO_BUS,
116
         "Device '%(device)' has no child bus",
117
    },
118
    {
119
         QERR_DEVICE_NO_HOTPLUG,
120
         "Device '%(device)' does not support hotplugging",
121
    },
122
    {
123
         QERR_DEVICE_NOT_ACTIVE,
124
         "Device '%(device)' has not been activated",
125
    },
126
    {
127
         QERR_DEVICE_NOT_ENCRYPTED,
128
         "Device '%(device)' is not encrypted",
129
    },
130
    {
131
         QERR_DEVICE_NOT_FOUND,
132
         "Device '%(device)' not found",
133
    },
134
    {
135
         QERR_DEVICE_NOT_REMOVABLE,
136
         "Device '%(device)' is not removable",
137
    },
138
    {
139
         QERR_DUPLICATE_ID,
140
         "Duplicate ID '%(id)' for %(object)",
141
    },
142
    {
143
         QERR_FD_NOT_FOUND,
144
         "File descriptor named '%(name)' not found",
145
    },
146
    {
147
         QERR_FD_NOT_SUPPLIED,
148
         "No file descriptor supplied via SCM_RIGHTS",
149
    },
150
    {
151
         QERR_FEATURE_DISABLED,
152
         "The feature '%(name)' is not enabled",
153
    },
154
    {
155
         QERR_INVALID_BLOCK_FORMAT,
156
         "Invalid block format '%(name)'",
157
    },
158
    {
159
         QERR_INVALID_OPTION_GROUP,
160
         "There is no option group '%(group)'",
161
    },
162
    {
163
         QERR_INVALID_PARAMETER,
164
         "Invalid parameter '%(name)'",
165
    },
166
    {
167
         QERR_INVALID_PARAMETER_COMBINATION,
168
         "Invalid parameter combination",
169
    },
170
    {
171
         QERR_INVALID_PARAMETER_TYPE,
172
         "Invalid parameter type for '%(name)', expected: %(expected)",
173
    },
174
    {
175
         QERR_INVALID_PARAMETER_VALUE,
176
         "Parameter '%(name)' expects %(expected)",
177
    },
178
    {
179
         QERR_INVALID_PASSWORD,
180
         "Password incorrect",
181
    },
182
    {
183
         QERR_IO_ERROR,
184
         "An IO error has occurred",
185
    },
186
    {
187
         QERR_JSON_PARSE_ERROR,
188
         "JSON parse error, %(message)",
189

    
190
    },
191
    {
192
         QERR_JSON_PARSING,
193
         "Invalid JSON syntax",
194
    },
195
    {
196
         QERR_KVM_MISSING_CAP,
197
         "Using KVM without %(capability), %(feature) unavailable",
198
    },
199
    {
200
         QERR_MIGRATION_ACTIVE,
201
         "There's a migration process in progress",
202
    },
203
    {
204
         QERR_MIGRATION_NOT_SUPPORTED,
205
         "State blocked by non-migratable device '%(device)'",
206
    },
207
    {
208
         QERR_MIGRATION_EXPECTED,
209
         "An incoming migration is expected before this command can be executed",
210
    },
211
    {
212
         QERR_MISSING_PARAMETER,
213
         "Parameter '%(name)' is missing",
214
    },
215
    {
216
         QERR_NO_BUS_FOR_DEVICE,
217
         "No '%(bus)' bus found for device '%(device)'",
218
    },
219
    {
220
         QERR_NOT_SUPPORTED,
221
         "Not supported",
222
    },
223
    {
224
         QERR_OPEN_FILE_FAILED,
225
         "Could not open '%(filename)'",
226
    },
227
    {
228
         QERR_PERMISSION_DENIED,
229
         "Insufficient permission to perform this operation",
230
    },
231
    {
232
         QERR_PROPERTY_NOT_FOUND,
233
         "Property '%(device).%(property)' not found",
234
    },
235
    {
236
         QERR_PROPERTY_VALUE_BAD,
237
         "Property '%(device).%(property)' doesn't take value '%(value)'",
238
    },
239
    {
240
         QERR_PROPERTY_VALUE_IN_USE,
241
         "Property '%(device).%(property)' can't take value '%(value)', it's in use",
242
    },
243
    {
244
         QERR_PROPERTY_VALUE_NOT_FOUND,
245
         "Property '%(device).%(property)' can't find value '%(value)'",
246
    },
247
    {
248
         QERR_PROPERTY_VALUE_NOT_POWER_OF_2,
249
         "Property '%(device).%(property)' doesn't take "
250
                     "value '%(value)', it's not a power of 2",
251
    },
252
    {
253
         QERR_PROPERTY_VALUE_OUT_OF_RANGE,
254
         "Property '%(device).%(property)' doesn't take "
255
                     "value %(value) (minimum: %(min), maximum: %(max))",
256
    },
257
    {
258
         QERR_QGA_COMMAND_FAILED,
259
         "Guest agent command failed, error was '%(message)'",
260
    },
261
    {
262
         QERR_QGA_LOGGING_FAILED,
263
         "Guest agent failed to log non-optional log statement",
264
    },
265
    {
266
         QERR_QMP_BAD_INPUT_OBJECT,
267
         "Expected '%(expected)' in QMP input",
268
    },
269
    {
270
         QERR_QMP_BAD_INPUT_OBJECT_MEMBER,
271
         "QMP input object member '%(member)' expects '%(expected)'",
272
    },
273
    {
274
         QERR_QMP_EXTRA_MEMBER,
275
         "QMP input object member '%(member)' is unexpected",
276
    },
277
    {
278
         QERR_RESET_REQUIRED,
279
         "Resetting the Virtual Machine is required",
280
    },
281
    {
282
         QERR_SET_PASSWD_FAILED,
283
         "Could not set password",
284
    },
285
    {
286
         QERR_TOO_MANY_FILES,
287
         "Too many open files",
288
    },
289
    {
290
         QERR_UNDEFINED_ERROR,
291
         "An undefined error has occurred",
292
    },
293
    {
294
         QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
295
         "'%(device)' uses a %(format) feature which is not "
296
                     "supported by this qemu version: %(feature)",
297
    },
298
    {
299
         QERR_UNSUPPORTED,
300
         "this feature or command is not currently supported",
301
    },
302
    {
303
         QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION,
304
         "Migration is disabled when VirtFS export path '%(path)' "
305
                     "is mounted in the guest using mount_tag '%(tag)'",
306
    },
307
    {
308
         QERR_VNC_SERVER_FAILED,
309
         "Could not start VNC server on %(target)",
310
    },
311
    {
312
         QERR_SOCKET_CONNECT_FAILED,
313
         "Failed to connect to socket",
314
    },
315
    {
316
         QERR_SOCKET_LISTEN_FAILED,
317
         "Failed to set socket to listening mode",
318
    },
319
    {
320
         QERR_SOCKET_BIND_FAILED,
321
         "Failed to bind socket",
322
    },
323
    {
324
         QERR_SOCKET_CREATE_FAILED,
325
         "Failed to create socket",
326
    },
327
    {}
328
};
329

    
330
/**
331
 * qerror_new(): Create a new QError
332
 *
333
 * Return strong reference.
334
 */
335
static QError *qerror_new(void)
336
{
337
    QError *qerr;
338

    
339
    qerr = g_malloc0(sizeof(*qerr));
340
    QOBJECT_INIT(qerr, &qerror_type);
341

    
342
    return qerr;
343
}
344

    
345
/**
346
 * qerror_from_info(): Create a new QError from error information
347
 *
348
 * Return strong reference.
349
 */
350
static QError *qerror_from_info(ErrorClass err_class, const char *fmt,
351
                                va_list *va)
352
{
353
    QError *qerr;
354

    
355
    qerr = qerror_new();
356
    loc_save(&qerr->loc);
357

    
358
    qerr->err_msg = g_strdup_vprintf(fmt, *va);
359
    qerr->err_class = err_class;
360

    
361
    return qerr;
362
}
363

    
364
static void parse_error(const QErrorStringTable *entry, int c)
365
{
366
    fprintf(stderr, "expected '%c' in '%s'", c, entry->desc);
367
    abort();
368
}
369

    
370
static const char *append_field(QDict *error, QString *outstr,
371
                                const QErrorStringTable *entry,
372
                                const char *start)
373
{
374
    QObject *obj;
375
    QDict *qdict;
376
    QString *key_qs;
377
    const char *end, *key;
378

    
379
    if (*start != '%')
380
        parse_error(entry, '%');
381
    start++;
382
    if (*start != '(')
383
        parse_error(entry, '(');
384
    start++;
385

    
386
    end = strchr(start, ')');
387
    if (!end)
388
        parse_error(entry, ')');
389

    
390
    key_qs = qstring_from_substr(start, 0, end - start - 1);
391
    key = qstring_get_str(key_qs);
392

    
393
    qdict = qobject_to_qdict(qdict_get(error, "data"));
394
    obj = qdict_get(qdict, key);
395
    if (!obj) {
396
        abort();
397
    }
398

    
399
    switch (qobject_type(obj)) {
400
        case QTYPE_QSTRING:
401
            qstring_append(outstr, qdict_get_str(qdict, key));
402
            break;
403
        case QTYPE_QINT:
404
            qstring_append_int(outstr, qdict_get_int(qdict, key));
405
            break;
406
        default:
407
            abort();
408
    }
409

    
410
    QDECREF(key_qs);
411
    return ++end;
412
}
413

    
414
static QString *qerror_format_desc(QDict *error,
415
                                   const QErrorStringTable *entry)
416
{
417
    QString *qstring;
418
    const char *p;
419

    
420
    assert(entry != NULL);
421

    
422
    qstring = qstring_new();
423

    
424
    for (p = entry->desc; *p != '\0';) {
425
        if (*p != '%') {
426
            qstring_append_chr(qstring, *p++);
427
        } else if (*(p + 1) == '%') {
428
            qstring_append_chr(qstring, '%');
429
            p += 2;
430
        } else {
431
            p = append_field(error, qstring, entry, p);
432
        }
433
    }
434

    
435
    return qstring;
436
}
437

    
438
char *qerror_format(const char *fmt, QDict *error)
439
{
440
    const QErrorStringTable *entry = NULL;
441
    QString *qstr;
442
    char *ret;
443
    int i;
444

    
445
    for (i = 0; qerror_table[i].error_fmt; i++) {
446
        if (strcmp(qerror_table[i].error_fmt, fmt) == 0) {
447
            entry = &qerror_table[i];
448
            break;
449
        }
450
    }
451

    
452
    qstr = qerror_format_desc(error, entry);
453
    ret = g_strdup(qstring_get_str(qstr));
454
    QDECREF(qstr);
455

    
456
    return ret;
457
}
458

    
459
/**
460
 * qerror_human(): Format QError data into human-readable string.
461
 */
462
QString *qerror_human(const QError *qerror)
463
{
464
    return qstring_from_str(qerror->err_msg);
465
}
466

    
467
/**
468
 * qerror_print(): Print QError data
469
 *
470
 * This function will print the member 'desc' of the specified QError object,
471
 * it uses error_report() for this, so that the output is routed to the right
472
 * place (ie. stderr or Monitor's device).
473
 */
474
static void qerror_print(QError *qerror)
475
{
476
    QString *qstring = qerror_human(qerror);
477
    loc_push_restore(&qerror->loc);
478
    error_report("%s", qstring_get_str(qstring));
479
    loc_pop(&qerror->loc);
480
    QDECREF(qstring);
481
}
482

    
483
void qerror_report(ErrorClass eclass, const char *fmt, ...)
484
{
485
    va_list va;
486
    QError *qerror;
487

    
488
    va_start(va, fmt);
489
    qerror = qerror_from_info(eclass, fmt, &va);
490
    va_end(va);
491

    
492
    if (monitor_cur_is_qmp()) {
493
        monitor_set_error(cur_mon, qerror);
494
    } else {
495
        qerror_print(qerror);
496
        QDECREF(qerror);
497
    }
498
}
499

    
500
/* Evil... */
501
struct Error
502
{
503
    QDict *obj;
504
    char *msg;
505
    ErrorClass err_class;
506
};
507

    
508
void qerror_report_err(Error *err)
509
{
510
    QError *qerr;
511

    
512
    qerr = qerror_new();
513
    loc_save(&qerr->loc);
514
    QINCREF(err->obj);
515
    qerr->error = err->obj;
516
    qerr->err_msg = g_strdup(err->msg);
517
    qerr->err_class = err->err_class;
518

    
519
    if (monitor_cur_is_qmp()) {
520
        monitor_set_error(cur_mon, qerr);
521
    } else {
522
        qerror_print(qerr);
523
        QDECREF(qerr);
524
    }
525
}
526

    
527
void assert_no_error(Error *err)
528
{
529
    if (err) {
530
        qerror_report_err(err);
531
        abort();
532
    }
533
}
534

    
535
/**
536
 * qobject_to_qerror(): Convert a QObject into a QError
537
 */
538
static QError *qobject_to_qerror(const QObject *obj)
539
{
540
    if (qobject_type(obj) != QTYPE_QERROR) {
541
        return NULL;
542
    }
543

    
544
    return container_of(obj, QError, base);
545
}
546

    
547
/**
548
 * qerror_destroy_obj(): Free all memory allocated by a QError
549
 */
550
static void qerror_destroy_obj(QObject *obj)
551
{
552
    QError *qerr;
553

    
554
    assert(obj != NULL);
555
    qerr = qobject_to_qerror(obj);
556

    
557
    QDECREF(qerr->error);
558
    g_free(qerr->err_msg);
559
    g_free(qerr);
560
}