New Rust bindings for nbdkit
by alan somers
The existing Rust bindings for nbdkit aren't very idiomatic Rust, and they
are missing a lot of features. So I've rewritten them. The new bindings
aren't backwards compatible, but I doubt that's a problem. Most likely,
nobody has tried to use them yet, since the crate hasn't even published to
crates.io. Please review the attached patch.
-Alan
4 years, 6 months
[PATCH] v2v: fix spelling errors in Python comments
by Kevin Locke
These were flagged by the [Lintian] [spelling-error-in-binary] rule.
[Lintian]: https://github.com/Debian/lintian
[spelling-error-in-binary]: https://lintian.debian.org/tags/spelling-error-in-binary.html
Signed-off-by: Kevin Locke <kevin(a)kevinlocke.name>
---
v2v/rhv-upload-plugin.py | 4 ++--
v2v/rhv-upload-vmcheck.py | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py
index d3e6260e..8c11012b 100644
--- a/v2v/rhv-upload-plugin.py
+++ b/v2v/rhv-upload-plugin.py
@@ -83,7 +83,7 @@ def parse_username():
def failing(func):
"""
- Decorator marking the handle as failed if any expection is raised in the
+ Decorator marking the handle as failed if any exception is raised in the
decorated function. This is used in close() to cleanup properly after
failures.
"""
@@ -358,7 +358,7 @@ def close(h):
http.close()
- # If the connection failed earlier ensure we cancel the trasfer. Canceling
+ # If the connection failed earlier ensure we cancel the transfer. Canceling
# the transfer will delete the disk.
if h['failed']:
try:
diff --git a/v2v/rhv-upload-vmcheck.py b/v2v/rhv-upload-vmcheck.py
index 0c597e19..6ad698aa 100644
--- a/v2v/rhv-upload-vmcheck.py
+++ b/v2v/rhv-upload-vmcheck.py
@@ -1,5 +1,5 @@
# -*- python -*-
-# oVirt or RHV VM existance check used by ‘virt-v2v -o rhv-upload’
+# oVirt or RHV VM existence check used by ‘virt-v2v -o rhv-upload’
# Copyright (C) 2018-2020 Red Hat Inc.
#
# This program is free software; you can redistribute it and/or modify
--
2.26.2
4 years, 6 months
[nbdkit] About the Rust bindings
by Richard W.M. Jones
[To continue the conversation from
https://github.com/libguestfs/nbdkit/issues/5]
> Currently there's no way for the Rust plugin to report an error. The
> idiomatic way to do it would be for each callback to return a Result
> object, much like how the Go plugin currently does it.
I'm sure it's not idiomatic for Rust, but I just wanted to say that
there is a way to return an error: return -1. But a bigger issue
seems to be how to pass back the correct errno (assuming that Rust
even collects this from low-level syscalls?).
For historical reasons nbdkit plugins written in C set errno on error
and nbdkit server reads the errno and may translate it into NBD errors
on the wire (so it's generally important to get it right).
However your plugin may set .errno_is_preserved = 0, then you can call
nbdkit_set_error() whenever convenient before returning an error to
set the errno that nbdkit will use. In OCaml plugins we have to go
through some hoops to convert OCaml errno (which use a different
numbering) to system errno:
https://github.com/libguestfs/nbdkit/blob/904c4e5fdca557d6d25a60e6fb12fa0...
The other issue (from golang bindings) was threads. Does Rust use
native system pthreads? If it does then there shouldn't be an issue.
golang implements its own green threads and that was a problem.
Rich.
--
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming and virtualization blog: http://rwmj.wordpress.com
libguestfs lets you edit virtual machines. Supports shell scripting,
bindings from many languages. http://libguestfs.org
4 years, 6 months
virt-v2v: test-v2v-oa-option.sh: output is not preallocated
by Kevin Locke
Hi All,
Thanks to your previous assistance, I'm able to compile virt-v2v
1.42.0 on Debian testing. However, when I run `make check`
tests/test-v2v-oa-option.sh fails with the following log:
-8<------------------------------------------------------------------
test-v2v-oa-option.sh: info: you can skip this test by setting SKIP_TEST_V2V_OA_OPTION_SH=1
[ 0.0] Opening the source -i libvirt -ic test:///home/kevin/tmp/virt-v2v/test-data/phony-guests/guests.xml windows
[ 0.0] Creating an overlay to protect the source from being modified
[ 0.2] Opening the overlay
[ 33.6] Inspecting the overlay
[ 62.1] Checking for sufficient free disk space in the guest
[ 62.1] Estimating space required on target for each disk
[ 62.1] Converting Microsoft Windows 7 Phony Edition to run on KVM
virt-v2v: warning: QEMU Guest Agent MSI not found on tools ISO/directory.
You may want to install the guest agent manually after conversion.
virt-v2v: warning: there are no virtio drivers available for this version
of Windows (6.1 i386 Client). virt-v2v looks for drivers in
/usr/share/virtio-win
The guest will be configured to use slower emulated devices.
virt-v2v: This guest does not have virtio drivers installed.
[ 71.0] Mapping filesystem data to avoid copying unused and blank areas
[ 87.7] Closing the overlay
[ 88.5] Assigning disks to buses
[ 88.5] Checking if the guest needs BIOS or UEFI to boot
[ 88.5] Initializing the target -o local -os test-v2v-oa-option.d
[ 88.5] Copying disk 1/1 to test-v2v-oa-option.d/windows-sda (qcow2)
(0.00/100%)
(1.50/100%)
(3.00/100%)
(4.50/100%)
(6.00/100%)
(10.50/100%)
(15.00/100%)
(16.49/100%)
(17.99/100%)
(19.49/100%)
(20.99/100%)
(22.49/100%)
(26.99/100%)
(28.49/100%)
(38.99/100%)
(40.49/100%)
(46.02/100%)
(47.52/100%)
(49.02/100%)
(50.52/100%)
(52.01/100%)
(56.51/100%)
(61.01/100%)
(62.51/100%)
(64.01/100%)
(67.01/100%)
(68.51/100%)
(70.01/100%)
(74.51/100%)
(76.01/100%)
(86.50/100%)
(88.00/100%)
(94.00/100%)
(95.50/100%)
(97.00/100%)
(98.50/100%)
(100.00/100%)
(100.00/100%)
[ 88.9] Creating output metadata
[ 88.9] Finishing off
./test-v2v-oa-option.sh: test failed: output is not preallocated
FAIL test-v2v-oa-option.sh (exit status: 1)
-8<------------------------------------------------------------------
For reference, the test machine is running Linux 5.7.0 and the source
is on an ext4 filesystem. If anyone could point me in the right
direction for tracking this down, I'd appreciate it once more.
Thanks again,
Kevin
4 years, 6 months
[PATCH] v2v: fix UEFI bootloader for linux guests
by Denis Plotnikov
Not all UEFI guests can survive conversion, because of lost bootloader
information in UEFI NVRAM. But some guest can cope with this because they
have a fallback bootloader and use UEFI Removable Media Boot Behavior.
(see https://uefi.org/sites/default/files/resources/UEFI_Spec_2_8_A_Feb14.pdf
3.5.1.1 Removable Media Boot Behavior) to load. If UEFI firmware can't find
a bootloader in its settings it uses the removable media boot behavior to
find a bootloader.
We can fix the guests which don't have such a fallback loader by providing
a temporary one. This bootloader is used for the first boot only, then the
conversion script restores the initial bootloader settings and removes the
temporary loader.
Signed-off-by: Denis Plotnikov <dplotnikov(a)virtuozzo.com>
---
v2v/convert_linux.ml | 15 +++++
v2v/linux_bootloaders.ml | 149 ++++++++++++++++++++++++++++++++++++++++++++--
v2v/linux_bootloaders.mli | 2 +
3 files changed, 162 insertions(+), 4 deletions(-)
diff --git a/v2v/convert_linux.ml b/v2v/convert_linux.ml
index e91ae12..77a2555 100644
--- a/v2v/convert_linux.ml
+++ b/v2v/convert_linux.ml
@@ -1122,6 +1122,21 @@ shutdown -h -P +0
Linux.augeas_reload g
);
+ (* Some linux uefi setups can't boot after conversion because of
+ lost uefi boot entries. The uefi boot entries are stored in uefi
+ NVRAM. The NVRAM content isn't a part of vm disk content and
+ usualy can't be converted with a vm. If a vm doesn't have uefi
+ fallback path (/EFI/BOOT/BOOT<arch>.efi), the vm is unbootable
+ after conversion. The following function will try to make an uefi
+ fallback path if the vm being converted is an uefi setup.
+ *)
+
+ let efi_fix_script = bootloader#fix_efi_boot () in
+
+ if efi_fix_script <> "" then
+ Firstboot.add_firstboot_script g inspect.i_root
+ "fix uefi boot" efi_fix_script;
+
(* Delete blkid caches if they exist, since they will refer to the old
* device names. blkid will rebuild these on demand.
*
diff --git a/v2v/linux_bootloaders.ml b/v2v/linux_bootloaders.ml
index de3d107..cdab7bf 100644
--- a/v2v/linux_bootloaders.ml
+++ b/v2v/linux_bootloaders.ml
@@ -36,6 +36,7 @@ class virtual bootloader = object
method virtual configure_console : unit -> unit
method virtual remove_console : unit -> unit
method update () = ()
+ method virtual fix_efi_boot : unit -> string
end
(* Helper function for SUSE: remove (hdX,X) prefix from a path. *)
@@ -43,6 +44,115 @@ let remove_hd_prefix =
let rex = PCRE.compile "^\\(hd.*\\)" in
PCRE.replace rex ""
+(* Standard uefi fallback path *)
+let uefi_fallback_path =
+ "/boot/efi/EFI/BOOT/"
+
+(* Helper function checks if 'source' contains 's' *)
+let contains source s =
+ let re = Str.regexp_string s in
+ try
+ ignore (Str.search_forward re source 0);
+ true
+ with Not_found -> false
+
+(* Helper function to get architecture suffixes for uefi files *)
+let get_uefi_arch_suffix arch =
+ let arch_suffix =
+ if contains arch "x86_64" then "X64"
+ else if contains arch "x86_32" then "X32"
+ else "" in
+ arch_suffix
+
+(* Function fixes uefi boot. It's used in both cases: legacy grub and grub2 *)
+let fix_uefi g distro distro_ver grub_config arch =
+ let cant_fix_uefi () = (
+ info (f_"Can't fix UEFI bootloader. VM may not boot.");
+ "" ) in
+
+ let file_exists file =
+ if g#exists file then
+ true
+ else (
+ info (f_"Can't find file: '%s' needed for UEFI bootloader fixing") file;
+ false ) in
+
+ let grub_path = String.sub grub_config 0 (String.rindex grub_config '/') in
+ let uefi_fallback_name =
+ let arch_suffix = get_uefi_arch_suffix arch in
+ if arch_suffix <> "" then
+ String.concat "" [uefi_fallback_path; "BOOT"; arch_suffix; ".EFI"]
+ else
+ "" in
+
+ if uefi_fallback_name = "" then (
+ info (f_"Can't determine UEFI fallback path.");
+ cant_fix_uefi () )
+ else if g#exists uefi_fallback_name then
+ (* don't do anything if uefi fallback exists *)
+ ""
+ else if uefi_fallback_name = "" then
+ cant_fix_uefi ()
+ else (
+ info (f_"Fixing UEFI bootloader.");
+ match distro, distro_ver with
+ | "centos", 6 ->
+ (* to make a bootable uefi centos 6 we need to
+ * copy grub.efi and grub.conf to UEFI fallback path
+ * and rename them to BOOT<arch>.efi and BOOT<arch>.conf
+ * correspondingly *)
+ let uefi_grub_name = String.concat "" [grub_path; "/grub.efi"] in
+ let uefi_grub_conf = String.concat "" [
+ String.sub uefi_fallback_name 0
+ (String.rindex uefi_fallback_name '.');
+ ".conf" ] in
+ if file_exists uefi_grub_name && file_exists grub_config then (
+ g#mkdir_p uefi_fallback_path;
+ g#cp uefi_grub_name uefi_fallback_name;
+ g#cp grub_config uefi_grub_conf;
+ let script = sprintf
+"#!/bin/bash
+efibootmgr -c -L \"CentOS 6\"
+rm -rf %s" uefi_fallback_path in
+ script )
+ else
+ cant_fix_uefi ()
+ | "ubuntu", 14 ->
+ (* to make a bootable uefi ubuntu 14 we need to
+ * copy shim<arch>.efi to UEFI fallback path
+ * and rename it to BOOT<arch>.efi, also we copy
+ * grub.efi and grub.cfg to UEFI fallback path without renaming *)
+ let arch_suffix =
+ String.lowercase_ascii (get_uefi_arch_suffix arch) in
+ let shim =
+ String.concat "" [grub_path; "/shim"; arch_suffix; ".efi"] in
+ let uefi_grub_name =
+ String.concat "" [grub_path; "/grub"; arch_suffix; ".efi"] in
+
+ if file_exists shim && file_exists uefi_grub_name
+ && file_exists grub_config then (
+ g#mkdir_p uefi_fallback_path;
+ g#cp shim uefi_fallback_name;
+ g#cp uefi_grub_name uefi_fallback_path;
+ g#cp grub_config uefi_fallback_path;
+ (* if the shim is at the standard path, clean up uefi fixing
+ * if not, then just don't clean up and leave the temp loader
+ * at UEFI fallback path for simplicity
+ *)
+ if contains shim "/boot/efi/EFI/ubuntu/shim" then
+ sprintf
+"#!/bin/bash
+sudo efibootmgr -c -L ubuntu -l \\\\EFI\\\\ubuntu\\\\shim%s.efi
+rm -rf %s" arch_suffix uefi_fallback_path
+ else
+ "")
+ else
+ cant_fix_uefi ()
+ | _, _ ->
+ info (f_"No UEFI fix rule for %s %d") distro distro_ver;
+ cant_fix_uefi ()
+ )
+
(* Grub1 (AKA grub-legacy) representation. *)
class bootloader_grub1 (g : G.guestfs) inspect grub_config =
let () =
@@ -60,6 +170,16 @@ class bootloader_grub1 (g : G.guestfs) inspect grub_config =
fun path -> List.mem_assoc path mounts
) [ "/boot/grub"; "/boot" ]
with Not_found -> "" in
+
+ let uefi_active =
+ match inspect.i_firmware with
+ | I_UEFI _ -> true
+ | _ -> false in
+
+ let arch = inspect.i_arch in
+ let distro = inspect.i_distro in
+ let distro_ver_major = inspect.i_major_version in
+
object
inherit bootloader
@@ -184,6 +304,12 @@ object
loop paths;
g#aug_save ()
+
+ method fix_efi_boot () =
+ if uefi_active then
+ fix_uefi g distro distro_ver_major grub_config arch
+ else
+ ""
end
(** The method used to get and set the default kernel in Grub2. *)
@@ -193,7 +319,7 @@ type default_kernel_method =
| MethodNone (** No known way. *)
(* Grub2 representation. *)
-class bootloader_grub2 (g : G.guestfs) grub_config =
+class bootloader_grub2 (g : G.guestfs) inspect grub_config =
let grub2_mkconfig_cmd =
let elems = [
@@ -221,6 +347,15 @@ class bootloader_grub2 (g : G.guestfs) grub_config =
MethodNone
) in
+ let uefi_active =
+ match inspect.i_firmware with
+ | I_UEFI _ -> true
+ | _ -> false in
+
+ let arch = inspect.i_arch in
+ let distro = inspect.i_distro in
+ let distro_ver_major = inspect.i_major_version in
+
object (self)
inherit bootloader
@@ -340,8 +475,14 @@ object (self)
method remove_console = self#grub2_update_console ~remove:true
- method update () =
- ignore (g#command [| grub2_mkconfig_cmd; "-o"; grub_config |])
+ method update () = (
+ ignore (g#command [| grub2_mkconfig_cmd; "-o"; grub_config |]))
+
+ method fix_efi_boot () =
+ if uefi_active then
+ fix_uefi g distro distro_ver_major grub_config arch
+ else
+ ""
end
(* Helper type used in detect_bootloader. *)
@@ -390,6 +531,6 @@ let detect_bootloader (g : G.guestfs) inspect =
let bl =
match typ with
| Grub1 -> new bootloader_grub1 g inspect grub_config
- | Grub2 -> new bootloader_grub2 g grub_config in
+ | Grub2 -> new bootloader_grub2 g inspect grub_config in
debug "detected bootloader %s at %s" bl#name grub_config;
bl
diff --git a/v2v/linux_bootloaders.mli b/v2v/linux_bootloaders.mli
index 30cdfe3..c4e1069 100644
--- a/v2v/linux_bootloaders.mli
+++ b/v2v/linux_bootloaders.mli
@@ -44,6 +44,8 @@ class virtual bootloader : object
(** Update the bootloader: For grub2 only this runs the
[grub2-mkconfig] command to rebuild the configuration. This
is not necessary for grub-legacy. *)
+ method virtual fix_efi_boot : unit -> string
+ (** fix UEFI bootloader and return a clean up script. *)
end
(** Encapsulates a Linux boot loader as object. *)
--
1.8.3.1
4 years, 6 months
[PATCH] v2v: convert-windows: remove installation reference for prl_strg driver
by Denis Plotnikov
There is an issue with removal of parallels disk paravirt driver.
Without the patch, the VM being migrated may not boot on the
desination with BSOD: 0x7b.
The patch is a workaround to prevent the BSOD.
Signed-off-by: Denis Plotnikov <dplotnikov(a)virtuozzo.com>
---
v2v/convert_windows.ml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/v2v/convert_windows.ml b/v2v/convert_windows.ml
index 4511c53c3..706202499 100644
--- a/v2v/convert_windows.ml
+++ b/v2v/convert_windows.ml
@@ -469,6 +469,8 @@ echo uninstalling Xen PV driver
let fb_script = "\
@echo off
+REG DELETE HKLM\\System\\CurrentControlSet\\Services\\prl_strg\\DriverInfo /v RefCount /f
+
echo uninstalling Parallels guest tools
" ^ uninst ^
(* ERROR_SUCCESS_REBOOT_REQUIRED == 3010 is OK too *)
--
2.17.0
4 years, 6 months
[PATCH] erlang: Port to libei for Erlang 23
by Richard W.M. Jones
From: Sergei Golovan <sgolovan(a)gmail.com>
Replace the use of liberl_interface, which is removed in Erlang 23,
by libei. The implementation uses the ei_decode_iodata() function
which has been introduces only for Erlang 23, so it doesnt work with
earlier Erlang versions.
---
erlang/Makefile.am | 1 -
erlang/main.c | 312 +++++++++++++++++++++++++-------------------
generator/erlang.ml | 239 ++++++++++++++++-----------------
3 files changed, 295 insertions(+), 257 deletions(-)
diff --git a/erlang/Makefile.am b/erlang/Makefile.am
index 19b0e973e..3da3f9145 100644
--- a/erlang/Makefile.am
+++ b/erlang/Makefile.am
@@ -90,7 +90,6 @@ erl_guestfs_CFLAGS = \
$(WARN_CFLAGS) $(WERROR_CFLAGS)
erl_guestfs_LDADD = \
- $(ERLANG_LIB_DIR_erl_interface)/lib/liberl_interface.a \
$(ERLANG_LIB_DIR_erl_interface)/lib/libei.a \
-lpthread \
$(top_builddir)/common/utils/libutils.la \
diff --git a/erlang/main.c b/erlang/main.c
index b9b3dced9..a56ee1fab 100644
--- a/erlang/main.c
+++ b/erlang/main.c
@@ -25,11 +25,7 @@
#include <errno.h>
#include <arpa/inet.h>
-#include <erl_interface.h>
-/* We should switch over to using
- #include <ei.h>
-instead of erl_interface.
-*/
+#include <ei.h>
#include "error.h"
#include "full-read.h"
@@ -38,36 +34,25 @@ instead of erl_interface.
#include "guestfs.h"
#include "guestfs-utils.h"
+#include "actions.h"
+
guestfs_h *g;
-extern ETERM *dispatch (ETERM *message);
-extern int atom_equals (ETERM *atom, const char *name);
-extern ETERM *make_error (const char *funname);
-extern ETERM *unknown_optarg (const char *funname, ETERM *optargname);
-extern ETERM *unknown_function (ETERM *fun);
-extern ETERM *make_string_list (char **r);
-extern ETERM *make_table (char **r);
-extern ETERM *make_bool (int r);
-extern char **get_string_list (ETERM *term);
-extern int get_bool (ETERM *term);
-extern int get_int (ETERM *term);
-extern int64_t get_int64 (ETERM *term);
-
/* This stops things getting out of hand, but also lets us detect
* protocol problems quickly.
*/
#define MAX_MESSAGE_SIZE (32*1024*1024)
-static unsigned char *read_message (void);
-static void write_reply (ETERM *);
+static char *read_message (void);
+static void write_reply (ei_x_buff *);
int
main (void)
{
- unsigned char *buf;
- ETERM *ret, *message;
-
- erl_init (NULL, 0);
+ char *buff;
+ int index;
+ int version;
+ ei_x_buff reply;
/* This process has a single libguestfs handle. If the Erlang
* system creates more than one handle, then more than one of these
@@ -79,15 +64,20 @@ main (void)
guestfs_set_error_handler (g, NULL, NULL);
- while ((buf = read_message ()) != NULL) {
- message = erl_decode (buf);
- free (buf);
+ while ((buff = read_message ()) != NULL) {
+ if (ei_x_new_with_version (&reply) != 0)
+ error (EXIT_FAILURE, 0, "could not allocate reply buffer");
- ret = dispatch (message);
- erl_free_term (message);
+ index = 0;
+ if (ei_decode_version (buff, &index, &version) != 0)
+ error (EXIT_FAILURE, 0, "could not interpret the input message");
- write_reply (ret);
- erl_free_term (ret);
+ if (dispatch (&reply, buff, &index) != 0)
+ error (EXIT_FAILURE, 0, "could not decode input data or encode reply message");
+
+ free (buff);
+ write_reply (&reply);
+ ei_x_free (&reply);
}
guestfs_close (g);
@@ -98,12 +88,12 @@ main (void)
/* The Erlang port always sends the length of the buffer as 4
* bytes in network byte order, followed by the message buffer.
*/
-static unsigned char *
+static char *
read_message (void)
{
uint32_t buf;
size_t size;
- unsigned char *r;
+ char *r;
errno = 0;
if (full_read (0, &buf, 4) != 4) {
@@ -129,19 +119,10 @@ read_message (void)
}
static void
-write_reply (ETERM *term)
+write_reply (ei_x_buff *buff)
{
- size_t size;
+ size_t size = buff->index;
unsigned char sbuf[4];
- unsigned char *buf;
-
- size = erl_term_len (term);
-
- buf = malloc (size);
- if (buf == NULL)
- error (EXIT_FAILURE, errno, "malloc");
-
- erl_encode (term, buf);
sbuf[0] = (size >> 24) & 0xff;
sbuf[1] = (size >> 16) & 0xff;
@@ -151,171 +132,228 @@ write_reply (ETERM *term)
if (full_write (1, sbuf, 4) != 4)
error (EXIT_FAILURE, errno, "write message size");
- if (full_write (1, buf, size) != size)
+ if (full_write (1, buff->buff, size) != size)
error (EXIT_FAILURE, errno, "write message content");
-
- free (buf);
}
/* Note that all published Erlang code/examples etc uses strncmp in
* a buggy way. This is the right way to do it.
*/
int
-atom_equals (ETERM *atom, const char *name)
+atom_equals (const char *atom, const char *name)
{
const size_t namelen = strlen (name);
- const size_t atomlen = ERL_ATOM_SIZE (atom);
+ const size_t atomlen = strlen (atom);
if (namelen != atomlen) return 0;
- return strncmp (ERL_ATOM_PTR (atom), name, atomlen) == 0;
+ return strncmp (atom, name, atomlen) == 0;
}
-ETERM *
-make_error (const char *funname)
+int
+make_error (ei_x_buff *buff, const char *funname)
{
- ETERM *error = erl_mk_atom ("error");
- ETERM *msg = erl_mk_string (guestfs_last_error (g));
- ETERM *num = erl_mk_int (guestfs_last_errno (g));
- ETERM *t[3] = { error, msg, num };
- return erl_mk_tuple (t, 3);
+ if (ei_x_encode_tuple_header (buff, 3) != 0) return -1;
+ if (ei_x_encode_atom (buff, "error") != 0) return -1;
+ if (ei_x_encode_string (buff, guestfs_last_error (g)) != 0) return -1;
+ if (ei_x_encode_long (buff, guestfs_last_errno (g)) != 0) return -1;
+ return 0;
}
-ETERM *
-unknown_function (ETERM *fun)
+int
+unknown_function (ei_x_buff *buff, const char *fun)
{
- ETERM *unknown = erl_mk_atom ("unknown");
- ETERM *funcopy = erl_copy_term (fun);
- ETERM *t[2] = { unknown, funcopy };
- return erl_mk_tuple (t, 2);
+ if (ei_x_encode_tuple_header (buff, 2) != 0) return -1;
+ if (ei_x_encode_atom (buff, "unknown") != 0) return -1;
+ if (ei_x_encode_atom (buff, fun) != 0) return -1;
+ return 0;
}
-ETERM *
-unknown_optarg (const char *funname, ETERM *optargname)
+int
+unknown_optarg (ei_x_buff *buff, const char *funname, const char *optargname)
{
- ETERM *unknownarg = erl_mk_atom ("unknownarg");
- ETERM *copy = erl_copy_term (optargname);
- ETERM *t[2] = { unknownarg, copy };
- return erl_mk_tuple (t, 2);
+ if (ei_x_encode_tuple_header (buff, 2) != 0) return -1;
+ if (ei_x_encode_atom (buff, "unknownarg") != 0) return -1;
+ if (ei_x_encode_atom (buff, optargname) != 0) return -1;
+ return 0;
}
-ETERM *
-make_string_list (char **r)
+int
+make_string_list (ei_x_buff *buff, char **r)
{
size_t i, size;
- CLEANUP_FREE ETERM **t = NULL;
- for (size = 0; r[size] != NULL; ++size)
- ;
+ for (size = 0; r[size] != NULL; ++size);
- t = malloc (sizeof (ETERM *) * size);
- if (t == NULL)
- return make_error ("make_string_list");
+ if (ei_x_encode_list_header (buff, size) != 0) return -1;
for (i = 0; r[i] != NULL; ++i)
- t[i] = erl_mk_string (r[i]);
+ if (ei_x_encode_string (buff, r[i]) != 0) return -1;
- return erl_mk_list (t, size);
+ if (size > 0)
+ if (ei_x_encode_empty_list (buff) != 0) return -1;
+
+ return 0;
}
/* Make a hash table. The number of elements returned by the C
* function is always even.
*/
-ETERM *
-make_table (char **r)
+int
+make_table (ei_x_buff *buff, char **r)
{
size_t i, size;
- CLEANUP_FREE ETERM **t = NULL;
- ETERM *a[2];
- for (size = 0; r[size] != NULL; ++size)
- ;
+ for (size = 0; r[size] != NULL; ++size);
- t = malloc (sizeof (ETERM *) * (size/2));
- if (t == NULL)
- return make_error ("make_table");
+ if (ei_x_encode_list_header (buff, size/2) != 0) return -1;
for (i = 0; r[i] != NULL; i += 2) {
- a[0] = erl_mk_string (r[i]);
- a[1] = erl_mk_string (r[i+1]);
- t[i/2] = erl_mk_tuple (a, 2);
+ if (ei_x_encode_tuple_header (buff, 2) != 0) return -1;
+ if (ei_x_encode_string (buff, r[i]) != 0) return -1;
+ if (ei_x_encode_string (buff, r[i+1]) != 0) return -1;
}
- return erl_mk_list (t, size/2);
+ if (size/2 > 0)
+ if (ei_x_encode_empty_list (buff) != 0) return -1;
+
+ return 0;
}
-ETERM *
-make_bool (int r)
+int
+make_bool (ei_x_buff *buff, int r)
{
if (r)
- return erl_mk_atom ("true");
+ return ei_x_encode_atom (buff, "true");
else
- return erl_mk_atom ("false");
+ return ei_x_encode_atom (buff, "false");
}
-char **
-get_string_list (ETERM *term)
+int
+decode_string_list (const char *buff, int *index, char ***res)
{
- ETERM *t;
- size_t i, size;
+ int i, size;
char **r;
- for (size = 0, t = term; !ERL_IS_EMPTY_LIST (t);
- size++, t = ERL_CONS_TAIL (t))
- ;
+ if (ei_decode_list_header (buff, index, &size) != 0)
+ error (EXIT_FAILURE, 0, "not a list");
r = malloc ((size+1) * sizeof (char *));
if (r == NULL)
error (EXIT_FAILURE, errno, "malloc");
- for (i = 0, t = term; !ERL_IS_EMPTY_LIST (t); i++, t = ERL_CONS_TAIL (t))
- r[i] = erl_iolist_to_string (ERL_CONS_HEAD (t));
+ for (i = 0; i < size; i++)
+ if (decode_string (buff, index, &r[i]) != 0) return -1;
+
+ // End of a list is encoded by an empty list, so skip it
+ if (size > 0 && buff[*index] == ERL_NIL_EXT)
+ (*index)++;
+
r[size] = NULL;
+ *res = r;
- return r;
+ return 0;
}
int
-get_bool (ETERM *term)
+decode_string (const char *buff, int *index, char **res)
{
- if (atom_equals (term, "true"))
- return 1;
+ size_t size;
+
+ if (decode_binary (buff, index, res, &size) != 0) return -1;
+
+ (*res)[size] = 0;
+
+ return 0;
+}
+
+int
+decode_binary (const char *buff, int *index, char **res, size_t *size)
+{
+ int index0;
+ int size0;
+ char *r;
+
+ index0 = *index;
+ if (ei_decode_iodata (buff, index, &size0, NULL) != 0) return -1;
+
+ r = malloc (size0+1); // In case if it's called from decode_string ()
+ if (r == NULL)
+ error (EXIT_FAILURE, errno, "malloc");
+
+ *index = index0;
+ if (ei_decode_iodata (buff, index, NULL, r) != 0) {
+ free (r);
+ return -1;
+ }
+
+ *res = r;
+ *size = (size_t) size0;
+
+ return 0;
+}
+
+int
+decode_bool (const char *buff, int *index, int *res)
+{
+ char atom[MAXATOMLEN];
+
+ if (ei_decode_atom (buff, index, atom) != 0) return -1;
+
+ if (atom_equals (atom, "true"))
+ *res = 1;
else
- return 0;
+ *res = 0;
+
+ return 0;
}
int
-get_int (ETERM *term)
+decode_int (const char *buff, int *index, int *res)
{
- switch (ERL_TYPE (term)) {
- case ERL_INTEGER:
- return ERL_INT_VALUE (term);
- case ERL_U_INTEGER:
- return (int) ERL_INT_UVALUE (term);
- case ERL_LONGLONG:
+ unsigned char c;
+ long l;
+ long long ll;
+
+ if (ei_decode_char (buff, index, (char *) &c) == 0) {
+ // Byte integers in Erlang are to be treated as unsigned
+ *res = (int) c;
+ return 0;
+ }
+ if (ei_decode_long (buff, index, &l) == 0) {
/* XXX check for overflow */
- return (int) ERL_LL_VALUE (term);
- case ERL_U_LONGLONG:
+ *res = (int) l;
+ return 0;
+ }
+ if (ei_decode_longlong (buff, index, &ll) == 0) {
/* XXX check for overflow */
- return (int) ERL_LL_UVALUE (term);
- default:
- /* XXX fail in some way */
- return -1;
+ *res = (int) ll;
+ return 0;
}
+ /* XXX fail in some way */
+ return -1;
}
-int64_t
-get_int64 (ETERM *term)
+int
+decode_int64 (const char *buff, int *index, int64_t *res)
{
- switch (ERL_TYPE (term)) {
- case ERL_INTEGER:
- return ERL_INT_VALUE (term);
- case ERL_U_INTEGER:
- return ERL_INT_UVALUE (term);
- case ERL_LONGLONG:
- return ERL_LL_VALUE (term);
- case ERL_U_LONGLONG:
- return (int64_t) ERL_LL_UVALUE (term);
- default:
- /* XXX fail in some way */
- return -1;
+ unsigned char c;
+ long l;
+ long long ll;
+
+ if (ei_decode_char (buff, index, (char *) &c) == 0) {
+ // Byte integers in Erlang are to be treated as unsigned
+ *res = (int64_t) c;
+ return 0;
+ }
+ if (ei_decode_long (buff, index, &l) == 0) {
+ *res = (int64_t) l;
+ return 0;
}
+ if (ei_decode_longlong (buff, index, &ll) == 0) {
+ /* XXX check for overflow */
+ *res = (int64_t) ll;
+ return 0;
+ }
+ /* XXX fail in some way */
+ return -1;
}
+
diff --git a/generator/erlang.ml b/generator/erlang.ml
index 0cee9c3ef..65af75aaf 100644
--- a/generator/erlang.ml
+++ b/generator/erlang.ml
@@ -192,30 +192,30 @@ and generate_erlang_actions_h () =
extern guestfs_h *g;
-extern ETERM *dispatch (ETERM *args_tuple);
-extern int atom_equals (ETERM *atom, const char *name);
-extern ETERM *make_error (const char *funname);
-extern ETERM *unknown_optarg (const char *funname, ETERM *optargname);
-extern ETERM *unknown_function (ETERM *fun);
-extern ETERM *make_string_list (char **r);
-extern ETERM *make_table (char **r);
-extern ETERM *make_bool (int r);
-extern char **get_string_list (ETERM *term);
-extern int get_bool (ETERM *term);
-extern int get_int (ETERM *term);
-extern int64_t get_int64 (ETERM *term);
-
-#define ARG(i) (ERL_TUPLE_ELEMENT(args_tuple,(i)+1))
+extern int dispatch (ei_x_buff *retbuff, const char *buff, int *index);
+extern int make_error (ei_x_buff *retbuff, const char *funname);
+extern int unknown_optarg (ei_x_buff *retbuff, const char *funname, const char *optargname);
+extern int unknown_function (ei_x_buff *retbuff, const char *fun);
+extern int make_string_list (ei_x_buff *buff, char **r);
+extern int make_table (ei_x_buff *buff, char **r);
+extern int make_bool (ei_x_buff *buff, int r);
+extern int atom_equals (const char *atom, const char *name);
+extern int decode_string_list (const char *buff, int *index, char ***res);
+extern int decode_string (const char *buff, int *index, char **res);
+extern int decode_binary (const char *buff, int *index, char **res, size_t *size);
+extern int decode_bool (const char *buff, int *index, int *res);
+extern int decode_int (const char *buff, int *index, int *res);
+extern int decode_int64 (const char *buff, int *index, int64_t *res);
";
let emit_copy_list_decl typ =
- pr "ETERM *make_%s_list (const struct guestfs_%s_list *%ss);\n"
+ pr "int make_%s_list (ei_x_buff *buff, const struct guestfs_%s_list *%ss);\n"
typ typ typ;
in
List.iter (
fun { s_name = typ; s_cols = cols } ->
- pr "ETERM *make_%s (const struct guestfs_%s *%s);\n" typ typ typ;
+ pr "int make_%s (ei_x_buff *buff, const struct guestfs_%s *%s);\n" typ typ typ;
) external_structs;
List.iter (
@@ -229,7 +229,7 @@ extern int64_t get_int64 (ETERM *term);
List.iter (
fun { name } ->
- pr "ETERM *run_%s (ETERM *args_tuple);\n" name
+ pr "int run_%s (ei_x_buff *retbuff, const char *buff, int *index);\n" name
) (actions |> external_functions |> sort);
pr "\n";
@@ -247,11 +247,7 @@ and generate_erlang_structs () =
#include <string.h>
#include <errno.h>
-#include <erl_interface.h>
-/* We should switch over to using
- #include <ei.h>
-instead of erl_interface.
-*/
+#include <ei.h>
#include \"guestfs.h\"
#include \"guestfs-utils.h\"
@@ -262,57 +258,61 @@ instead of erl_interface.
(* Struct copy functions. *)
let emit_copy_list_function typ =
pr "\n";
- pr "ETERM *\n";
- pr "make_%s_list (const struct guestfs_%s_list *%ss)\n" typ typ typ;
+ pr "int\n";
+ pr "make_%s_list (ei_x_buff *buff, const struct guestfs_%s_list *%ss)\n" typ typ typ;
pr "{\n";
pr " size_t len = %ss->len;\n" typ;
pr " size_t i;\n";
- pr " CLEANUP_FREE ETERM **t;\n";
pr "\n";
- pr " t = malloc (sizeof (ETERM *) * len);\n";
- pr " if (t == NULL)\n";
- pr " return make_error (\"make_%s_list\");\n" typ;
+ pr " if (ei_x_encode_list_header (buff, len) != 0) return -1;\n";
+ pr " for (i = 0; i < len; ++i) {\n";
+ pr " if (make_%s (buff, &%ss->val[i]) != 0) return -1;\n" typ typ;
+ pr " }\n";
+ pr " if (len > 0)\n";
+ pr " if (ei_x_encode_empty_list (buff) != 0) return -1;\n";
pr "\n";
- pr " for (i = 0; i < len; ++i)\n";
- pr " t[i] = make_%s (&%ss->val[i]);\n" typ typ;
- pr "\n";
- pr " return erl_mk_list (t, len);\n";
+ pr " return 0;\n";
pr "}\n";
in
List.iter (
fun { s_name = typ; s_cols = cols } ->
pr "\n";
- pr "ETERM *\n";
- pr "make_%s (const struct guestfs_%s *%s)\n" typ typ typ;
+ pr "int\n";
+ pr "make_%s (ei_x_buff *buff, const struct guestfs_%s *%s)\n" typ typ typ;
pr "{\n";
- pr " ETERM *t[%d];\n" (List.length cols);
+ pr " if (ei_x_encode_list_header (buff, %d) !=0) return -1;\n" (List.length cols);
pr "\n";
List.iteri (
fun i col ->
(match col with
| name, FString ->
- pr " t[%d] = erl_mk_string (%s->%s);\n" i typ name
+ pr " if (ei_x_encode_string (buff, %s->%s) != 0) return -1;\n" typ name
| name, FBuffer ->
- pr " t[%d] = erl_mk_estring (%s->%s, %s->%s_len);\n"
- i typ name typ name
+ pr " if (ei_x_encode_string_len (buff, %s->%s, %s->%s_len) != 0) return -1;\n"
+ typ name typ name
| name, FUUID ->
- pr " t[%d] = erl_mk_estring (%s->%s, 32);\n" i typ name
+ pr " if (ei_x_encode_string_len (buff, %s->%s, 32) != 0) return -1;\n" typ name
| name, (FBytes|FInt64|FUInt64) ->
- pr " t[%d] = erl_mk_longlong (%s->%s);\n" i typ name
+ pr " if (ei_x_encode_longlong (buff, %s->%s) != 0) return -1;\n" typ name
| name, (FInt32|FUInt32) ->
- pr " t[%d] = erl_mk_int (%s->%s);\n" i typ name
+ pr " if (ei_x_encode_long (buff, %s->%s) != 0) return -1;\n" typ name
| name, FOptPercent ->
- pr " if (%s->%s >= 0)\n" typ name;
- pr " t[%d] = erl_mk_float (%s->%s);\n" i typ name;
- pr " else\n";
- pr " t[%d] = erl_mk_atom (\"undefined\");\n" i;
+ pr " if (%s->%s >= 0) {\n" typ name;
+ pr " if (ei_x_encode_double (buff, %s->%s) != 0) return -1;\n" typ name;
+ pr " } else {\n";
+ pr " if (ei_x_encode_atom (buff, \"undefined\") != 0) return -1;\n";
+ pr " }\n"
| name, FChar ->
- pr " t[%d] = erl_mk_int (%s->%s);\n" i typ name
+ pr " if (ei_x_encode_char (buff, %s->%s) != 0) return -1;\n" typ name
);
) cols;
+ if cols <> [] then (
+ pr "\n";
+ pr " if (ei_x_encode_empty_list (buff) != 0) return -1;\n"
+ );
pr "\n";
- pr " return erl_mk_list (t, %d);\n" (List.length cols);
+ pr " return 0;\n";
pr "}\n";
) external_structs;
@@ -341,11 +341,7 @@ and generate_erlang_actions actions () =
#include <string.h>
#include <errno.h>
-#include <erl_interface.h>
-/* We should switch over to using
- #include <ei.h>
-instead of erl_interface.
-*/
+#include <ei.h>
#include \"guestfs.h\"
#include \"guestfs-utils.h\"
@@ -358,33 +354,43 @@ instead of erl_interface.
fun { name; style = (ret, args, optargs as style);
c_function; c_optarg_prefix } ->
pr "\n";
- pr "ETERM *\n";
- pr "run_%s (ETERM *args_tuple)\n" name;
+ pr "int\n";
+ pr "run_%s (ei_x_buff *retbuff, const char *buff, int *idx)\n" name;
pr "{\n";
List.iteri (
fun i ->
function
| String (_, n) ->
- pr " CLEANUP_FREE char *%s = erl_iolist_to_string (ARG (%d));\n" n i
+ pr " CLEANUP_FREE char *%s;\n" n;
+ pr " if (decode_string (buff, idx, &%s) != 0) return -1;\n" n
| OptString n ->
pr " CLEANUP_FREE char *%s;\n" n;
- pr " if (atom_equals (ARG (%d), \"undefined\"))\n" i;
- pr " %s = NULL;\n" n;
- pr " else\n";
- pr " %s = erl_iolist_to_string (ARG (%d));\n" n i
+ pr " char %s_opt[MAXATOMLEN];\n" n;
+ pr " if (ei_decode_atom(buff, idx, %s_opt) == 0) {\n" n;
+ pr " if (atom_equals (%s_opt, \"undefined\"))\n" n;
+ pr " %s = NULL;\n" n;
+ pr " else\n";
+ pr " %s = %s_opt;\n" n n;
+ pr " } else {\n";
+ pr " if (decode_string (buff, idx, &%s) != 0) return -1;\n" n;
+ pr " }\n"
| BufferIn n ->
- pr " ETERM *%s_bin = erl_iolist_to_binary (ARG (%d));\n" n i;
- pr " const void *%s = ERL_BIN_PTR (%s_bin);\n" n n;
- pr " size_t %s_size = ERL_BIN_SIZE (%s_bin);\n" n n
+ pr " CLEANUP_FREE char *%s;\n" n;
+ pr " size_t %s_size;\n" n;
+ pr " if (decode_binary (buff, idx, &%s, &%s_size) != 0) return -1;\n" n n
| StringList (_, n) ->
- pr " CLEANUP_FREE_STRING_LIST char **%s = get_string_list (ARG (%d));\n" n i
+ pr " CLEANUP_FREE_STRING_LIST char **%s;\n" n;
+ pr " if (decode_string_list (buff, idx, &%s) != 0) return -1;\n" n
| Bool n ->
- pr " int %s = get_bool (ARG (%d));\n" n i
+ pr " int %s;\n" n;
+ pr " if (decode_bool (buff, idx, &%s) != 0) return -1;\n" n
| Int n ->
- pr " int %s = get_int (ARG (%d));\n" n i
+ pr " int %s;\n" n;
+ pr " if (decode_int (buff, idx, &%s) != 0) return -1;\n" n
| Int64 n ->
- pr " int64_t %s = get_int64 (ARG (%d));\n" n i
+ pr " int64_t %s;\n" n;
+ pr " if (decode_int64 (buff, idx, &%s) != 0) return -1;\n" n
| Pointer (t, n) ->
pr " void * /* %s */ %s = POINTER_NOT_IMPLEMENTED (\"%s\");\n" t n t
) args;
@@ -394,11 +400,13 @@ instead of erl_interface.
pr "\n";
pr " struct %s optargs_s = { .bitmask = 0 };\n" c_function;
pr " struct %s *optargs = &optargs_s;\n" c_function;
- pr " ETERM *optargst = ARG (%d);\n" (List.length args);
- pr " while (!ERL_IS_EMPTY_LIST (optargst)) {\n";
- pr " ETERM *hd = ERL_CONS_HEAD (optargst);\n";
- pr " ETERM *hd_name = ERL_TUPLE_ELEMENT (hd, 0);\n";
- pr " ETERM *hd_value = ERL_TUPLE_ELEMENT (hd, 1);\n";
+ pr " int optargsize;\n";
+ pr " if (ei_decode_list_header (buff, idx, &optargsize) != 0) return -1;\n";
+ pr " for (int i = 0; i < optargsize; i++) {\n";
+ pr " int hd;\n";
+ pr " if (ei_decode_tuple_header (buff, idx, &hd) != 0) return -1;\n";
+ pr " char hd_name[MAXATOMLEN];\n";
+ pr " if (ei_decode_atom (buff, idx, hd_name) != 0) return -1;\n";
pr "\n";
List.iter (
fun argt ->
@@ -407,21 +415,22 @@ instead of erl_interface.
pr " if (atom_equals (hd_name, \"%s\")) {\n" n;
pr " optargs_s.bitmask |= %s_%s_BITMASK;\n"
c_optarg_prefix uc_n;
- pr " optargs_s.%s = " n;
+ pr " ";
(match argt with
- | OBool _ -> pr "get_bool (hd_value)"
- | OInt _ -> pr "get_int (hd_value)"
- | OInt64 _ -> pr "get_int64 (hd_value)"
- | OString _ -> pr "erl_iolist_to_string (hd_value)"
- | OStringList n -> pr "get_string_list (hd_value)"
+ | OBool _ -> pr "if (decode_bool (buff, idx, &optargs_s.%s) != 0) return -1;" n
+ | OInt _ -> pr "if (decode_int (buff, idx, &optargs_s.%s) != 0) return -1" n
+ | OInt64 _ -> pr "if (decode_int64 (buff, idx, &optargs_s.%s) != 0) return -1" n
+ | OString _ -> pr "if (decode_string (buff, idx, (char **) &optargs_s.%s) != 0) return -1" n
+ | OStringList n -> pr "if (decode_string_list (buff, idx, (char ***) &optargs_s.%s) != 0) return -1" n
);
pr ";\n";
pr " }\n";
pr " else\n";
) optargs;
- pr " return unknown_optarg (\"%s\", hd_name);\n" name;
- pr " optargst = ERL_CONS_TAIL (optargst);\n";
+ pr " return unknown_optarg (retbuff, \"%s\", hd_name);\n" name;
pr " }\n";
+ pr " if (optargsize > 0 && buff[*idx] == ERL_NIL_EXT)\n";
+ pr " (*idx)++;\n";
pr "\n";
);
@@ -471,52 +480,46 @@ instead of erl_interface.
| `CannotReturnError -> ()
| `ErrorIsMinusOne ->
pr " if (r == -1)\n";
- pr " return make_error (\"%s\");\n" name;
+ pr " return make_error (retbuff, \"%s\");\n" name;
| `ErrorIsNULL ->
pr " if (r == NULL)\n";
- pr " return make_error (\"%s\");\n" name;
+ pr " return make_error (retbuff, \"%s\");\n" name;
);
pr "\n";
(match ret with
- | RErr -> pr " return erl_mk_atom (\"ok\");\n"
- | RInt _ -> pr " return erl_mk_int (r);\n"
- | RInt64 _ -> pr " return erl_mk_longlong (r);\n"
- | RBool _ -> pr " return make_bool (r);\n"
- | RConstString _ -> pr " return erl_mk_string (r);\n"
+ | RErr -> pr " if (ei_x_encode_atom (retbuff, \"ok\") != 0) return -1;\n"
+ | RInt _ -> pr " if (ei_x_encode_long (retbuff, r) != 0) return -1;\n"
+ | RInt64 _ -> pr " if (ei_x_encode_longlong (retbuff, r) != 0) return -1;\n"
+ | RBool _ -> pr " if (make_bool (retbuff, r) != 0) return -1;\n"
+ | RConstString _ -> pr " if (ei_x_encode_string (retbuff, r) != 0) return -1;\n"
| RConstOptString _ ->
- pr " ETERM *rt;\n";
- pr " if (r)\n";
- pr " rt = erl_mk_string (r);\n";
- pr " else\n";
- pr " rt = erl_mk_atom (\"undefined\");\n";
- pr " return rt;\n"
+ pr " if (r) {\n";
+ pr " if (ei_x_encode_string (retbuff, r) != 0) return -1;\n";
+ pr " } else {\n";
+ pr " if (ei_x_encode_atom (retbuff, \"undefined\") != 0) return -1;\n";
+ pr " }\n"
| RString _ ->
- pr " ETERM *rt = erl_mk_string (r);\n";
+ pr " if (ei_x_encode_string (retbuff, r) != 0) return -1;\n";
pr " free (r);\n";
- pr " return rt;\n"
| RStringList _ ->
- pr " ETERM *rt = make_string_list (r);\n";
- pr " guestfs_int_free_string_list (r);\n\n";
- pr " return rt;\n"
+ pr " if (make_string_list (retbuff, r) != 0) return -1;\n";
+ pr " guestfs_int_free_string_list (r);\n"
| RStruct (_, typ) ->
- pr " ETERM *rt = make_%s (r);\n" typ;
- pr " guestfs_free_%s (r);\n" typ;
- pr " return rt;\n"
+ pr " if (make_%s (retbuff, r) != 0) return -1;\n" typ;
+ pr " guestfs_free_%s (r);\n" typ
| RStructList (_, typ) ->
- pr " ETERM *rt = make_%s_list (r);\n" typ;
- pr " guestfs_free_%s_list (r);\n" typ;
- pr " return rt;\n"
+ pr " if (make_%s_list (retbuff, r) != 0) return -1;\n" typ;
+ pr " guestfs_free_%s_list (r);\n" typ
| RHashtable _ ->
- pr " ETERM *rt = make_table (r);\n";
- pr " guestfs_int_free_string_list (r);\n";
- pr " return rt;\n"
+ pr " if (make_table (retbuff, r) != 0) return -1;\n";
+ pr " guestfs_int_free_string_list (r);\n"
| RBufferOut _ ->
- pr " ETERM *rt = erl_mk_estring (r, size);\n";
+ pr " if (ei_x_encode_binary (retbuff, r, size) != 0) return -1;\n";
pr " free (r);\n";
- pr " return rt;\n"
);
+ pr " return 0;\n";
pr "}\n";
) (actions |> external_functions |> sort);
@@ -532,23 +535,21 @@ and generate_erlang_dispatch () =
#include <string.h>
#include <errno.h>
-#include <erl_interface.h>
-/* We should switch over to using
- #include <ei.h>
-instead of erl_interface.
-*/
+#include <ei.h>
#include \"guestfs.h\"
#include \"guestfs-utils.h\"
#include \"actions.h\"
-ETERM *
-dispatch (ETERM *args_tuple)
+int
+dispatch (ei_x_buff *retbuff, const char *buff, int *index)
{
- ETERM *fun;
+ int arity;
+ char fun[MAXATOMLEN];
- fun = ERL_TUPLE_ELEMENT (args_tuple, 0);
+ if (ei_decode_tuple_header (buff, index, &arity) != 0) return -1;
+ if (ei_decode_atom (buff, index, fun) != 0) return -1;
/* XXX We should use gperf here. */
";
@@ -556,10 +557,10 @@ dispatch (ETERM *args_tuple)
List.iter (
fun { name; style = ret, args, optargs } ->
pr "if (atom_equals (fun, \"%s\"))\n" name;
- pr " return run_%s (args_tuple);\n" name;
+ pr " return run_%s (retbuff, buff, index);\n" name;
pr " else ";
) (actions |> external_functions |> sort);
- pr "return unknown_function (fun);
+ pr "return unknown_function (retbuff, fun);
}
";
--
2.26.2
4 years, 6 months