2
0

qerror.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  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. #include "monitor.h"
  13. #include "qjson.h"
  14. #include "qerror.h"
  15. #include "qemu-common.h"
  16. static void qerror_destroy_obj(QObject *obj);
  17. static const QType qerror_type = {
  18. .code = QTYPE_QERROR,
  19. .destroy = qerror_destroy_obj,
  20. };
  21. /**
  22. * The 'desc' parameter is a printf-like string, the format of the format
  23. * string is:
  24. *
  25. * %(KEY)
  26. *
  27. * Where KEY is a QDict key, which has to be passed to qerror_from_info().
  28. *
  29. * Example:
  30. *
  31. * "foo error on device: %(device) slot: %(slot_nr)"
  32. *
  33. * A single percent sign can be printed if followed by a second one,
  34. * for example:
  35. *
  36. * "running out of foo: %(foo)%%"
  37. *
  38. * Please keep the entries in alphabetical order.
  39. * Use "sed -n '/^static.*qerror_table\[\]/,/^};/s/QERR_/&/gp' qerror.c | sort -c"
  40. * to check.
  41. */
  42. static const QErrorStringTable qerror_table[] = {
  43. {
  44. .error_fmt = QERR_BAD_BUS_FOR_DEVICE,
  45. .desc = "Device '%(device)' can't go on a %(bad_bus_type) bus",
  46. },
  47. {
  48. .error_fmt = QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
  49. .desc = "Block format '%(format)' used by device '%(name)' does not support feature '%(feature)'",
  50. },
  51. {
  52. .error_fmt = QERR_BUS_NOT_FOUND,
  53. .desc = "Bus '%(bus)' not found",
  54. },
  55. {
  56. .error_fmt = QERR_BUS_NO_HOTPLUG,
  57. .desc = "Bus '%(bus)' does not support hotplugging",
  58. },
  59. {
  60. .error_fmt = QERR_COMMAND_NOT_FOUND,
  61. .desc = "The command %(name) has not been found",
  62. },
  63. {
  64. .error_fmt = QERR_DEVICE_ENCRYPTED,
  65. .desc = "Device '%(device)' is encrypted",
  66. },
  67. {
  68. .error_fmt = QERR_DEVICE_INIT_FAILED,
  69. .desc = "Device '%(device)' could not be initialized",
  70. },
  71. {
  72. .error_fmt = QERR_DEVICE_IN_USE,
  73. .desc = "Device '%(device)' is in use",
  74. },
  75. {
  76. .error_fmt = QERR_DEVICE_FEATURE_BLOCKS_MIGRATION,
  77. .desc = "Migration is disabled when using feature '%(feature)' in device '%(device)'",
  78. },
  79. {
  80. .error_fmt = QERR_DEVICE_LOCKED,
  81. .desc = "Device '%(device)' is locked",
  82. },
  83. {
  84. .error_fmt = QERR_DEVICE_MULTIPLE_BUSSES,
  85. .desc = "Device '%(device)' has multiple child busses",
  86. },
  87. {
  88. .error_fmt = QERR_DEVICE_NOT_ACTIVE,
  89. .desc = "Device '%(device)' has not been activated",
  90. },
  91. {
  92. .error_fmt = QERR_DEVICE_NOT_ENCRYPTED,
  93. .desc = "Device '%(device)' is not encrypted",
  94. },
  95. {
  96. .error_fmt = QERR_DEVICE_NOT_FOUND,
  97. .desc = "Device '%(device)' not found",
  98. },
  99. {
  100. .error_fmt = QERR_DEVICE_NOT_REMOVABLE,
  101. .desc = "Device '%(device)' is not removable",
  102. },
  103. {
  104. .error_fmt = QERR_DEVICE_NO_BUS,
  105. .desc = "Device '%(device)' has no child bus",
  106. },
  107. {
  108. .error_fmt = QERR_DEVICE_NO_HOTPLUG,
  109. .desc = "Device '%(device)' does not support hotplugging",
  110. },
  111. {
  112. .error_fmt = QERR_DUPLICATE_ID,
  113. .desc = "Duplicate ID '%(id)' for %(object)",
  114. },
  115. {
  116. .error_fmt = QERR_FD_NOT_FOUND,
  117. .desc = "File descriptor named '%(name)' not found",
  118. },
  119. {
  120. .error_fmt = QERR_FD_NOT_SUPPLIED,
  121. .desc = "No file descriptor supplied via SCM_RIGHTS",
  122. },
  123. {
  124. .error_fmt = QERR_FEATURE_DISABLED,
  125. .desc = "The feature '%(name)' is not enabled",
  126. },
  127. {
  128. .error_fmt = QERR_INVALID_BLOCK_FORMAT,
  129. .desc = "Invalid block format '%(name)'",
  130. },
  131. {
  132. .error_fmt = QERR_INVALID_PARAMETER,
  133. .desc = "Invalid parameter '%(name)'",
  134. },
  135. {
  136. .error_fmt = QERR_INVALID_PARAMETER_TYPE,
  137. .desc = "Invalid parameter type, expected: %(expected)",
  138. },
  139. {
  140. .error_fmt = QERR_INVALID_PARAMETER_VALUE,
  141. .desc = "Parameter '%(name)' expects %(expected)",
  142. },
  143. {
  144. .error_fmt = QERR_INVALID_PASSWORD,
  145. .desc = "Password incorrect",
  146. },
  147. {
  148. .error_fmt = QERR_JSON_PARSING,
  149. .desc = "Invalid JSON syntax",
  150. },
  151. {
  152. .error_fmt = QERR_JSON_PARSE_ERROR,
  153. .desc = "JSON parse error, %(message)",
  154. },
  155. {
  156. .error_fmt = QERR_KVM_MISSING_CAP,
  157. .desc = "Using KVM without %(capability), %(feature) unavailable",
  158. },
  159. {
  160. .error_fmt = QERR_MIGRATION_EXPECTED,
  161. .desc = "An incoming migration is expected before this command can be executed",
  162. },
  163. {
  164. .error_fmt = QERR_MISSING_PARAMETER,
  165. .desc = "Parameter '%(name)' is missing",
  166. },
  167. {
  168. .error_fmt = QERR_NO_BUS_FOR_DEVICE,
  169. .desc = "No '%(bus)' bus found for device '%(device)'",
  170. },
  171. {
  172. .error_fmt = QERR_OPEN_FILE_FAILED,
  173. .desc = "Could not open '%(filename)'",
  174. },
  175. {
  176. .error_fmt = QERR_PROPERTY_NOT_FOUND,
  177. .desc = "Property '%(device).%(property)' not found",
  178. },
  179. {
  180. .error_fmt = QERR_PROPERTY_VALUE_BAD,
  181. .desc = "Property '%(device).%(property)' doesn't take value '%(value)'",
  182. },
  183. {
  184. .error_fmt = QERR_PROPERTY_VALUE_IN_USE,
  185. .desc = "Property '%(device).%(property)' can't take value '%(value)', it's in use",
  186. },
  187. {
  188. .error_fmt = QERR_PROPERTY_VALUE_NOT_FOUND,
  189. .desc = "Property '%(device).%(property)' can't find value '%(value)'",
  190. },
  191. {
  192. .error_fmt = QERR_QMP_BAD_INPUT_OBJECT,
  193. .desc = "Expected '%(expected)' in QMP input",
  194. },
  195. {
  196. .error_fmt = QERR_QMP_BAD_INPUT_OBJECT_MEMBER,
  197. .desc = "QMP input object member '%(member)' expects '%(expected)'",
  198. },
  199. {
  200. .error_fmt = QERR_QMP_EXTRA_MEMBER,
  201. .desc = "QMP input object member '%(member)' is unexpected",
  202. },
  203. {
  204. .error_fmt = QERR_RESET_REQUIRED,
  205. .desc = "Resetting the Virtual Machine is required",
  206. },
  207. {
  208. .error_fmt = QERR_SET_PASSWD_FAILED,
  209. .desc = "Could not set password",
  210. },
  211. {
  212. .error_fmt = QERR_ADD_CLIENT_FAILED,
  213. .desc = "Could not add client",
  214. },
  215. {
  216. .error_fmt = QERR_TOO_MANY_FILES,
  217. .desc = "Too many open files",
  218. },
  219. {
  220. .error_fmt = QERR_UNDEFINED_ERROR,
  221. .desc = "An undefined error has ocurred",
  222. },
  223. {
  224. .error_fmt = QERR_UNSUPPORTED,
  225. .desc = "this feature or command is not currently supported",
  226. },
  227. {
  228. .error_fmt = QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
  229. .desc = "'%(device)' uses a %(format) feature which is not "
  230. "supported by this qemu version: %(feature)",
  231. },
  232. {
  233. .error_fmt = QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION,
  234. .desc = "Migration is disabled when VirtFS export path '%(path)' "
  235. "is mounted in the guest using mount_tag '%(tag)'",
  236. },
  237. {
  238. .error_fmt = QERR_VNC_SERVER_FAILED,
  239. .desc = "Could not start VNC server on %(target)",
  240. },
  241. {
  242. .error_fmt = QERR_QGA_LOGGING_FAILED,
  243. .desc = "Guest agent failed to log non-optional log statement",
  244. },
  245. {
  246. .error_fmt = QERR_QGA_COMMAND_FAILED,
  247. .desc = "Guest agent command failed, error was '%(message)'",
  248. },
  249. {}
  250. };
  251. /**
  252. * qerror_new(): Create a new QError
  253. *
  254. * Return strong reference.
  255. */
  256. QError *qerror_new(void)
  257. {
  258. QError *qerr;
  259. qerr = g_malloc0(sizeof(*qerr));
  260. QOBJECT_INIT(qerr, &qerror_type);
  261. return qerr;
  262. }
  263. static void GCC_FMT_ATTR(2, 3) qerror_abort(const QError *qerr,
  264. const char *fmt, ...)
  265. {
  266. va_list ap;
  267. fprintf(stderr, "qerror: bad call in function '%s':\n", qerr->func);
  268. fprintf(stderr, "qerror: -> ");
  269. va_start(ap, fmt);
  270. vfprintf(stderr, fmt, ap);
  271. va_end(ap);
  272. fprintf(stderr, "\nqerror: call at %s:%d\n", qerr->file, qerr->linenr);
  273. abort();
  274. }
  275. static void GCC_FMT_ATTR(2, 0) qerror_set_data(QError *qerr,
  276. const char *fmt, va_list *va)
  277. {
  278. QObject *obj;
  279. obj = qobject_from_jsonv(fmt, va);
  280. if (!obj) {
  281. qerror_abort(qerr, "invalid format '%s'", fmt);
  282. }
  283. if (qobject_type(obj) != QTYPE_QDICT) {
  284. qerror_abort(qerr, "error format is not a QDict '%s'", fmt);
  285. }
  286. qerr->error = qobject_to_qdict(obj);
  287. obj = qdict_get(qerr->error, "class");
  288. if (!obj) {
  289. qerror_abort(qerr, "missing 'class' key in '%s'", fmt);
  290. }
  291. if (qobject_type(obj) != QTYPE_QSTRING) {
  292. qerror_abort(qerr, "'class' key value should be a QString");
  293. }
  294. obj = qdict_get(qerr->error, "data");
  295. if (!obj) {
  296. qerror_abort(qerr, "missing 'data' key in '%s'", fmt);
  297. }
  298. if (qobject_type(obj) != QTYPE_QDICT) {
  299. qerror_abort(qerr, "'data' key value should be a QDICT");
  300. }
  301. }
  302. static void qerror_set_desc(QError *qerr, const char *fmt)
  303. {
  304. int i;
  305. // FIXME: inefficient loop
  306. for (i = 0; qerror_table[i].error_fmt; i++) {
  307. if (strcmp(qerror_table[i].error_fmt, fmt) == 0) {
  308. qerr->entry = &qerror_table[i];
  309. return;
  310. }
  311. }
  312. qerror_abort(qerr, "error format '%s' not found", fmt);
  313. }
  314. /**
  315. * qerror_from_info(): Create a new QError from error information
  316. *
  317. * The information consists of:
  318. *
  319. * - file the file name of where the error occurred
  320. * - linenr the line number of where the error occurred
  321. * - func the function name of where the error occurred
  322. * - fmt JSON printf-like dictionary, there must exist keys 'class' and
  323. * 'data'
  324. * - va va_list of all arguments specified by fmt
  325. *
  326. * Return strong reference.
  327. */
  328. QError *qerror_from_info(const char *file, int linenr, const char *func,
  329. const char *fmt, va_list *va)
  330. {
  331. QError *qerr;
  332. qerr = qerror_new();
  333. loc_save(&qerr->loc);
  334. qerr->linenr = linenr;
  335. qerr->file = file;
  336. qerr->func = func;
  337. if (!fmt) {
  338. qerror_abort(qerr, "QDict not specified");
  339. }
  340. qerror_set_data(qerr, fmt, va);
  341. qerror_set_desc(qerr, fmt);
  342. return qerr;
  343. }
  344. static void parse_error(const QErrorStringTable *entry, int c)
  345. {
  346. fprintf(stderr, "expected '%c' in '%s'", c, entry->desc);
  347. abort();
  348. }
  349. static const char *append_field(QDict *error, QString *outstr,
  350. const QErrorStringTable *entry,
  351. const char *start)
  352. {
  353. QObject *obj;
  354. QDict *qdict;
  355. QString *key_qs;
  356. const char *end, *key;
  357. if (*start != '%')
  358. parse_error(entry, '%');
  359. start++;
  360. if (*start != '(')
  361. parse_error(entry, '(');
  362. start++;
  363. end = strchr(start, ')');
  364. if (!end)
  365. parse_error(entry, ')');
  366. key_qs = qstring_from_substr(start, 0, end - start - 1);
  367. key = qstring_get_str(key_qs);
  368. qdict = qobject_to_qdict(qdict_get(error, "data"));
  369. obj = qdict_get(qdict, key);
  370. if (!obj) {
  371. abort();
  372. }
  373. switch (qobject_type(obj)) {
  374. case QTYPE_QSTRING:
  375. qstring_append(outstr, qdict_get_str(qdict, key));
  376. break;
  377. case QTYPE_QINT:
  378. qstring_append_int(outstr, qdict_get_int(qdict, key));
  379. break;
  380. default:
  381. abort();
  382. }
  383. QDECREF(key_qs);
  384. return ++end;
  385. }
  386. static QString *qerror_format_desc(QDict *error,
  387. const QErrorStringTable *entry)
  388. {
  389. QString *qstring;
  390. const char *p;
  391. assert(entry != NULL);
  392. qstring = qstring_new();
  393. for (p = entry->desc; *p != '\0';) {
  394. if (*p != '%') {
  395. qstring_append_chr(qstring, *p++);
  396. } else if (*(p + 1) == '%') {
  397. qstring_append_chr(qstring, '%');
  398. p += 2;
  399. } else {
  400. p = append_field(error, qstring, entry, p);
  401. }
  402. }
  403. return qstring;
  404. }
  405. QString *qerror_format(const char *fmt, QDict *error)
  406. {
  407. const QErrorStringTable *entry = NULL;
  408. int i;
  409. for (i = 0; qerror_table[i].error_fmt; i++) {
  410. if (strcmp(qerror_table[i].error_fmt, fmt) == 0) {
  411. entry = &qerror_table[i];
  412. break;
  413. }
  414. }
  415. return qerror_format_desc(error, entry);
  416. }
  417. /**
  418. * qerror_human(): Format QError data into human-readable string.
  419. */
  420. QString *qerror_human(const QError *qerror)
  421. {
  422. return qerror_format_desc(qerror->error, qerror->entry);
  423. }
  424. /**
  425. * qerror_print(): Print QError data
  426. *
  427. * This function will print the member 'desc' of the specified QError object,
  428. * it uses error_report() for this, so that the output is routed to the right
  429. * place (ie. stderr or Monitor's device).
  430. */
  431. void qerror_print(QError *qerror)
  432. {
  433. QString *qstring = qerror_human(qerror);
  434. loc_push_restore(&qerror->loc);
  435. error_report("%s", qstring_get_str(qstring));
  436. loc_pop(&qerror->loc);
  437. QDECREF(qstring);
  438. }
  439. void qerror_report_internal(const char *file, int linenr, const char *func,
  440. const char *fmt, ...)
  441. {
  442. va_list va;
  443. QError *qerror;
  444. va_start(va, fmt);
  445. qerror = qerror_from_info(file, linenr, func, fmt, &va);
  446. va_end(va);
  447. if (monitor_cur_is_qmp()) {
  448. monitor_set_error(cur_mon, qerror);
  449. } else {
  450. qerror_print(qerror);
  451. QDECREF(qerror);
  452. }
  453. }
  454. /* Evil... */
  455. struct Error
  456. {
  457. QDict *obj;
  458. const char *fmt;
  459. char *msg;
  460. };
  461. void qerror_report_err(Error *err)
  462. {
  463. QError *qerr;
  464. int i;
  465. qerr = qerror_new();
  466. loc_save(&qerr->loc);
  467. QINCREF(err->obj);
  468. qerr->error = err->obj;
  469. for (i = 0; qerror_table[i].error_fmt; i++) {
  470. if (strcmp(qerror_table[i].error_fmt, err->fmt) == 0) {
  471. qerr->entry = &qerror_table[i];
  472. break;
  473. }
  474. }
  475. if (monitor_cur_is_qmp()) {
  476. monitor_set_error(cur_mon, qerr);
  477. } else {
  478. qerror_print(qerr);
  479. QDECREF(qerr);
  480. }
  481. }
  482. /**
  483. * qobject_to_qerror(): Convert a QObject into a QError
  484. */
  485. QError *qobject_to_qerror(const QObject *obj)
  486. {
  487. if (qobject_type(obj) != QTYPE_QERROR) {
  488. return NULL;
  489. }
  490. return container_of(obj, QError, base);
  491. }
  492. /**
  493. * qerror_destroy_obj(): Free all memory allocated by a QError
  494. */
  495. static void qerror_destroy_obj(QObject *obj)
  496. {
  497. QError *qerr;
  498. assert(obj != NULL);
  499. qerr = qobject_to_qerror(obj);
  500. QDECREF(qerr->error);
  501. g_free(qerr);
  502. }