[Libguestfs] Misc Java patches

Richard W.M. Jones rjones at redhat.com
Thu Jan 10 09:19:35 UTC 2013


Only tested on ARM (!) so far, but if someone can test them on
x86{,64} that'd be great.

Rich.

-- 
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming blog: http://rwmj.wordpress.com
Fedora now supports 80 OCaml packages (the OPEN alternative to F#)
-------------- next part --------------
From 387616241206c2b6e3a1bbaedd84cb3b586975d9 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones at redhat.com>
Date: Fri, 4 Jan 2013 12:33:48 +0900
Subject: [PATCH 1/7] Update copyright dates for 2013.

On generated files in git and README.
---
 README               | 2 +-
 gobject/Makefile.inc | 2 +-
 java/Makefile.inc    | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/README b/README
index 1196e0f..6a5692f 100644
--- a/README
+++ b/README
@@ -346,7 +346,7 @@ attention to the qemu command line and kernel output.
 Copyright and license information
 ----------------------------------------------------------------------
 
-Copyright (C) 2009-2012 Red Hat Inc.
+Copyright (C) 2009-2013 Red Hat Inc.
 
 The library is distributed under the LGPLv2+.  The programs are
 distributed under the GPLv2+.  Please see the files COPYING and
diff --git a/gobject/Makefile.inc b/gobject/Makefile.inc
index 8708994..25c383e 100644
--- a/gobject/Makefile.inc
+++ b/gobject/Makefile.inc
@@ -3,7 +3,7 @@
 #   generator/ *.ml
 # ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.
 #
-# Copyright (C) 2009-2012 Red Hat Inc.
+# Copyright (C) 2009-2013 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
diff --git a/java/Makefile.inc b/java/Makefile.inc
index 9dd39de..985be59 100644
--- a/java/Makefile.inc
+++ b/java/Makefile.inc
@@ -3,7 +3,7 @@
 #   generator/ *.ml
 # ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.
 #
-# Copyright (C) 2009-2012 Red Hat Inc.
+# Copyright (C) 2009-2013 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
-- 
1.7.11.7

-------------- next part --------------
From 33f9dd68b244d3d8c6afb9032413626ff62beda9 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones at redhat.com>
Date: Wed, 9 Jan 2013 12:28:23 +0900
Subject: [PATCH 2/7] Refresh README file.

---
 README | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/README b/README
index 6a5692f..28db6c5 100644
--- a/README
+++ b/README
@@ -166,12 +166,12 @@ To build the Perl tools:
 Building
 ----------------------------------------------------------------------
 
-Then make the daemon, library and root filesystem:
+Build the daemon, library and root filesystem:
 
   ./configure
   make
 
-Finally run the tests:
+Run the tests:
 
   make check
 
@@ -189,6 +189,10 @@ some libvirt guests installed, that these guests' disks are accessible
 by the current user, and these tests may fail for other reasons which
 are not necessarily because of real problems.
 
+ make help
+
+lists all 'make' targets.
+
 If everything works, you can install the library and tools by running
 this command as root:
 
@@ -292,7 +296,7 @@ distributions.  Non-Linux ports are trickier, but we will accept
 patches if they aren't too invasive.
 
 The main porting issues are with the dependencies needed to build the
-appliance.  You will need to port the febootstrap first
+appliance.  You will need to port febootstrap first
 (http://people.redhat.com/~rjones/febootstrap/).
 
 
-- 
1.7.11.7

-------------- next part --------------
From da00e6e1b0645e69431a2161aeebb4f18a01f3a0 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones at redhat.com>
Date: Mon, 7 Jan 2013 06:46:09 +0900
Subject: [PATCH 3/7] java: Tidy up javadoc.

---
 generator/java.ml                                      | 16 ++++++++++++++--
 java/com/redhat/et/libguestfs/LibGuestFSException.java |  4 +++-
 2 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/generator/java.ml b/generator/java.ml
index c83bf80..270ad44 100644
--- a/generator/java.ml
+++ b/generator/java.ml
@@ -40,7 +40,19 @@ import java.util.HashMap;
 import java.util.Map;
 
 /**
- * The GuestFS object is a libguestfs handle.
+ * Libguestfs handle.
+ * <p>
+ * The <code>GuestFS</code> object corresponds to a libguestfs handle.
+ * <p>
+ * Note that the main documentation for the libguestfs API is in
+ * the following man pages:
+ * <p>
+ * <ol>
+ * <li> <a href=\"http://libguestfs.org/guestfs-java.3.html\"><code>guestfs-java(3)</code></a> and </li>
+ * <li> <a href=\"http://libguestfs.org/guestfs.3.html\"><code>guestfs(3)</code></a>. </li>
+ * </ol>
+ * <p>
+ * This javadoc is <b>not</b> a good introduction to using libguestfs.
  *
  * @author rjones
  */
@@ -384,7 +396,7 @@ and generate_java_struct jtyp cols () =
 package com.redhat.et.libguestfs;
 
 /**
- * Libguestfs %s structure.
+ * %s structure.
  *
  * @author rjones
  * @see GuestFS
diff --git a/java/com/redhat/et/libguestfs/LibGuestFSException.java b/java/com/redhat/et/libguestfs/LibGuestFSException.java
index c7bcc05..7b5a27f 100644
--- a/java/com/redhat/et/libguestfs/LibGuestFSException.java
+++ b/java/com/redhat/et/libguestfs/LibGuestFSException.java
@@ -1,5 +1,5 @@
 /* libguestfs Java bindings
- * Copyright (C) 2009 Red Hat Inc.
+ * Copyright (C) 2009-2013 Red Hat Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -19,6 +19,8 @@
 package com.redhat.et.libguestfs;
 
 /**
+ * Libguestfs error class.
+ * <p>
  * This exception is thrown when some error occurs when using the
  * libguestfs library.  The error message is always a simple
  * printable string.
-- 
1.7.11.7

-------------- next part --------------
From f3eabd6c849f39380f698433e1cac95fd0627189 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones at redhat.com>
Date: Mon, 7 Jan 2013 23:41:46 +0900
Subject: [PATCH 4/7] java: Change synopsis in man page to show use of
 add_drive.

---
 java/examples/guestfs-java.pod | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/java/examples/guestfs-java.pod b/java/examples/guestfs-java.pod
index 0795c86..6e032b4 100644
--- a/java/examples/guestfs-java.pod
+++ b/java/examples/guestfs-java.pod
@@ -9,7 +9,13 @@ guestfs-java - How to use libguestfs from Java
  import com.redhat.et.libguestfs.*;
  
  GuestFS g = new GuestFS ();
- g.add_drive_opts ("disk.img");
+ g.add_drive ("disk.img",
+              new HashMap<String,Object>() {
+                {
+                    put ("readonly", Boolean.TRUE);
+                    put ("format", "raw");
+                }
+              });
  g.launch ();
 
 =head1 DESCRIPTION
-- 
1.7.11.7

-------------- next part --------------
From e18e3674b53dce63a88f58387ad5109c6b780716 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones at redhat.com>
Date: Tue, 8 Jan 2013 11:29:31 +0900
Subject: [PATCH 5/7] java: Use defined constants for flags in call to
 guestfs_create_flags.

---
 generator/java.ml | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/generator/java.ml b/generator/java.ml
index 270ad44..1879f50 100644
--- a/generator/java.ml
+++ b/generator/java.ml
@@ -67,6 +67,10 @@ public class GuestFS {
    */
   long g;
 
+  /* guestfs_create_flags values defined in <guestfs.h> */
+  private static int CREATE_NO_ENVIRONMENT   = 1;
+  private static int CREATE_NO_CLOSE_ON_EXIT = 2;
+
   /**
    * Create a libguestfs handle, setting flags.
    *
@@ -82,11 +86,11 @@ public class GuestFS {
     if (optargs != null)
       _optobj = optargs.get (\"environment\");
     if (_optobj != null && !((Boolean) _optobj).booleanValue())
-      flags |= 1;
+      flags |= CREATE_NO_ENVIRONMENT;
     if (optargs != null)
       _optobj = optargs.get (\"close_on_exit\");
     if (_optobj != null && !((Boolean) _optobj).booleanValue())
-      flags |= 2;
+      flags |= CREATE_NO_CLOSE_ON_EXIT;
 
     g = _create (flags);
   }
@@ -100,6 +104,7 @@ public class GuestFS {
   {
     g = _create (0);
   }
+
   private native long _create (int flags) throws LibGuestFSException;
 
   /**
-- 
1.7.11.7

-------------- next part --------------
From 4b9c9401aac30054333af891f9630a59b63d474a Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones at redhat.com>
Date: Fri, 4 Jan 2013 05:07:16 +0900
Subject: [PATCH 6/7] java: Implement the event API.

---
 generator/java.ml                                | 302 ++++++++++++++++++++++-
 generator/main.ml                                |   3 +-
 java/Makefile.am                                 |   6 +-
 java/com/redhat/et/libguestfs/EventCallback.java |  33 +++
 java/examples/guestfs-java.pod                   |  30 +++
 java/t/GuestFS400Events.java                     |  95 +++++++
 6 files changed, 465 insertions(+), 4 deletions(-)
 create mode 100644 java/com/redhat/et/libguestfs/EventCallback.java
 create mode 100644 java/t/GuestFS400Events.java

diff --git a/generator/java.ml b/generator/java.ml
index 1879f50..9ef09ad 100644
--- a/generator/java.ml
+++ b/generator/java.ml
@@ -1,5 +1,5 @@
 (* libguestfs
- * Copyright (C) 2009-2012 Red Hat Inc.
+ * Copyright (C) 2009-2013 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
@@ -27,6 +27,7 @@ open Docstrings
 open Optgroups
 open Actions
 open Structs
+open Events
 open C
 
 (* Generate Java bindings GuestFS.java file. *)
@@ -133,6 +134,117 @@ public class GuestFS {
 
 ";
 
+  (* Events. *)
+  pr "  // Event bitmasks.\n\n";
+  List.iter (
+    fun (name, bitmask) ->
+      pr "  /**\n";
+      pr "   * Event '%s'.\n" name;
+      pr "   *\n";
+      pr "   * @see #set_event_callback\n";
+      pr "   */\n";
+      pr "  public static final long EVENT_%s = 0x%x;\n" (String.uppercase name) bitmask;
+      pr "\n";
+  ) events;
+
+  pr "  /** Bitmask of all events. */\n";
+  pr "  public static final long EVENT_ALL = 0x%x;\n" ((1 lsl List.length events) - 1);
+  pr "\n";
+
+  pr "  /** Utility function to turn an event number or bitmask into a string. */\n";
+  pr "  public static String eventToString (long events)\n";
+  pr "  {\n";
+  pr "    if (events == 0)\n";
+  pr "      return \"\";\n";
+  pr "\n";
+  pr "    String ret = \"\";\n";
+  pr "\n";
+  List.iter (
+    fun (name, bitmask) ->
+      pr "    if ((events & EVENT_%s) != 0) {\n" (String.uppercase name);
+      pr "      ret = ret + \"|EVENT_%s\";\n" (String.uppercase name);
+      pr "      events &= ~0x%x;\n" bitmask;
+      pr "    }\n";
+  ) events;
+  pr "\n";
+  pr "    if (events != 0)\n";
+  pr "      ret = events + ret;\n";
+  pr "    else\n";
+  pr "       ret = ret.substring (1);\n";
+  pr "\n";
+  pr "    return ret;\n";
+  pr "  }\n";
+
+  pr "
+  /**
+   * Set an event handler.
+   * <p>
+   * Set an event handler (<code>callback</code>) which is called when any
+   * event from the set (<code>events</code>) is raised by the API.
+   * <code>events</code> is one or more <code>EVENT_*</code> constants,
+   * bitwise ORed together.
+   * <p>
+   * When an event happens, the callback object's <code>event</code> method
+   * is invoked like this:
+   * <pre>
+   * callback.event (event,    // the specific event which fired (long)
+   *                 eh,       // the event handle (int)
+   *                 buffer,   // event data (String)
+   *                 array     // event data (long[])
+   *                 );
+   * </pre>
+   * Note that you can pass arbitrary data from the main program to the
+   * callback by putting it into your {@link EventCallback callback object},
+   * then accessing it in the callback via <code>this</code>.
+   * <p>
+   * This function returns an event handle which may be used to delete
+   * the event.  Note that event handlers are deleted automatically when
+   * the libguestfs handle is closed.
+   *
+   * @throws LibGuestFSException
+   * @see The section \"EVENTS\" in the guestfs(3) manual
+   * @see #delete_event_callback
+   */
+  public int set_event_callback (EventCallback callback, long events)
+    throws LibGuestFSException
+  {
+    if (g == 0)
+      throw new LibGuestFSException (\"set_event_callback: handle is closed\");
+
+    return _set_event_callback (g, callback, events);
+  }
+
+  private native int _set_event_callback (long g, EventCallback callback,
+                                          long events)
+    throws LibGuestFSException;
+
+  /**
+   * Delete an event handler.
+   * <p>
+   * Delete a previously registered event handler.  The 'eh' parameter is
+   * the event handle returned from a previous call to
+   * {@link #set_event_callback set_event_callback}.
+   * <p>
+   * Note that event handlers are deleted automatically when the
+   * libguestfs handle is closed.
+   *
+   * @throws LibGuestFSException
+   * @see #set_event_callback
+   */
+  public void delete_event_callback (int eh)
+    throws LibGuestFSException
+  {
+    if (g == 0)
+      throw new LibGuestFSException (\"delete_event_callback: handle is closed\");
+
+    _delete_event_callback (g, eh);
+  }
+
+  private native void _delete_event_callback (long g, int eh);
+
+";
+
+  (* Methods. *)
   List.iter (
     fun ({ name = name; style = (ret, args, optargs as style);
            in_docs = in_docs; shortdesc = shortdesc;
@@ -433,10 +545,25 @@ and generate_java_c () =
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <inttypes.h>
 
 #include \"com_redhat_et_libguestfs_GuestFS.h\"
 #include \"guestfs.h\"
 
+/* This is the opaque data passed between _set_event_callback and
+ * the C wrapper which calls the Java event callback.
+ *
+ * NB: The 'callback' in the following struct is registered as a global
+ * reference.  It must be freed along with the struct.
+ */
+struct callback_data {
+  JavaVM *jvm;           // JVM
+  jobject callback;      // object supporting EventCallback interface
+  jmethodID method;      // callback.event method
+};
+
+static struct callback_data **get_all_event_callbacks (guestfs_h *g, size_t *len_rtn);
+
 /* Note that this function returns.  The exception is not thrown
  * until after the wrapper function returns.
  */
@@ -469,7 +596,180 @@ Java_com_redhat_et_libguestfs_GuestFS__1close
   (JNIEnv *env, jobject obj, jlong jg)
 {
   guestfs_h *g = (guestfs_h *) (long) jg;
+  size_t len, i;
+  struct callback_data **data;
+
+  /* There is a nasty, difficult to solve case here where the
+   * user deletes events in one of the callbacks that we are
+   * about to invoke, resulting in a double-free.  XXX
+   */
+  data = get_all_event_callbacks (g, &len);
+
   guestfs_close (g);
+
+  for (i = 0; i < len; ++i) {
+    (*env)->DeleteGlobalRef (env, data[i]->callback);
+    free (data[i]);
+  }
+  free (data);
+}
+
+/* See EventCallback interface. */
+#define METHOD_NAME \"event\"
+#define METHOD_SIGNATURE \"(JILjava/lang/String;[J)V\"
+
+static void
+guestfs_java_callback (guestfs_h *g,
+                       void *opaque,
+                       uint64_t event,
+                       int event_handle,
+                       int flags,
+                       const char *buf, size_t buf_len,
+                       const uint64_t *array, size_t array_len)
+{
+  struct callback_data *data = opaque;
+  JavaVM *jvm = data->jvm;
+  JNIEnv *env;
+  int r;
+  jstring jbuf;
+  jlongArray jarray;
+  size_t i;
+  jlong jl;
+
+  /* Get the Java environment.  See:
+   * http://stackoverflow.com/questions/12900695/how-to-obtain-jni-interface-pointer-jnienv-for-asynchronous-calls
+   */
+  r = (*jvm)->GetEnv (jvm, (void **) &env, JNI_VERSION_1_6);
+  if (r != JNI_OK) {
+    switch (r) {
+    case JNI_EDETACHED:
+      /* This can happen when the close event is generated during an atexit
+       * cleanup.  The JVM has probably been destroyed so I doubt it is
+       * safe to run Java code at this point.
+       */
+      fprintf (stderr, \"%%s: event %%\" PRIu64 \" (eh %%d) ignored because the thread is not attached to the JVM.  This can happen when libguestfs handles are cleaned up at program exit after the JVM has been destroyed.\\n\",
+               __func__, event, event_handle);
+      return;
+
+    default:
+      fprintf (stderr, \"%%s: jvm->GetEnv failed! (JNI_* error code = %%d)\\n\",
+               __func__, r);
+      return;
+    }
+  }
+
+  /* Convert the buffer and array to Java objects. */
+  jbuf = (*env)->NewStringUTF (env, buf); // XXX size
+
+  jarray = (*env)->NewLongArray (env, array_len);
+  for (i = 0; i < array_len; ++i) {
+    jl = array[i];
+    (*env)->SetLongArrayRegion (env, jarray, i, 1, &jl);
+  }
+
+  /* Call the event method.  If it throws an exception, all we can do is
+   * print it on stderr.
+   */
+  (*env)->ExceptionClear (env);
+  (*env)->CallVoidMethod (env, data->callback, data->method,
+                          (jlong) event, (jint) event_handle,
+                          jbuf, jarray);
+  if ((*env)->ExceptionOccurred (env)) {
+    (*env)->ExceptionDescribe (env);
+    (*env)->ExceptionClear (env);
+  }
+}
+
+JNIEXPORT jint JNICALL
+Java_com_redhat_et_libguestfs_GuestFS__1set_1event_1callback
+  (JNIEnv *env, jobject obj, jlong jg, jobject jcallback, jlong jevents)
+{
+  guestfs_h *g = (guestfs_h *) (long) jg;
+  int r;
+  struct callback_data *data;
+  jclass callback_class;
+  jmethodID method;
+  char key[64];
+
+  callback_class = (*env)->GetObjectClass (env, jcallback);
+  method = (*env)->GetMethodID (env, callback_class, METHOD_NAME, METHOD_SIGNATURE);
+  if (method == 0) {
+    throw_exception (env, \"GuestFS.set_event_callback: callback class does not implement the EventCallback interface\");
+    return -1;
+  }
+
+  data = guestfs___safe_malloc (g, sizeof *data);
+  (*env)->GetJavaVM (env, &data->jvm);
+  data->method = method;
+
+  r = guestfs_set_event_callback (g, guestfs_java_callback,
+                                  (uint64_t) jevents, 0, data);
+  if (r == -1) {
+    free (data);
+    throw_exception (env, guestfs_last_error (g));
+    return -1;
+  }
+
+  /* Register jcallback as a global reference so the GC won't free it. */
+  data->callback = (*env)->NewGlobalRef (env, jcallback);
+
+  /* Store 'data' in the handle, so we can free it at some point. */
+  snprintf (key, sizeof key, \"_java_event_%%d\", r);
+  guestfs_set_private (g, key, data);
+
+  return (jint) r;
+}
+
+JNIEXPORT void JNICALL
+Java_com_redhat_et_libguestfs_GuestFS__1delete_1event_1callback
+  (JNIEnv *env, jobject obj, jlong jg, jint eh)
+{
+  guestfs_h *g = (guestfs_h *) (long) jg;
+  char key[64];
+  struct callback_data *data;
+
+  snprintf (key, sizeof key, \"_java_event_%%d\", eh);
+
+  data = guestfs_get_private (g, key);
+  if (data) {
+    (*env)->DeleteGlobalRef (env, data->callback);
+    free (data);
+    guestfs_set_private (g, key, NULL);
+    guestfs_delete_event_callback (g, eh);
+  }
+}
+
+static struct callback_data **
+get_all_event_callbacks (guestfs_h *g, size_t *len_rtn)
+{
+  struct callback_data **r;
+  size_t i;
+  const char *key;
+  struct callback_data *data;
+
+  /* Count the length of the array that will be needed. */
+  *len_rtn = 0;
+  data = guestfs_first_private (g, &key);
+  while (data != NULL) {
+    if (strncmp (key, \"_java_event_\", strlen (\"_java_event_\")) == 0)
+      (*len_rtn)++;
+    data = guestfs_next_private (g, &key);
+  }
+
+  /* Copy them into the return array. */
+  r = guestfs___safe_malloc (g, sizeof (struct callback_data *) * (*len_rtn));
+
+  i = 0;
+  data = guestfs_first_private (g, &key);
+  while (data != NULL) {
+    if (strncmp (key, \"_java_event_\", strlen (\"_java_event_\")) == 0) {
+      r[i] = data;
+      i++;
+    }
+    data = guestfs_next_private (g, &key);
+  }
+
+  return r;
 }
 
 ";
diff --git a/generator/main.ml b/generator/main.ml
index 618052b..69ebe05 100644
--- a/generator/main.ml
+++ b/generator/main.ml
@@ -138,7 +138,8 @@ Run it from the top source directory using the command
       output_to filename (generate_java_struct jtyp cols)
   ) structs;
   delete_except_generated
-    ~skip:["java/com/redhat/et/libguestfs/LibGuestFSException.java"]
+    ~skip:["java/com/redhat/et/libguestfs/LibGuestFSException.java";
+           "java/com/redhat/et/libguestfs/EventCallback.java"]
     "java/com/redhat/et/libguestfs/*.java";
 
   output_to "java/Makefile.inc" generate_java_makefile_inc;
diff --git a/java/Makefile.am b/java/Makefile.am
index b655ae9..449f40b 100644
--- a/java/Makefile.am
+++ b/java/Makefile.am
@@ -1,5 +1,5 @@
 # libguestfs Java bindings
-# Copyright (C) 2009-2012 Red Hat Inc.
+# Copyright (C) 2009-2013 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
@@ -33,13 +33,15 @@ include $(srcdir)/Makefile.inc
 
 java_sources = \
 	$(java_built_sources) \
+	com/redhat/et/libguestfs/EventCallback.java \
 	com/redhat/et/libguestfs/LibGuestFSException.java
 
 java_tests = \
 	Bindtests.java \
 	t/GuestFS005Load.java \
 	t/GuestFS010Basic.java \
-	t/GuestFS080OptArgs.java
+	t/GuestFS080OptArgs.java \
+	t/GuestFS400Events.java
 
 EXTRA_DIST = \
 	$(java_sources) \
diff --git a/java/com/redhat/et/libguestfs/EventCallback.java b/java/com/redhat/et/libguestfs/EventCallback.java
new file mode 100644
index 0000000..a5e84e1
--- /dev/null
+++ b/java/com/redhat/et/libguestfs/EventCallback.java
@@ -0,0 +1,33 @@
+/* libguestfs Java bindings
+ * Copyright (C) 2009-2013 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package com.redhat.et.libguestfs;
+
+/**
+ * Event callback interface.
+ * <p>
+ * This is the interface for event callbacks.  See the
+ * {@link GuestFS#set_event_callback set_event_callback method}
+ * for details.
+ *
+ * @author rjones
+ * @see GuestFS
+ */
+public interface EventCallback {
+  public void event (long event, int eh, String buffer, long[] array);
+}
diff --git a/java/examples/guestfs-java.pod b/java/examples/guestfs-java.pod
index 6e032b4..c777e05 100644
--- a/java/examples/guestfs-java.pod
+++ b/java/examples/guestfs-java.pod
@@ -40,6 +40,36 @@ is the error message (a C<String>).
 
 Calling any method on a closed handle raises the same exception.
 
+=head2 EVENTS
+
+The L<libguestfs event API|guestfs(3)/EVENTS> is fully supported from
+Java.  Create a class which implements the C<EventCallback> interface,
+create an instance of this class, and then call the C<GuestFS#set_event_callback>
+method to register this instance.  The C<event> method of the class is
+called when libguestfs generates an event.
+
+For example, this will print all trace events:
+
+ GuestFS g = new GuestFS ();
+ g.set_trace (true);
+ g.set_event_callback (
+   new EventCallback () {
+     public void event (long event, int eh,
+                        String buffer, long[] array) {
+       System.out.println (GuestFS.eventToString (event) +
+                           ": " + buffer);
+     }
+   },
+   GuestFS.EVENT_TRACE);
+ g.add_drive_ro ("disk.img");
+ // etc.
+
+The output looks similar to this:
+
+ EVENT_TRACE: add_drive_ro "disk.img"
+ EVENT_TRACE: add_drive_ro = 0
+ // etc.
+
 =head1 EXAMPLE 1: CREATE A DISK IMAGE
 
 @EXAMPLE1@
diff --git a/java/t/GuestFS400Events.java b/java/t/GuestFS400Events.java
new file mode 100644
index 0000000..98236d8
--- /dev/null
+++ b/java/t/GuestFS400Events.java
@@ -0,0 +1,95 @@
+/* libguestfs Java bindings
+ * Copyright (C) 2013 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+import java.io.*;
+import java.util.HashMap;
+import com.redhat.et.libguestfs.*;
+
+public class GuestFS400Events
+{
+    static class PrintEvent implements EventCallback
+    {
+        public void event (long event, int eh, String buffer, long[] array)
+        {
+            String msg = "event=" + GuestFS.eventToString (event) + " " +
+                "eh=" + eh + " ";
+
+            if (buffer != null)
+                msg += "buffer='" + buffer + "' ";
+
+            if (array.length > 0) {
+                msg += "array[" + array.length + "]={";
+                for (int i = 0; i < array.length; ++i)
+                    msg += " " + array[i];
+                msg += " }";
+            }
+
+            System.out.println ("java event logged: " + msg);
+        }
+    }
+
+    static class CloseInvoked extends PrintEvent
+    {
+        private int close_invoked = 0;
+
+        public void event (long event, int eh, String buffer, long[] array)
+        {
+            super.event (event, eh, buffer, array);
+            close_invoked++;
+        }
+
+        public int getCloseInvoked ()
+        {
+            return close_invoked;
+        }
+    }
+
+    public static void main (String[] argv)
+    {
+        try {
+            GuestFS g = new GuestFS ();
+
+            // Grab all messages into an event handler that just
+            // prints each event.
+            g.set_event_callback (new PrintEvent (),
+                                  GuestFS.EVENT_APPLIANCE|GuestFS.EVENT_LIBRARY|
+                                  GuestFS.EVENT_TRACE);
+
+            // Check that the close event is invoked.
+            CloseInvoked ci = new CloseInvoked ();
+            g.set_event_callback (ci, GuestFS.EVENT_CLOSE);
+
+            // Now make sure we see some messages.
+            g.set_trace (true);
+            g.set_verbose (true);
+
+            // Do some stuff.
+            g.add_drive_ro ("/dev/null");
+            g.set_autosync (true);
+
+            // Close the handle.
+            assert ci.getCloseInvoked() == 0;
+            g.close ();
+            assert ci.getCloseInvoked() == 1;
+        }
+        catch (Exception exn) {
+            System.err.println (exn);
+            System.exit (1);
+        }
+    }
+}
-- 
1.7.11.7

-------------- next part --------------
From 9586488a34d5d99f7d98b597d4d5aeda61943c1d Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones at redhat.com>
Date: Thu, 10 Jan 2013 06:25:30 +0900
Subject: [PATCH 7/7] podwrapper: Refresh podwrapper man page.

This also adds a rule so you can do:

 make podwrapper.1

if you want to read the documentation as a man page.
---
 .gitignore       |  1 +
 Makefile.am      | 11 ++++++++++
 podwrapper.pl.in | 63 ++++++++++++++++++++++++++++++++++++--------------------
 3 files changed, 53 insertions(+), 22 deletions(-)

diff --git a/.gitignore b/.gitignore
index 7f8c892..394e20a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -320,6 +320,7 @@ Makefile.in
 /po-docs/po4a.conf
 /po-docs/*/*.pod
 /po-docs/*/stamp-update-po
+/podwrapper.1
 /podwrapper.pl
 /po/*.gmo
 /python/bindtests.py
diff --git a/Makefile.am b/Makefile.am
index d8b6590..42052c0 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -288,11 +288,22 @@ stamp-guestfs-release-notes.pod: guestfs-release-notes.pod
 	  $<
 	touch $@
 
+# NB. podwrapper is an internal tool, so the man page mustn't be installed.
+noinst_MANS = podwrapper.1
+podwrapper.1: podwrapper.pl
+	$(PODWRAPPER) \
+	  --section 1 \
+	  --man $@-t \
+	  --license GPLv2+ \
+	  $<
+	mv $@-t $@
+
 # Make clean.
 
 CLEANFILES = \
 	html/*.html \
 	pod2htm?.tmp \
+	podwrapper.1 \
 	qemu-wrapper.sh \
 	stamp-guestfs-release-notes.pod
 
diff --git a/podwrapper.pl.in b/podwrapper.pl.in
index 46c71f2..3998782 100755
--- a/podwrapper.pl.in
+++ b/podwrapper.pl.in
@@ -32,27 +32,37 @@ use File::Basename;
 
 =head1 NAME
 
-podwrapper.pl - Generate various output formats from POD input files
+podwrapper.pl - Generate libguestfs documentation from POD input files
 
 =head1 SYNOPSIS
 
+ man_MANS = virt-foo.1
+ 
  virt-foo.1 $(top_builddir)/html/virt-foo.1.html: stamp-virt-foo.pod
+ 
  stamp-virt-foo.pod: virt-foo.pod
-   $(PODWRAPPER) --man virt-foo.1 --html virt-foo.1.html $<
-   touch $@
+         $(PODWRAPPER) \
+           --section 1 \
+           --man virt-foo.1 \
+           --html $(top_builddir)/html/virt-foo.1.html \
+           --license GPLv2+ \
+           $<
+         touch $@
+ 
+ CLEANFILES += stamp-virt-foo.pod
 
 =head1 DESCRIPTION
 
-podwrapper is a Perl script that generates various output formats
+podwrapper.pl is a Perl script that generates various output formats
 from POD input files that libguestfs uses for most documentation.
 
-You should specify an input file, and one or more output formats.
-For example:
+You must specify one input file, and one or more output formats.  The
+output options are I<--man>, I<--html> and I<--text> (see below).
 
- podwrapper.pl virt-foo.pod --man virt-foo.1
+In C<Makefile.am> files, use a variation of the boilerplate shown in
+the L</SYNOPSIS> section above.
 
-will turn C<virt-foo.pod> into a man page C<virt-foo.1>.  The output
-options are I<--man>, I<--html> and I<--text> (see below).
+For information about the POD format, see L<perlpod(1)>.
 
 =head1 OPTIONS
 
@@ -70,7 +80,7 @@ Display brief help.
 
 my $html;
 
-=item B<--html=output.html>
+=item B<--html output.html>
 
 Write a web page to C<output.html>.  If this option is not
 given, then no web page output is produced.
@@ -79,7 +89,7 @@ given, then no web page output is produced.
 
 my @inserts;
 
-=item B<--insert=filename:__PATTERN__>
+=item B<--insert filename:__PATTERN__>
 
 In the input file, replace the literal text C<__PATTERN__> with the
 replacement file C<filename>.  You can give this option multiple
@@ -95,7 +105,11 @@ patterns, in fact you can use any string as the pattern.
 
 my @licenses;
 
-=item B<--license=GPLv2+|LGPLv2+|examples>
+=item B<--license GPLv2+>
+
+=item B<--license LGPLv2+>
+
+=item B<--license examples>
 
 Add the given license to the end of the man page.  This parameter
 is required.  The parameter may be given multiple times (eg. for
@@ -105,16 +119,16 @@ mixed content).
 
 my $man;
 
-=item B<--man=output.n>
+=item B<--man output.n>
 
-Write a man page to C<output.n>.  If this option is not
-given, then no man page output is produced.
+Write a man page to C<output.n> (C<n> is the manual section number).
+If this option is not given, then no man page output is produced.
 
 =cut
 
 my $name;
 
-=item B<--name=name>
+=item B<--name name>
 
 Set the name of the man page.  If not set, defaults to the basename
 of the input file.
@@ -123,7 +137,7 @@ of the input file.
 
 my $section;
 
-=item B<--section=N>
+=item B<--section N>
 
 Set the section of the man page (a number such as C<1> for
 command line utilities or C<3> for C API documentation).  If
@@ -143,7 +157,7 @@ subdirectory.
 
 my $text;
 
-=item B<--text=output.txt>
+=item B<--text output.txt>
 
 Write a text file to C<output.txt>.  If this option is not
 given, then no text output is produced.
@@ -152,7 +166,7 @@ given, then no text output is produced.
 
 my @verbatims;
 
-=item B<--verbatim=filename:@PATTERN@>
+=item B<--verbatim filename:__PATTERN__>
 
 In the input file, replace the literal text C<__PATTERN__> with the
 replacement file C<filename>.  You can give this option multiple
@@ -529,11 +543,16 @@ sub read_verbatim_file
     $r;
 }
 
+=head1 SEE ALSO
+
+L<perlpod(1)>,
+L<Pod::Simple(3pm)>,
+libguestfs.git/README.
+
 =head1 AUTHOR
 
 Richard W.M. Jones.
 
-=head1 SEE ALSO
+=head1 COPYRIGHT
 
-libguestfs.git/README,
-L<Pod::Simple>
+Copyright (C) 2012-2013 Red Hat Inc.
-- 
1.7.11.7



More information about the Libguestfs mailing list