Add Lua bindings.

These are relatively complete, although only lightly tested.  Missing:

 - events
 - last_errno
 - user_cancel
This commit is contained in:
Richard W.M. Jones
2012-11-17 10:10:13 +00:00
parent 4a2e8e8957
commit ff8bfd3e92
32 changed files with 1212 additions and 0 deletions

6
.gitignore vendored
View File

@@ -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

View File

@@ -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 \

View File

@@ -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 ............... "])

View File

@@ -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)>,

View File

@@ -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)>,

View File

@@ -47,6 +47,7 @@ SOURCES = \
csharp.ml \
php.ml \
erlang.ml \
lua.ml \
gobject.ml \
bindtests.ml \
errnostring.ml \

561
generator/lua.ml Normal file
View File

@@ -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;

View File

@@ -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;

View File

@@ -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)>,

79
lua/Makefile.am Normal file
View File

@@ -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

2
lua/examples/LICENSE Normal file
View File

@@ -0,0 +1,2 @@
All the examples in the lua/examples/ subdirectory may be freely
copied without any restrictions.

40
lua/examples/Makefile.am Normal file
View File

@@ -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 $@

View File

@@ -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 ()

View File

@@ -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.

View File

@@ -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

19
lua/tests/010-load.lua Executable file
View File

@@ -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"

21
lua/tests/020-create.lua Executable file
View File

@@ -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 ()

21
lua/tests/025-create-flags.lua Executable file
View File

@@ -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 }

42
lua/tests/030-config.lua Executable file
View File

@@ -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 ()

47
lua/tests/050-lvcreate.lua Executable file
View File

@@ -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")

65
lua/tests/060-readdir.lua Executable file
View File

@@ -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")

25
lua/tests/070-optargs.lua Executable file
View File

@@ -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 })

View File

@@ -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)>,

View File

@@ -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)>,

View File

@@ -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 \

View File

@@ -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

View File

@@ -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 \

View File

@@ -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

View File

@@ -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)>,

View File

@@ -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)>,

8
run.in
View File

@@ -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

View File

@@ -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)>,