Richard W.M. Jones
2020-Jun-01 19:39 UTC
[Libguestfs] [PATCH] erlang: Port to libei for Erlang 23
From: Sergei Golovan <sgolovan@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
Richard W.M. Jones
2020-Jun-04 12:49 UTC
Re: [Libguestfs] [PATCH] erlang: Port to libei for Erlang 23
This is basically all fine, and pushed. I modified a tiny bit. In docs/guestfs-building.pod, I updated the documentation to note that Erlang >= 23 is required. Its seems from what I can tell that we do _not_ have to change the m4/guestfs-erlang.m4 configure test since the module uses the same name. Thanks, Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com virt-df lists disk usage of guests without needing to install any software inside the virtual machine. Supports Linux and Windows. http://people.redhat.com/~rjones/virt-df/