qerror.c 13 KB

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