1 /*
2  * virerror.c: error handling and reporting code for libvirt
3  *
4  * Copyright (C) 2006-2019 Red Hat, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library.  If not, see
18  * <http://www.gnu.org/licenses/>.
19  */
20 
21 #include <config.h>
22 
23 #include <stdarg.h>
24 
25 #include "virerror.h"
26 #include "datatypes.h"
27 #include "viralloc.h"
28 #include "virlog.h"
29 #include "virthread.h"
30 #include "virstring.h"
31 #include "virbuffer.h"
32 
33 #define LIBVIRT_VIRERRORPRIV_H_ALLOW
34 #include "virerrorpriv.h"
35 #undef LIBVIRT_VIRERRORPRIV_H_ALLOW
36 
37 VIR_LOG_INIT("util.error");
38 
39 virThreadLocal virLastErr;
40 
41 virErrorFunc virErrorHandler = NULL;     /* global error handler */
42 void *virUserData = NULL;        /* associated data */
43 virErrorLogPriorityFunc virErrorLogPriorityFilter = NULL;
44 
virErrorLevelPriority(virErrorLevel level)45 static virLogPriority virErrorLevelPriority(virErrorLevel level)
46 {
47     switch (level) {
48         case VIR_ERR_NONE:
49             return VIR_LOG_INFO;
50         case VIR_ERR_WARNING:
51             return VIR_LOG_WARN;
52         case VIR_ERR_ERROR:
53             return VIR_LOG_ERROR;
54     }
55     return VIR_LOG_ERROR;
56 }
57 
58 
59 VIR_ENUM_DECL(virErrorDomain);
60 VIR_ENUM_IMPL(virErrorDomain,
61               VIR_ERR_DOMAIN_LAST,
62               "", /* 0 */
63               "Xen Driver",
64               "Xen Daemon",
65               "Xen Store",
66               "S-Expression",
67 
68               "XML Util", /* 5 */
69               "Domain",
70               "XML-RPC",
71               "Proxy Daemon",
72               "Config File",
73 
74               "QEMU Driver", /* 10 */
75               "Network",
76               "Test Driver",
77               "Remote Driver",
78               "OpenVZ Driver",
79 
80               "Xen XM Driver", /* 15 */
81               "Linux Statistics",
82               "LXC Driver",
83               "Storage Driver",
84               "Network Driver",
85 
86               "Domain Config", /* 20 */
87               "User Mode Linux Driver",
88               "Node Device Driver",
89               "Xen Inotify Driver",
90               "Security Driver",
91 
92               "VirtualBox Driver", /* 25 */
93               "Network Interface Driver",
94               "Open Nebula Driver",
95               "ESX Driver",
96               "Power Hypervisor Driver",
97 
98               "Secrets Driver", /* 30 */
99               "CPU Driver",
100               "XenAPI Driver",
101               "Network Filter Driver",
102               "Lifecycle Hook",
103 
104               "Domain Snapshot", /* 35 */
105               "Audit Utils",
106               "Sysinfo Utils",
107               "I/O Stream Utils",
108               "VMware Driver",
109 
110               "Event Loop", /* 40 */
111               "Xen Light Driver",
112               "Lock Driver",
113               "Hyper-V Driver",
114               "Capabilities Utils",
115 
116               "URI Utils", /* 45 */
117               "Authentication Utils",
118               "DBus Utils",
119               "Parallels Cloud Server",
120               "Device Config",
121 
122               "SSH transport layer", /* 50 */
123               "Lock Space",
124               "Init control",
125               "Identity",
126               "Cgroup",
127 
128               "Access Manager", /* 55 */
129               "Systemd",
130               "Bhyve",
131               "Crypto",
132               "Firewall",
133 
134               "Polkit", /* 60 */
135               "Thread jobs",
136               "Admin Interface",
137               "Log Manager",
138               "Xen XL Config",
139 
140               "Perf", /* 65 */
141               "Libssh transport layer",
142               "Resource control",
143               "FirewallD",
144               "Domain Checkpoint",
145 
146               "TPM", /* 70 */
147               "BPF",
148               "Cloud-Hypervisor Driver",
149 );
150 
151 
152 /*
153  * Internal helper that is called when a thread exits, to
154  * release the error object stored in the thread local
155  */
156 static void
virLastErrFreeData(void * data)157 virLastErrFreeData(void *data)
158 {
159     virErrorPtr err = data;
160     if (!err)
161         return;
162     virResetError(err);
163     g_free(err);
164 }
165 
166 
167 /**
168  * virErrorInitialize:
169  *
170  * Initialize the error data (per thread)
171  *
172  * Returns 0 in case of success, -1 in case of failure.
173  */
174 int
virErrorInitialize(void)175 virErrorInitialize(void)
176 {
177     return virThreadLocalInit(&virLastErr, virLastErrFreeData);
178 }
179 
180 
181 /*
182  * Internal helper to ensure a generic error code is stored
183  * in case where API returns failure, but forgot to set an
184  * error
185  */
186 static void
virErrorGenericFailure(virErrorPtr err)187 virErrorGenericFailure(virErrorPtr err)
188 {
189     err->code = VIR_ERR_INTERNAL_ERROR;
190     err->domain = VIR_FROM_NONE;
191     err->level = VIR_ERR_ERROR;
192     err->message = g_strdup(_("An error occurred, but the cause is unknown"));
193 }
194 
195 
196 /*
197  * Internal helper to perform a deep copy of an error
198  */
199 static int
virCopyError(virErrorPtr from,virErrorPtr to)200 virCopyError(virErrorPtr from,
201              virErrorPtr to)
202 {
203     int ret = 0;
204     if (!to)
205         return 0;
206     virResetError(to);
207     if (!from)
208         return 0;
209     to->code = from->code;
210     to->domain = from->domain;
211     to->level = from->level;
212     to->message = g_strdup(from->message);
213     to->str1 = g_strdup(from->str1);
214     to->str2 = g_strdup(from->str2);
215     to->str3 = g_strdup(from->str3);
216     to->int1 = from->int1;
217     to->int2 = from->int2;
218     /*
219      * Deliberately not setting 'conn', 'dom', 'net' references
220      */
221     return ret;
222 }
223 
224 
225 virErrorPtr
virErrorCopyNew(virErrorPtr err)226 virErrorCopyNew(virErrorPtr err)
227 {
228     virErrorPtr ret = g_new0(virError, 1);
229     virCopyError(err, ret);
230     return ret;
231 }
232 
233 
234 static virErrorPtr
virLastErrorObject(void)235 virLastErrorObject(void)
236 {
237     virErrorPtr err;
238     err = virThreadLocalGet(&virLastErr);
239     if (!err) {
240         err = g_new0(virError, 1);
241         if (virThreadLocalSet(&virLastErr, err) < 0)
242             g_clear_pointer(&err, g_free);
243     }
244     return err;
245 }
246 
247 
248 /**
249  * virGetLastError:
250  *
251  * Provide a pointer to the last error caught at the library level
252  *
253  * The error object is kept in thread local storage, so separate
254  * threads can safely access this concurrently.
255  *
256  * Returns a pointer to the last error or NULL if none occurred.
257  */
258 virErrorPtr
virGetLastError(void)259 virGetLastError(void)
260 {
261     virErrorPtr err = virLastErrorObject();
262     if (!err || err->code == VIR_ERR_OK)
263         return NULL;
264     return err;
265 }
266 
267 
268 /**
269  * virGetLastErrorCode:
270  *
271  * Get the most recent error code (enum virErrorNumber).
272  *
273  * Returns the most recent error code, or VIR_ERR_OK if none is set.
274  */
275 int
virGetLastErrorCode(void)276 virGetLastErrorCode(void)
277 {
278     virErrorPtr err = virLastErrorObject();
279     if (!err)
280         return VIR_ERR_OK;
281     return err->code;
282 }
283 
284 
285 /**
286  * virGetLastErrorDomain:
287  *
288  * Get the most recent error domain (enum virErrorDomain).
289  *
290  * Returns a numerical value of the most recent error's origin, or VIR_FROM_NONE
291  * if none is set.
292  */
293 int
virGetLastErrorDomain(void)294 virGetLastErrorDomain(void)
295 {
296     virErrorPtr err = virLastErrorObject();
297     if (!err)
298         return VIR_FROM_NONE;
299     return err->domain;
300 }
301 
302 
303 /**
304  * virGetLastErrorMessage:
305  *
306  * Get the most recent error message
307  *
308  * Returns the most recent error message string in this
309  * thread, or a generic message if none is set
310  */
311 const char *
virGetLastErrorMessage(void)312 virGetLastErrorMessage(void)
313 {
314     virErrorPtr err = virLastErrorObject();
315     if (err && err->code == VIR_ERR_OK)
316         return _("no error");
317     if (!err || !err->message)
318         return _("unknown error");
319     return err->message;
320 }
321 
322 
323 /**
324  * virSetError:
325  * @newerr: previously saved error object
326  *
327  * Set the current error from a previously saved error object
328  *
329  * Can be used to re-set an old error, which may have been squashed by
330  * other functions (like cleanup routines).
331  *
332  * Returns 0 on success, -1 on failure.  Leaves errno unchanged.
333  */
334 int
virSetError(virErrorPtr newerr)335 virSetError(virErrorPtr newerr)
336 {
337     virErrorPtr err;
338     int saved_errno = errno;
339     int ret = -1;
340 
341     err = virLastErrorObject();
342     if (!err)
343         goto cleanup;
344 
345     virResetError(err);
346     ret = virCopyError(newerr, err);
347  cleanup:
348     errno = saved_errno;
349     return ret;
350 }
351 
352 /**
353  * virCopyLastError:
354  * @to: target to receive the copy
355  *
356  * Copy the content of the last error caught at the library level
357  *
358  * The error object is kept in thread local storage, so separate
359  * threads can safely access this concurrently.
360  *
361  * One will need to free the result with virResetError()
362  *
363  * Returns error code or -1 in case of parameter error.
364  */
365 int
virCopyLastError(virErrorPtr to)366 virCopyLastError(virErrorPtr to)
367 {
368     virErrorPtr err = virLastErrorObject();
369 
370     if (!to)
371         return -1;
372 
373     /* We can't guarantee caller has initialized it to zero */
374     memset(to, 0, sizeof(*to));
375     if (err) {
376         virCopyError(err, to);
377     } else {
378         virResetError(to);
379         to->code = VIR_ERR_NO_MEMORY;
380         to->domain = VIR_FROM_NONE;
381         to->level = VIR_ERR_ERROR;
382     }
383     return to->code;
384 }
385 
386 /**
387  * virSaveLastError:
388  *
389  * Save the last error into a new error object.  On success, errno is
390  * unchanged; on failure, errno is ENOMEM.
391  *
392  * Returns a pointer to the copied error or NULL if allocation failed.
393  * It is the caller's responsibility to free the error with
394  * virFreeError().
395  */
396 virErrorPtr
virSaveLastError(void)397 virSaveLastError(void)
398 {
399     virErrorPtr to;
400     int saved_errno = errno;
401 
402     to = g_new0(virError, 1);
403 
404     virCopyLastError(to);
405     errno = saved_errno;
406     return to;
407 }
408 
409 
410 /**
411  * virErrorPreserveLast:
412  * @saveerr: pointer to virErrorPtr for storing last error object
413  *
414  * Preserves the currently set last error (for the thread) into @saveerr so that
415  * it can be restored via virErrorRestore(). @saveerr must be passed to
416  * virErrorRestore()
417  */
418 void
virErrorPreserveLast(virErrorPtr * saveerr)419 virErrorPreserveLast(virErrorPtr *saveerr)
420 {
421     int saved_errno = errno;
422     virErrorPtr lasterr = virGetLastError();
423 
424     *saveerr = NULL;
425 
426     if (lasterr)
427         *saveerr = virErrorCopyNew(lasterr);
428 
429     errno = saved_errno;
430 }
431 
432 
433 /**
434  * virErrorRestore:
435  * @savederr: error object holding saved error
436  *
437  * Restores the error passed via @savederr and clears associated memory.
438  */
439 void
virErrorRestore(virErrorPtr * savederr)440 virErrorRestore(virErrorPtr *savederr)
441 {
442     int saved_errno = errno;
443 
444     if (!*savederr)
445         return;
446 
447     virSetError(*savederr);
448     virFreeError(*savederr);
449     *savederr = NULL;
450     errno = saved_errno;
451 }
452 
453 
454 /**
455  * virResetError:
456  * @err: pointer to the virError to clean up
457  *
458  * Reset the error being pointed to
459  */
460 void
virResetError(virErrorPtr err)461 virResetError(virErrorPtr err)
462 {
463     if (err == NULL)
464         return;
465     VIR_FREE(err->message);
466     VIR_FREE(err->str1);
467     VIR_FREE(err->str2);
468     VIR_FREE(err->str3);
469     memset(err, 0, sizeof(virError));
470 }
471 
472 /**
473  * virFreeError:
474  * @err: error to free
475  *
476  * Resets and frees the given error.
477  */
478 void
virFreeError(virErrorPtr err)479 virFreeError(virErrorPtr err)
480 {
481     virResetError(err);
482     g_free(err);
483 }
484 
485 /**
486  * virResetLastError:
487  *
488  * Reset the last error caught at the library level.
489  *
490  * The error object is kept in thread local storage, so separate
491  * threads can safely access this concurrently, only resetting
492  * their own error object.
493  */
494 void
virResetLastError(void)495 virResetLastError(void)
496 {
497     virErrorPtr err = virLastErrorObject();
498     if (err)
499         virResetError(err);
500 }
501 
502 /**
503  * virConnGetLastError:
504  * @conn: pointer to the hypervisor connection
505  *
506  * Provide a pointer to the last error caught on that connection
507  *
508  * This method is not protected against access from multiple
509  * threads. In a multi-threaded application, always use the
510  * global virGetLastError() API which is backed by thread
511  * local storage.
512  *
513  * If the connection object was discovered to be invalid by
514  * an API call, then the error will be reported against the
515  * global error object.
516  *
517  * Since 0.6.0, all errors reported in the per-connection object
518  * are also duplicated in the global error object. As such an
519  * application can always use virGetLastError(). This method
520  * remains for backwards compatibility.
521  *
522  * Returns a pointer to the last error or NULL if none occurred.
523  */
524 virErrorPtr
virConnGetLastError(virConnectPtr conn)525 virConnGetLastError(virConnectPtr conn)
526 {
527     if (conn == NULL)
528         return NULL;
529     return &conn->err;
530 }
531 
532 /**
533  * virConnCopyLastError:
534  * @conn: pointer to the hypervisor connection
535  * @to: target to receive the copy
536  *
537  * Copy the content of the last error caught on that connection
538  *
539  * This method is not protected against access from multiple
540  * threads. In a multi-threaded application, always use the
541  * global virGetLastError() API which is backed by thread
542  * local storage.
543  *
544  * If the connection object was discovered to be invalid by
545  * an API call, then the error will be reported against the
546  * global error object.
547  *
548  * Since 0.6.0, all errors reported in the per-connection object
549  * are also duplicated in the global error object. As such an
550  * application can always use virGetLastError(). This method
551  * remains for backwards compatibility.
552  *
553  * One will need to free the result with virResetError()
554  *
555  * Returns 0 if no error was found and the error code otherwise and -1 in case
556  *         of parameter error.
557  */
558 int
virConnCopyLastError(virConnectPtr conn,virErrorPtr to)559 virConnCopyLastError(virConnectPtr conn, virErrorPtr to)
560 {
561     /* We can't guarantee caller has initialized it to zero */
562     memset(to, 0, sizeof(*to));
563 
564     if (conn == NULL)
565         return -1;
566     virObjectLock(conn);
567     if (conn->err.code == VIR_ERR_OK)
568         virResetError(to);
569     else
570         virCopyError(&conn->err, to);
571     virObjectUnlock(conn);
572     return to->code;
573 }
574 
575 /**
576  * virConnResetLastError:
577  * @conn: pointer to the hypervisor connection
578  *
579  * The error object is kept in thread local storage, so separate
580  * threads can safely access this concurrently.
581  *
582  * Reset the last error caught on that connection
583  */
584 void
virConnResetLastError(virConnectPtr conn)585 virConnResetLastError(virConnectPtr conn)
586 {
587     if (conn == NULL)
588         return;
589     virObjectLock(conn);
590     virResetError(&conn->err);
591     virObjectUnlock(conn);
592 }
593 
594 /**
595  * virSetErrorFunc:
596  * @userData: pointer to the user data provided in the handler callback
597  * @handler: the function to get called in case of error or NULL
598  *
599  * Set a library global error handling function, if @handler is NULL,
600  * it will reset to default printing on stderr. The error raised there
601  * are those for which no handler at the connection level could caught.
602  */
603 void
virSetErrorFunc(void * userData,virErrorFunc handler)604 virSetErrorFunc(void *userData, virErrorFunc handler)
605 {
606     virErrorHandler = handler;
607     virUserData = userData;
608 }
609 
610 /**
611  * virConnSetErrorFunc:
612  * @conn: pointer to the hypervisor connection
613  * @userData: pointer to the user data provided in the handler callback
614  * @handler: the function to get called in case of error or NULL
615  *
616  * Set a connection error handling function, if @handler is NULL
617  * it will reset to default which is to pass error back to the global
618  * library handler.
619  */
620 void
virConnSetErrorFunc(virConnectPtr conn,void * userData,virErrorFunc handler)621 virConnSetErrorFunc(virConnectPtr conn, void *userData,
622                     virErrorFunc handler)
623 {
624     if (conn == NULL)
625         return;
626     virObjectLock(conn);
627     conn->handler = handler;
628     conn->userData = userData;
629     virObjectUnlock(conn);
630 }
631 
632 /**
633  * virDefaultErrorFunc:
634  * @err: pointer to the error.
635  *
636  * Default routine reporting an error to stderr.
637  */
638 void
virDefaultErrorFunc(virErrorPtr err)639 virDefaultErrorFunc(virErrorPtr err)
640 {
641     const char *lvl = "", *dom = "", *domain = "", *network = "";
642     int len;
643 
644     if ((err == NULL) || (err->code == VIR_ERR_OK))
645         return;
646     switch (err->level) {
647         case VIR_ERR_NONE:
648             lvl = "";
649             break;
650         case VIR_ERR_WARNING:
651             lvl = _("warning");
652             break;
653         case VIR_ERR_ERROR:
654             lvl = _("error");
655             break;
656     }
657     dom = virErrorDomainTypeToString(err->domain);
658     if (!dom)
659         dom = "Unknown";
660     if ((err->dom != NULL) && (err->code != VIR_ERR_INVALID_DOMAIN)) {
661         domain = err->dom->name;
662     } else if ((err->net != NULL) && (err->code != VIR_ERR_INVALID_NETWORK)) {
663         network = err->net->name;
664     }
665     len = strlen(err->message);
666     if ((err->domain == VIR_FROM_XML) && (err->code == VIR_ERR_XML_DETAIL) &&
667         (err->int1 != 0))
668         fprintf(stderr, "libvirt: %s %s %s%s: line %d: %s",
669                 dom, lvl, domain, network, err->int1, err->message);
670     else if ((len == 0) || (err->message[len - 1] != '\n'))
671         fprintf(stderr, "libvirt: %s %s %s%s: %s\n",
672                 dom, lvl, domain, network, err->message);
673     else
674         fprintf(stderr, "libvirt: %s %s %s%s: %s",
675                 dom, lvl, domain, network, err->message);
676 }
677 
678 /**
679  * virDispatchError:
680  * @conn: pointer to the hypervisor connection
681  *
682  * Internal helper to do final stage of error
683  * reporting in public APIs.
684  *
685  *  - Copy the global error to per-connection error if needed
686  *  - Set a generic error message if none is already set
687  *  - Invoke the error callback functions
688  */
689 void
virDispatchError(virConnectPtr conn)690 virDispatchError(virConnectPtr conn)
691 {
692     virErrorPtr err = virLastErrorObject();
693     virErrorFunc handler = virErrorHandler;
694     void *userData = virUserData;
695 
696     /* Can only happen on OOM.  */
697     if (!err)
698         return;
699 
700     /* Set a generic error message if none is already set */
701     if (err->code == VIR_ERR_OK)
702         virErrorGenericFailure(err);
703 
704     /* Copy the global error to per-connection error if needed */
705     if (conn) {
706         virObjectLock(conn);
707         virCopyError(err, &conn->err);
708 
709         if (conn->handler != NULL) {
710             handler = conn->handler;
711             userData = conn->userData;
712         }
713         virObjectUnlock(conn);
714     }
715 
716     /* Invoke the error callback functions */
717     if (handler != NULL) {
718         (handler)(userData, err);
719     } else {
720         virDefaultErrorFunc(err);
721     }
722 }
723 
724 
725 /*
726  * Reports an error through the logging subsystem
727  */
728 static
virRaiseErrorLog(const char * filename,const char * funcname,size_t linenr,virErrorPtr err,virLogMetadata * meta)729 void virRaiseErrorLog(const char *filename,
730                       const char *funcname,
731                       size_t linenr,
732                       virErrorPtr err,
733                       virLogMetadata *meta)
734 {
735     int priority;
736 
737     /*
738      * Hook up the error or warning to the logging facility
739      */
740     priority = virErrorLevelPriority(err->level);
741     if (virErrorLogPriorityFilter)
742         priority = virErrorLogPriorityFilter(err, priority);
743 
744     /* We don't want to pollute stderr if no logging outputs
745      * are explicitly requested by the user, since the default
746      * error function already pollutes stderr and most apps
747      * hate & thus disable that too. If the daemon has set
748      * a priority filter though, we should always forward
749      * all errors to the logging code.
750      */
751     if (virLogGetNbOutputs() > 0 ||
752         virErrorLogPriorityFilter)
753         virLogMessage(&virLogSelf,
754                       priority,
755                       filename, linenr, funcname,
756                       meta, "%s", err->message);
757 }
758 
759 
760 /**
761  * virRaiseErrorInternal:
762  *
763  * Internal helper to assign and raise error. Note that @msgarg, @str1arg,
764  * @str2arg and @str3arg if non-NULL must be heap-allocated strings and are
765  * stolen and freed by this function.
766  */
767 static void
virRaiseErrorInternal(const char * filename,const char * funcname,size_t linenr,int domain,int code,virErrorLevel level,char * msgarg,char * str1arg,char * str2arg,char * str3arg,int int1,int int2)768 virRaiseErrorInternal(const char *filename,
769                       const char *funcname,
770                       size_t linenr,
771                       int domain,
772                       int code,
773                       virErrorLevel level,
774                       char *msgarg,
775                       char *str1arg,
776                       char *str2arg,
777                       char *str3arg,
778                       int int1,
779                       int int2)
780 {
781     g_autofree char *msg = msgarg;
782     g_autofree char *str1 = str1arg;
783     g_autofree char *str2 = str2arg;
784     g_autofree char *str3 = str3arg;
785     virErrorPtr to;
786     virLogMetadata meta[] = {
787         { .key = "LIBVIRT_DOMAIN", .s = NULL, .iv = domain },
788         { .key = "LIBVIRT_CODE", .s = NULL, .iv = code },
789         { .key = NULL },
790     };
791 
792     /*
793      * All errors are recorded in thread local storage
794      * For compatibility, public API calls will copy them
795      * to the per-connection error object when necessary
796      */
797     if (!(to = virLastErrorObject()))
798         return;
799 
800     virResetError(to);
801 
802     if (code == VIR_ERR_OK)
803         return;
804 
805     if (!msg)
806         msg = g_strdup(_("No error message provided"));
807 
808     /* Deliberately not setting conn, dom & net fields since
809      * they are utterly unsafe. */
810     to->domain = domain;
811     to->code = code;
812     to->message = g_steal_pointer(&msg);
813     to->level = level;
814     to->str1 = g_steal_pointer(&str1);
815     to->str2 = g_steal_pointer(&str2);
816     to->str3 = g_steal_pointer(&str3);
817     to->int1 = int1;
818     to->int2 = int2;
819 
820     virRaiseErrorLog(filename, funcname, linenr, to, meta);
821 }
822 
823 
824 /**
825  * virRaiseErrorFull:
826  * @filename: filename where error was raised
827  * @funcname: function name where error was raised
828  * @linenr: line number where error was raised
829  * @domain: the virErrorDomain indicating where it's coming from
830  * @code: the virErrorNumber code for the error
831  * @level: the virErrorLevel for the error
832  * @str1: extra string info
833  * @str2: extra string info
834  * @str3: extra string info
835  * @int1: extra int info
836  * @int2: extra int info
837  * @fmt:  the message to display/transmit
838  * @...:  extra parameters for the message display
839  *
840  * Internal routine called when an error is detected. It will raise it
841  * immediately if a callback is found and store it for later handling.
842  */
843 void
virRaiseErrorFull(const char * filename,const char * funcname,size_t linenr,int domain,int code,virErrorLevel level,const char * str1,const char * str2,const char * str3,int int1,int int2,const char * fmt,...)844 virRaiseErrorFull(const char *filename,
845                   const char *funcname,
846                   size_t linenr,
847                   int domain,
848                   int code,
849                   virErrorLevel level,
850                   const char *str1,
851                   const char *str2,
852                   const char *str3,
853                   int int1,
854                   int int2,
855                   const char *fmt, ...)
856 {
857     int save_errno = errno;
858     char *msg = NULL;
859 
860     if (fmt) {
861         va_list ap;
862 
863         va_start(ap, fmt);
864         msg = g_strdup_vprintf(fmt, ap);
865         va_end(ap);
866     }
867 
868     virRaiseErrorInternal(filename, funcname, linenr,
869                           domain, code, level,
870                           msg, g_strdup(str1), g_strdup(str2), g_strdup(str3),
871                           int1, int2);
872 
873     errno = save_errno;
874 }
875 
876 
877 /**
878  * virRaiseErrorObject:
879  * @filename: filename where error was raised
880  * @funcname: function name where error was raised
881  * @linenr: line number where error was raised
882  * @newerr: the error object to report
883  *
884  * Sets the thread local error object to be a copy of
885  * @newerr and logs the error
886  *
887  * This is like virRaiseErrorFull, except that it accepts the
888  * error information via a pre-filled virErrorPtr object
889  *
890  * This is like virSetError, except that it will trigger the
891  * logging callbacks.
892  *
893  * The caller must clear the @newerr instance afterwards, since
894  * it will be copied into the thread local error.
895  */
virRaiseErrorObject(const char * filename,const char * funcname,size_t linenr,virErrorPtr newerr)896 void virRaiseErrorObject(const char *filename,
897                          const char *funcname,
898                          size_t linenr,
899                          virErrorPtr newerr)
900 {
901     int saved_errno = errno;
902     virErrorPtr err;
903     virLogMetadata meta[] = {
904         { .key = "LIBVIRT_DOMAIN", .s = NULL, .iv = newerr->domain },
905         { .key = "LIBVIRT_CODE", .s = NULL, .iv = newerr->code },
906         { .key = NULL },
907     };
908 
909     err = virLastErrorObject();
910     if (!err)
911         goto cleanup;
912 
913     virResetError(err);
914     virCopyError(newerr, err);
915     virRaiseErrorLog(filename, funcname, linenr,
916                      err, meta);
917  cleanup:
918     errno = saved_errno;
919 }
920 
921 
922 typedef struct {
923     const char *msg;
924     const char *msginfo;
925 } virErrorMsgTuple;
926 
927 
928 static const virErrorMsgTuple virErrorMsgStrings[] = {
929     [VIR_ERR_OK] = { NULL, NULL },
930     [VIR_ERR_INTERNAL_ERROR] = {
931         N_("internal error"),
932         N_("internal error: %s") },
933     [VIR_ERR_NO_MEMORY] = {
934         N_("out of memory"),
935         N_("out of memory: %s") },
936     [VIR_ERR_NO_SUPPORT] = {
937         N_("this function is not supported by the connection driver"),
938         N_("this function is not supported by the connection driver: %s") },
939     [VIR_ERR_UNKNOWN_HOST] = {
940         N_("unknown host"),
941         N_("unknown host %s") },
942     [VIR_ERR_NO_CONNECT] = {
943         N_("no connection driver available"),
944         N_("no connection driver available for %s") },
945     [VIR_ERR_INVALID_CONN] = {
946         N_("invalid connection pointer in"),
947         N_("invalid connection pointer in %s") },
948     [VIR_ERR_INVALID_DOMAIN] = {
949         N_("invalid domain pointer in"),
950         N_("invalid domain pointer in %s") },
951     [VIR_ERR_INVALID_ARG] = {
952         N_("invalid argument"),
953         N_("invalid argument: %s") },
954     [VIR_ERR_OPERATION_FAILED] = {
955         N_("operation failed"),
956         N_("operation failed: %s") },
957     [VIR_ERR_GET_FAILED] = {
958         N_("GET operation failed"),
959         N_("GET operation failed: %s") },
960     [VIR_ERR_POST_FAILED] = {
961         N_("POST operation failed"),
962         N_("POST operation failed: %s") },
963     [VIR_ERR_HTTP_ERROR] = {
964         N_("got unknown HTTP error code"),
965         N_("got unknown HTTP error code %s") },
966     [VIR_ERR_SEXPR_SERIAL] = {
967         N_("failed to serialize S-Expr"),
968         N_("failed to serialize S-Expr: %s") },
969     [VIR_ERR_NO_XEN] = {
970         N_("could not use Xen hypervisor entry"),
971         N_("could not use Xen hypervisor entry %s") },
972     [VIR_ERR_XEN_CALL] = {
973         N_("failed Xen syscall"),
974         N_("failed Xen syscall %s") },
975     [VIR_ERR_OS_TYPE] = {
976         N_("unknown OS type"),
977         N_("unknown OS type %s") },
978     [VIR_ERR_NO_KERNEL] = {
979         N_("missing kernel information"),
980         N_("missing kernel information: %s") },
981     [VIR_ERR_NO_ROOT] = {
982         N_("missing root device information"),
983         N_("missing root device information in %s") },
984     [VIR_ERR_NO_SOURCE] = {
985         N_("missing source information for device"),
986         N_("missing source information for device %s") },
987     [VIR_ERR_NO_TARGET] = {
988         N_("missing target information for device"),
989         N_("missing target information for device %s") },
990     [VIR_ERR_NO_NAME] = {
991         N_("missing name information"),
992         N_("missing name information in %s") },
993     [VIR_ERR_NO_OS] = {
994         N_("missing operating system information"),
995         N_("missing operating system information for %s") },
996     [VIR_ERR_NO_DEVICE] = {
997         N_("missing devices information"),
998         N_("missing devices information for %s") },
999     [VIR_ERR_NO_XENSTORE] = {
1000         N_("could not connect to Xen Store"),
1001         N_("could not connect to Xen Store %s") },
1002     [VIR_ERR_DRIVER_FULL] = {
1003         N_("too many drivers registered"),
1004         N_("too many drivers registered in %s") },
1005     [VIR_ERR_CALL_FAILED] = {
1006         N_("library call failed"),
1007         N_("library call failed: %s") },
1008     [VIR_ERR_XML_ERROR] = {
1009         N_("XML description is invalid or not well formed"),
1010         N_("XML error: %s") },
1011     [VIR_ERR_DOM_EXIST] = {
1012         N_("this domain exists already"),
1013         N_("domain %s exists already") },
1014     [VIR_ERR_OPERATION_DENIED] = {
1015         N_("operation forbidden for read only access"),
1016         N_("operation forbidden: %s") },
1017     [VIR_ERR_OPEN_FAILED] = {
1018         N_("failed to open configuration file"),
1019         N_("failed to open configuration file %s") },
1020     [VIR_ERR_READ_FAILED] = {
1021         N_("failed to read configuration file"),
1022         N_("failed to read configuration file %s") },
1023     [VIR_ERR_PARSE_FAILED] = {
1024         N_("failed to parse configuration file"),
1025         N_("failed to parse configuration file %s") },
1026     [VIR_ERR_CONF_SYNTAX] = {
1027         N_("configuration file syntax error"),
1028         N_("configuration file syntax error: %s") },
1029     [VIR_ERR_WRITE_FAILED] = {
1030         N_("failed to write configuration file"),
1031         N_("failed to write configuration file: %s") },
1032     [VIR_ERR_XML_DETAIL] = {
1033         N_("parser error"),
1034         "%s" },
1035     [VIR_ERR_INVALID_NETWORK] = {
1036         N_("invalid network pointer in"),
1037         N_("invalid network pointer in %s") },
1038     [VIR_ERR_NETWORK_EXIST] = {
1039         N_("this network exists already"),
1040         N_("network %s exists already") },
1041     [VIR_ERR_SYSTEM_ERROR] = {
1042         N_("system call error"),
1043         "%s" },
1044     [VIR_ERR_RPC] = {
1045         N_("RPC error"),
1046         "%s" },
1047     [VIR_ERR_GNUTLS_ERROR] = {
1048         N_("GNUTLS call error"),
1049         "%s" },
1050     [VIR_WAR_NO_NETWORK] = {
1051         N_("Failed to find the network"),
1052         N_("Failed to find the network: %s") },
1053     [VIR_ERR_NO_DOMAIN] = {
1054         N_("Domain not found"),
1055         N_("Domain not found: %s") },
1056     [VIR_ERR_NO_NETWORK] = {
1057         N_("Network not found"),
1058         N_("Network not found: %s") },
1059     [VIR_ERR_INVALID_MAC] = {
1060         N_("invalid MAC address"),
1061         N_("invalid MAC address: %s") },
1062     [VIR_ERR_AUTH_FAILED] = {
1063         N_("authentication failed"),
1064         N_("authentication failed: %s") },
1065     [VIR_ERR_INVALID_STORAGE_POOL] = {
1066         N_("invalid storage pool pointer in"),
1067         N_("invalid storage pool pointer in %s") },
1068     [VIR_ERR_INVALID_STORAGE_VOL] = {
1069         N_("invalid storage volume pointer in"),
1070         N_("invalid storage volume pointer in %s") },
1071     [VIR_WAR_NO_STORAGE] = {
1072         N_("Failed to find a storage driver"),
1073         N_("Failed to find a storage driver: %s") },
1074     [VIR_ERR_NO_STORAGE_POOL] = {
1075         N_("Storage pool not found"),
1076         N_("Storage pool not found: %s") },
1077     [VIR_ERR_NO_STORAGE_VOL] = {
1078         N_("Storage volume not found"),
1079         N_("Storage volume not found: %s") },
1080     [VIR_WAR_NO_NODE] = {
1081         N_("Failed to find a node driver"),
1082         N_("Failed to find a node driver: %s") },
1083     [VIR_ERR_INVALID_NODE_DEVICE] = {
1084         N_("invalid node device pointer"),
1085         N_("invalid node device pointer in %s") },
1086     [VIR_ERR_NO_NODE_DEVICE] = {
1087         N_("Node device not found"),
1088         N_("Node device not found: %s") },
1089     [VIR_ERR_NO_SECURITY_MODEL] = {
1090         N_("Security model not found"),
1091         N_("Security model not found: %s") },
1092     [VIR_ERR_OPERATION_INVALID] = {
1093         N_("Requested operation is not valid"),
1094         N_("Requested operation is not valid: %s") },
1095     [VIR_WAR_NO_INTERFACE] = {
1096         N_("Failed to find the interface"),
1097         N_("Failed to find the interface: %s") },
1098     [VIR_ERR_NO_INTERFACE] = {
1099         N_("Interface not found"),
1100         N_("Interface not found: %s") },
1101     [VIR_ERR_INVALID_INTERFACE] = {
1102         N_("invalid interface pointer in"),
1103         N_("invalid interface pointer in %s") },
1104     [VIR_ERR_MULTIPLE_INTERFACES] = {
1105         N_("multiple matching interfaces found"),
1106         N_("multiple matching interfaces found: %s") },
1107     [VIR_WAR_NO_NWFILTER] = {
1108         N_("Failed to start the nwfilter driver"),
1109         N_("Failed to start the nwfilter driver: %s") },
1110     [VIR_ERR_INVALID_NWFILTER] = {
1111         N_("Invalid network filter"),
1112         N_("Invalid network filter: %s") },
1113     [VIR_ERR_NO_NWFILTER] = {
1114         N_("Network filter not found"),
1115         N_("Network filter not found: %s") },
1116     [VIR_ERR_BUILD_FIREWALL] = {
1117         N_("Error while building firewall"),
1118         N_("Error while building firewall: %s") },
1119     [VIR_WAR_NO_SECRET] = {
1120         N_("Failed to find a secret storage driver"),
1121         N_("Failed to find a secret storage driver: %s") },
1122     [VIR_ERR_INVALID_SECRET] = {
1123         N_("Invalid secret"),
1124         N_("Invalid secret: %s") },
1125     [VIR_ERR_NO_SECRET] = {
1126         N_("Secret not found"),
1127         N_("Secret not found: %s") },
1128     [VIR_ERR_CONFIG_UNSUPPORTED] = {
1129         N_("unsupported configuration"),
1130         N_("unsupported configuration: %s") },
1131     [VIR_ERR_OPERATION_TIMEOUT] = {
1132         N_("Timed out during operation"),
1133         N_("Timed out during operation: %s") },
1134     [VIR_ERR_MIGRATE_PERSIST_FAILED] = {
1135         N_("Failed to make domain persistent after migration"),
1136         N_("Failed to make domain persistent after migration: %s") },
1137     [VIR_ERR_HOOK_SCRIPT_FAILED] = {
1138         N_("Hook script execution failed"),
1139         N_("Hook script execution failed: %s") },
1140     [VIR_ERR_INVALID_DOMAIN_SNAPSHOT] = {
1141         N_("Invalid domain snapshot"),
1142         N_("Invalid domain snapshot: %s") },
1143     [VIR_ERR_NO_DOMAIN_SNAPSHOT] = {
1144         N_("Domain snapshot not found"),
1145         N_("Domain snapshot not found: %s") },
1146     [VIR_ERR_INVALID_STREAM] = {
1147         N_("invalid stream pointer"),
1148         N_("invalid stream pointer in %s") },
1149     [VIR_ERR_ARGUMENT_UNSUPPORTED] = {
1150         N_("argument unsupported"),
1151         N_("argument unsupported: %s") },
1152     [VIR_ERR_STORAGE_PROBE_FAILED] = {
1153         N_("Storage pool probe failed"),
1154         N_("Storage pool probe failed: %s") },
1155     [VIR_ERR_STORAGE_POOL_BUILT] = {
1156         N_("Storage pool already built"),
1157         N_("Storage pool already built: %s") },
1158     [VIR_ERR_SNAPSHOT_REVERT_RISKY] = {
1159         N_("revert requires force"),
1160         N_("revert requires force: %s") },
1161     [VIR_ERR_OPERATION_ABORTED] = {
1162         N_("operation aborted"),
1163         N_("operation aborted: %s") },
1164     [VIR_ERR_AUTH_CANCELLED] = {
1165         N_("authentication cancelled"),
1166         N_("authentication cancelled: %s") },
1167     [VIR_ERR_NO_DOMAIN_METADATA] = {
1168         N_("metadata not found"),
1169         N_("metadata not found: %s") },
1170     [VIR_ERR_MIGRATE_UNSAFE] = {
1171         N_("Unsafe migration"),
1172         N_("Unsafe migration: %s") },
1173     [VIR_ERR_OVERFLOW] = {
1174         N_("numerical overflow"),
1175         N_("numerical overflow: %s") },
1176     [VIR_ERR_BLOCK_COPY_ACTIVE] = {
1177         N_("block copy still active"),
1178         N_("block copy still active: %s") },
1179     [VIR_ERR_OPERATION_UNSUPPORTED] = {
1180         N_("Operation not supported"),
1181         N_("Operation not supported: %s") },
1182     [VIR_ERR_SSH] = {
1183         N_("SSH transport error"),
1184         N_("SSH transport error: %s") },
1185     [VIR_ERR_AGENT_UNRESPONSIVE] = {
1186         N_("Guest agent is not responding"),
1187         N_("Guest agent is not responding: %s") },
1188     [VIR_ERR_RESOURCE_BUSY] = {
1189         N_("resource busy"),
1190         N_("resource busy: %s") },
1191     [VIR_ERR_ACCESS_DENIED] = {
1192         N_("access denied"),
1193         N_("access denied: %s") },
1194     [VIR_ERR_DBUS_SERVICE] = {
1195         N_("error from service"),
1196         N_("error from service: %s") },
1197     [VIR_ERR_STORAGE_VOL_EXIST] = {
1198         N_("this storage volume exists already"),
1199         N_("storage volume %s exists already") },
1200     [VIR_ERR_CPU_INCOMPATIBLE] = {
1201         N_("the CPU is incompatible with host CPU"),
1202         N_("the CPU is incompatible with host CPU: %s") },
1203     [VIR_ERR_XML_INVALID_SCHEMA] = {
1204         N_("XML document failed to validate against schema"),
1205         N_("XML document failed to validate against schema: %s") },
1206     [VIR_ERR_MIGRATE_FINISH_OK] = {
1207         N_("migration successfully aborted"),
1208         N_("migration successfully aborted: %s") },
1209     [VIR_ERR_AUTH_UNAVAILABLE] = {
1210         N_("authentication unavailable"),
1211         N_("authentication unavailable: %s") },
1212     [VIR_ERR_NO_SERVER] = {
1213         N_("Server not found"),
1214         N_("Server not found: %s") },
1215     [VIR_ERR_NO_CLIENT] = {
1216         N_("Client not found"),
1217         N_("Client not found: %s") },
1218     [VIR_ERR_AGENT_UNSYNCED] = {
1219         N_("guest agent replied with wrong id to guest-sync command"),
1220         N_("guest agent replied with wrong id to guest-sync command: %s") },
1221     [VIR_ERR_LIBSSH] = {
1222         N_("libssh transport error"),
1223         N_("libssh transport error: %s") },
1224     [VIR_ERR_DEVICE_MISSING] = {
1225         N_("device not found"),
1226         N_("device not found: %s") },
1227     [VIR_ERR_INVALID_NWFILTER_BINDING] = {
1228         N_("Invalid network filter binding"),
1229         N_("Invalid network filter binding: %s") },
1230     [VIR_ERR_NO_NWFILTER_BINDING] = {
1231         N_("Network filter binding not found"),
1232         N_("Network filter binding not found: %s") },
1233     [VIR_ERR_INVALID_DOMAIN_CHECKPOINT] = {
1234         N_("Invalid domain checkpoint"),
1235         N_("Invalid domain checkpoint: %s") },
1236     [VIR_ERR_NO_DOMAIN_CHECKPOINT] = {
1237         N_("Domain checkpoint not found"),
1238         N_("Domain checkpoint not found: %s") },
1239     [VIR_ERR_NO_DOMAIN_BACKUP] = {
1240         N_("Domain backup job id not found"),
1241         N_("Domain backup job id not found: %s") },
1242     [VIR_ERR_INVALID_NETWORK_PORT] = {
1243         N_("Invalid network port pointer"),
1244         N_("Invalid network port pointer: %s") },
1245     [VIR_ERR_NETWORK_PORT_EXIST] = {
1246         N_("this network port exists already"),
1247         N_("network port %s exists already") },
1248     [VIR_ERR_NO_NETWORK_PORT] = {
1249         N_("network port not found"),
1250         N_("network port not found: %s") },
1251     [VIR_ERR_NO_HOSTNAME] = {
1252         N_("no hostname found"),
1253         N_("no hostname found: %s") },
1254     [VIR_ERR_CHECKPOINT_INCONSISTENT] = {
1255         N_("checkpoint inconsistent"),
1256         N_("checkpoint inconsistent: %s") },
1257     [VIR_ERR_MULTIPLE_DOMAINS] = {
1258         N_("multiple matching domains found"),
1259         N_("multiple matching domains found: %s") },
1260 };
1261 
1262 G_STATIC_ASSERT(G_N_ELEMENTS(virErrorMsgStrings) == VIR_ERR_NUMBER_LAST);
1263 
1264 
1265 /**
1266  * virErrorMsg:
1267  * @error: the virErrorNumber
1268  * @info: additional info string
1269  *
1270  * Internal routine to get the message associated to @error raised
1271  * from the library.
1272  *
1273  * Returns a *printf format string which describes @error. The returned string
1274  * contains exactly one '%s' modifier if @info is non-NULL, or no modifiers at
1275  * all if @info is NULL. If @error is invalid NULL is returned.
1276  */
1277 const char *
virErrorMsg(virErrorNumber error,const char * info)1278 virErrorMsg(virErrorNumber error, const char *info)
1279 {
1280     if (error >= VIR_ERR_NUMBER_LAST)
1281         return NULL;
1282 
1283     if (info)
1284         return _(virErrorMsgStrings[error].msginfo);
1285     else
1286         return _(virErrorMsgStrings[error].msg);
1287 }
1288 
1289 
1290 /**
1291  * virReportErrorHelper:
1292  *
1293  * @domcode: the virErrorDomain indicating where it's coming from
1294  * @errorcode: the virErrorNumber code for the error
1295  * @filename: Source file error is dispatched from
1296  * @funcname: Function error is dispatched from
1297  * @linenr: Line number error is dispatched from
1298  * @fmt:  the format string
1299  * @...:  extra parameters for the message display
1300  *
1301  * Helper function to do most of the grunt work for individual driver
1302  * ReportError
1303  */
virReportErrorHelper(int domcode,int errorcode,const char * filename,const char * funcname,size_t linenr,const char * fmt,...)1304 void virReportErrorHelper(int domcode,
1305                           int errorcode,
1306                           const char *filename,
1307                           const char *funcname,
1308                           size_t linenr,
1309                           const char *fmt, ...)
1310 {
1311     int save_errno = errno;
1312     char *detail = NULL;
1313     char *errormsg = NULL;
1314     char *fullmsg = NULL;
1315 
1316     if (fmt) {
1317         va_list args;
1318 
1319         va_start(args, fmt);
1320         detail = g_strdup_vprintf(fmt, args);
1321         va_end(args);
1322     }
1323 
1324     errormsg = g_strdup(virErrorMsg(errorcode, detail));
1325 
1326     if (errormsg) {
1327         if (detail)
1328             fullmsg = g_strdup_printf(errormsg, detail);
1329         else
1330             fullmsg = g_strdup(errormsg);
1331     }
1332 
1333     virRaiseErrorInternal(filename, funcname, linenr,
1334                           domcode, errorcode, VIR_ERR_ERROR,
1335                           fullmsg, errormsg, detail, NULL, -1, -1);
1336 
1337     errno = save_errno;
1338 }
1339 
1340 /**
1341  * virReportSystemErrorFull:
1342  * @domcode: the virErrorDomain indicating where it's coming from
1343  * @theerrno: an errno number
1344  * @filename: filename where error was raised
1345  * @funcname: function name where error was raised
1346  * @linenr: line number where error was raised
1347  * @fmt:  the message to display/transmit
1348  * @...:  extra parameters for the message display
1349  *
1350  * Convenience internal routine called when a system error is detected.
1351  */
virReportSystemErrorFull(int domcode,int theerrno,const char * filename,const char * funcname,size_t linenr,const char * fmt,...)1352 void virReportSystemErrorFull(int domcode,
1353                               int theerrno,
1354                               const char *filename,
1355                               const char *funcname,
1356                               size_t linenr,
1357                               const char *fmt, ...)
1358 {
1359     int save_errno = errno;
1360     virBuffer buf = VIR_BUFFER_INITIALIZER;
1361     char *detail = NULL;
1362     char *errormsg = NULL;
1363     char *fullmsg = NULL;
1364 
1365     if (fmt) {
1366         va_list args;
1367 
1368         va_start(args, fmt);
1369         virBufferVasprintf(&buf, fmt, args);
1370         va_end(args);
1371 
1372         virBufferAddLit(&buf, ": ");
1373     }
1374 
1375     virBufferAdd(&buf, g_strerror(theerrno), -1);
1376 
1377     detail = virBufferContentAndReset(&buf);
1378     errormsg = g_strdup(virErrorMsg(VIR_ERR_SYSTEM_ERROR, detail));
1379     fullmsg = g_strdup_printf(errormsg, detail);
1380 
1381     virRaiseErrorInternal(filename, funcname, linenr,
1382                           domcode, VIR_ERR_SYSTEM_ERROR, VIR_ERR_ERROR,
1383                           fullmsg, errormsg, detail, NULL, theerrno, -1);
1384     errno = save_errno;
1385 }
1386 
1387 
1388 /**
1389  * virSetErrorLogPriorityFunc:
1390  * @func: function to install
1391  *
1392  * Install a function used to filter error logging based on error priority.
1393  */
virSetErrorLogPriorityFunc(virErrorLogPriorityFunc func)1394 void virSetErrorLogPriorityFunc(virErrorLogPriorityFunc func)
1395 {
1396     virErrorLogPriorityFilter = func;
1397 }
1398 
1399 
1400 /**
1401  * virErrorSetErrnoFromLastError:
1402  *
1403  * If the last error had a code of VIR_ERR_SYSTEM_ERROR
1404  * then set errno to the value saved in the error object.
1405  *
1406  * If the last error had a code of VIR_ERR_NO_MEMORY
1407  * then set errno to ENOMEM
1408  *
1409  * Otherwise set errno to EIO.
1410  */
virErrorSetErrnoFromLastError(void)1411 void virErrorSetErrnoFromLastError(void)
1412 {
1413     virErrorPtr err = virGetLastError();
1414     if (err && err->code == VIR_ERR_SYSTEM_ERROR) {
1415         errno = err->int1;
1416     } else if (err && err->code == VIR_ERR_NO_MEMORY) {
1417         errno = ENOMEM;
1418     } else {
1419         errno = EIO;
1420     }
1421 }
1422 
1423 
1424 /**
1425  * virLastErrorIsSystemErrno:
1426  * @errnum: the errno value
1427  *
1428  * Check if the last error reported is a system
1429  * error with the specific errno value.
1430  *
1431  * If @errnum is zero, any system error will pass.
1432  *
1433  * Returns true if the last error was a system error with errno == @errnum
1434  */
virLastErrorIsSystemErrno(int errnum)1435 bool virLastErrorIsSystemErrno(int errnum)
1436 {
1437     virErrorPtr err = virGetLastError();
1438     if (!err)
1439         return false;
1440     if (err->code != VIR_ERR_SYSTEM_ERROR)
1441         return false;
1442     if (errnum != 0 && err->int1 != errnum)
1443         return false;
1444     return true;
1445 }
1446 
1447 
1448 /**
1449  * virLastErrorPrefixMessage:
1450  * @fmt: printf-style formatting string
1451  * @...: Arguments for @fmt
1452  *
1453  * Prefixes last error reported with message formatted from @fmt. This is useful
1454  * if the low level error message does not convey enough information to describe
1455  * the problem.
1456  */
1457 void
virLastErrorPrefixMessage(const char * fmt,...)1458 virLastErrorPrefixMessage(const char *fmt, ...)
1459 {
1460     int save_errno = errno;
1461     virErrorPtr err = virGetLastError();
1462     g_autofree char *fmtmsg = NULL;
1463     g_autofree char *newmsg = NULL;
1464     va_list args;
1465 
1466     if (!err)
1467         return;
1468 
1469     va_start(args, fmt);
1470     fmtmsg = g_strdup_vprintf(fmt, args);
1471     va_end(args);
1472 
1473     newmsg = g_strdup_printf("%s: %s", fmtmsg, err->message);
1474 
1475     VIR_FREE(err->message);
1476     err->message = g_steal_pointer(&newmsg);
1477 
1478     errno = save_errno;
1479 }
1480