[PATCH 5/8] vbox: Introduce vboxReportError()
Martin Kletzander
mkletzan at redhat.com
Tue Jan 24 09:22:47 UTC 2023
On Mon, Jan 23, 2023 at 10:35:52AM +0100, Michal Privoznik wrote:
>When a VirtualBox API fails it produced an exception. Until now,
>we did not have correct APIs wired up to get the exception and
>its error message. Thus, we were left with plain:
>
> virReportError("virtualbox API failed, rc=%08x", rc);
>
>This is not very user friendly because those rc values are hard
>to parse (e.g. some values are defined as a sum of a base value
>and some other value) and also it expects users to know where to
>look.
>
>But now that we have all machinery needed for querying
>exceptions, vboxReportError() can be introduced. The aim is to
>query VirtualBox exceptions and append them after the error
>message we intent to report. If the exception can't be queried
>successfully, this behaves exactly like virReportError().
>
>Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
>---
> src/vbox/vbox_common.c | 113 +++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 113 insertions(+)
>
>diff --git a/src/vbox/vbox_common.c b/src/vbox/vbox_common.c
>index bd77641d39..2a913e5975 100644
>--- a/src/vbox/vbox_common.c
>+++ b/src/vbox/vbox_common.c
>@@ -63,6 +63,119 @@ static struct _vboxDriver *vbox_driver;
> static struct _vboxDriver *vboxDriverObjNew(void);
> static __thread bool vboxDriverDisposed;
>
>+#define vboxReportError(errcode, ...) \
>+ vboxReportErrorHelper(data, errcode, __FILE__, \
>+ __FUNCTION__, __LINE__, __VA_ARGS__)
>+
>+static void G_GNUC_PRINTF(6, 7) G_GNUC_UNUSED
>+vboxReportErrorHelper(struct _vboxDriver *data,
>+ int errcode,
>+ const char *filename,
>+ const char *funcname,
>+ size_t linenr,
>+ const char *fmt, ...)
>+{
>+ int save_errno = errno;
>+ g_auto(virBuffer) errBuf = VIR_BUFFER_INITIALIZER;
>+ nsIException *ex = NULL;
>+ IVirtualBoxErrorInfo *ei = NULL;
>+ const nsID *vboxErrorInfoIID = NULL;
>+ bool multipleLines = false;
>+ nsresult rc;
>+ g_autofree char *detail = NULL;
>+
>+ if (fmt) {
>+ va_list args;
>+
>+ va_start(args, fmt);
>+ detail = g_strdup_vprintf(fmt, args);
>+ va_end(args);
>+ }
>+
>+ rc = gVBoxAPI.UPFN.GetException(data->pFuncs, &ex);
>+ if (NS_FAILED(rc) || !ex) {
>+ VIR_WARN("failed to get exception object");
>+ goto report;
>+ }
>+
>+ vboxErrorInfoIID = gVBoxAPI.UIVirtualBoxErrorInfo.GetIID();
>+ rc = VBOX_QUERY_INTERFACE(ex, vboxErrorInfoIID, (void **)&ei);
>+ if (NS_FAILED(rc) || !ei) {
>+ VIR_WARN("unable to typecast exception object");
>+ goto report;
>+ }
>+
>+ while (ei) {
>+ IVirtualBoxErrorInfo *ei_next = NULL;
>+ PRUnichar *componentUtf16 = NULL;
>+ char *componentUtf8 = NULL;
>+ PRUnichar *textUtf16 = NULL;
>+ char *textUtf8 = NULL;
>+
>+ rc = gVBoxAPI.UIVirtualBoxErrorInfo.GetComponent(ei, &componentUtf16);
>+ if (NS_FAILED(rc)) {
>+ VIR_WARN("failed to get error text");
Maybe s/text/component/ so that we know where to look if more things go
wrong. But wow on the complexity of getting a sensible error message
from vbox. I guess it'd be easier in C++.
>+ goto report;
>+ }
>+
>+ rc = gVBoxAPI.UIVirtualBoxErrorInfo.GetText(ei, &textUtf16);
>+ if (NS_FAILED(rc)) {
>+ VBOX_UTF16_FREE(componentUtf16);
>+ VIR_WARN("failed to get error text");
>+ goto report;
>+ }
>+
>+ VBOX_UTF16_TO_UTF8(componentUtf16, &componentUtf8);
>+ VBOX_UTF16_FREE(componentUtf16);
>+
>+ VBOX_UTF16_TO_UTF8(textUtf16, &textUtf8);
>+ VBOX_UTF16_FREE(textUtf16);
>+
>+ virBufferAsprintf(&errBuf, "%s: %s", componentUtf8, textUtf8);
>+ VBOX_UTF8_FREE(componentUtf8);
>+ VBOX_UTF8_FREE(textUtf8);
>+
>+ if (multipleLines)
>+ virBufferAddChar(&errBuf, '\n');
>+ else
>+ multipleLines = true;
>+
>+ rc = gVBoxAPI.UIVirtualBoxErrorInfo.GetNext(ei, &ei_next);
>+ if (NS_FAILED(rc)) {
>+ break;
>+ }
>+
>+ VBOX_RELEASE(ei);
>+ ei = ei_next;
>+ }
>+
>+ report:
>+ if (virBufferUse(&errBuf)) {
>+ const char *vboxErr = virBufferCurrentContent(&errBuf);
>+ g_autofree char *newDetail = NULL;
>+
>+ if (!detail || STREQ(detail, "")) {
>+ newDetail = g_strdup(vboxErr);
>+ } else {
>+ newDetail = g_strdup_printf("%s: %s", detail, vboxErr);
>+ }
>+
>+ VIR_FREE(detail);
>+ detail = g_steal_pointer(&newDetail);
>+ }
>+
>+ virReportErrorHelper(VIR_FROM_THIS, errcode, filename, funcname, linenr, "%s", detail);
>+
>+ rc = gVBoxAPI.UPFN.ClearException(data->pFuncs);
>+ if (NS_FAILED(rc)) {
>+ VIR_WARN("failed to clear exception");
>+ }
>+
>+ VBOX_RELEASE(ei);
>+ VBOX_RELEASE(ex);
>+ errno = save_errno;
>+}
>+
> static int
> vboxDomainDevicesDefPostParse(virDomainDeviceDef *dev G_GNUC_UNUSED,
> const virDomainDef *def G_GNUC_UNUSED,
>--
>2.39.1
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20230124/1cee18fe/attachment.sig>
More information about the libvir-list
mailing list