diff options
author | Richard W.M. Jones <rjones@redhat.com> | 2012-11-17 10:10:13 +0000 |
---|---|---|
committer | Richard W.M. Jones <rjones@redhat.com> | 2012-11-17 20:02:42 +0000 |
commit | ff8bfd3e92f21955d0a91b481583131f356b8fe4 (patch) | |
tree | 7c3b36c732ea0b83209180099ba03f5ef1948238 | |
parent | 4a2e8e89577ad4031aba1b2e5afb65ca58c2c39d (diff) | |
download | libguestfs-ff8bfd3e92f21955d0a91b481583131f356b8fe4.tar.gz libguestfs-ff8bfd3e92f21955d0a91b481583131f356b8fe4.tar.xz libguestfs-ff8bfd3e92f21955d0a91b481583131f356b8fe4.zip |
Add Lua bindings.
These are relatively complete, although only lightly tested. Missing:
- events
- last_errno
- user_cancel
32 files changed, 1212 insertions, 0 deletions
@@ -164,6 +164,7 @@ Makefile.in /html/guestfs-examples.3.html /html/guestfs-faq.1.html /html/guestfs-java.3.html +/html/guestfs-lua.3.html /html/guestfs-ocaml.3.html /html/guestfs-performance.1.html /html/guestfs-perl.3.html @@ -215,6 +216,11 @@ Makefile.in /libtool /local* /ltmain.sh +/lua/examples/guestfs-lua.3 +/lua/examples/stamp-guestfs-lua.pod +/lua/guestfs.so +/lua/lua-guestfs.c +/lua/test.img /m4/ChangeLog /m4/gnulib-cache.m4 /m4/intmax.m4 diff --git a/Makefile.am b/Makefile.am index 12896f40..1ae78496 100644 --- a/Makefile.am +++ b/Makefile.am @@ -94,6 +94,9 @@ endif if HAVE_ERLANG SUBDIRS += erlang erlang/examples endif +if HAVE_LUA +SUBDIRS += lua lua/examples +endif if HAVE_GOBJECT SUBDIRS += gobject endif @@ -175,6 +178,7 @@ HTMLFILES = \ html/guestfs-erlang.3.html \ html/guestfs-faq.1.html \ html/guestfs-java.3.html \ + html/guestfs-lua.3.html \ html/guestfs-ocaml.3.html \ html/guestfs-performance.1.html \ html/guestfs-perl.3.html \ diff --git a/configure.ac b/configure.ac index 73183698..9fe7d4ae 100644 --- a/configure.ac +++ b/configure.ac @@ -1240,6 +1240,28 @@ if test "x$enable_erlang" != "xno"; then fi AM_CONDITIONAL([HAVE_ERLANG], [test "x$ERLANG" != "xno" && test "x$ERLC" != "xno"]) +dnl Lua +LUA=no +AC_ARG_ENABLE([lua], + AS_HELP_STRING([--disable-lua], [disable Lua language bindings]), + [], + [enable_lua=yes]) +AS_IF([test "x$enable_lua" != "xno"],[ + LUA= + AC_CHECK_PROG([LUA],[lua],[lua],[no]) + AC_CHECK_HEADER([lua.h],[have_lua_h=yes]) + AC_CHECK_HEADER([lauxlib.h],[have_lauxlib_h=yes]) + AC_CHECK_LIB([lua],[lua_checkstack],[have_lua_lib=yes]) + + AS_IF([test "x$LUA" != "xno"],[ + AC_MSG_CHECKING([for Lua version]) + LUA_VERSION=`$LUA -e 'print(_VERSION)' | awk '{print $2}'` + AC_MSG_RESULT([$LUA_VERSION]) + AC_SUBST([LUA_VERSION]) + ]) +]) +AM_CONDITIONAL([HAVE_LUA], [test "x$LUA" != "xno" && test "x$have_lua_h" = "xyes" && test "x$have_lauxlib_h" = "xyes" && test "x$have_lua_lib" = "xyes"]) + dnl Check for Perl modules needed by Perl virt tools (virt-df, etc.) AS_IF([test "x$PERL" != "xno"], [ @@ -1368,6 +1390,8 @@ AC_CONFIG_FILES([Makefile inspector/Makefile java/Makefile java/examples/Makefile + lua/Makefile + lua/examples/Makefile ocaml/META ocaml/Makefile ocaml/examples/Makefile @@ -1452,6 +1476,8 @@ AS_ECHO_N(["PHP bindings ........................ "]) if test "x$HAVE_PHP_TRUE" = "x"; then echo "yes"; else echo "no"; fi AS_ECHO_N(["Erlang bindings ..................... "]) if test "x$HAVE_ERLANG_TRUE" = "x"; then echo "yes"; else echo "no"; fi +AS_ECHO_N(["Lua bindings ........................ "]) +if test "x$HAVE_LUA_TRUE" = "x"; then echo "yes"; else echo "no"; fi AS_ECHO_N(["gobject bindings .................... "]) if test "x$HAVE_GOBJECT_TRUE" = "x"; then echo "yes"; else echo "no"; fi AS_ECHO_N(["gobject introspection ............... "]) diff --git a/examples/guestfs-examples.pod b/examples/guestfs-examples.pod index ef507edb..aba7caa9 100644 --- a/examples/guestfs-examples.pod +++ b/examples/guestfs-examples.pod @@ -35,6 +35,7 @@ libguestfs, you also need to read L<guestfs(3)>. L<guestfs(3)>, L<guestfs-erlang(3)>, L<guestfs-java(3)>, +L<guestfs-lua(3)>, L<guestfs-ocaml(3)>, L<guestfs-perl(3)>, L<guestfs-python(3)>, diff --git a/examples/guestfs-recipes.pod b/examples/guestfs-recipes.pod index 1a1e51c4..0a12703f 100644 --- a/examples/guestfs-recipes.pod +++ b/examples/guestfs-recipes.pod @@ -500,6 +500,7 @@ L<guestfish(1)>, L<guestfs-examples(3)>, L<guestfs-erlang(3)>, L<guestfs-java(3)>, +L<guestfs-lua(3)>, L<guestfs-ocaml(3)>, L<guestfs-perl(3)>, L<guestfs-python(3)>, diff --git a/generator/Makefile.am b/generator/Makefile.am index e218ffac..bc920708 100644 --- a/generator/Makefile.am +++ b/generator/Makefile.am @@ -47,6 +47,7 @@ SOURCES = \ csharp.ml \ php.ml \ erlang.ml \ + lua.ml \ gobject.ml \ bindtests.ml \ errnostring.ml \ diff --git a/generator/lua.ml b/generator/lua.ml new file mode 100644 index 00000000..4f652e96 --- /dev/null +++ b/generator/lua.ml @@ -0,0 +1,561 @@ +(* libguestfs + * Copyright (C) 2012 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 + *) + +(* Please read generator/README first. *) + +open Printf + +open Types +open Utils +open Pr +open Docstrings +open Optgroups +open Actions +open Structs +open C +open Events + +let generate_lua_c () = + generate_header CStyle LGPLv2plus; + + pr "\ +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <inttypes.h> +#include <string.h> + +/*#define LUA_LIB*/ +#include <lua.h> +#include <lauxlib.h> + +#include <guestfs.h> + +#define LUA_GUESTFS_HANDLE \"guestfs handle\" + +/* This struct is managed on the Lua heap. If the GC collects it, + * the Lua '__gc' function is called which ends up calling + * lua_guestfs_finalizer. If we need to store other per-handle + * data in future, that can be placed into this struct. + */ +struct userdata { + guestfs_h *g; /* Libguestfs handle, NULL if closed. */ +}; + +static struct userdata *get_handle (lua_State *L, int index); +static char **get_string_list (lua_State *L, int index); +static void push_string_list (lua_State *L, char **strs); +static void push_table (lua_State *L, char **table); +static int64_t get_int64 (lua_State *L, int index); +static void push_int64 (lua_State *L, int64_t i64); + +"; + + List.iter ( + function + | typ, RStructOnly -> + pr "static void push_%s (lua_State *L, struct guestfs_%s *v);\n" typ typ; + | typ, (RStructListOnly | RStructAndList) -> + pr "static void push_%s (lua_State *L, struct guestfs_%s *v);\n" typ typ; + pr "static void push_%s_list (lua_State *L, struct guestfs_%s_list *v);\n" typ typ + ) (rstructs_used_by all_functions); + + pr "\ + +#define OPTARG_IF_SET(index, name, code) \\ + do { \\ + lua_pushliteral (L, name); \\ + lua_gettable (L, index); \\ + if (!lua_isnil (L, -1)) { \\ + code \\ + } \\ + lua_pop (L, 1); \\ + } while (0) + +/* Create a new connection. */ +static int +lua_guestfs_create (lua_State *L) +{ + guestfs_h *g; + struct userdata *u; + unsigned flags = 0; + + if (lua_gettop (L) == 1) { + OPTARG_IF_SET (1, \"environment\", + if (! lua_toboolean (L, -1)) + flags |= GUESTFS_CREATE_NO_ENVIRONMENT; + ); + OPTARG_IF_SET (1, \"close_on_exit\", + if (! lua_toboolean (L, -1)) + flags |= GUESTFS_CREATE_NO_CLOSE_ON_EXIT; + ); + } + else if (lua_gettop (L) > 1) + return luaL_error (L, \"Guestfs.create: too many arguments\"); + + g = guestfs_create_flags (flags); + if (!g) + return luaL_error (L, \"Guestfs.create: cannot create handle: %%m\"); + + u = lua_newuserdata (L, sizeof (struct userdata)); + luaL_getmetatable (L, LUA_GUESTFS_HANDLE); + lua_setmetatable (L, -2); + + u->g = g; + + return 1; +} + +/* Finalizer. */ +static int +lua_guestfs_finalizer (lua_State *L) +{ + struct userdata *u = get_handle (L, 1); + + if (u->g) + guestfs_close (u->g); + + /* u will be freed by Lua when we return. */ + + return 0; +} + +/* Explicit close. */ +static int +lua_guestfs_close (lua_State *L) +{ + struct userdata *u = get_handle (L, 1); + + if (u->g) { + guestfs_close (u->g); + u->g = NULL; + } + + return 0; +} + +"; + + List.iter ( + fun { name = name; style = (ret, args, optargs as style); + c_function = c_function; c_optarg_prefix = c_optarg_prefix } -> + pr "static int\n"; + pr "lua_guestfs_%s (lua_State *L)\n" name; + pr "{\n"; + + (match ret with + | RErr -> + pr " int r;\n"; + | RInt _ + | RBool _ -> + pr " int r;\n"; + | RInt64 _ -> + pr " int64_t r;\n"; + | RConstString _ -> + pr " const char *r;\n"; + | RConstOptString _ -> + pr " const char *r;\n"; + | RString _ -> + pr " char *r;\n"; + | RStringList _ | RHashtable _ -> + pr " char **r;\n"; + | RStruct (_, typ) -> + pr " struct guestfs_%s *r;\n" typ; + | RStructList (_, typ) -> + pr " struct guestfs_%s_list *r;\n" typ; + | RBufferOut _ -> + pr " char *r;\n"; + pr " size_t size;\n"; + ); + + (* Handle, arguments. *) + pr " struct userdata *u = get_handle (L, 1);\n"; + pr " guestfs_h *g = u->g;\n"; + + List.iter ( + function + | Pathname n | Device n | Dev_or_Path n | String n + | FileIn n | FileOut n | Key n -> + pr " const char *%s;\n" n + | BufferIn n -> + pr " const char *%s;\n" n; + pr " size_t %s_size;\n" n; + | OptString n -> + pr " const char *%s;\n" n; + | StringList n | DeviceList n -> + pr " char **%s;\n" n + | Bool n -> pr " int %s;\n" n + | Int n -> pr " int %s;\n" n + | Int64 n -> pr " int64_t %s;\n" n + | Pointer (t, n) -> pr " %s %s;\n" t n + ) args; + if optargs <> [] then ( + pr " struct %s optargs_s = { .bitmask = 0 };\n" c_function; + pr " struct %s *optargs = &optargs_s;\n" c_function + ); + pr "\n"; + + pr " if (g == NULL)\n"; + pr " luaL_error (L, \"Guestfs.%%s: handle is closed\",\n"; + pr " \"%s\");\n" name; + pr "\n"; + + iteri ( + fun i -> + let i = i+2 in (* Lua indexes from 1(!), plus the handle. *) + function + | Pathname n | Device n | Dev_or_Path n | String n + | FileIn n | FileOut n | Key n -> + pr " %s = luaL_checkstring (L, %d);\n" n i + | BufferIn n -> + pr " %s = luaL_checklstring (L, %d, &%s_size);\n" n i n + | OptString n -> + pr " %s = luaL_optstring (L, %d, NULL);\n" n i + | StringList n | DeviceList n -> + pr " %s = get_string_list (L, %d);\n" n i + | Bool n -> + pr " %s = lua_toboolean (L, %d);\n" n i + | Int n -> + pr " %s = lua_tointeger (L, %d);\n" n i + | Int64 n -> + pr " %s = get_int64 (L, %d);\n" n i + | Pointer (t, n) -> assert false + ) args; + + if optargs <> [] then ( + (* Index of the optarg table on the stack. *) + let optarg_index = List.length args + 2 in + + pr "\n"; + pr " /* Check for optional arguments, encoded in a table. */\n"; + pr " if (lua_type (L, %d) == LUA_TTABLE) {\n" optarg_index; + + List.iter ( + fun optarg -> + let n = name_of_optargt optarg in + let uc_n = String.uppercase n in + pr " OPTARG_IF_SET (%d, \"%s\",\n" optarg_index n; + pr " optargs_s.bitmask |= %s_%s_BITMASK;\n" + c_optarg_prefix uc_n; + (match optarg with + | OBool n -> + pr " optargs_s.%s = lua_toboolean (L, -1);\n" n + | OInt n -> + pr " optargs_s.%s = lua_tointeger (L, -1);\n" n + | OInt64 n -> + pr " optargs_s.%s = get_int64 (L, -1);\n" n + | OString n -> + pr " optargs_s.%s = luaL_checkstring (L, -1);\n" n + | OStringList n -> + pr " optargs_s.%s = get_string_list (L, -1);\n" n + ); + pr " );\n" + ) optargs; + + pr " }\n"; + ); + pr "\n"; + + (* Invoke the C function. *) + pr " r = %s " c_function; + generate_c_call_args ~handle:"g" style; + pr ";\n"; + + (* Free temporary data. *) + List.iter ( + function + | Pathname _ | Device _ | Dev_or_Path _ | String _ + | FileIn _ | FileOut _ | Key _ + | BufferIn _ | OptString _ + | Bool _ | Int _ | Int64 _ + | Pointer _ -> () + | StringList n | DeviceList n -> + pr " free (%s);\n" n + ) args; + List.iter ( + function + | OBool _ | OInt _ | OInt64 _ | OString _ -> () + | OStringList n -> + pr " free ((char *) optargs_s.%s);\n" n + ) optargs; + + (* Handle errors. *) + (match errcode_of_ret ret with + | `CannotReturnError -> () + | `ErrorIsMinusOne -> + pr " if (r == -1)\n"; + pr " return luaL_error (L, \"Guestfs.%%s: %%s\",\n"; + pr " \"%s\", guestfs_last_error (g));\n" name; + pr "\n" + | `ErrorIsNULL -> + pr " if (r == NULL)\n"; + pr " return luaL_error (L, \"Guestfs.%%s: %%s\",\n"; + pr " \"%s\", guestfs_last_error (g));\n" name; + pr "\n"; + ); + + (* Push return value on the stack. *) + (match ret with + | RErr -> () + | RInt _ -> + pr " lua_pushinteger (L, r);\n" + | RBool _ -> + pr " lua_pushboolean (L, r);\n" + | RInt64 _ -> + pr " push_int64 (L, r);\n" + | RConstString _ + | RConstOptString _ + | RString _ -> + pr " lua_pushstring (L, r);\n" + | RStringList _ -> + pr " push_string_list (L, r);\n" + | RHashtable _ -> + pr " push_table (L, r);\n" + | RStruct (_, typ) -> + pr " push_%s (L, r);\n" typ + | RStructList (_, typ) -> + pr " push_%s_list (L, r);\n" typ + | RBufferOut _ -> + pr " lua_pushlstring (L, r, size);\n" + ); + + if ret = RErr then + pr " return 0;\n" + else + pr " return 1;\n"; + pr "}\n"; + pr "\n" + ) all_functions_sorted; + + pr "\ +static struct userdata * +get_handle (lua_State *L, int index) +{ + struct userdata *u; + + u = luaL_checkudata (L, index, LUA_GUESTFS_HANDLE); + return u; +} + +/* NB: caller must free the array, but NOT the strings */ +static char ** +get_string_list (lua_State *L, int index) +{ + size_t len = lua_objlen (L, index); + size_t i; + char **strs; + + strs = malloc ((len+1) * sizeof (char *)); + if (strs == NULL) { + luaL_error (L, \"get_string_list: malloc failed: %%m\"); + /*NOTREACHED*/ + return NULL; + } + + for (i = 0; i < len; ++i) { + lua_pushinteger (L, i+1 /* because of base 1 arrays */); + lua_gettable (L, index); + strs[i] = (char *) luaL_checkstring (L, -1); + lua_pop (L, 1); + } + strs[len] = NULL; + + return strs; +} + +static void +push_string_list (lua_State *L, char **strs) +{ + size_t i; + + lua_newtable (L); + for (i = 0; strs[i] != NULL; ++i) { + lua_pushinteger (L, i+1 /* because of base 1 arrays */); + lua_pushstring (L, strs[i]); + lua_settable (L, -3); + } +} + +static void +push_table (lua_State *L, char **table) +{ + size_t i; + + lua_newtable (L); + for (i = 0; table[i] != NULL; i += 2) { + lua_pushstring (L, table[i]); + lua_pushstring (L, table[i+1]); + lua_settable (L, -3); + } +} + +/* Because Lua doesn't have real 64 bit ints (eg. on 32 bit), which + * sucks, we implement these as strings. It's left as an exercise to + * the caller to turn strings to/from integers. + */ +static int64_t +get_int64 (lua_State *L, int index) +{ + int64_t r; + const char *s; + + s = luaL_checkstring (L, index); + if (sscanf (s, \"%%\" SCNi64, &r) != 1) + return luaL_error (L, \"int64 parameter expected\"); + return r; +} + +static void +push_int64 (lua_State *L, int64_t i64) +{ + char s[64]; + + snprintf (s, sizeof s, \"%%\" PRIi64, i64); + lua_pushstring (L, s); +} + +"; + + let generate_push_struct typ = + pr "static void\n"; + pr "push_%s (lua_State *L, struct guestfs_%s *v)\n" typ typ; + pr "{\n"; + pr " lua_newtable (L);\n"; + List.iter ( + fun (n, field) -> + pr " lua_pushliteral (L, \"%s\");\n" n; + (match field with + | FChar -> + pr " lua_pushlstring (L, &v->%s, 1);\n" n + | FString -> + pr " lua_pushstring (L, v->%s);\n" n + | FBuffer -> + pr " lua_pushlstring (L, v->%s, v->%s_len);\n" n n + | FUInt32 + | FInt32 -> + pr " lua_pushinteger (L, v->%s);\n" n + | FUInt64 + | FInt64 + | FBytes -> + pr " push_int64 (L, (int64_t) v->%s);\n" n + | FUUID -> + pr " lua_pushlstring (L, v->%s, 32);\n" n + | FOptPercent -> + pr " lua_pushnumber (L, v->%s);\n" n + ); + pr " lua_settable (L, -3);\n" + ) (lookup_struct typ).s_cols; + pr "}\n"; + pr "\n"; + + and generate_push_struct_list typ = + pr "static void\n"; + pr "push_%s_list (lua_State *L, struct guestfs_%s_list *v)\n" typ typ; + pr "{\n"; + pr " size_t i;\n"; + pr "\n"; + pr " lua_newtable (L);\n"; + pr " for (i = 0; i < v->len; ++i) {\n"; + pr " lua_pushinteger (L, i+1 /* because of base 1 arrays */);\n"; + pr " push_%s (L, &v->val[i]);\n" typ; + pr " lua_settable (L, -3);\n"; + pr " }\n"; + pr "}\n"; + pr "\n" + in + + List.iter ( + function + | typ, RStructOnly -> + generate_push_struct typ + | typ, (RStructListOnly | RStructAndList) -> + generate_push_struct typ; + generate_push_struct_list typ + ) (rstructs_used_by all_functions); + + pr "\ + +static luaL_Reg handle_methods[] = { + { \"__gc\", lua_guestfs_finalizer }, + { \"create\", lua_guestfs_create }, + { \"close\", lua_guestfs_close }, + +"; + + List.iter ( + fun { name = name } -> pr " { \"%s\", lua_guestfs_%s },\n" name name + ) all_functions_sorted; + + pr "\ + + { NULL, NULL } +}; + +static void +make_version_string (char *version, size_t size) +{ + guestfs_h *g; + struct guestfs_version *v; + + g = guestfs_create (); + v = guestfs_version (g); + snprintf (version, size, + \"libguestfs %%\" PRIi64 \".%%\" PRIi64 \".%%\" PRIi64 \"%%s\", + v->major, v->minor, v->release, v->extra); + free (v); + guestfs_close (g); +} + +extern int luaopen_guestfs (lua_State *L); + +int +luaopen_guestfs (lua_State *L) +{ + char v[256]; + + /* Create metatable and register methods into it. */ + luaL_newmetatable (L, LUA_GUESTFS_HANDLE); + luaL_register (L, NULL /* \"guestfs\" ? XXX */, handle_methods); + + /* Set __index field of metatable to point to itself. */ + lua_pushvalue (L, -1); + lua_setfield (L, -1, \"__index\"); + + /* Add _COPYRIGHT, etc. fields to the metatable. */ + lua_pushliteral (L, \"_COPYRIGHT\"); + lua_pushliteral (L, \"Copyright (C) %s Red Hat Inc.\"); + lua_settable (L, -3); + + lua_pushliteral (L, \"_DESCRIPTION\"); + lua_pushliteral (L, \"Lua binding to libguestfs\"); + lua_settable (L, -3); + + lua_pushliteral (L, \"_VERSION\"); + make_version_string (v, sizeof v); + lua_pushlstring (L, v, strlen (v)); + lua_settable (L, -3); + + /* Expose metatable to lua as \"Guestfs\". */ + lua_setglobal (L, \"Guestfs\"); + + return 1; +} + +" copyright_years; diff --git a/generator/main.ml b/generator/main.ml index f8df1295..55867474 100644 --- a/generator/main.ml +++ b/generator/main.ml @@ -41,6 +41,7 @@ open Haskell open Csharp open Php open Erlang +open Lua open Gobject open Bindtests open Errnostring @@ -152,6 +153,7 @@ Run it from the top source directory using the command output_to "erlang/guestfs.erl" generate_erlang_erl; output_to "erlang/erl-guestfs.c" generate_erlang_c; output_to ~perm:0o555 "erlang/bindtests.erl" generate_erlang_bindtests; + output_to "lua/lua-guestfs.c" generate_lua_c; output_to "gobject/bindtests.js" generate_gobject_js_bindtests; output_to "gobject/Makefile.inc" generate_gobject_makefile; diff --git a/java/examples/guestfs-java.pod b/java/examples/guestfs-java.pod index 23da8ad4..0795c86b 100644 --- a/java/examples/guestfs-java.pod +++ b/java/examples/guestfs-java.pod @@ -47,6 +47,7 @@ Calling any method on a closed handle raises the same exception. L<guestfs(3)>, L<guestfs-examples(3)>, L<guestfs-erlang(3)>, +L<guestfs-lua(3)>, L<guestfs-ocaml(3)>, L<guestfs-perl(3)>, L<guestfs-python(3)>, diff --git a/lua/Makefile.am b/lua/Makefile.am new file mode 100644 index 00000000..e642a130 --- /dev/null +++ b/lua/Makefile.am @@ -0,0 +1,79 @@ +# libguestfs Lua bindings +# Copyright (C) 2012 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 + +lualibdir = $(libdir)/lua/$(LUA_VERSION) + +generator_built = \ + lua-guestfs.c + +EXTRA_DIST = \ + $(generator_built) + +CLEANFILES = *~ guestfs.so + +if HAVE_LUA + +# Libtool forces us to use 'libluaguestfs.so' instead of the desired +# name 'guestfs.so'. However we'll rename it in the install hook. +# Cannot use 'noinst' here as that prevents the shared library from +# being built at all. +lualib_LTLIBRARIES = libluaguestfs.la +libluaguestfs_la_SOURCES = lua-guestfs.c + +libluaguestfs_la_CFLAGS = \ + $(WARN_CFLAGS) $(WERROR_CFLAGS) \ + -I$(top_srcdir)/src -I$(top_builddir)/src +libluaguestfs_la_LIBADD = $(top_builddir)/src/libguestfs.la +libluaguestfs_la_LDFLAGS = -avoid-version -shared + +# Hack so we can run without installing. +noinst_DATA = guestfs.so +guestfs.so: libluaguestfs.la + ln -sf .libs/libluaguestfs.so $@ + +# Tests. +TESTS_ENVIRONMENT = $(top_builddir)/run --test +TESTS = \ + tests/010-load.lua \ + tests/020-create.lua \ + tests/025-create-flags.lua \ + tests/030-config.lua \ + tests/070-optargs.lua + +if ENABLE_APPLIANCE +TESTS += \ + tests/050-lvcreate.lua \ + tests/060-readdir.lua +endif + +EXTRA_DIST += \ + tests/010-load.lua \ + tests/020-create.lua \ + tests/025-create-flags.lua \ + tests/030-config.lua \ + tests/050-lvcreate.lua \ + tests/060-readdir.lua \ + tests/070-optargs.lua + +# Custom install rule. +install-data-hook: + mkdir -p $(DESTDIR)$(lualibdir) + mv $(DESTDIR)$(lualibdir)/libluaguestfs.so $(DESTDIR)$(lualibdir)/guestfs.so + +endif diff --git a/lua/examples/LICENSE b/lua/examples/LICENSE new file mode 100644 index 00000000..c5976b51 --- /dev/null +++ b/lua/examples/LICENSE @@ -0,0 +1,2 @@ +All the examples in the lua/examples/ subdirectory may be freely +copied without any restrictions. diff --git a/lua/examples/Makefile.am b/lua/examples/Makefile.am new file mode 100644 index 00000000..8dc4650c --- /dev/null +++ b/lua/examples/Makefile.am @@ -0,0 +1,40 @@ +# libguestfs Lua examples +# Copyright (C) 2012 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. + +EXTRA_DIST = \ + LICENSE \ + create_disk.lua \ + inspect_vm.lua \ + guestfs-lua.pod + +CLEANFILES = stamp-guestfs-lua.pod + +man_MANS = guestfs-lua.3 +noinst_DATA = $(top_builddir)/html/guestfs-lua.3.html + +guestfs-lua.3 $(top_builddir)/html/guestfs-lua.3.html: stamp-guestfs-lua.pod + +stamp-guestfs-lua.pod: guestfs-lua.pod create_disk.lua inspect_vm.lua + $(PODWRAPPER) \ + --section 3 \ + --man guestfs-lua.3 \ + --html $(top_builddir)/html/guestfs-lua.3.html \ + --verbatim $(srcdir)/create_disk.lua:@EXAMPLE1@ \ + --verbatim $(srcdir)/inspect_vm.lua:@EXAMPLE2@ \ + --license examples \ + $< + touch $@ diff --git a/lua/examples/create_disk.lua b/lua/examples/create_disk.lua new file mode 100644 index 00000000..2dfc1fc2 --- /dev/null +++ b/lua/examples/create_disk.lua @@ -0,0 +1,66 @@ +-- Example showing how to create a disk image. + +require "guestfs" + +output = "disk.img" + +g = Guestfs.create () + +-- Create a raw-format sparse disk image, 512 MB in size. +file = io.open (output, "w") +file:seek ("set", 512 * 1024 * 1024) +file:write (' ') +file:close () + +-- Set the trace flag so that we can see each libguestfs call. +g:set_trace (true) + +-- Attach the disk image to libguestfs. +g:add_drive (output, { format = "raw", readonly = false }) + +-- Run the libguestfs back-end. +g:launch () + +-- Get the list of devices. Because we only added one drive +-- above, we expect that this list should contain a single +-- element. +devices = g:list_devices () +if table.getn (devices) ~= 1 then + error "expected a single device from list-devices" +end + +-- Partition the disk as one single MBR partition. +g:part_disk (devices[1], "mbr") + +-- Get the list of partitions. We expect a single element, which +-- is the partition we have just created. +partitions = g:list_partitions () +if table.getn (partitions) ~= 1 then + error "expected a single partition from list-partitions" +end + +-- Create a filesystem on the partition. +g:mkfs ("ext4", partitions[1]) + +-- Now mount the filesystem so that we can add files. +g:mount (partitions[1], "/") + +-- Create some files and directories. +g:touch ("/empty") +message = "Hello, world\n" +g:write ("/hello", message) +g:mkdir ("/foo") + +-- This one uploads the local file /etc/resolv.conf into +-- the disk image. +g:upload ("/etc/resolv.conf", "/foo/resolv.conf") + +-- Because we wrote to the disk and we want to detect write +-- errors, call g:shutdown. You don't need to do this: +-- g:close will do it implicitly. +g:shutdown () + +-- Note also that handles are automatically closed if they are +-- reaped by the garbage collector. You only need to call close +-- if you want to close the handle right away. +g:close () diff --git a/lua/examples/guestfs-lua.pod b/lua/examples/guestfs-lua.pod new file mode 100644 index 00000000..33c9b811 --- /dev/null +++ b/lua/examples/guestfs-lua.pod @@ -0,0 +1,97 @@ +=encoding utf8 + +=head1 NAME + +guestfs-lua - How to use libguestfs from Lua + +=head1 SYNOPSIS + + require "guestfs" + g = Guestfs.create () + g:add_drive ("test.img", { format = "raw", readonly = "true" }) + g:launch () + devices = g:list_devices () + g:close () + +=head1 DESCRIPTION + +This manual page documents how to call libguestfs from the Lua +programming language. This page just documents the differences from +the C API and gives some examples. If you are not familiar with using +libguestfs, you also need to read L<guestfs(3)>. + +=head2 OPENING AND CLOSING THE HANDLE + +To create a new handle, call: + + g = Guestfs.create () + +You can also use the optional arguments: + + g = Guestfs.create { environment = 0, close_on_exit = 0 } + +to set the flags C<GUESTFS_CREATE_NO_ENVIRONMENT> +and/or C<GUESTFS_CREATE_NO_CLOSE_ON_EXIT>. + +The handle will be closed by the garbage collector, but you can +also close it explicitly by doing: + + g:close () + +=head2 CALLING METHODS + +Use the ordinary Lua convention for calling methods on the handle. +For example: + + g:set_verbose (true) + +=head2 FUNCTIONS WITH OPTIONAL ARGUMENTS + +For functions that take optional arguments, the first arguments are +the non-optional ones. The optional final argument is a table +supplying the optional arguments. + + g:add_drive ("test.img") + +or: + + g:add_drive ("test.img", { format = "raw", readonly = "true" }) + +=head2 64 BIT VALUES + +Currently 64 bit values must be passed as strings, and are returned as +strings. This is because 32 bit Lua cannot handle 64 bit integers +properly. We hope to come up with a better solution later. + +=head2 ERRORS + +Errors are converted into exceptions. Use C<pcall> to catch these. + +=head1 EXAMPLE 1: CREATE A DISK IMAGE + +@EXAMPLE1@ + +=head1 EXAMPLE 2: INSPECT A VIRTUAL MACHINE DISK IMAGE + +@EXAMPLE2@ + +=head1 SEE ALSO + +L<guestfs(3)>, +L<guestfs-examples(3)>, +L<guestfs-java(3)>, +L<guestfs-ocaml(3)>, +L<guestfs-perl(3)>, +L<guestfs-python(3)>, +L<guestfs-recipes(1)>, +L<guestfs-ruby(3)>, +L<http://www.erlang.org/>. +L<http://libguestfs.org/>. + +=head1 AUTHORS + +Richard W.M. Jones (C<rjones at redhat dot com>) + +=head1 COPYRIGHT + +Copyright (C) 2012 Red Hat Inc. diff --git a/lua/examples/inspect_vm.lua b/lua/examples/inspect_vm.lua new file mode 100644 index 00000000..1bee10b3 --- /dev/null +++ b/lua/examples/inspect_vm.lua @@ -0,0 +1,62 @@ +-- Example showing how to inspect a virtual machine disk. + +require "guestfs" + +if table.getn (arg) == 1 then + disk = arg[1] +else + error ("usage: inspect_vm disk.img") +end + +g = Guestfs.create () + +-- Attach the disk image read-only to libguestfs. +g:add_drive (disk, { -- format:"raw" + readonly = true }) + +-- Run the libguestfs back-end. +g:launch () + +-- Ask libguestfs to inspect for operating systems. +roots = g:inspect_os () +if table.getn (roots) == 0 then + error ("inspect_vm: no operating systems found") +end + +for _, root in ipairs (roots) do + print ("Root device: ", root) + + -- Print basic information about the operating system. + print (" Product name: ", g:inspect_get_product_name (root)) + print (" Version: ", + g:inspect_get_major_version (root), + g:inspect_get_minor_version (root)) + print (" Type: ", g:inspect_get_type (root)) + print (" Distro: ", g:inspect_get_distro (root)) + + -- Mount up the disks, like guestfish -i. + -- + -- Sort keys by length, shortest first, so that we end up + -- mounting the filesystems in the correct order. + mps = g:inspect_get_mountpoints (root) + table.sort (mps, + function (a, b) + return string.len (a) < string.len (b) + end) + for mp,dev in pairs (mps) do + pcall (function () g:mount_ro (dev, mp) end) + end + + -- If /etc/issue.net file exists, print up to 3 lines. + filename = "/etc/issue.net" + if g:is_file (filename) then + print ("--- ", filename, " ---") + lines = g:head_n (3, filename) + for _, line in ipairs (lines) do + print (line) + end + end + + -- Unmount everything. + g:umount_all () +end diff --git a/lua/tests/010-load.lua b/lua/tests/010-load.lua new file mode 100755 index 00000000..4443e322 --- /dev/null +++ b/lua/tests/010-load.lua @@ -0,0 +1,19 @@ +#!/usr/bin/lua +-- libguestfs Lua bindings -*- lua -*- +-- Copyright (C) 2012 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. + +require "guestfs" diff --git a/lua/tests/020-create.lua b/lua/tests/020-create.lua new file mode 100755 index 00000000..527aa0bc --- /dev/null +++ b/lua/tests/020-create.lua @@ -0,0 +1,21 @@ +#!/usr/bin/lua +-- libguestfs Lua bindings -*- lua -*- +-- Copyright (C) 2012 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. + +require "guestfs" + +local g = Guestfs.create () diff --git a/lua/tests/025-create-flags.lua b/lua/tests/025-create-flags.lua new file mode 100755 index 00000000..881b1834 --- /dev/null +++ b/lua/tests/025-create-flags.lua @@ -0,0 +1,21 @@ +#!/usr/bin/lua +-- libguestfs Lua bindings -*- lua -*- +-- Copyright (C) 2012 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. + +require "guestfs" + +local g = Guestfs.create { environment = 0 } diff --git a/lua/tests/030-config.lua b/lua/tests/030-config.lua new file mode 100755 index 00000000..a1325584 --- /dev/null +++ b/lua/tests/030-config.lua @@ -0,0 +1,42 @@ +#!/usr/bin/lua +-- libguestfs Lua bindings -*- lua -*- +-- Copyright (C) 2012 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. + +require "guestfs" + +local g = Guestfs.create () + +local verbose = g:get_verbose () +g:set_verbose (true) +g:set_verbose (verbose) + +g:set_autosync (false) +g:set_autosync (true) + +g:set_path (".") +if g:get_path () ~= "." then + error () +end + +g:add_drive ("/dev/null") + +local version = g:version () +for k,v in pairs (version) do + print(k,v) +end + +g:close () diff --git a/lua/tests/050-lvcreate.lua b/lua/tests/050-lvcreate.lua new file mode 100755 index 00000000..a9d9920e --- /dev/null +++ b/lua/tests/050-lvcreate.lua @@ -0,0 +1,47 @@ +#!/usr/bin/lua +-- libguestfs Lua bindings -*- lua -*- +-- Copyright (C) 2012 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. + +require "guestfs" + +local g = Guestfs.create () + +file = io.open ("test.img", "w") +file:seek ("set", 500 * 1024 * 1024) +file:write (' ') +file:close () + +g:add_drive ("test.img") + +g:launch () + +g:pvcreate ("/dev/sda") +g:vgcreate ("VG", {"/dev/sda"}) +g:lvcreate ("LV1", "VG", 200) +g:lvcreate ("LV2", "VG", 200) + +local lvs = g:lvs () +if table.getn (lvs) ~= 2 or lvs[1] ~= "/dev/VG/LV1" or lvs[2] ~= "/dev/VG/LV2" +then + error ("g:lvs returned incorrect result") +end + +g:shutdown () + +g:close () + +os.remove ("test.img") diff --git a/lua/tests/060-readdir.lua b/lua/tests/060-readdir.lua new file mode 100755 index 00000000..dd060840 --- /dev/null +++ b/lua/tests/060-readdir.lua @@ -0,0 +1,65 @@ +#!/usr/bin/lua +-- libguestfs Lua bindings -*- lua -*- +-- Copyright (C) 2012 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. + +require "guestfs" + +local g = Guestfs.create () + +file = io.open ("test.img", "w") +file:seek ("set", 10 * 1024 * 1024) +file:write (' ') +file:close () + +g:add_drive ("test.img") + +g:launch () + +g:part_disk ("/dev/sda", "mbr") +g:mkfs ("ext2", "/dev/sda1") +g:mount ("/dev/sda1", "/") +g:mkdir ("/p") +g:touch ("/q") + +local dirs = g:readdir ("/") + +function print_dirs(dirs) + for i,dentry in ipairs (dirs) do + for k,v in pairs (dentry) do + print(i, k, v) + end + end +end + +print_dirs (dirs) +table.sort (dirs, function (a,b) return a["name"] < b["name"] end) +print_dirs (dirs) + +-- Slots 1, 2, 3 contain "." and ".." and "lost+found" respectively. + +if (dirs[4]["name"] ~= "p") then + error "incorrect name in slot 4" +end +if (dirs[5]["name"] ~= "q") then + error "incorrect name in slot 5" +end + +g:shutdown () + +g:close () + +os.remove ("test.img") diff --git a/lua/tests/070-optargs.lua b/lua/tests/070-optargs.lua new file mode 100755 index 00000000..fe0ec753 --- /dev/null +++ b/lua/tests/070-optargs.lua @@ -0,0 +1,25 @@ +#!/usr/bin/lua +-- libguestfs Lua bindings -*- lua -*- +-- Copyright (C) 2012 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. + +require "guestfs" + +local g = Guestfs.create () + +g:add_drive ("/dev/null") +g:add_drive ("/dev/null", { readonly = true }) +g:add_drive ("/dev/null", { format = "raw", readonly = false }) diff --git a/ocaml/examples/guestfs-ocaml.pod b/ocaml/examples/guestfs-ocaml.pod index 8a4c94fd..f91d6d2c 100644 --- a/ocaml/examples/guestfs-ocaml.pod +++ b/ocaml/examples/guestfs-ocaml.pod @@ -81,6 +81,7 @@ L<guestfs(3)>, L<guestfs-examples(3)>, L<guestfs-erlang(3)>, L<guestfs-java(3)>, +L<guestfs-lua(3)>, L<guestfs-perl(3)>, L<guestfs-python(3)>, L<guestfs-recipes(1)>, diff --git a/perl/examples/guestfs-perl.pod b/perl/examples/guestfs-perl.pod index ab3f0359..95a1b604 100644 --- a/perl/examples/guestfs-perl.pod +++ b/perl/examples/guestfs-perl.pod @@ -44,6 +44,7 @@ L<guestfs(3)>, L<guestfs-examples(3)>, L<guestfs-erlang(3)>, L<guestfs-java(3)>, +L<guestfs-lua(3)>, L<guestfs-ocaml(3)>, L<guestfs-python(3)>, L<guestfs-recipes(1)>, diff --git a/po-docs/ja/Makefile.am b/po-docs/ja/Makefile.am index 27432f03..d3413ec1 100644 --- a/po-docs/ja/Makefile.am +++ b/po-docs/ja/Makefile.am @@ -30,6 +30,7 @@ MANPAGES = \ guestfs-examples.3 \ guestfs-faq.1 \ guestfs-java.3 \ + guestfs-lua.3 \ guestfs-ocaml.3 \ guestfs-performance.1 \ guestfs-perl.3 \ diff --git a/po-docs/podfiles b/po-docs/podfiles index 5e23ea15..74f722d4 100644 --- a/po-docs/podfiles +++ b/po-docs/podfiles @@ -24,6 +24,7 @@ ../guestfs-release-notes.pod ../inspector/virt-inspector.pod ../java/examples/guestfs-java.pod +../lua/examples/guestfs-lua.pod ../ocaml/examples/guestfs-ocaml.pod ../perl/examples/guestfs-perl.pod ../python/examples/guestfs-python.pod diff --git a/po-docs/uk/Makefile.am b/po-docs/uk/Makefile.am index 27432f03..d3413ec1 100644 --- a/po-docs/uk/Makefile.am +++ b/po-docs/uk/Makefile.am @@ -30,6 +30,7 @@ MANPAGES = \ guestfs-examples.3 \ guestfs-faq.1 \ guestfs-java.3 \ + guestfs-lua.3 \ guestfs-ocaml.3 \ guestfs-performance.1 \ guestfs-perl.3 \ diff --git a/po/POTFILES b/po/POTFILES index 622c0158..ece787a8 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -203,6 +203,7 @@ gobject/src/struct-xfsinfo.c gobject/src/tristate.c inspector/virt-inspector.c java/com_redhat_et_libguestfs_GuestFS.c +lua/lua-guestfs.c ocaml/guestfs-c-actions.c ocaml/guestfs-c.c perl/Guestfs.c diff --git a/python/examples/guestfs-python.pod b/python/examples/guestfs-python.pod index 52010155..b17cf078 100644 --- a/python/examples/guestfs-python.pod +++ b/python/examples/guestfs-python.pod @@ -45,6 +45,7 @@ L<guestfs(3)>, L<guestfs-examples(3)>, L<guestfs-erlang(3)>, L<guestfs-java(3)>, +L<guestfs-lua(3)>, L<guestfs-ocaml(3)>, L<guestfs-perl(3)>, L<guestfs-recipes(1)>, diff --git a/ruby/examples/guestfs-ruby.pod b/ruby/examples/guestfs-ruby.pod index e3b86481..82b1325a 100644 --- a/ruby/examples/guestfs-ruby.pod +++ b/ruby/examples/guestfs-ruby.pod @@ -39,6 +39,7 @@ L<guestfs(3)>, L<guestfs-examples(3)>, L<guestfs-erlang(3)>, L<guestfs-java(3)>, +L<guestfs-lua(3)>, L<guestfs-ocaml(3)>, L<guestfs-perl(3)>, L<guestfs-python(3)>, @@ -93,6 +93,14 @@ export CAML_LD_LIBRARY_PATH="$b/ocaml" export JAVA_EXE=@JAVA_EXE@ export CLASSPATH="$b/java:$b/java/t:$b/java/libguestfs-@VERSION@.jar" +# For Lua. +if [ -z "$LUA_CPATH" ]; then + LUA_CPATH="$b/lua/?.so" +else + LUA_CPATH="$b/lua/?.so;$LUA_CPATH" +fi +export LUA_CPATH + # For GObject, Javascript and friends. export GJS=@GJS@ if [ -z "$GI_TYPELIB_PATH" ]; then diff --git a/src/guestfs.pod b/src/guestfs.pod index 1e1fe416..cc6b27b8 100644 --- a/src/guestfs.pod +++ b/src/guestfs.pod @@ -880,6 +880,10 @@ and we are looking for help to complete this binding. Full documentation is contained in the Javadoc which is distributed with libguestfs. For examples, see L<guestfs-java(3)>. +=item B<Lua> + +See L<guestfs-lua(3)>. + =item B<OCaml> See L<guestfs-ocaml(3)>. @@ -3751,6 +3755,8 @@ Command line tools written in Perl (L<virt-win-reg(1)> and many others). =item C<java> +=item C<lua> + =item C<ocaml> =item C<php> @@ -4027,6 +4033,7 @@ See L</LIBGUESTFS_CACHEDIR>, L</LIBGUESTFS_TMPDIR>. L<guestfs-examples(3)>, L<guestfs-erlang(3)>, L<guestfs-java(3)>, +L<guestfs-lua(3)>, L<guestfs-ocaml(3)>, L<guestfs-perl(3)>, L<guestfs-python(3)>, |