common: Bundle the libvirt-ocaml library for use by virt-v2v

Add a copy of the libvirt-ocaml library, currently available at:
  https://libvirt.org/git/?p=libvirt-ocaml.git;a=summary
This is a snapshot at commit d3ed8dcf1b0a6a8a855ceecbe0bb97f21e6665e3,
which has all the features we need (and that builds fine).
It is expected to stay synchronized with upstream, until there is a new
upstream release, and it will be widespread enough.
This commit is contained in:
Pino Toscano
2018-08-30 11:43:32 +02:00
parent c0d95dcde8
commit 99493eeddd
11 changed files with 6658 additions and 0 deletions

2
.gitignore vendored
View File

@@ -133,6 +133,8 @@ Makefile.in
/common/mlaugeas/.depend
/common/mlgettext/.depend
/common/mlgettext/common_gettext.ml
/common/mllibvirt/.depend
/common/mllibvirt/libvirt_c.c
/common/mlpcre/.depend
/common/mlpcre/pcre_tests
/common/mlprogress/.depend

View File

@@ -163,6 +163,9 @@ SUBDIRS += common/mlprogress
SUBDIRS += common/mlvisit
SUBDIRS += common/mlxml
SUBDIRS += common/mltools
if HAVE_LIBVIRT
SUBDIRS += common/mllibvirt
endif
SUBDIRS += customize
SUBDIRS += builder builder/templates
SUBDIRS += get-kernel

View File

