This commit embeds the ocaml-augeas library (upstream here:
http://git.annexia.org/?p=ocaml-augeas.git;a=summary). It's identical
to the upstream version and should remain so.
We can work towards using system ocaml-augeas, when it's more widely
available.
---
daemon/Makefile.am | 3 +
daemon/augeas-c.c | 288 +++++++++++++++++++++++++++++++++++++++++++++++++++
daemon/augeas.README | 8 ++
daemon/augeas.ml | 59 +++++++++++
daemon/augeas.mli | 95 +++++++++++++++++
daemon/daemon-c.c | 2 +
docs/C_SOURCE_FILES | 1 +
7 files changed, 456 insertions(+)
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 1f7cb2277..5008045c3 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -61,6 +61,7 @@ guestfsd_SOURCES = \
actions.h \
available.c \
augeas.c \
+ augeas-c.c \
base64.c \
blkdiscard.c \
blkid.c \
@@ -240,6 +241,7 @@ guestfsd_CFLAGS = \
# library and then linked to the daemon. See
#
https://caml.inria.fr/pub/docs/manual-ocaml/intfc.html
SOURCES_MLI = \
+ augeas.mli \
blkid.mli \
btrfs.mli \
chroot.mli \
@@ -261,6 +263,7 @@ SOURCES_MLI = \
utils.mli
SOURCES_ML = \
+ augeas.ml \
types.ml \
utils.ml \
structs.ml \
diff --git a/daemon/augeas-c.c b/daemon/augeas-c.c
new file mode 100644
index 000000000..c06bf92da
--- /dev/null
+++ b/daemon/augeas-c.c
@@ -0,0 +1,288 @@
+/* Augeas OCaml bindings
+ * Copyright (C) 2008-2012 Red Hat Inc., Richard W.M. Jones
+ *
+ * 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
+ *
+ * $Id: augeas_c.c,v 1.1 2008/05/06 10:48:20 rjones Exp $
+ */
+
+#include "config.h"
+
+#include <augeas.h>
+
+#include <caml/alloc.h>
+#include <caml/memory.h>
+#include <caml/mlvalues.h>
+#include <caml/fail.h>
+#include <caml/callback.h>
+#include <caml/custom.h>
+
+typedef augeas *augeas_t;
+
+/* Raise an Augeas.Error exception. */
+static void
+raise_error (const char *msg)
+{
+ caml_raise_with_string (*caml_named_value ("Augeas.Error"), msg);
+}
+
+/* Map OCaml flags to C flags. */
+static int flag_map[] = {
+ /* AugSaveBackup */ AUG_SAVE_BACKUP,
+ /* AugSaveNewFile */ AUG_SAVE_NEWFILE,
+ /* AugTypeCheck */ AUG_TYPE_CHECK,
+ /* AugNoStdinc */ AUG_NO_STDINC,
+ /* AugSaveNoop */ AUG_SAVE_NOOP,
+ /* AugNoLoad */ AUG_NO_LOAD,
+};
+
+/* Wrap and unwrap augeas_t handles, with a finalizer. */
+#define Augeas_t_val(rv) (*(augeas_t *)Data_custom_val(rv))
+
+static void
+augeas_t_finalize (value tv)
+{
+ augeas_t t = Augeas_t_val (tv);
+ if (t) aug_close (t);
+}
+
+static struct custom_operations custom_operations = {
+ (char *) "augeas_t_custom_operations",
+ augeas_t_finalize,
+ custom_compare_default,
+ custom_hash_default,
+ custom_serialize_default,
+ custom_deserialize_default
+};
+
+static value Val_augeas_t (augeas_t t)
+{
+ CAMLparam0 ();
+ CAMLlocal1 (rv);
+ /* We could choose these so that the GC can make better decisions.
+ * See 18.9.2 of the OCaml manual.
+ */
+ const int used = 0;
+ const int max = 1;
+
+ rv = caml_alloc_custom (&custom_operations,
+ sizeof (augeas_t), used, max);
+ Augeas_t_val(rv) = t;
+
+ CAMLreturn (rv);
+}
+
+#pragma GCC diagnostic ignored "-Wmissing-prototypes"
+
+/* val create : string -> string option -> flag list -> t */
+CAMLprim value
+ocaml_augeas_create (value rootv, value loadpathv, value flagsv)
+{
+ CAMLparam1 (rootv);
+ char *root = String_val (rootv);
+ char *loadpath;
+ int flags = 0, i;
+ augeas_t t;
+
+ /* Optional loadpath. */
+ loadpath =
+ loadpathv == Val_int (0)
+ ? NULL
+ : String_val (Field (loadpathv, 0));
+
+ /* Convert list of flags to C. */
+ for (; flagsv != Val_int (0); flagsv = Field (flagsv, 1)) {
+ i = Int_val (Field (flagsv, 0));
+ flags |= flag_map[i];
+ }
+
+ t = aug_init (root, loadpath, flags);
+
+ if (t == NULL)
+ raise_error ("Augeas.create");
+
+ CAMLreturn (Val_augeas_t (t));
+}
+
+/* val close : t -> unit */
+CAMLprim value
+ocaml_augeas_close (value tv)
+{
+ CAMLparam1 (tv);
+ augeas_t t = Augeas_t_val (tv);
+
+ if (t) {
+ aug_close (t);
+ Augeas_t_val(tv) = NULL; /* So the finalizer doesn't double-free. */
+ }
+
+ CAMLreturn (Val_unit);
+}
+
+/* val get : t -> path -> value option */
+CAMLprim value
+ocaml_augeas_get (value tv, value pathv)
+{
+ CAMLparam2 (tv, pathv);
+ CAMLlocal2 (optv, v);
+ augeas_t t = Augeas_t_val (tv);
+ char *path = String_val (pathv);
+ const char *val;
+ int r;
+
+ r = aug_get (t, path, &val);
+ if (r == 1) { /* Return Some val */
+ v = caml_copy_string (val);
+ optv = caml_alloc (1, 0);
+ Field (optv, 0) = v;
+ } else if (r == 0) /* Return None */
+ optv = Val_int (0);
+ else if (r == -1) /* Error or multiple matches */
+ raise_error ("Augeas.get");
+ else
+ failwith ("Augeas.get: bad return value");
+
+ CAMLreturn (optv);
+}
+
+/* val exists : t -> path -> bool */
+CAMLprim value
+ocaml_augeas_exists (value tv, value pathv)
+{
+ CAMLparam2 (tv, pathv);
+ CAMLlocal1 (v);
+ augeas_t t = Augeas_t_val (tv);
+ char *path = String_val (pathv);
+ int r;
+
+ r = aug_get (t, path, NULL);
+ if (r == 1) /* Return true. */
+ v = Val_int (1);
+ else if (r == 0) /* Return false */
+ v = Val_int (0);
+ else if (r == -1) /* Error or multiple matches */
+ raise_error ("Augeas.exists");
+ else
+ failwith ("Augeas.exists: bad return value");
+
+ CAMLreturn (v);
+}
+
+/* val insert : t -> ?before:bool -> path -> string -> unit */
+CAMLprim value
+ocaml_augeas_insert (value tv, value beforev, value pathv, value labelv)
+{
+ CAMLparam4 (tv, beforev, pathv, labelv);
+ augeas_t t = Augeas_t_val (tv);
+ char *path = String_val (pathv);
+ char *label = String_val (labelv);
+ int before;
+
+ before = beforev == Val_int (0) ? 0 : Int_val (Field (beforev, 0));
+
+ if (aug_insert (t, path, label, before) == -1)
+ raise_error ("Augeas.insert");
+
+ CAMLreturn (Val_unit);
+}
+
+/* val rm : t -> path -> int */
+CAMLprim value
+ocaml_augeas_rm (value tv, value pathv)
+{
+ CAMLparam2 (tv, pathv);
+ augeas_t t = Augeas_t_val (tv);
+ char *path = String_val (pathv);
+ int r;
+
+ r = aug_rm (t, path);
+ if (r == -1)
+ raise_error ("Augeas.rm");
+
+ CAMLreturn (Val_int (r));
+}
+
+/* val matches : t -> path -> path list */
+CAMLprim value
+ocaml_augeas_match (value tv, value pathv)
+{
+ CAMLparam2 (tv, pathv);
+ CAMLlocal3 (rv, v, cons);
+ augeas_t t = Augeas_t_val (tv);
+ char *path = String_val (pathv);
+ char **matches;
+ int r, i;
+
+ r = aug_match (t, path, &matches);
+ if (r == -1)
+ raise_error ("Augeas.matches");
+
+ /* Copy the paths to a list. */
+ rv = Val_int (0);
+ for (i = 0; i < r; ++i) {
+ v = caml_copy_string (matches[i]);
+ free (matches[i]);
+ cons = caml_alloc (2, 0);
+ Field (cons, 1) = rv;
+ Field (cons, 0) = v;
+ rv = cons;
+ }
+
+ free (matches);
+
+ CAMLreturn (rv);
+}
+
+/* val count_matches : t -> path -> int */
+CAMLprim value
+ocaml_augeas_count_matches (value tv, value pathv)
+{
+ CAMLparam2 (tv, pathv);
+ augeas_t t = Augeas_t_val (tv);
+ char *path = String_val (pathv);
+ int r;
+
+ r = aug_match (t, path, NULL);
+ if (r == -1)
+ raise_error ("Augeas.count_matches");
+
+ CAMLreturn (Val_int (r));
+}
+
+/* val save : t -> unit */
+CAMLprim value
+ocaml_augeas_save (value tv)
+{
+ CAMLparam1 (tv);
+ augeas_t t = Augeas_t_val (tv);
+
+ if (aug_save (t) == -1)
+ raise_error ("Augeas.save");
+
+ CAMLreturn (Val_unit);
+}
+
+/* val load : t -> unit */
+CAMLprim value
+ocaml_augeas_load (value tv)
+{
+ CAMLparam1 (tv);
+ augeas_t t = Augeas_t_val (tv);
+
+ if (aug_load (t) == -1)
+ raise_error ("Augeas.load");
+
+ CAMLreturn (Val_unit);
+}
diff --git a/daemon/augeas.README b/daemon/augeas.README
new file mode 100644
index 000000000..938dfd255
--- /dev/null
+++ b/daemon/augeas.README
@@ -0,0 +1,8 @@
+The files augeas-c.c, augeas.ml and augeas.mli come from the
+ocaml-augeas library:
+
+
http://git.annexia.org/?p=ocaml-augeas.git
+
+which is released under a compatible license. We try to keep them
+identical, so if you make changes to these files then you must also
+submit the changes to ocaml-augeas, and vice versa.
\ No newline at end of file
diff --git a/daemon/augeas.ml b/daemon/augeas.ml
new file mode 100644
index 000000000..f556df0f1
--- /dev/null
+++ b/daemon/augeas.ml
@@ -0,0 +1,59 @@
+(* Augeas OCaml bindings
+ * Copyright (C) 2008 Red Hat Inc., Richard W.M. Jones
+ *
+ * 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
+ *
+ * $Id: augeas.ml,v 1.2 2008/05/06 10:48:20 rjones Exp $
+ *)
+
+type t
+
+exception Error of string
+
+type flag =
+ | AugSaveBackup
+ | AugSaveNewFile
+ | AugTypeCheck
+ | AugNoStdinc
+ | AugSaveNoop
+ | AugNoLoad
+
+type path = string
+
+type value = string
+
+external create : string -> string option -> flag list -> t
+ = "ocaml_augeas_create"
+external close : t -> unit
+ = "ocaml_augeas_close"
+external get : t -> path -> value option
+ = "ocaml_augeas_get"
+external exists : t -> path -> bool
+ = "ocaml_augeas_exists"
+external insert : t -> ?before:bool -> path -> string -> unit
+ = "ocaml_augeas_insert"
+external rm : t -> path -> int
+ = "ocaml_augeas_rm"
+external matches : t -> path -> path list
+ = "ocaml_augeas_match"
+external count_matches : t -> path -> int
+ = "ocaml_augeas_count_matches"
+external save : t -> unit
+ = "ocaml_augeas_save"
+external load : t -> unit
+ = "ocaml_augeas_load"
+
+let () =
+ Callback.register_exception "Augeas.Error" (Error "")
diff --git a/daemon/augeas.mli b/daemon/augeas.mli
new file mode 100644
index 000000000..64e824014
--- /dev/null
+++ b/daemon/augeas.mli
@@ -0,0 +1,95 @@
+(** Augeas OCaml bindings *)
+(* Copyright (C) 2008 Red Hat Inc., Richard W.M. Jones
+ *
+ * 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
+ *
+ * $Id: augeas.mli,v 1.2 2008/05/06 10:48:20 rjones Exp $
+ *)
+
+type t
+ (** Augeas library handle. *)
+
+exception Error of string
+ (** This exception is thrown when the underlying Augeas library
+ returns an error. *)
+
+type flag =
+ | AugSaveBackup (** Rename original with .augsave *)
+ | AugSaveNewFile (** Save changes to .augnew *)
+ | AugTypeCheck (** Type-check lenses *)
+ | AugNoStdinc
+ | AugSaveNoop
+ | AugNoLoad
+ (** Flags passed to the {!create} function. *)
+
+type path = string
+ (** A path expression.
+
+ Note in future we may replace this with a type-safe path constructor. *)
+
+type value = string
+ (** A value. *)
+
+val create : string -> string option -> flag list -> t
+ (** [create root loadpath flags] creates an Augeas handle.
+
+ [root] is a file system path describing the location
+ of the configuration files.
+
+ [loadpath] is an optional colon-separated list of directories
+ which are searched for schema definitions.
+
+ [flags] is a list of flags. *)
+
+val close : t -> unit
+ (** [close handle] closes the handle.
+
+ You don't need to close handles explicitly with this function:
+ they will be finalized eventually by the garbage collector.
+ However calling this function frees up any resources used by the
+ underlying Augeas library immediately.
+
+ Do not use the handle after closing it. *)
+
+val get : t -> path -> value option
+ (** [get t path] returns the value at [path], or [None] if there
+ is no value. *)
+
+val exists : t -> path -> bool
+ (** [exists t path] returns true iff there is a value at [path]. *)
+
+val insert : t -> ?before:bool -> path -> string -> unit
+ (** [insert t ?before path label] inserts [label] as a sibling
+ of [path]. By default it is inserted after [path], unless
+ [~before:true] is specified. *)
+
+val rm : t -> path -> int
+ (** [rm t path] removes all nodes matching [path].
+
+ Returns the number of nodes removed (which may be 0). *)
+
+val matches : t -> path -> path list
+ (** [matches t path] returns a list of path expressions
+ of all nodes matching [path]. *)
+
+val count_matches : t -> path -> int
+ (** [count_matches t path] counts the number of nodes matching
+ [path] but does not return them (see {!matches}). *)
+
+val save : t -> unit
+ (** [save t] saves all pending changes to disk. *)
+
+val load : t -> unit
+ (** [load t] loads files into the tree. *)
diff --git a/daemon/daemon-c.c b/daemon/daemon-c.c
index cbb3d8918..061d7f00b 100644
--- a/daemon/daemon-c.c
+++ b/daemon/daemon-c.c
@@ -65,6 +65,8 @@ guestfs_int_daemon_exn_to_reply_with_error (const char *func, value
exn)
reply_with_error ("%s", String_val (Field (exn, 1)));
else if (STREQ (exn_name, "Invalid_argument"))
reply_with_error ("invalid argument: %s", String_val (Field (exn, 1)));
+ else if (STREQ (exn_name, "Augeas.Error"))
+ reply_with_error ("augeas error: %s", String_val (Field (exn, 1)));
else
reply_with_error ("internal error: %s: unhandled exception thrown: %s",
func, exn_name);
diff --git a/docs/C_SOURCE_FILES b/docs/C_SOURCE_FILES
index d7f190b3f..08a965892 100644
--- a/docs/C_SOURCE_FILES
+++ b/docs/C_SOURCE_FILES
@@ -65,6 +65,7 @@ customize/perl_edit-c.c
daemon/9p.c
daemon/acl.c
daemon/actions.h
+daemon/augeas-c.c
daemon/augeas.c
daemon/available.c
daemon/base64.c
--
2.13.2