in base libvirt.
* libvirt/libvirt_c.c: Gracefully handle the case where libvirt
throws an error number we have not heard of before (eg. when
dynamic linking with newer libvirt).
* configure.ac: Check <libvirt/virterror.h> exists.
* configure.ac: Version 0.3.3.4.
+2007-11-20 Richard Jones <rjones@redhat.com>
+
+ * libvirt/libvirt.mli, libvirt/libvirt.ml: New error numbers
+ in base libvirt.
+ * libvirt/libvirt_c.c: Gracefully handle the case where libvirt
+ throws an error number we have not heard of before (eg. when
+ dynamic linking with newer libvirt).
+ * configure.ac: Check <libvirt/virterror.h> exists.
+ * configure.ac: Version 0.3.3.4.
+ * virt-top/virt-top.pod: Fixed ocaml libvirt website URI in manpage.
+
+2007-11-19 Richard Jones <rjones@redhat.com>
+
+ * virt-top/virt-top.pod: Example connection URIs in virt-top manpage
+ (bug 390691).
+
2007-11-14 Richard Jones <rjones@redhat.com>
* libvirt/libvirt.mli: Added filename = string type to clarify
dnl Process this file with autoconf to produce a configure script.
-AC_INIT(ocaml-libvirt,0.3.3.3)
+AC_INIT(ocaml-libvirt,0.3.3.4)
dnl Check for basic C environment.
AC_PROG_CC
dnl See: http://libvirt.org/hvsupport.html
AC_CHECK_FUNCS([virConnectGetHostname virConnectGetURI virDomainBlockStats virDomainGetSchedulerParameters virDomainGetSchedulerType virDomainInterfaceStats virDomainMigrate virDomainSetSchedulerParameters virNodeGetFreeMemory virNodeGetCellsFreeMemory])
+dnl We also use <libvirt/virterror.h>
+AC_CHECK_HEADER([libvirt/virterror.h],
+ [],
+ AC_MSG_ERROR([You must install libvirt development package]))
+
dnl Check for optional ncurses.
AC_CHECK_LIB(ncurses,initscr)
| VIR_WAR_NO_NETWORK
| VIR_ERR_NO_DOMAIN
| VIR_ERR_NO_NETWORK
+ | VIR_ERR_INVALID_MAC
+ | VIR_ERR_UNKNOWN of int
let string_of_code = function
| VIR_ERR_OK -> "VIR_ERR_OK"
| VIR_WAR_NO_NETWORK -> "VIR_WAR_NO_NETWORK"
| VIR_ERR_NO_DOMAIN -> "VIR_ERR_NO_DOMAIN"
| VIR_ERR_NO_NETWORK -> "VIR_ERR_NO_NETWORK"
-
- type level =
- | VIR_ERR_NONE
- | VIR_ERR_WARNING
- | VIR_ERR_ERROR
-
- let string_of_level = function
- | VIR_ERR_NONE -> "VIR_ERR_NONE"
- | VIR_ERR_WARNING -> "VIR_ERR_WARNING"
- | VIR_ERR_ERROR -> "VIR_ERR_ERROR"
+ | VIR_ERR_INVALID_MAC -> "VIR_ERR_INVALID_MAC"
+ | VIR_ERR_UNKNOWN i -> "VIR_ERR_" ^ string_of_int i
type domain =
| VIR_FROM_NONE
| VIR_FROM_TEST
| VIR_FROM_REMOTE
| VIR_FROM_OPENVZ
+ | VIR_FROM_XENXM
+ | VIR_FROM_STATS_LINUX
+ | VIR_FROM_UNKNOWN of int
let string_of_domain = function
| VIR_FROM_NONE -> "VIR_FROM_NONE"
| VIR_FROM_TEST -> "VIR_FROM_TEST"
| VIR_FROM_REMOTE -> "VIR_FROM_REMOTE"
| VIR_FROM_OPENVZ -> "VIR_FROM_OPENVZ"
+ | VIR_FROM_XENXM -> "VIR_FROM_XENXM"
+ | VIR_FROM_STATS_LINUX -> "VIR_FROM_STATS_LINUX"
+ | VIR_FROM_UNKNOWN i -> "VIR_FROM_" ^ string_of_int i
+
+ type level =
+ | VIR_ERR_NONE
+ | VIR_ERR_WARNING
+ | VIR_ERR_ERROR
+ | VIR_ERR_UNKNOWN_LEVEL of int
+
+ let string_of_level = function
+ | VIR_ERR_NONE -> "VIR_ERR_NONE"
+ | VIR_ERR_WARNING -> "VIR_ERR_WARNING"
+ | VIR_ERR_ERROR -> "VIR_ERR_ERROR"
+ | VIR_ERR_UNKNOWN_LEVEL i -> "VIR_ERR_LEVEL_" ^ string_of_int i
type t = {
code : code;
| VIR_WAR_NO_NETWORK
| VIR_ERR_NO_DOMAIN
| VIR_ERR_NO_NETWORK
+ | VIR_ERR_INVALID_MAC
+ (* ^^ NB: If you add a variant you MUST edit libvirt_c.c:MAX_VIR_* *)
+ | VIR_ERR_UNKNOWN of int
(** See [<libvirt/virterror.h>] for meaning of these codes. *)
val string_of_code : code -> string
- type level =
- | VIR_ERR_NONE
- | VIR_ERR_WARNING
- | VIR_ERR_ERROR
- (** No error, a warning or an error. *)
-
- val string_of_level : level -> string
-
type domain =
| VIR_FROM_NONE
| VIR_FROM_XEN
| VIR_FROM_TEST
| VIR_FROM_REMOTE
| VIR_FROM_OPENVZ
+ | VIR_FROM_XENXM
+ | VIR_FROM_STATS_LINUX
+ (* ^^ NB: If you add a variant you MUST edit libvirt_c.c: MAX_VIR_* *)
+ | VIR_FROM_UNKNOWN of int
(** Subsystem / driver which produced the error. *)
val string_of_domain : domain -> string
+ type level =
+ | VIR_ERR_NONE
+ | VIR_ERR_WARNING
+ | VIR_ERR_ERROR
+ (* ^^ NB: If you add a variant you MUST edit libvirt_c.c: MAX_VIR_* *)
+ | VIR_ERR_UNKNOWN_LEVEL of int
+ (** No error, a warning or an error. *)
+
+ val string_of_level : level -> string
+
type t = {
code : code; (** Error code. *)
domain : domain; (** Origin of the error. *)
CAMLreturn (Val_unit);
}
+/* Convert the virErrorNumber, virErrorDomain and virErrorLevel enums
+ * into values (longs because they are variants in OCaml).
+ *
+ * The enum values are part of the libvirt ABI so they cannot change,
+ * which means that we can convert these numbers directly into
+ * OCaml variants (which use the same ordering) very fast.
+ *
+ * The tricky part here is when we are linked to a newer version of
+ * libvirt than the one we were compiled against. If the newer libvirt
+ * generates an error code which we don't know about then we need
+ * to convert it into VIR_*_UNKNOWN (code).
+ */
+
+#define MAX_VIR_CODE 44 /* VIR_ERR_INVALID_MAC */
+#define MAX_VIR_DOMAIN 16 /* VIR_FROM_STATS_LINUX */
+#define MAX_VIR_LEVEL VIR_ERR_ERROR
+
+static inline value
+Val_err_number (virErrorNumber code)
+{
+ CAMLparam0 ();
+ CAMLlocal1 (rv);
+
+ if (0 <= code && code <= MAX_VIR_CODE)
+ rv = Val_int (code);
+ else {
+ rv = caml_alloc (1, 0); /* VIR_ERR_UNKNOWN (code) */
+ Store_field (rv, 0, Val_int (code));
+ }
+
+ CAMLreturn (rv);
+}
+
+static inline value
+Val_err_domain (virErrorDomain code)
+{
+ CAMLparam0 ();
+ CAMLlocal1 (rv);
+
+ if (0 <= code && code <= MAX_VIR_DOMAIN)
+ rv = Val_int (code);
+ else {
+ rv = caml_alloc (1, 0); /* VIR_FROM_UNKNOWN (code) */
+ Store_field (rv, 0, Val_int (code));
+ }
+
+ CAMLreturn (rv);
+}
+
+static inline value
+Val_err_level (virErrorLevel code)
+{
+ CAMLparam0 ();
+ CAMLlocal1 (rv);
+
+ if (0 <= code && code <= MAX_VIR_LEVEL)
+ rv = Val_int (code);
+ else {
+ rv = caml_alloc (1, 0); /* VIR_ERR_UNKNOWN_LEVEL (code) */
+ Store_field (rv, 0, Val_int (code));
+ }
+
+ CAMLreturn (rv);
+}
+
+/* Convert a virterror to a value. */
static value
Val_virterror (virErrorPtr err)
{
CAMLlocal3 (rv, connv, optv);
rv = caml_alloc (12, 0);
- Store_field (rv, 0, Val_int (err->code));
- Store_field (rv, 1, Val_int (err->domain));
+ Store_field (rv, 0, Val_err_number (err->code));
+ Store_field (rv, 1, Val_err_domain (err->domain));
Store_field (rv, 2,
Val_opt (err->message, (Val_ptr_t) caml_copy_string));
- Store_field (rv, 3, Val_int (err->level));
+ Store_field (rv, 3, Val_err_level (err->level));
/* conn, dom and net fields, all optional */
if (err->conn) {