@@ -0,0 +1,102 @@
# libguestfs OCaml tools common code
# Copyright (C) 2018 Red Hat Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
include $(top_srcdir)/subdir-rules.mk
EXTRA_DIST = \
$(SOURCES_MLI) \
$(SOURCES_ML) \
generator.pl \
libvirt_c_epilogue.c \
libvirt_c_oneoffs.c \
libvirt_c_prologue.c \
libvirt.README
SOURCES_MLI = \
libvirt.mli
SOURCES_ML = \
libvirt.ml
SOURCES_C = \
libvirt_c.c
# Automatically generate the C code from a Perl script 'generator.pl'.
libvirt_c.c: $(srcdir)/generator.pl
$(PERL) -w $<
CLEANFILES += \
libvirt_c.c
# We pretend that we're building a C library. automake handles the
# compilation of the C sources for us. At the end we take the C
# objects and OCaml objects and link them into the OCaml library.
# This C library is never used.
noinst_LIBRARIES = libmllibvirt.a
if !HAVE_OCAMLOPT
MLLIBVIRT_CMA = mllibvirt.cma
else
MLLIBVIRT_CMA = mllibvirt.cmxa
endif
noinst_DATA = $(MLLIBVIRT_CMA)
libmllibvirt_a_SOURCES = $(SOURCES_C)
libmllibvirt_a_CPPFLAGS = \
-I. \
-I$(top_builddir) \
-I$(shell $(OCAMLC) -where)
libmllibvirt_a_CFLAGS = \
$(WARN_CFLAGS) $(WERROR_CFLAGS) \
$(LIBVIRT_CFLAGS) \
-fPIC
BOBJECTS = $(SOURCES_ML:.ml=.cmo)
XOBJECTS = $(BOBJECTS:.cmo=.cmx)
OCAMLPACKAGES =
OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR)
if !HAVE_OCAMLOPT
OBJECTS = $(BOBJECTS)
else
OBJECTS = $(XOBJECTS)
endif
libmllibvirt_a_DEPENDENCIES = $(OBJECTS)
$(MLLIBVIRT_CMA): $(OBJECTS) libmllibvirt.a
$(OCAMLFIND) mklib $(OCAMLPACKAGES) \
$(OBJECTS) $(libmllibvirt_a_OBJECTS) -cclib -lvirt -o mllibvirt
# Dependencies.
depend: .depend
.depend: $(wildcard $(abs_srcdir)/*.mli) $(wildcard $(abs_srcdir)/*.ml)
rm -f $@ $@-t
$(OCAMLFIND) ocamldep -I ../../ocaml -I $(abs_srcdir) $^ | \
$(SED) 's/ *$$//' | \
$(SED) -e :a -e '/ *\\$$/N; s/ *\\\n */ /; ta' | \
$(SED) -e 's,$(abs_srcdir)/,$(builddir)/,g' | \
sort > $@-t
mv $@-t $@
-include .depend
.PHONY: depend docs

908
common/mllibvirt/generator.pl Executable file
View File

@@ -0,0 +1,908 @@
#!/usr/bin/perl -w
#
# OCaml bindings for libvirt.
# (C) Copyright 2007-2015 Richard W.M. Jones, Red Hat Inc.
# https://libvirt.org/
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version,
# with the OCaml linking exception described in ../COPYING.LIB.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# This generates libvirt_c.c (the core of the bindings). You don't
# need to run this program unless you are extending the bindings
# themselves (eg. because libvirt has been extended).
#
# Please read libvirt/README.
use strict;
#----------------------------------------------------------------------
# The functions in the libvirt API that we can generate.
# The 'sig' (signature) doesn't have a meaning or any internal structure.
# It is interpreted by the generation functions below to indicate what
# "class" the function falls into, and to generate the right class of
# binding.
my @functions = (
{ name => "virConnectClose", sig => "conn : free" },
{ name => "virConnectGetHostname", sig => "conn : string" },
{ name => "virConnectGetURI", sig => "conn : string" },
{ name => "virConnectGetType", sig => "conn : static string" },
{ name => "virConnectNumOfDomains", sig => "conn : int" },
{ name => "virConnectListDomains", sig => "conn, int : int array" },
{ name => "virConnectNumOfDefinedDomains", sig => "conn : int" },
{ name => "virConnectListDefinedDomains",
sig => "conn, int : string array" },
{ name => "virConnectNumOfNetworks", sig => "conn : int" },
{ name => "virConnectListNetworks", sig => "conn, int : string array" },
{ name => "virConnectNumOfDefinedNetworks", sig => "conn : int" },
{ name => "virConnectListDefinedNetworks",
sig => "conn, int : string array" },
{ name => "virConnectNumOfStoragePools", sig => "conn : int" },
{ name => "virConnectListStoragePools",
sig => "conn, int : string array" },
{ name => "virConnectNumOfDefinedStoragePools",
sig => "conn : int" },
{ name => "virConnectListDefinedStoragePools",
sig => "conn, int : string array" },
{ name => "virConnectNumOfSecrets", sig => "conn : int" },
{ name => "virConnectListSecrets", sig => "conn, int : string array" },
{ name => "virConnectGetCapabilities", sig => "conn : string" },
{ name => "virConnectDomainEventDeregisterAny",
sig => "conn, int : unit" },
{ name => "virDomainCreateLinux", sig => "conn, string, 0U : dom" },
{ name => "virDomainCreateXML", sig => "conn, string, unsigned : dom" },
{ name => "virDomainFree", sig => "dom : free" },
{ name => "virDomainDestroy", sig => "dom : free" },
{ name => "virDomainLookupByName", sig => "conn, string : dom" },
{ name => "virDomainLookupByID", sig => "conn, int : dom" },
{ name => "virDomainLookupByUUID", sig => "conn, uuid : dom" },
{ name => "virDomainLookupByUUIDString", sig => "conn, string : dom" },
{ name => "virDomainGetName", sig => "dom : static string" },
{ name => "virDomainGetOSType", sig => "dom : string" },
{ name => "virDomainGetXMLDesc", sig => "dom, 0 : string" },
{ name => "virDomainGetUUID", sig => "dom : uuid" },
{ name => "virDomainGetUUIDString", sig => "dom : uuid string" },
{ name => "virDomainGetMaxVcpus", sig => "dom : int" },
{ name => "virDomainSave", sig => "dom, string : unit" },
{ name => "virDomainRestore", sig => "conn, string : unit" },
{ name => "virDomainCoreDump", sig => "dom, string, 0 : unit" },
{ name => "virDomainSuspend", sig => "dom : unit" },
{ name => "virDomainResume", sig => "dom : unit" },
{ name => "virDomainShutdown", sig => "dom : unit" },
{ name => "virDomainReboot", sig => "dom, 0 : unit" },
{ name => "virDomainDefineXML", sig => "conn, string : dom" },
{ name => "virDomainUndefine", sig => "dom : unit" },
{ name => "virDomainCreate", sig => "dom : unit" },
{ name => "virDomainAttachDevice", sig => "dom, string : unit" },
{ name => "virDomainDetachDevice", sig => "dom, string : unit" },
{ name => "virDomainGetAutostart", sig => "dom : bool" },
{ name => "virDomainSetAutostart", sig => "dom, bool : unit" },
{ name => "virNetworkFree", sig => "net : free" },
{ name => "virNetworkDestroy", sig => "net : free" },
{ name => "virNetworkLookupByName", sig => "conn, string : net" },
{ name => "virNetworkLookupByUUID", sig => "conn, uuid : net" },
{ name => "virNetworkLookupByUUIDString", sig => "conn, string : net" },
{ name => "virNetworkGetName", sig => "net : static string" },
{ name => "virNetworkGetXMLDesc", sig => "net, 0 : string" },
{ name => "virNetworkGetBridgeName", sig => "net : string" },
{ name => "virNetworkGetUUID", sig => "net : uuid" },
{ name => "virNetworkGetUUIDString", sig => "net : uuid string" },
{ name => "virNetworkUndefine", sig => "net : unit" },
{ name => "virNetworkCreateXML", sig => "conn, string : net" },
{ name => "virNetworkDefineXML", sig => "conn, string : net" },
{ name => "virNetworkCreate", sig => "net : unit" },
{ name => "virNetworkGetAutostart", sig => "net : bool" },
{ name => "virNetworkSetAutostart", sig => "net, bool : unit" },
{ name => "virStoragePoolFree", sig => "pool : free" },
{ name => "virStoragePoolDestroy", sig => "pool : free" },
{ name => "virStoragePoolLookupByName",
sig => "conn, string : pool" },
{ name => "virStoragePoolLookupByUUID",
sig => "conn, uuid : pool" },
{ name => "virStoragePoolLookupByUUIDString",
sig => "conn, string : pool" },
{ name => "virStoragePoolGetName",
sig => "pool : static string" },
{ name => "virStoragePoolGetXMLDesc",
sig => "pool, 0U : string" },
{ name => "virStoragePoolGetUUID",
sig => "pool : uuid" },
{ name => "virStoragePoolGetUUIDString",
sig => "pool : uuid string" },
{ name => "virStoragePoolCreateXML",
sig => "conn, string, 0U : pool" },
{ name => "virStoragePoolDefineXML",
sig => "conn, string, 0U : pool" },
{ name => "virStoragePoolBuild",
sig => "pool, uint : unit" },
{ name => "virStoragePoolUndefine",
sig => "pool : unit" },
{ name => "virStoragePoolCreate",
sig => "pool, 0U : unit" },
{ name => "virStoragePoolDelete",
sig => "pool, uint : unit" },
{ name => "virStoragePoolRefresh",
sig => "pool, 0U : unit" },
{ name => "virStoragePoolGetAutostart",
sig => "pool : bool" },
{ name => "virStoragePoolSetAutostart",
sig => "pool, bool : unit" },
{ name => "virStoragePoolNumOfVolumes",
sig => "pool : int" },
{ name => "virStoragePoolListVolumes",
sig => "pool, int : string array" },
{ name => "virStorageVolFree", sig => "vol : free" },
{ name => "virStorageVolDelete",
sig => "vol, uint : unit" },
{ name => "virStorageVolLookupByName",
sig => "pool, string : vol from pool" },
{ name => "virStorageVolLookupByKey",
sig => "conn, string : vol" },
{ name => "virStorageVolLookupByPath",
sig => "conn, string : vol" },
{ name => "virStorageVolCreateXML",
sig => "pool, string, 0U : vol from pool" },
{ name => "virStorageVolGetXMLDesc",
sig => "vol, 0U : string" },
{ name => "virStorageVolGetPath",
sig => "vol : string" },
{ name => "virStorageVolGetKey",
sig => "vol : static string" },
{ name => "virStorageVolGetName",
sig => "vol : static string" },
{ name => "virStoragePoolLookupByVolume",
sig => "vol : pool from vol" },
{ name => "virSecretFree", sig => "sec : free" },
{ name => "virSecretUndefine", sig => "sec : unit" },
{ name => "virSecretLookupByUUID", sig => "conn, uuid : sec" },
{ name => "virSecretLookupByUUIDString", sig => "conn, string : sec" },
{ name => "virSecretDefineXML", sig => "conn, string, 0 : sec" },
{ name => "virSecretGetUUID", sig => "sec : uuid" },
{ name => "virSecretGetUUIDString", sig => "sec : uuid string" },
{ name => "virSecretGetUsageType", sig => "sec : int" },
{ name => "virSecretGetUsageID", sig => "sec : static string" },
{ name => "virSecretGetXMLDesc", sig => "sec, 0 : string" },
);
# Functions we haven't implemented anywhere yet but which are mentioned
# in 'libvirt.ml'.
#
# We create stubs for these, but eventually they need to either be
# moved ^^^ so they are auto-generated, or implementations of them
# written in 'libvirt_c_oneoffs.c'.
my @unimplemented = (
);
#----------------------------------------------------------------------
# Open the output file.
my $filename = "libvirt_c.c";
open F, ">$filename" or die "$filename: $!";
# Write the prologue.
print F <<'END';
/* !!! WARNING WARNING WARNING WARNING WARNING WARNING WARNING !!!
*
* THIS FILE IS AUTOMATICALLY GENERATED BY 'generator.pl'.
*
* Any changes you make to this file may be overwritten.
*/
/* OCaml bindings for libvirt.
* (C) Copyright 2007-2015 Richard W.M. Jones, Red Hat Inc.
* https://libvirt.org/
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version,
* with the OCaml linking exception described in ../COPYING.LIB.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libvirt/libvirt.h>
#include <libvirt/virterror.h>
#include <caml/config.h>
#include <caml/alloc.h>
#include <caml/callback.h>
#include <caml/custom.h>
#include <caml/fail.h>
#include <caml/memory.h>
#include <caml/misc.h>
#include <caml/mlvalues.h>
#include <caml/signals.h>
#include "libvirt_c_prologue.c"
#include "libvirt_c_oneoffs.c"
END
#----------------------------------------------------------------------
sub camel_case_to_underscores
{
my $name = shift;
$name =~ s/([A-Z][a-z]+|XML|URI|OS|UUID)/$1,/g;
my @subs = split (/,/, $name);
@subs = map { lc($_) } @subs;
join "_", @subs
}
# Helper functions dealing with signatures.
sub short_name_to_c_type
{
local $_ = shift;
if ($_ eq "conn") { "virConnectPtr" }
elsif ($_ eq "dom") { "virDomainPtr" }
elsif ($_ eq "net") { "virNetworkPtr" }
elsif ($_ eq "pool") { "virStoragePoolPtr" }
elsif ($_ eq "vol") { "virStorageVolPtr" }
elsif ($_ eq "sec") { "virSecretPtr" }
else {
die "unknown short name $_"
}
}
# OCaml argument names.
sub gen_arg_names
{
my $sig = shift;
if ($sig =~ /^(\w+) : string$/) {
( "$1v" )
} elsif ($sig =~ /^(\w+) : static string$/) {
( "$1v" )
} elsif ($sig =~ /^(\w+) : int$/) {
( "$1v" )
} elsif ($sig =~ /^(\w+) : uuid$/) {
( "$1v" )
} elsif ($sig =~ /^(\w+) : uuid string$/) {
( "$1v" )
} elsif ($sig =~ /^(\w+) : bool$/) {
( "$1v" )
} elsif ($sig =~ /^(\w+), bool : unit$/) {
( "$1v", "bv" )
} elsif ($sig eq "conn, int : int array") {
( "connv", "iv" )
} elsif ($sig =~ /^(\w+), int : string array$/) {
( "$1v", "iv" )
} elsif ($sig =~ /^(\w+), 0U? : string$/) {
( "$1v" )
} elsif ($sig =~ /^(\w+), 0U? : unit$/) {
( "$1v" )
} elsif ($sig =~ /^(\w+) : unit$/) {
( "$1v" )
} elsif ($sig =~ /^(\w+) : free$/) {
( "$1v" )
} elsif ($sig =~ /^(\w+), string : unit$/) {
( "$1v", "strv" )
} elsif ($sig =~ /^(\w+), string, 0U? : unit$/) {
( "$1v", "strv" )
} elsif ($sig =~ /^(\w+), string : (\w+)$/) {
( "$1v", "strv" )
} elsif ($sig =~ /^(\w+), string, 0U? : (\w+)$/) {
( "$1v", "strv" )
} elsif ($sig =~ /^(\w+), string, unsigned : (\w+)$/) {
( "$1v", "strv", "uv" )
} elsif ($sig =~ /^(\w+), u?int : (\w+)$/) {
( "$1v", "iv" )
} elsif ($sig =~ /^(\w+), uuid : (\w+)$/) {
( "$1v", "uuidv" )
} elsif ($sig =~ /^(\w+), 0U? : (\w+)$/) {
( "$1v" )
} elsif ($sig =~ /^(\w+) : (\w+)$/) {
( "$1v" )
} elsif ($sig =~ /^(\w+), string : (\w+) from \w+$/) {
( "$1v", "strv" )
} elsif ($sig =~ /^(\w+), string, 0U? : (\w+) from \w+$/) {
( "$1v", "strv" )
} elsif ($sig =~ /^(\w+), 0U? : (\w+) from \w+$/) {
( "$1v" )
} elsif ($sig =~ /^(\w+) : (\w+) from \w+$/) {
( "$1v" )
} else {
die "unknown signature $sig"
}
}
# Unpack the first (object) argument.
sub gen_unpack_args
{
local $_ = shift;
if ($_ eq "conn") {
"virConnectPtr conn = Connect_val (connv);"
} elsif ($_ eq "dom") {
"virDomainPtr dom = Domain_val (domv);"
} elsif ($_ eq "net") {
"virNetworkPtr net = Network_val (netv);"
} elsif ($_ eq "pool") {
"virStoragePoolPtr pool = Pool_val (poolv);"
} elsif ($_ eq "vol") {
"virStorageVolPtr vol = Volume_val (volv);"
} elsif ($_ eq "sec") {
"virSecretPtr sec = Secret_val (secv);"
} else {
die "unknown short name $_"
}
}
# Pack the result if it's an object.
sub gen_pack_result
{
local $_ = shift;
if ($_ eq "dom") { "rv = Val_domain (r, connv);" }
elsif ($_ eq "net") { "rv = Val_network (r, connv);" }
elsif ($_ eq "pool") { "rv = Val_pool (r, connv);" }
elsif ($_ eq "vol") { "rv = Val_volume (r, connv);" }
elsif ($_ eq "sec") { "rv = Val_secret (r, connv);" }
else {
die "unknown short name $_"
}
}
sub gen_free_arg
{
local $_ = shift;
if ($_ eq "conn") { "Connect_val (connv) = NULL;" }
elsif ($_ eq "dom") { "Domain_val (domv) = NULL;" }
elsif ($_ eq "net") { "Network_val (netv) = NULL;" }
elsif ($_ eq "pool") { "Pool_val (poolv) = NULL;" }
elsif ($_ eq "vol") { "Volume_val (volv) = NULL;" }
elsif ($_ eq "sec") { "Secret_val (secv) = NULL;" }
else {
die "unknown short name $_"
}
}
# Generate the C body for each signature (class of function).
sub gen_c_code
{
my $sig = shift;
my $c_name = shift;
if ($sig =~ /^(\w+) : string$/) {
"\
CAMLlocal1 (rv);
" . gen_unpack_args ($1) . "
char *r;
NONBLOCKING (r = $c_name ($1));
CHECK_ERROR (!r, \"$c_name\");
rv = caml_copy_string (r);
free (r);
CAMLreturn (rv);
"
} elsif ($sig =~ /^(\w+) : static string$/) {
"\
CAMLlocal1 (rv);
" . gen_unpack_args ($1) . "
const char *r;
NONBLOCKING (r = $c_name ($1));
CHECK_ERROR (!r, \"$c_name\");
rv = caml_copy_string (r);
CAMLreturn (rv);
"
} elsif ($sig =~ /^(\w+) : int$/) {
"\
" . gen_unpack_args ($1) . "
int r;
NONBLOCKING (r = $c_name ($1));
CHECK_ERROR (r == -1, \"$c_name\");
CAMLreturn (Val_int (r));
"
} elsif ($sig =~ /^(\w+) : uuid$/) {
"\
CAMLlocal1 (rv);
" . gen_unpack_args ($1) . "
unsigned char uuid[VIR_UUID_BUFLEN];
int r;
NONBLOCKING (r = $c_name ($1, uuid));
CHECK_ERROR (r == -1, \"$c_name\");
/* UUIDs are byte arrays with a fixed length. */
rv = caml_alloc_string (VIR_UUID_BUFLEN);
memcpy (String_val (rv), uuid, VIR_UUID_BUFLEN);
CAMLreturn (rv);
"
} elsif ($sig =~ /^(\w+) : uuid string$/) {
"\
CAMLlocal1 (rv);
" . gen_unpack_args ($1) . "
char uuid[VIR_UUID_STRING_BUFLEN];
int r;
NONBLOCKING (r = $c_name ($1, uuid));
CHECK_ERROR (r == -1, \"$c_name\");
rv = caml_copy_string (uuid);
CAMLreturn (rv);
"
} elsif ($sig =~ /^(\w+) : bool$/) {
"\
" . gen_unpack_args ($1) . "
int r, b;
NONBLOCKING (r = $c_name ($1, &b));
CHECK_ERROR (r == -1, \"$c_name\");
CAMLreturn (b ? Val_true : Val_false);
"
} elsif ($sig =~ /^(\w+), bool : unit$/) {
"\
" . gen_unpack_args ($1) . "
int r, b;
b = bv == Val_true ? 1 : 0;
NONBLOCKING (r = $c_name ($1, b));
CHECK_ERROR (r == -1, \"$c_name\");
CAMLreturn (Val_unit);
"
} elsif ($sig eq "conn, int : int array") {
"\
CAMLlocal1 (rv);
virConnectPtr conn = Connect_val (connv);
int i = Int_val (iv);
int *ids, r;
/* Some libvirt List* functions still throw exceptions if i == 0,
* so catch that and return an empty array directly. This changes
* the semantics slightly (masking other failures) but it's
* unlikely anyone will care. RWMJ 2008/06/10
*/
if (i == 0) {
rv = caml_alloc (0, 0);
CAMLreturn (rv);
}
ids = malloc (sizeof (*ids) * i);
if (ids == NULL)
caml_raise_out_of_memory ();
NONBLOCKING (r = $c_name (conn, ids, i));
CHECK_ERROR_CLEANUP (r == -1, free (ids), \"$c_name\");
rv = caml_alloc (r, 0);
for (i = 0; i < r; ++i)
Store_field (rv, i, Val_int (ids[i]));
free (ids);
CAMLreturn (rv);
"
} elsif ($sig =~ /^(\w+), int : string array$/) {
"\
CAMLlocal2 (rv, strv);
" . gen_unpack_args ($1) . "
int i = Int_val (iv);
char **names;
int r;
/* Some libvirt List* functions still throw exceptions if i == 0,
* so catch that and return an empty array directly. This changes
* the semantics slightly (masking other failures) but it's
* unlikely anyone will care. RWMJ 2008/06/10
*/
if (i == 0) {
rv = caml_alloc (0, 0);
CAMLreturn (rv);
}
names = malloc (sizeof (*names) * i);
if (names == NULL)
caml_raise_out_of_memory ();
NONBLOCKING (r = $c_name ($1, names, i));
CHECK_ERROR_CLEANUP (r == -1, free (names), \"$c_name\");
rv = caml_alloc (r, 0);
for (i = 0; i < r; ++i) {
strv = caml_copy_string (names[i]);
Store_field (rv, i, strv);
free (names[i]);
}
free (names);
CAMLreturn (rv);
"
} elsif ($sig =~ /^(\w+), 0U? : string$/) {
"\
CAMLlocal1 (rv);
" . gen_unpack_args ($1) . "
char *r;
NONBLOCKING (r = $c_name ($1, 0));
CHECK_ERROR (!r, \"$c_name\");
rv = caml_copy_string (r);
free (r);
CAMLreturn (rv);
"
} elsif ($sig =~ /^(\w+), 0U? : unit$/) {
"\
" . gen_unpack_args ($1) . "
int r;
NONBLOCKING (r = $c_name ($1, 0));
CHECK_ERROR (r == -1, \"$c_name\");
CAMLreturn (Val_unit);
"
} elsif ($sig =~ /^(\w+) : unit$/) {
"\
" . gen_unpack_args ($1) . "
int r;
NONBLOCKING (r = $c_name ($1));
CHECK_ERROR (r == -1, \"$c_name\");
CAMLreturn (Val_unit);
"
} elsif ($sig =~ /^(\w+) : free$/) {
"\
" . gen_unpack_args ($1) . "
int r;
NONBLOCKING (r = $c_name ($1));
CHECK_ERROR (r == -1, \"$c_name\");
/* So that we don't double-free in the finalizer: */
" . gen_free_arg ($1) . "
CAMLreturn (Val_unit);
"
} elsif ($sig =~ /^(\w+), string : unit$/) {
"\
" . gen_unpack_args ($1) . "
char *str = String_val (strv);
int r;
NONBLOCKING (r = $c_name ($1, str));
CHECK_ERROR (r == -1, \"$c_name\");
CAMLreturn (Val_unit);
"
} elsif ($sig =~ /^(\w+), string, 0U? : unit$/) {
"\
CAMLlocal1 (rv);
" . gen_unpack_args ($1) . "
char *str = String_val (strv);
int r;
NONBLOCKING (r = $c_name ($1, str, 0));
CHECK_ERROR (!r, \"$c_name\");
CAMLreturn (Val_unit);
"
} elsif ($sig =~ /^(\w+), string : (\w+)$/) {
my $c_ret_type = short_name_to_c_type ($2);
"\
CAMLlocal1 (rv);
" . gen_unpack_args ($1) . "
char *str = String_val (strv);
$c_ret_type r;
NONBLOCKING (r = $c_name ($1, str));
CHECK_ERROR (!r, \"$c_name\");
" . gen_pack_result ($2) . "
CAMLreturn (rv);
"
} elsif ($sig =~ /^(\w+), string, 0U? : (\w+)$/) {
my $c_ret_type = short_name_to_c_type ($2);
"\
CAMLlocal1 (rv);
" . gen_unpack_args ($1) . "
char *str = String_val (strv);
$c_ret_type r;
NONBLOCKING (r = $c_name ($1, str, 0));
CHECK_ERROR (!r, \"$c_name\");
" . gen_pack_result ($2) . "
CAMLreturn (rv);
"
} elsif ($sig =~ /^(\w+), string, unsigned : (\w+)$/) {
my $c_ret_type = short_name_to_c_type ($2);
"\
CAMLlocal1 (rv);
" . gen_unpack_args ($1) . "
char *str = String_val (strv);
unsigned int u = Int_val (uv);
$c_ret_type r;
NONBLOCKING (r = $c_name ($1, str, u));
CHECK_ERROR (!r, \"$c_name\");
" . gen_pack_result ($2) . "
CAMLreturn (rv);
"
} elsif ($sig =~ /^(\w+), (u?)int : unit$/) {
my $unsigned = $2 eq "u" ? "unsigned " : "";
"\
" . gen_unpack_args ($1) . "
${unsigned}int i = Int_val (iv);
int r;
NONBLOCKING (r = $c_name ($1, i));
CHECK_ERROR (r == -1, \"$c_name\");
CAMLreturn (Val_unit);
"
} elsif ($sig =~ /^(\w+), (u?)int : (\w+)$/) {
my $c_ret_type = short_name_to_c_type ($3);
my $unsigned = $2 eq "u" ? "unsigned " : "";
"\
CAMLlocal1 (rv);
" . gen_unpack_args ($1) . "
${unsigned}int i = Int_val (iv);
$c_ret_type r;
NONBLOCKING (r = $c_name ($1, i));
CHECK_ERROR (!r, \"$c_name\");
" . gen_pack_result ($3) . "
CAMLreturn (rv);
"
} elsif ($sig =~ /^(\w+), uuid : (\w+)$/) {
my $c_ret_type = short_name_to_c_type ($2);
"\
CAMLlocal1 (rv);
" . gen_unpack_args ($1) . "
unsigned char *uuid = (unsigned char *) String_val (uuidv);
$c_ret_type r;
NONBLOCKING (r = $c_name ($1, uuid));
CHECK_ERROR (!r, \"$c_name\");
" . gen_pack_result ($2) . "
CAMLreturn (rv);
"
} elsif ($sig =~ /^(\w+), 0U? : (\w+)$/) {
my $c_ret_type = short_name_to_c_type ($2);
"\
CAMLlocal1 (rv);
" . gen_unpack_args ($1) . "
$c_ret_type r;
NONBLOCKING (r = $c_name ($1, 0));
CHECK_ERROR (!r, \"$c_name\");
" . gen_pack_result ($2) . "
CAMLreturn (rv);
"
} elsif ($sig =~ /^(\w+) : (\w+)$/) {
my $c_ret_type = short_name_to_c_type ($2);
"\
CAMLlocal1 (rv);
" . gen_unpack_args ($1) . "
$c_ret_type r;
NONBLOCKING (r = $c_name ($1));
CHECK_ERROR (!r, \"$c_name\");
" . gen_pack_result ($2) . "
CAMLreturn (rv);
"
} elsif ($sig =~ /^(\w+), string : (\w+) from (\w+)$/) {
my $c_ret_type = short_name_to_c_type ($2);
"\
CAMLlocal2 (rv, connv);
" . gen_unpack_args ($1) . "
char *str = String_val (strv);
$c_ret_type r;
NONBLOCKING (r = $c_name ($1, str));
CHECK_ERROR (!r, \"$c_name\");
connv = Field ($3v, 1);
" . gen_pack_result ($2) . "
CAMLreturn (rv);
"
} elsif ($sig =~ /^(\w+), string, 0U? : (\w+) from (\w+)$/) {
my $c_ret_type = short_name_to_c_type ($2);
"\
CAMLlocal2 (rv, connv);
" . gen_unpack_args ($1) . "
char *str = String_val (strv);
$c_ret_type r;
NONBLOCKING (r = $c_name ($1, str, 0));
CHECK_ERROR (!r, \"$c_name\");
connv = Field ($3v, 1);
" . gen_pack_result ($2) . "
CAMLreturn (rv);
"
} elsif ($sig =~ /^(\w+), 0U? : (\w+) from (\w+)$/) {
my $c_ret_type = short_name_to_c_type ($2);
"\
CAMLlocal2 (rv, connv);
" . gen_unpack_args ($1) . "
$c_ret_type r;
NONBLOCKING (r = $c_name ($1, 0));
CHECK_ERROR (!r, \"$c_name\");
connv = Field ($3v, 1);
" . gen_pack_result ($2) . "
CAMLreturn (rv);
"
} elsif ($sig =~ /^(\w+) : (\w+) from (\w+)$/) {
my $c_ret_type = short_name_to_c_type ($2);
"\
CAMLlocal2 (rv, connv);
" . gen_unpack_args ($1) . "
$c_ret_type r;
NONBLOCKING (r = $c_name ($1));
CHECK_ERROR (!r, \"$c_name\");
connv = Field ($3v, 1);
" . gen_pack_result ($2) . "
CAMLreturn (rv);
"
} else {
die "unknown signature $sig"
}
}
# Generate each function.
foreach my $function (@functions) {
my $c_name = $function->{name};
my $sig = $function->{sig};
#print "generating $c_name with sig \"$sig\" ...\n";
#my $is_pool_func = $c_name =~ /^virStoragePool/;
#my $is_vol_func = $c_name =~ /^virStorageVol/;
# Generate an equivalent C-external name for the function, unless
# one is defined already.
my $c_external_name;
if (exists ($function->{c_external_name})) {
$c_external_name = $function->{c_external_name};
} elsif ($c_name =~ /^vir/) {
$c_external_name = substr $c_name, 3;
$c_external_name = camel_case_to_underscores ($c_external_name);
$c_external_name = "ocaml_libvirt_" . $c_external_name;
} else {
die "cannot convert c_name $c_name to c_external_name"
}
print F <<END;
/* Automatically generated binding for $c_name.
* In generator.pl this function has signature "$sig".
*/
END
my @arg_names = gen_arg_names ($sig);
my $nr_arg_names = scalar @arg_names;
my $arg_names = join ", ", @arg_names;
my $arg_names_as_values = join (", ", map { "value $_" } @arg_names);
# Generate the start of the function, arguments.
print F <<END;
CAMLprim value
$c_external_name ($arg_names_as_values)
{
CAMLparam$nr_arg_names ($arg_names);
END
# Generate the internals of the function.
print F (gen_c_code ($sig, $c_name));
# Finish off the function.
print F <<END;
}
END
}
#----------------------------------------------------------------------
# Unimplemented functions.
if (@unimplemented) {
printf "$0: warning: %d unimplemented functions\n", scalar (@unimplemented);
print F <<'END';
/* The following functions are unimplemented and always fail.
* See generator.pl '@unimplemented'
*/
END
foreach my $c_external_name (@unimplemented) {
print F <<END;
CAMLprim value
$c_external_name ()
{
failwith ("$c_external_name is unimplemented");
}
END
} # end foreach
} # end if @unimplemented
#----------------------------------------------------------------------
# Write the epilogue.
print F <<'END';
#include "libvirt_c_epilogue.c"
/* EOF */
END
close F;
print "$0: written $filename\n"

View File

@@ -0,0 +1,12 @@
The files generator.pl, libvirt_c_epilogue.c, libvirt_c_oneoffs.c,
libvirt_c_prologue.c, libvirt.ml, and libvirt.mli come from the
libvirt-ocaml library:
https://libvirt.org/git/?p=libvirt-ocaml.git
which is released under a compatible license. We want to keep them
identical, so changes to these files must be submitted to
libvirt-ocaml first.
Before libguestfs 1.42 is released we hope to have unbundled this
library and will require that libvirt-ocaml is used instead.

1673
common/mllibvirt/libvirt.ml Normal file

File diff suppressed because it is too large Load Diff

1647
common/mllibvirt/libvirt.mli Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,462 @@
/* OCaml bindings for libvirt.
* (C) Copyright 2007 Richard W.M. Jones, Red Hat Inc.
* https://libvirt.org/
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version,
* with the OCaml linking exception described in ../COPYING.LIB.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* Please read libvirt/README file. */
static const char *
Optstring_val (value strv)
{
if (strv == Val_int (0)) /* None */
return NULL;
else /* Some string */
return String_val (Field (strv, 0));
}
static value
Val_opt (void *ptr, Val_ptr_t Val_ptr)
{
CAMLparam0 ();
CAMLlocal2 (optv, ptrv);
if (ptr) { /* Some ptr */
optv = caml_alloc (1, 0);
ptrv = Val_ptr (ptr);
Store_field (optv, 0, ptrv);
} else /* None */
optv = Val_int (0);
CAMLreturn (optv);
}
static value
Val_opt_const (const void *ptr, Val_const_ptr_t Val_ptr)
{
CAMLparam0 ();
CAMLlocal2 (optv, ptrv);
if (ptr) { /* Some ptr */
optv = caml_alloc (1, 0);
ptrv = Val_ptr (ptr);
Store_field (optv, 0, ptrv);
} else /* None */
optv = Val_int (0);
CAMLreturn (optv);
}
#if 0
static value
option_default (value option, value deflt)
{
if (option == Val_int (0)) /* "None" */
return deflt;
else /* "Some 'a" */
return Field (option, 0);
}
#endif
static void
_raise_virterror (const char *fn)
{
CAMLparam0 ();
CAMLlocal1 (rv);
virErrorPtr errp;
struct _virError err;
errp = virGetLastError ();
if (!errp) {
/* Fake a _virError structure. */
memset (&err, 0, sizeof err);
err.code = VIR_ERR_INTERNAL_ERROR;
err.domain = VIR_FROM_NONE;
err.level = VIR_ERR_ERROR;
err.message = (char *) fn;
errp = &err;
}
rv = Val_virterror (errp);
caml_raise_with_arg (*caml_named_value ("ocaml_libvirt_virterror"), rv);
/*NOTREACHED*/
/* Suppresses a compiler warning. */
(void) caml__frame;
}
static int
_list_length (value listv)
{
CAMLparam1 (listv);
int len = 0;
for (; listv != Val_emptylist; listv = Field (listv, 1), ++len) {}
CAMLreturnT (int, len);
}
static value
Val_virconnectcredential (const virConnectCredentialPtr cred)
{
CAMLparam0 ();
CAMLlocal1 (rv);
rv = caml_alloc (4, 0);
Store_field (rv, 0, Val_int (cred->type - 1));
Store_field (rv, 1, caml_copy_string (cred->prompt));
Store_field (rv, 2,
Val_opt_const (cred->challenge,
(Val_const_ptr_t) caml_copy_string));
Store_field (rv, 3,
Val_opt_const (cred->defresult,
(Val_const_ptr_t) caml_copy_string));
CAMLreturn (rv);
}
/* 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 104 /* VIR_ERR_NO_DOMAIN_BACKUP */
#define MAX_VIR_DOMAIN 69 /* VIR_FROM_DOMAIN_CHECKPOINT */
#define MAX_VIR_LEVEL VIR_ERR_ERROR
static inline value
Val_err_number (virErrorNumber code)
{
CAMLparam0 ();
CAMLlocal1 (rv);
if (0 <= (int) 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 <= (int) 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 <= (int) 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)
{
CAMLparam0 ();
CAMLlocal3 (rv, connv, optv);
rv = caml_alloc (9, 0);
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_err_level (err->level));
Store_field (rv, 4,
Val_opt (err->str1, (Val_ptr_t) caml_copy_string));
Store_field (rv, 5,
Val_opt (err->str2, (Val_ptr_t) caml_copy_string));
Store_field (rv, 6,
Val_opt (err->str3, (Val_ptr_t) caml_copy_string));
Store_field (rv, 7, caml_copy_int32 (err->int1));
Store_field (rv, 8, caml_copy_int32 (err->int2));
CAMLreturn (rv);
}
static void conn_finalize (value);
static void dom_finalize (value);
static void net_finalize (value);
static void pol_finalize (value);
static void vol_finalize (value);
static void sec_finalize (value);
static struct custom_operations conn_custom_operations = {
(char *) "conn_custom_operations",
conn_finalize,
custom_compare_default,
custom_hash_default,
custom_serialize_default,
custom_deserialize_default
};
static struct custom_operations dom_custom_operations = {
(char *) "dom_custom_operations",
dom_finalize,
custom_compare_default,
custom_hash_default,
custom_serialize_default,
custom_deserialize_default
};
static struct custom_operations net_custom_operations = {
(char *) "net_custom_operations",
net_finalize,
custom_compare_default,
custom_hash_default,
custom_serialize_default,
custom_deserialize_default
};
static struct custom_operations pol_custom_operations = {
(char *) "pol_custom_operations",
pol_finalize,
custom_compare_default,
custom_hash_default,
custom_serialize_default,
custom_deserialize_default
};
static struct custom_operations vol_custom_operations = {
(char *) "vol_custom_operations",
vol_finalize,
custom_compare_default,
custom_hash_default,
custom_serialize_default,
custom_deserialize_default
};
static struct custom_operations sec_custom_operations = {
(char *) "sec_custom_operations",
sec_finalize,
custom_compare_default,
custom_hash_default,
custom_serialize_default,
custom_deserialize_default
};
static value
Val_connect (virConnectPtr conn)
{
CAMLparam0 ();
CAMLlocal1 (rv);
rv = caml_alloc_custom (&conn_custom_operations,
sizeof (virConnectPtr), 0, 1);
Connect_val (rv) = conn;
CAMLreturn (rv);
}
static value
Val_dom (virDomainPtr dom)
{
CAMLparam0 ();
CAMLlocal1 (rv);
rv = caml_alloc_custom (&dom_custom_operations,
sizeof (virDomainPtr), 0, 1);
Dom_val (rv) = dom;
CAMLreturn (rv);
}
static value
Val_net (virNetworkPtr net)
{
CAMLparam0 ();
CAMLlocal1 (rv);
rv = caml_alloc_custom (&net_custom_operations,
sizeof (virNetworkPtr), 0, 1);
Net_val (rv) = net;
CAMLreturn (rv);
}
static value
Val_pol (virStoragePoolPtr pol)
{
CAMLparam0 ();
CAMLlocal1 (rv);
rv = caml_alloc_custom (&pol_custom_operations,
sizeof (virStoragePoolPtr), 0, 1);
Pol_val (rv) = pol;
CAMLreturn (rv);
}
static value
Val_vol (virStorageVolPtr vol)
{
CAMLparam0 ();
CAMLlocal1 (rv);
rv = caml_alloc_custom (&vol_custom_operations,
sizeof (virStorageVolPtr), 0, 1);
Vol_val (rv) = vol;
CAMLreturn (rv);
}
static value
Val_sec (virSecretPtr sec)
{
CAMLparam0 ();
CAMLlocal1 (rv);
rv = caml_alloc_custom (&sec_custom_operations,
sizeof (virSecretPtr), 0, 1);
Sec_val (rv) = sec;
CAMLreturn (rv);
}
/* This wraps up the (dom, conn) pair (Domain.t). */
static value
Val_domain (virDomainPtr dom, value connv)
{
CAMLparam1 (connv);
CAMLlocal2 (rv, v);
rv = caml_alloc_tuple (2);
v = Val_dom (dom);
Store_field (rv, 0, v);
Store_field (rv, 1, connv);
CAMLreturn (rv);
}
/* This wraps up the (net, conn) pair (Network.t). */
static value
Val_network (virNetworkPtr net, value connv)
{
CAMLparam1 (connv);
CAMLlocal2 (rv, v);
rv = caml_alloc_tuple (2);
v = Val_net (net);
Store_field (rv, 0, v);
Store_field (rv, 1, connv);
CAMLreturn (rv);
}
/* This wraps up the (pol, conn) pair (Pool.t). */
static value
Val_pool (virStoragePoolPtr pol, value connv)
{
CAMLparam1 (connv);
CAMLlocal2 (rv, v);
rv = caml_alloc_tuple (2);
v = Val_pol (pol);
Store_field (rv, 0, v);
Store_field (rv, 1, connv);
CAMLreturn (rv);
}
/* This wraps up the (vol, conn) pair (Volume.t). */
static value
Val_volume (virStorageVolPtr vol, value connv)
{
CAMLparam1 (connv);
CAMLlocal2 (rv, v);
rv = caml_alloc_tuple (2);
v = Val_vol (vol);
Store_field (rv, 0, v);
Store_field (rv, 1, connv);
CAMLreturn (rv);
}
/* This wraps up the (sec, conn) pair (Secret.t). */
static value
Val_secret (virSecretPtr sec, value connv)
{
CAMLparam1 (connv);
CAMLlocal2 (rv, v);
rv = caml_alloc_tuple (2);
v = Val_sec (sec);
Store_field (rv, 0, v);
Store_field (rv, 1, connv);
CAMLreturn (rv);
}
static void
conn_finalize (value connv)
{
virConnectPtr conn = Connect_val (connv);
if (conn) (void) virConnectClose (conn);
}
static void
dom_finalize (value domv)
{
virDomainPtr dom = Dom_val (domv);
if (dom) (void) virDomainFree (dom);
}
static void
net_finalize (value netv)
{
virNetworkPtr net = Net_val (netv);
if (net) (void) virNetworkFree (net);
}
static void
pol_finalize (value polv)
{
virStoragePoolPtr pol = Pol_val (polv);
if (pol) (void) virStoragePoolFree (pol);
}
static void
vol_finalize (value volv)
{
virStorageVolPtr vol = Vol_val (volv);
if (vol) (void) virStorageVolFree (vol);
}
static void
sec_finalize (value secv)
{
virSecretPtr sec = Sec_val (secv);
if (sec) (void) virSecretFree (sec);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,134 @@
/* OCaml bindings for libvirt.
* (C) Copyright 2007 Richard W.M. Jones, Red Hat Inc.
* https://libvirt.org/
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version,
* with the OCaml linking exception described in ../COPYING.LIB.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* Please read libvirt/README file. */
static const char *Optstring_val (value strv);
typedef value (*Val_ptr_t) (void *);
static value Val_opt (void *ptr, Val_ptr_t Val_ptr);
typedef value (*Val_const_ptr_t) (const void *);
static value Val_opt_const (const void *ptr, Val_const_ptr_t Val_ptr);
/*static value option_default (value option, value deflt);*/
static void _raise_virterror (const char *fn) Noreturn;
static value Val_virterror (virErrorPtr err);
static int _list_length (value listv);
static value Val_virconnectcredential (const virConnectCredentialPtr cred);
/* Use this around synchronous libvirt API calls to release the OCaml
* lock, allowing other threads to run simultaneously. 'code' must not
* perform any caml_* calls, run any OCaml code, or raise any exception.
* https://web.archive.org/web/20030521020915/http://caml.inria.fr/archives/200106/msg00199.html
*/
#define NONBLOCKING(code) \
do { \
caml_enter_blocking_section (); \
code; \
caml_leave_blocking_section (); \
} while (0)
/* Empty macro to use as empty parameter for other macros, since
* a null token as parameter when calling a macro is not allowed
* before C99.
*/
#define EMPTY
/* Check error condition from a libvirt function, and automatically raise
* an exception if one is found.
*/
#define CHECK_ERROR_CLEANUP(cond, cleanup, fn) \
do { if (cond) { cleanup; _raise_virterror (fn); } } while (0)
#define CHECK_ERROR(cond, fn) \
CHECK_ERROR_CLEANUP(cond, EMPTY, fn)
/*----------------------------------------------------------------------*/
/* Some notes about the use of custom blocks to store virConnectPtr,
* virDomainPtr and virNetworkPtr.
*------------------------------------------------------------------
*
* Libvirt does some tricky reference counting to keep track of
* virConnectPtr's, virDomainPtr's and virNetworkPtr's.
*
* There is only one function which can return a virConnectPtr
* (virConnectOpen*) and that allocates a new one each time.
*
* virDomainPtr/virNetworkPtr's on the other hand can be returned
* repeatedly (for the same underlying domain/network), and we must
* keep track of each one and explicitly free it with virDomainFree
* or virNetworkFree. If we lose track of one then the reference
* counting in libvirt will keep it open. We therefore wrap these
* in a custom block with a finalizer function.
*
* We also have to allow the user to explicitly free them, in
* which case we set the pointer inside the custom block to NULL.
* The finalizer notices this and doesn't free the object.
*
* Domains and networks "belong to" a connection. We have to avoid
* the situation like this:
*
* let conn = Connect.open ... in
* let dom = Domain.lookup_by_id conn 0 in
* (* conn goes out of scope and is garbage collected *)
* printf "dom name = %s\n" (Domain.get_name dom)
*
* The reason is that when conn is garbage collected, virConnectClose
* is called and any subsequent operations on dom will fail (in fact
* will probably segfault). To stop this from happening, the OCaml
* wrappers store domains (and networks) as explicit (dom, conn)
* pairs.
*
* Update 2008/01: Storage pools and volumes work the same way as
* domains and networks.
*/
/* Unwrap a custom block. */
#define Connect_val(rv) (*((virConnectPtr *)Data_custom_val(rv)))
#define Dom_val(rv) (*((virDomainPtr *)Data_custom_val(rv)))
#define Net_val(rv) (*((virNetworkPtr *)Data_custom_val(rv)))
#define Pol_val(rv) (*((virStoragePoolPtr *)Data_custom_val(rv)))
#define Vol_val(rv) (*((virStorageVolPtr *)Data_custom_val(rv)))
#define Sec_val(rv) (*((virSecretPtr *)Data_custom_val(rv)))
/* Wrap up a pointer to something in a custom block. */
static value Val_connect (virConnectPtr conn);
static value Val_dom (virDomainPtr dom);
static value Val_net (virNetworkPtr net);
static value Val_pol (virStoragePoolPtr pool);
static value Val_vol (virStorageVolPtr vol);
static value Val_sec (virSecretPtr sec);
/* Domains and networks are stored as pairs (dom/net, conn), so have
* some convenience functions for unwrapping and wrapping them.
*/
#define Domain_val(rv) (Dom_val(Field((rv),0)))
#define Network_val(rv) (Net_val(Field((rv),0)))
#define Pool_val(rv) (Pol_val(Field((rv),0)))
#define Volume_val(rv) (Vol_val(Field((rv),0)))
#define Secret_val(rv) (Sec_val(Field((rv),0)))
#define Connect_domv(rv) (Connect_val(Field((rv),1)))
#define Connect_netv(rv) (Connect_val(Field((rv),1)))
#define Connect_polv(rv) (Connect_val(Field((rv),1)))
#define Connect_volv(rv) (Connect_val(Field((rv),1)))
#define Connect_secv(rv) (Connect_val(Field((rv),1)))
static value Val_domain (virDomainPtr dom, value connv);
static value Val_network (virNetworkPtr net, value connv);
static value Val_pool (virStoragePoolPtr pol, value connv);
static value Val_volume (virStorageVolPtr vol, value connv);
static value Val_secret (virSecretPtr sec, value connv);

View File

@@ -243,6 +243,7 @@ AC_CONFIG_FILES([Makefile
common/miniexpect/Makefile
common/mlaugeas/Makefile
common/mlgettext/Makefile
common/mllibvirt/Makefile
common/mlpcre/Makefile
common/mlprogress/Makefile
common/mlstdutils/Makefile