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