Added Augeas support.
authorRichard Jones <rjones@redhat.com>
Thu, 9 Apr 2009 12:19:38 +0000 (13:19 +0100)
committerRichard Jones <rjones@redhat.com>
Thu, 9 Apr 2009 12:19:38 +0000 (13:19 +0100)
26 files changed:
README
configure.ac
daemon/Makefile.am
daemon/actions.h
daemon/augeas.c [new file with mode: 0644]
daemon/configure.ac
daemon/stubs.c
fish/cmds.c
guestfish-actions.pod
guestfs-actions.pod
libguestfs.spec.in
make-initramfs.sh.in
ocaml/guestfs.ml
ocaml/guestfs.mli
ocaml/guestfs_c_actions.c
perl/Guestfs.xs
perl/lib/Sys/Guestfs.pm
src/generator.ml
src/guestfs-actions.c
src/guestfs-actions.h
src/guestfs-structs.h
src/guestfs.c
src/guestfs.h
src/guestfs_protocol.c
src/guestfs_protocol.h
src/guestfs_protocol.x

diff --git a/README b/README
index f90bf46..ecb5362 100644 (file)
--- a/README
+++ b/README
@@ -35,6 +35,8 @@ Requirements
 
 - XDR, rpcgen
 
+- Augeas (http://augeas.net/)
+
 - perldoc (pod2man, pod2text) to generate the manual pages and
 other documentation.
 
index 0e1df67..7c533eb 100644 (file)
@@ -15,7 +15,7 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-AC_INIT([libguestfs],[0.6])
+AC_INIT([libguestfs],[0.7])
 AM_INIT_AUTOMAKE
 
 AC_CONFIG_MACRO_DIR([m4])
@@ -90,6 +90,18 @@ AC_DEFINE_UNQUOTED([REPO],["$REPO"],[Name of Fedora repository.])
 
 AC_DEFINE_UNQUOTED([host_cpu],["$host_cpu"],[Host architecture.])
 
+dnl --with-updates to specify a Fedora updates repository.
+AC_ARG_WITH([updates],
+       [AS_HELP_STRING([--with-updates],
+         [set name of Fedora updates repository @<:@default=updates-released-f10@:>@])],
+       [],
+       [with_updates=updates-released-f10])
+UPDATES="$with_updates"
+AC_SUBST(UPDATES)
+AC_DEFINE_UNQUOTED([UPDATES],["$UPDATES"],[Name of Fedora updates repository.])
+
+AC_DEFINE_UNQUOTED([host_cpu],["$host_cpu"],[Host architecture.])
+
 dnl --with-mirror to specify a local Fedora mirror.
 AC_ARG_WITH([mirror],
        [AS_HELP_STRING([--with-mirror],
index 4d56034..bdeeacf 100644 (file)
@@ -20,6 +20,7 @@ ACLOCAL_AMFLAGS = -I m4
 noinst_PROGRAMS = guestfsd
 guestfsd_SOURCES = \
        actions.h \
+       augeas.c \
        daemon.h \
        devsparts.c \
        file.c \
index 01fe68d..6a41c7d 100644 (file)
 #include "../src/guestfs_protocol.h"
 
 extern int do_mount (const char *device, const char *mountpoint);
-extern int do_sync ();
+extern int do_sync (void);
 extern int do_touch (const char *path);
 extern char *do_cat (const char *path);
 extern char *do_ll (const char *directory);
 extern char **do_ls (const char *directory);
-extern char **do_list_devices ();
-extern char **do_list_partitions ();
-extern char **do_pvs ();
-extern char **do_vgs ();
-extern char **do_lvs ();
-extern guestfs_lvm_int_pv_list *do_pvs_full ();
-extern guestfs_lvm_int_vg_list *do_vgs_full ();
-extern guestfs_lvm_int_lv_list *do_lvs_full ();
+extern char **do_list_devices (void);
+extern char **do_list_partitions (void);
+extern char **do_pvs (void);
+extern char **do_vgs (void);
+extern char **do_lvs (void);
+extern guestfs_lvm_int_pv_list *do_pvs_full (void);
+extern guestfs_lvm_int_vg_list *do_vgs_full (void);
+extern guestfs_lvm_int_lv_list *do_lvs_full (void);
 extern char **do_read_lines (const char *path);
+extern int do_aug_init (const char *root, int flags);
+extern int do_aug_close (void);
+extern int do_aug_defvar (const char *name, const char *expr);
+extern guestfs_aug_defnode_ret *do_aug_defnode (const char *name, const char *expr, const char *val);
+extern char *do_aug_get (const char *path);
+extern int do_aug_set (const char *path, const char *val);
+extern int do_aug_insert (const char *path, const char *label, int before);
+extern int do_aug_rm (const char *path);
+extern int do_aug_mv (const char *src, const char *dest);
+extern char **do_aug_match (const char *path);
+extern int do_aug_save (void);
+extern int do_aug_load (void);
diff --git a/daemon/augeas.c b/daemon/augeas.c
new file mode 100644 (file)
index 0000000..2b27387
--- /dev/null
@@ -0,0 +1,278 @@
+/* libguestfs - the guestfsd daemon
+ * Copyright (C) 2009 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <augeas.h>
+
+#include "daemon.h"
+#include "actions.h"
+
+/* The Augeas handle.  We maintain a single handle per daemon, which
+ * is all that is necessary and reduces the complexity of the API
+ * considerably.
+ */
+static augeas *aug = NULL;
+
+#define NEED_AUG(errcode)                                              \
+  do {                                                                 \
+    if (!aug) {                                                                \
+      reply_with_error ("%s: you must call 'aug-init' first to initialize Augeas", __func__); \
+      return (errcode);                                                        \
+    }                                                                  \
+  }                                                                    \
+  while (0)
+
+/* We need to rewrite the root path so it is based at /sysroot. */
+int
+do_aug_init (const char *root, int flags)
+{
+  char *buf;
+  int len;
+
+  NEED_ROOT (-1);
+  ABS_PATH (root, -1);
+
+  if (aug) {
+    aug_close (aug);
+    aug = NULL;
+  }
+
+  len = strlen (root) + 8;
+  buf = malloc (len);
+  if (!buf) {
+    reply_with_perror ("malloc");
+    return -1;
+  }
+  snprintf (buf, len, "/sysroot%s", root);
+
+  aug = aug_init (buf, NULL, flags);
+  free (buf);
+
+  if (!aug) {
+    reply_with_error ("Augeas initialization failed");
+    return -1;
+  }
+
+  return 0;
+}
+
+int
+do_aug_close (void)
+{
+  NEED_AUG(-1);
+
+  aug_close (aug);
+  aug = NULL;
+
+  return 0;
+}
+
+int
+do_aug_defvar (const char *name, const char *expr)
+{
+  int r;
+
+  NEED_AUG (-1);
+
+  r = aug_defvar (aug, name, expr);
+  if (r == -1) {
+    reply_with_error ("Augeas defvar failed");
+    return -1;
+  }
+  return r;
+}
+
+guestfs_aug_defnode_ret *
+do_aug_defnode (const char *name, const char *expr, const char *val)
+{
+  static guestfs_aug_defnode_ret r;
+  int created;
+
+  NEED_AUG (NULL);
+
+  r.nrnodes = aug_defnode (aug, name, expr, val, &created);
+  if (r.nrnodes == -1) {
+    reply_with_error ("Augeas defnode failed");
+    return NULL;
+  }
+  r.created = created;
+  return &r;
+}
+
+char *
+do_aug_get (const char *path)
+{
+  const char *value = NULL;
+  char *v;
+  int r;
+
+  NEED_AUG (NULL);
+
+  r = aug_get (aug, path, &value);
+  if (r == 0) {
+    reply_with_error ("no matching node");
+    return NULL;
+  }
+  if (r != 1) {
+    reply_with_error ("Augeas get failed");
+    return NULL;
+  }
+
+  /* value can still be NULL here, eg. try with path == "/augeas".
+   * I don't understand this case, and it seems to contradict the
+   * documentation.
+   */
+  if (value == NULL) {
+    reply_with_error ("Augeas returned NULL match");
+    return NULL;
+  }
+
+  /* The value is an internal Augeas string, so we must copy it. GC FTW. */
+  v = strdup (value);
+  if (v == NULL) {
+    reply_with_perror ("strdup");
+    return NULL;
+  }
+
+  return v;                    /* Caller frees. */
+}
+
+int
+do_aug_set (const char *path, const char *val)
+{
+  int r;
+
+  NEED_AUG (-1);
+
+  r = aug_set (aug, path, val);
+  if (r == -1) {
+    reply_with_error ("Augeas set failed");
+    return -1;
+  }
+
+  return 0;
+}
+
+int
+do_aug_insert (const char *path, const char *label, int before)
+{
+  int r;
+
+  NEED_AUG (-1);
+
+  r = aug_insert (aug, path, label, before);
+  if (r == -1) {
+    reply_with_error ("Augeas insert failed");
+    return -1;
+  }
+
+  return 0;
+}
+
+int
+do_aug_rm (const char *path)
+{
+  int r;
+
+  NEED_AUG (-1);
+
+  r = aug_rm (aug, path);
+  if (r == -1) {
+    reply_with_error ("Augeas rm failed");
+    return -1;
+  }
+
+  return r;
+}
+
+int
+do_aug_mv (const char *src, const char *dest)
+{
+  int r;
+
+  NEED_AUG (-1);
+
+  r = aug_mv (aug, src, dest);
+  if (r == -1) {
+    reply_with_error ("Augeas mv failed");
+    return -1;
+  }
+
+  return 0;
+}
+
+char **
+do_aug_match (const char *path)
+{
+  char **matches = NULL;
+  void *vp;
+  int r;
+
+  NEED_AUG (NULL);
+
+  r = aug_match (aug, path, &matches);
+  if (r == -1) {
+    reply_with_error ("Augeas match failed");
+    return NULL;
+  }
+
+  /* This returns an array of length r, which we must extend
+   * and add a terminating NULL.
+   */
+  vp = realloc (matches, sizeof (char *) * (r+1));
+  if (vp == NULL) {
+    reply_with_perror ("realloc");
+    free (vp);
+    return NULL;
+  }
+  matches = vp;
+  matches[r] = NULL;
+
+  return matches;              /* Caller frees. */
+}
+
+int
+do_aug_save (void)
+{
+  NEED_AUG (-1);
+
+  if (aug_save (aug) == -1) {
+    reply_with_error ("Augeas save failed");
+    return -1;
+  }
+
+  return 0;
+}
+
+int
+do_aug_load (void)
+{
+  NEED_AUG (-1);
+
+  if (aug_load (aug) == -1) {
+    reply_with_error ("Augeas load failed");
+    return -1;
+  }
+
+  return 0;
+}
index af0a78a..7ce03ab 100644 (file)
@@ -15,7 +15,7 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-AC_INIT([libguestfs-daemon],[0.2])
+AC_INIT([libguestfs-daemon],[0.7])
 AM_INIT_AUTOMAKE
 
 AC_CONFIG_MACRO_DIR([m4])
@@ -37,6 +37,11 @@ test "x$U" != "x" && AC_MSG_ERROR([Compiler not ANSI compliant])
 
 AC_PROG_CC_C_O
 
+dnl Check for Augeas.
+AC_CHECK_LIB([augeas],[aug_match],,[
+       AC_MSG_ERROR([Augeas library not found])
+       ])
+
 dnl Check for XDR library.
 AC_CHECK_LIB([portablexdr],[xdrmem_create],[],[
        AC_SEARCH_LIBS([xdrmem_create],[rpc xdr nsl])
index fab115c..38aea33 100644 (file)
@@ -43,7 +43,7 @@ static void mount_stub (XDR *xdr_in)
   memset (&args, 0, sizeof args);
 
   if (!xdr_guestfs_mount_args (xdr_in, &args)) {
-    reply_with_error ("mount: daemon failed to decode procedure arguments");
+    reply_with_error ("%s: daemon failed to decode procedure arguments", "mount");
     return;
   }
   device = args.device;
@@ -78,7 +78,7 @@ static void touch_stub (XDR *xdr_in)
   memset (&args, 0, sizeof args);
 
   if (!xdr_guestfs_touch_args (xdr_in, &args)) {
-    reply_with_error ("touch: daemon failed to decode procedure arguments");
+    reply_with_error ("%s: daemon failed to decode procedure arguments", "touch");
     return;
   }
   path = args.path;
@@ -100,7 +100,7 @@ static void cat_stub (XDR *xdr_in)
   memset (&args, 0, sizeof args);
 
   if (!xdr_guestfs_cat_args (xdr_in, &args)) {
-    reply_with_error ("cat: daemon failed to decode procedure arguments");
+    reply_with_error ("%s: daemon failed to decode procedure arguments", "cat");
     return;
   }
   path = args.path;
@@ -125,7 +125,7 @@ static void ll_stub (XDR *xdr_in)
   memset (&args, 0, sizeof args);
 
   if (!xdr_guestfs_ll_args (xdr_in, &args)) {
-    reply_with_error ("ll: daemon failed to decode procedure arguments");
+    reply_with_error ("%s: daemon failed to decode procedure arguments", "ll");
     return;
   }
   directory = args.directory;
@@ -150,7 +150,7 @@ static void ls_stub (XDR *xdr_in)
   memset (&args, 0, sizeof args);
 
   if (!xdr_guestfs_ls_args (xdr_in, &args)) {
-    reply_with_error ("ls: daemon failed to decode procedure arguments");
+    reply_with_error ("%s: daemon failed to decode procedure arguments", "ls");
     return;
   }
   directory = args.directory;
@@ -258,7 +258,7 @@ static void pvs_full_stub (XDR *xdr_in)
 
   struct guestfs_pvs_full_ret ret;
   ret.physvols = *r;
-  reply ((xdrproc_t) &xdr_guestfs_pvs_full_ret, (char *) &ret);
+  reply ((xdrproc_t) xdr_guestfs_pvs_full_ret, (char *) &ret);
   xdr_free ((xdrproc_t) xdr_guestfs_pvs_full_ret, (char *) &ret);
 }
 
@@ -273,7 +273,7 @@ static void vgs_full_stub (XDR *xdr_in)
 
   struct guestfs_vgs_full_ret ret;
   ret.volgroups = *r;
-  reply ((xdrproc_t) &xdr_guestfs_vgs_full_ret, (char *) &ret);
+  reply ((xdrproc_t) xdr_guestfs_vgs_full_ret, (char *) &ret);
   xdr_free ((xdrproc_t) xdr_guestfs_vgs_full_ret, (char *) &ret);
 }
 
@@ -288,7 +288,7 @@ static void lvs_full_stub (XDR *xdr_in)
 
   struct guestfs_lvs_full_ret ret;
   ret.logvols = *r;
-  reply ((xdrproc_t) &xdr_guestfs_lvs_full_ret, (char *) &ret);
+  reply ((xdrproc_t) xdr_guestfs_lvs_full_ret, (char *) &ret);
   xdr_free ((xdrproc_t) xdr_guestfs_lvs_full_ret, (char *) &ret);
 }
 
@@ -301,7 +301,7 @@ static void read_lines_stub (XDR *xdr_in)
   memset (&args, 0, sizeof args);
 
   if (!xdr_guestfs_read_lines_args (xdr_in, &args)) {
-    reply_with_error ("read_lines: daemon failed to decode procedure arguments");
+    reply_with_error ("%s: daemon failed to decode procedure arguments", "read_lines");
     return;
   }
   path = args.path;
@@ -318,6 +318,268 @@ static void read_lines_stub (XDR *xdr_in)
   free_strings (r);
 }
 
+static void aug_init_stub (XDR *xdr_in)
+{
+  int r;
+  struct guestfs_aug_init_args args;
+  const char *root;
+  int flags;
+
+  memset (&args, 0, sizeof args);
+
+  if (!xdr_guestfs_aug_init_args (xdr_in, &args)) {
+    reply_with_error ("%s: daemon failed to decode procedure arguments", "aug_init");
+    return;
+  }
+  root = args.root;
+  flags = args.flags;
+
+  r = do_aug_init (root, flags);
+  if (r == -1)
+    /* do_aug_init has already called reply_with_error, so just return */
+    return;
+
+  reply (NULL, NULL);
+}
+
+static void aug_close_stub (XDR *xdr_in)
+{
+  int r;
+
+  r = do_aug_close ();
+  if (r == -1)
+    /* do_aug_close has already called reply_with_error, so just return */
+    return;
+
+  reply (NULL, NULL);
+}
+
+static void aug_defvar_stub (XDR *xdr_in)
+{
+  int r;
+  struct guestfs_aug_defvar_args args;
+  const char *name;
+  const char *expr;
+
+  memset (&args, 0, sizeof args);
+
+  if (!xdr_guestfs_aug_defvar_args (xdr_in, &args)) {
+    reply_with_error ("%s: daemon failed to decode procedure arguments", "aug_defvar");
+    return;
+  }
+  name = args.name;
+  expr = args.expr ? *args.expr : NULL;
+
+  r = do_aug_defvar (name, expr);
+  if (r == -1)
+    /* do_aug_defvar has already called reply_with_error, so just return */
+    return;
+
+  struct guestfs_aug_defvar_ret ret;
+  ret.nrnodes = r;
+  reply ((xdrproc_t) &xdr_guestfs_aug_defvar_ret, (char *) &ret);
+}
+
+static void aug_defnode_stub (XDR *xdr_in)
+{
+  guestfs_aug_defnode_ret *r;
+  struct guestfs_aug_defnode_args args;
+  const char *name;
+  const char *expr;
+  const char *val;
+
+  memset (&args, 0, sizeof args);
+
+  if (!xdr_guestfs_aug_defnode_args (xdr_in, &args)) {
+    reply_with_error ("%s: daemon failed to decode procedure arguments", "aug_defnode");
+    return;
+  }
+  name = args.name;
+  expr = args.expr;
+  val = args.val;
+
+  r = do_aug_defnode (name, expr, val);
+  if (r == NULL)
+    /* do_aug_defnode has already called reply_with_error, so just return */
+    return;
+
+  reply ((xdrproc_t) xdr_guestfs_aug_defnode_ret, (char *) r);
+  xdr_free ((xdrproc_t) xdr_guestfs_aug_defnode_ret, (char *) r);
+}
+
+static void aug_get_stub (XDR *xdr_in)
+{
+  char *r;
+  struct guestfs_aug_get_args args;
+  const char *path;
+
+  memset (&args, 0, sizeof args);
+
+  if (!xdr_guestfs_aug_get_args (xdr_in, &args)) {
+    reply_with_error ("%s: daemon failed to decode procedure arguments", "aug_get");
+    return;
+  }
+  path = args.path;
+
+  r = do_aug_get (path);
+  if (r == NULL)
+    /* do_aug_get has already called reply_with_error, so just return */
+    return;
+
+  struct guestfs_aug_get_ret ret;
+  ret.val = r;
+  reply ((xdrproc_t) &xdr_guestfs_aug_get_ret, (char *) &ret);
+  free (r);
+}
+
+static void aug_set_stub (XDR *xdr_in)
+{
+  int r;
+  struct guestfs_aug_set_args args;
+  const char *path;
+  const char *val;
+
+  memset (&args, 0, sizeof args);
+
+  if (!xdr_guestfs_aug_set_args (xdr_in, &args)) {
+    reply_with_error ("%s: daemon failed to decode procedure arguments", "aug_set");
+    return;
+  }
+  path = args.path;
+  val = args.val;
+
+  r = do_aug_set (path, val);
+  if (r == -1)
+    /* do_aug_set has already called reply_with_error, so just return */
+    return;
+
+  reply (NULL, NULL);
+}
+
+static void aug_insert_stub (XDR *xdr_in)
+{
+  int r;
+  struct guestfs_aug_insert_args args;
+  const char *path;
+  const char *label;
+  int before;
+
+  memset (&args, 0, sizeof args);
+
+  if (!xdr_guestfs_aug_insert_args (xdr_in, &args)) {
+    reply_with_error ("%s: daemon failed to decode procedure arguments", "aug_insert");
+    return;
+  }
+  path = args.path;
+  label = args.label;
+  before = args.before;
+
+  r = do_aug_insert (path, label, before);
+  if (r == -1)
+    /* do_aug_insert has already called reply_with_error, so just return */
+    return;
+
+  reply (NULL, NULL);
+}
+
+static void aug_rm_stub (XDR *xdr_in)
+{
+  int r;
+  struct guestfs_aug_rm_args args;
+  const char *path;
+
+  memset (&args, 0, sizeof args);
+
+  if (!xdr_guestfs_aug_rm_args (xdr_in, &args)) {
+    reply_with_error ("%s: daemon failed to decode procedure arguments", "aug_rm");
+    return;
+  }
+  path = args.path;
+
+  r = do_aug_rm (path);
+  if (r == -1)
+    /* do_aug_rm has already called reply_with_error, so just return */
+    return;
+
+  struct guestfs_aug_rm_ret ret;
+  ret.nrnodes = r;
+  reply ((xdrproc_t) &xdr_guestfs_aug_rm_ret, (char *) &ret);
+}
+
+static void aug_mv_stub (XDR *xdr_in)
+{
+  int r;
+  struct guestfs_aug_mv_args args;
+  const char *src;
+  const char *dest;
+
+  memset (&args, 0, sizeof args);
+
+  if (!xdr_guestfs_aug_mv_args (xdr_in, &args)) {
+    reply_with_error ("%s: daemon failed to decode procedure arguments", "aug_mv");
+    return;
+  }
+  src = args.src;
+  dest = args.dest;
+
+  r = do_aug_mv (src, dest);
+  if (r == -1)
+    /* do_aug_mv has already called reply_with_error, so just return */
+    return;
+
+  reply (NULL, NULL);
+}
+
+static void aug_match_stub (XDR *xdr_in)
+{
+  char **r;
+  struct guestfs_aug_match_args args;
+  const char *path;
+
+  memset (&args, 0, sizeof args);
+
+  if (!xdr_guestfs_aug_match_args (xdr_in, &args)) {
+    reply_with_error ("%s: daemon failed to decode procedure arguments", "aug_match");
+    return;
+  }
+  path = args.path;
+
+  r = do_aug_match (path);
+  if (r == NULL)
+    /* do_aug_match has already called reply_with_error, so just return */
+    return;
+
+  struct guestfs_aug_match_ret ret;
+  ret.matches.matches_len = count_strings (r);
+  ret.matches.matches_val = r;
+  reply ((xdrproc_t) &xdr_guestfs_aug_match_ret, (char *) &ret);
+  free_strings (r);
+}
+
+static void aug_save_stub (XDR *xdr_in)
+{
+  int r;
+
+  r = do_aug_save ();
+  if (r == -1)
+    /* do_aug_save has already called reply_with_error, so just return */
+    return;
+
+  reply (NULL, NULL);
+}
+
+static void aug_load_stub (XDR *xdr_in)
+{
+  int r;
+
+  r = do_aug_load ();
+  if (r == -1)
+    /* do_aug_load has already called reply_with_error, so just return */
+    return;
+
+  reply (NULL, NULL);
+}
+
 void dispatch_incoming_message (XDR *xdr_in)
 {
   switch (proc_nr) {
@@ -366,6 +628,42 @@ void dispatch_incoming_message (XDR *xdr_in)
     case GUESTFS_PROC_READ_LINES:
       read_lines_stub (xdr_in);
       break;
+    case GUESTFS_PROC_AUG_INIT:
+      aug_init_stub (xdr_in);
+      break;
+    case GUESTFS_PROC_AUG_CLOSE:
+      aug_close_stub (xdr_in);
+      break;
+    case GUESTFS_PROC_AUG_DEFVAR:
+      aug_defvar_stub (xdr_in);
+      break;
+    case GUESTFS_PROC_AUG_DEFNODE:
+      aug_defnode_stub (xdr_in);
+      break;
+    case GUESTFS_PROC_AUG_GET:
+      aug_get_stub (xdr_in);
+      break;
+    case GUESTFS_PROC_AUG_SET:
+      aug_set_stub (xdr_in);
+      break;
+    case GUESTFS_PROC_AUG_INSERT:
+      aug_insert_stub (xdr_in);
+      break;
+    case GUESTFS_PROC_AUG_RM:
+      aug_rm_stub (xdr_in);
+      break;
+    case GUESTFS_PROC_AUG_MV:
+      aug_mv_stub (xdr_in);
+      break;
+    case GUESTFS_PROC_AUG_MATCH:
+      aug_match_stub (xdr_in);
+      break;
+    case GUESTFS_PROC_AUG_SAVE:
+      aug_save_stub (xdr_in);
+      break;
+    case GUESTFS_PROC_AUG_LOAD:
+      aug_load_stub (xdr_in);
+      break;
     default:
       reply_with_error ("dispatch_incoming_message: unknown procedure number %d", proc_nr);
   }
index aaf97a8..5c7d553 100644 (file)
@@ -33,6 +33,18 @@ void list_commands (void)
   list_builtin_commands ();
   printf ("%-20s %s\n", "add-cdrom", "add a CD-ROM disk image to examine");
   printf ("%-20s %s\n", "add-drive", "add an image to examine or modify");
+  printf ("%-20s %s\n", "aug-close", "close the current Augeas handle");
+  printf ("%-20s %s\n", "aug-defnode", "define an Augeas node");
+  printf ("%-20s %s\n", "aug-defvar", "define an Augeas variable");
+  printf ("%-20s %s\n", "aug-get", "look up the value of an Augeas path");
+  printf ("%-20s %s\n", "aug-init", "create a new Augeas handle");
+  printf ("%-20s %s\n", "aug-insert", "insert a sibling Augeas node");
+  printf ("%-20s %s\n", "aug-load", "load files into the tree");
+  printf ("%-20s %s\n", "aug-match", "return Augeas nodes which match path");
+  printf ("%-20s %s\n", "aug-mv", "move Augeas node");
+  printf ("%-20s %s\n", "aug-rm", "remove an Augeas path");
+  printf ("%-20s %s\n", "aug-save", "write all pending Augeas changes to disk");
+  printf ("%-20s %s\n", "aug-set", "set Augeas path to value");
   printf ("%-20s %s\n", "cat", "list the contents of a file");
   printf ("%-20s %s\n", "config", "add qemu parameters");
   printf ("%-20s %s\n", "get-autosync", "get autosync mode");
@@ -140,6 +152,42 @@ void display_command (const char *cmd)
   if (strcasecmp (cmd, "read_lines") == 0 || strcasecmp (cmd, "read-lines") == 0)
     pod2text ("read-lines - read file as lines", " read-lines <path>\n\nReturn the contents of the file named C<path>.\n\nThe file contents are returned as a list of lines.  Trailing\nC<LF> and C<CRLF> character sequences are I<not> returned.\n\nNote that this function cannot correctly handle binary files\n(specifically, files containing C<\\0> character which is treated\nas end of line).  For those you need to use the C<read_file>\nfunction which has a more complex interface.");
   else
+  if (strcasecmp (cmd, "aug_init") == 0 || strcasecmp (cmd, "aug-init") == 0)
+    pod2text ("aug-init - create a new Augeas handle", " aug-init <root> <flags>\n\nCreate a new Augeas handle for editing configuration files.\nIf there was any previous Augeas handle associated with this\nguestfs session, then it is closed.\n\nYou must call this before using any other C<aug_*>\ncommands.\n\nC<root> is the filesystem root.  C<root> must not be NULL,\nuse C</> instead.\n\nThe flags are the same as the flags defined in\nE<lt>augeas.hE<gt>, the logical I<or> of the following\nintegers:\n\n=over 4\n\n=item 1 C<AUG_SAVE_BACKUP>\n\nKeep the original file with a C<.augsave> extension.\n\n=item 2 C<AUG_SAVE_NEWFILE>\n\nSave changes into a file with extension C<.augnew>, and\ndo not overwrite original.  Overrides C<AUG_SAVE_BACKUP>.\n\n=item 4 C<AUG_TYPE_CHECK>\n\nTypecheck lenses (can be expensive).\n\n=item 8 C<AUG_NO_STDINC>\n\nDo not use standard load path for modules.\n\n=item 16 C<AUG_SAVE_NOOP>\n\nMake save a no-op, just record what would have been changed.\n\n=item 32 C<AUG_NO_LOAD>\n\nDo not load the tree in C<aug_init>.\n\n=back\n\nTo close the handle, you can call C<aug_close>.\n\nTo find out more about Augeas, see L<http://augeas.net/>.");
+  else
+  if (strcasecmp (cmd, "aug_close") == 0 || strcasecmp (cmd, "aug-close") == 0)
+    pod2text ("aug-close - close the current Augeas handle", " aug-close\n\nClose the current Augeas handle and free up any resources\nused by it.  After calling this, you have to call\nC<aug_init> again before you can use any other\nAugeas functions.");
+  else
+  if (strcasecmp (cmd, "aug_defvar") == 0 || strcasecmp (cmd, "aug-defvar") == 0)
+    pod2text ("aug-defvar - define an Augeas variable", " aug-defvar <name> <expr>\n\nDefines an Augeas variable C<name> whose value is the result\nof evaluating C<expr>.  If C<expr> is NULL, then C<name> is\nundefined.\n\nOn success this returns the number of nodes in C<expr>, or\nC<0> if C<expr> evaluates to something which is not a nodeset.");
+  else
+  if (strcasecmp (cmd, "aug_defnode") == 0 || strcasecmp (cmd, "aug-defnode") == 0)
+    pod2text ("aug-defnode - define an Augeas node", " aug-defnode <name> <expr> <val>\n\nDefines a variable C<name> whose value is the result of\nevaluating C<expr>.\n\nIf C<expr> evaluates to an empty nodeset, a node is created,\nequivalent to calling C<aug_set> C<expr>, C<value>.\nC<name> will be the nodeset containing that single node.\n\nOn success this returns a pair containing the\nnumber of nodes in the nodeset, and a boolean flag\nif a node was created.");
+  else
+  if (strcasecmp (cmd, "aug_get") == 0 || strcasecmp (cmd, "aug-get") == 0)
+    pod2text ("aug-get - look up the value of an Augeas path", " aug-get <path>\n\nLook up the value associated with C<path>.  If C<path>\nmatches exactly one node, the C<value> is returned.");
+  else
+  if (strcasecmp (cmd, "aug_set") == 0 || strcasecmp (cmd, "aug-set") == 0)
+    pod2text ("aug-set - set Augeas path to value", " aug-set <path> <val>\n\nSet the value associated with C<path> to C<value>.");
+  else
+  if (strcasecmp (cmd, "aug_insert") == 0 || strcasecmp (cmd, "aug-insert") == 0)
+    pod2text ("aug-insert - insert a sibling Augeas node", " aug-insert <path> <label> <before>\n\nCreate a new sibling C<label> for C<path>, inserting it into\nthe tree before or after C<path> (depending on the boolean\nflag C<before>).\n\nC<path> must match exactly one existing node in the tree, and\nC<label> must be a label, ie. not contain C</>, C<*> or end\nwith a bracketed index C<[N]>.");
+  else
+  if (strcasecmp (cmd, "aug_rm") == 0 || strcasecmp (cmd, "aug-rm") == 0)
+    pod2text ("aug-rm - remove an Augeas path", " aug-rm <path>\n\nRemove C<path> and all of its children.\n\nOn success this returns the number of entries which were removed.");
+  else
+  if (strcasecmp (cmd, "aug_mv") == 0 || strcasecmp (cmd, "aug-mv") == 0)
+    pod2text ("aug-mv - move Augeas node", " aug-mv <src> <dest>\n\nMove the node C<src> to C<dest>.  C<src> must match exactly\none node.  C<dest> is overwritten if it exists.");
+  else
+  if (strcasecmp (cmd, "aug_match") == 0 || strcasecmp (cmd, "aug-match") == 0)
+    pod2text ("aug-match - return Augeas nodes which match path", " aug-match <path>\n\nReturns a list of paths which match the path expression C<path>.\nThe returned paths are sufficiently qualified so that they match\nexactly one node in the current tree.");
+  else
+  if (strcasecmp (cmd, "aug_save") == 0 || strcasecmp (cmd, "aug-save") == 0)
+    pod2text ("aug-save - write all pending Augeas changes to disk", " aug-save\n\nThis writes all pending changes to disk.\n\nThe flags which were passed to C<aug_init> affect exactly\nhow files are saved.");
+  else
+  if (strcasecmp (cmd, "aug_load") == 0 || strcasecmp (cmd, "aug-load") == 0)
+    pod2text ("aug-load - load files into the tree", " aug-load\n\nLoad files into the tree.\n\nSee C<aug_load> in the Augeas documentation for the full gory\ndetails.");
+  else
     display_builtin_command (cmd);
 }
 
@@ -627,6 +675,198 @@ static int run_read_lines (const char *cmd, int argc, char *argv[])
   return 0;
 }
 
+static int run_aug_init (const char *cmd, int argc, char *argv[])
+{
+  int r;
+  const char *root;
+  int flags;
+  if (argc != 2) {
+    fprintf (stderr, "%s should have 2 parameter(s)\n", cmd);
+    fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd);
+    return -1;
+  }
+  root = argv[0];
+  flags = atoi (argv[1]);
+  r = guestfs_aug_init (g, root, flags);
+  return r;
+}
+
+static int run_aug_close (const char *cmd, int argc, char *argv[])
+{
+  int r;
+  if (argc != 0) {
+    fprintf (stderr, "%s should have 0 parameter(s)\n", cmd);
+    fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd);
+    return -1;
+  }
+  r = guestfs_aug_close (g);
+  return r;
+}
+
+static int run_aug_defvar (const char *cmd, int argc, char *argv[])
+{
+  int r;
+  const char *name;
+  const char *expr;
+  if (argc != 2) {
+    fprintf (stderr, "%s should have 2 parameter(s)\n", cmd);
+    fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd);
+    return -1;
+  }
+  name = argv[0];
+  expr = strcmp (argv[1], "") != 0 ? argv[1] : NULL;
+  r = guestfs_aug_defvar (g, name, expr);
+  if (r == -1) return -1;
+  if (r) printf ("%d\n", r);
+  return 0;
+}
+
+static int run_aug_defnode (const char *cmd, int argc, char *argv[])
+{
+  struct guestfs_int_bool *r;
+  const char *name;
+  const char *expr;
+  const char *val;
+  if (argc != 3) {
+    fprintf (stderr, "%s should have 3 parameter(s)\n", cmd);
+    fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd);
+    return -1;
+  }
+  name = argv[0];
+  expr = argv[1];
+  val = argv[2];
+  r = guestfs_aug_defnode (g, name, expr, val);
+  if (r == NULL) return -1;
+  printf ("%d, %s\n", r->i,
+    r->b ? "true" : "false");
+  guestfs_free_int_bool (r);
+  return 0;
+}
+
+static int run_aug_get (const char *cmd, int argc, char *argv[])
+{
+  char *r;
+  const char *path;
+  if (argc != 1) {
+    fprintf (stderr, "%s should have 1 parameter(s)\n", cmd);
+    fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd);
+    return -1;
+  }
+  path = argv[0];
+  r = guestfs_aug_get (g, path);
+  if (r == NULL) return -1;
+  printf ("%s\n", r);
+  free (r);
+  return 0;
+}
+
+static int run_aug_set (const char *cmd, int argc, char *argv[])
+{
+  int r;
+  const char *path;
+  const char *val;
+  if (argc != 2) {
+    fprintf (stderr, "%s should have 2 parameter(s)\n", cmd);
+    fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd);
+    return -1;
+  }
+  path = argv[0];
+  val = argv[1];
+  r = guestfs_aug_set (g, path, val);
+  return r;
+}
+
+static int run_aug_insert (const char *cmd, int argc, char *argv[])
+{
+  int r;
+  const char *path;
+  const char *label;
+  int before;
+  if (argc != 3) {
+    fprintf (stderr, "%s should have 3 parameter(s)\n", cmd);
+    fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd);
+    return -1;
+  }
+  path = argv[0];
+  label = argv[1];
+  before = is_true (argv[2]) ? 1 : 0;
+  r = guestfs_aug_insert (g, path, label, before);
+  return r;
+}
+
+static int run_aug_rm (const char *cmd, int argc, char *argv[])
+{
+  int r;
+  const char *path;
+  if (argc != 1) {
+    fprintf (stderr, "%s should have 1 parameter(s)\n", cmd);
+    fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd);
+    return -1;
+  }
+  path = argv[0];
+  r = guestfs_aug_rm (g, path);
+  if (r == -1) return -1;
+  if (r) printf ("%d\n", r);
+  return 0;
+}
+
+static int run_aug_mv (const char *cmd, int argc, char *argv[])
+{
+  int r;
+  const char *src;
+  const char *dest;
+  if (argc != 2) {
+    fprintf (stderr, "%s should have 2 parameter(s)\n", cmd);
+    fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd);
+    return -1;
+  }
+  src = argv[0];
+  dest = argv[1];
+  r = guestfs_aug_mv (g, src, dest);
+  return r;
+}
+
+static int run_aug_match (const char *cmd, int argc, char *argv[])
+{
+  char **r;
+  const char *path;
+  if (argc != 1) {
+    fprintf (stderr, "%s should have 1 parameter(s)\n", cmd);
+    fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd);
+    return -1;
+  }
+  path = argv[0];
+  r = guestfs_aug_match (g, path);
+  if (r == NULL) return -1;
+  print_strings (r);
+  free_strings (r);
+  return 0;
+}
+
+static int run_aug_save (const char *cmd, int argc, char *argv[])
+{
+  int r;
+  if (argc != 0) {
+    fprintf (stderr, "%s should have 0 parameter(s)\n", cmd);
+    fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd);
+    return -1;
+  }
+  r = guestfs_aug_save (g);
+  return r;
+}
+
+static int run_aug_load (const char *cmd, int argc, char *argv[])
+{
+  int r;
+  if (argc != 0) {
+    fprintf (stderr, "%s should have 0 parameter(s)\n", cmd);
+    fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd);
+    return -1;
+  }
+  r = guestfs_aug_load (g);
+  return r;
+}
+
 int run_action (const char *cmd, int argc, char *argv[])
 {
   if (strcasecmp (cmd, "launch") == 0 || strcasecmp (cmd, "run") == 0)
@@ -707,6 +947,42 @@ int run_action (const char *cmd, int argc, char *argv[])
   if (strcasecmp (cmd, "read_lines") == 0 || strcasecmp (cmd, "read-lines") == 0)
     return run_read_lines (cmd, argc, argv);
   else
+  if (strcasecmp (cmd, "aug_init") == 0 || strcasecmp (cmd, "aug-init") == 0)
+    return run_aug_init (cmd, argc, argv);
+  else
+  if (strcasecmp (cmd, "aug_close") == 0 || strcasecmp (cmd, "aug-close") == 0)
+    return run_aug_close (cmd, argc, argv);
+  else
+  if (strcasecmp (cmd, "aug_defvar") == 0 || strcasecmp (cmd, "aug-defvar") == 0)
+    return run_aug_defvar (cmd, argc, argv);
+  else
+  if (strcasecmp (cmd, "aug_defnode") == 0 || strcasecmp (cmd, "aug-defnode") == 0)
+    return run_aug_defnode (cmd, argc, argv);
+  else
+  if (strcasecmp (cmd, "aug_get") == 0 || strcasecmp (cmd, "aug-get") == 0)
+    return run_aug_get (cmd, argc, argv);
+  else
+  if (strcasecmp (cmd, "aug_set") == 0 || strcasecmp (cmd, "aug-set") == 0)
+    return run_aug_set (cmd, argc, argv);
+  else
+  if (strcasecmp (cmd, "aug_insert") == 0 || strcasecmp (cmd, "aug-insert") == 0)
+    return run_aug_insert (cmd, argc, argv);
+  else
+  if (strcasecmp (cmd, "aug_rm") == 0 || strcasecmp (cmd, "aug-rm") == 0)
+    return run_aug_rm (cmd, argc, argv);
+  else
+  if (strcasecmp (cmd, "aug_mv") == 0 || strcasecmp (cmd, "aug-mv") == 0)
+    return run_aug_mv (cmd, argc, argv);
+  else
+  if (strcasecmp (cmd, "aug_match") == 0 || strcasecmp (cmd, "aug-match") == 0)
+    return run_aug_match (cmd, argc, argv);
+  else
+  if (strcasecmp (cmd, "aug_save") == 0 || strcasecmp (cmd, "aug-save") == 0)
+    return run_aug_save (cmd, argc, argv);
+  else
+  if (strcasecmp (cmd, "aug_load") == 0 || strcasecmp (cmd, "aug-load") == 0)
+    return run_aug_load (cmd, argc, argv);
+  else
     {
       fprintf (stderr, "%s: unknown command\n", cmd);
       return -1;
index 13e23ae..00911db 100644 (file)
@@ -23,6 +23,158 @@ image).
 
 This is equivalent to the qemu parameter C<-drive file=filename>.
 
+=head2 aug-close
+
+ aug-close
+
+Close the current Augeas handle and free up any resources
+used by it.  After calling this, you have to call
+C<aug_init> again before you can use any other
+Augeas functions.
+
+=head2 aug-defnode
+
+ aug-defnode name expr val
+
+Defines a variable C<name> whose value is the result of
+evaluating C<expr>.
+
+If C<expr> evaluates to an empty nodeset, a node is created,
+equivalent to calling C<aug_set> C<expr>, C<value>.
+C<name> will be the nodeset containing that single node.
+
+On success this returns a pair containing the
+number of nodes in the nodeset, and a boolean flag
+if a node was created.
+
+=head2 aug-defvar
+
+ aug-defvar name expr
+
+Defines an Augeas variable C<name> whose value is the result
+of evaluating C<expr>.  If C<expr> is NULL, then C<name> is
+undefined.
+
+On success this returns the number of nodes in C<expr>, or
+C<0> if C<expr> evaluates to something which is not a nodeset.
+
+=head2 aug-get
+
+ aug-get path
+
+Look up the value associated with C<path>.  If C<path>
+matches exactly one node, the C<value> is returned.
+
+=head2 aug-init
+
+ aug-init root flags
+
+Create a new Augeas handle for editing configuration files.
+If there was any previous Augeas handle associated with this
+guestfs session, then it is closed.
+
+You must call this before using any other C<aug_*>
+commands.
+
+C<root> is the filesystem root.  C<root> must not be NULL,
+use C</> instead.
+
+The flags are the same as the flags defined in
+E<lt>augeas.hE<gt>, the logical I<or> of the following
+integers:
+
+=over 4
+
+=item 1 C<AUG_SAVE_BACKUP>
+
+Keep the original file with a C<.augsave> extension.
+
+=item 2 C<AUG_SAVE_NEWFILE>
+
+Save changes into a file with extension C<.augnew>, and
+do not overwrite original.  Overrides C<AUG_SAVE_BACKUP>.
+
+=item 4 C<AUG_TYPE_CHECK>
+
+Typecheck lenses (can be expensive).
+
+=item 8 C<AUG_NO_STDINC>
+
+Do not use standard load path for modules.
+
+=item 16 C<AUG_SAVE_NOOP>
+
+Make save a no-op, just record what would have been changed.
+
+=item 32 C<AUG_NO_LOAD>
+
+Do not load the tree in C<aug_init>.
+
+=back
+
+To close the handle, you can call C<aug_close>.
+
+To find out more about Augeas, see L<http://augeas.net/>.
+
+=head2 aug-insert
+
+ aug-insert path label true|false
+
+Create a new sibling C<label> for C<path>, inserting it into
+the tree before or after C<path> (depending on the boolean
+flag C<before>).
+
+C<path> must match exactly one existing node in the tree, and
+C<label> must be a label, ie. not contain C</>, C<*> or end
+with a bracketed index C<[N]>.
+
+=head2 aug-load
+
+ aug-load
+
+Load files into the tree.
+
+See C<aug_load> in the Augeas documentation for the full gory
+details.
+
+=head2 aug-match
+
+ aug-match path
+
+Returns a list of paths which match the path expression C<path>.
+The returned paths are sufficiently qualified so that they match
+exactly one node in the current tree.
+
+=head2 aug-mv
+
+ aug-mv src dest
+
+Move the node C<src> to C<dest>.  C<src> must match exactly
+one node.  C<dest> is overwritten if it exists.
+
+=head2 aug-rm
+
+ aug-rm path
+
+Remove C<path> and all of its children.
+
+On success this returns the number of entries which were removed.
+
+=head2 aug-save
+
+ aug-save
+
+This writes all pending changes to disk.
+
+The flags which were passed to C<aug_init> affect exactly
+how files are saved.
+
+=head2 aug-set
+
+ aug-set path val
+
+Set the value associated with C<path> to C<value>.
+
 =head2 cat
 
  cat path
index fd720f9..c5fadcf 100644 (file)
@@ -29,6 +29,203 @@ This is equivalent to the qemu parameter C<-drive file=filename>.
 
 This function returns 0 on success or -1 on error.
 
+=head2 guestfs_aug_close
+
+ int guestfs_aug_close (guestfs_h *handle);
+
+Close the current Augeas handle and free up any resources
+used by it.  After calling this, you have to call
+C<guestfs_aug_init> again before you can use any other
+Augeas functions.
+
+This function returns 0 on success or -1 on error.
+
+=head2 guestfs_aug_defnode
+
+ struct guestfs_int_bool *guestfs_aug_defnode (guestfs_h *handle,
+               const char *name,
+               const char *expr,
+               const char *val);
+
+Defines a variable C<name> whose value is the result of
+evaluating C<expr>.
+
+If C<expr> evaluates to an empty nodeset, a node is created,
+equivalent to calling C<guestfs_aug_set> C<expr>, C<value>.
+C<name> will be the nodeset containing that single node.
+
+On success this returns a pair containing the
+number of nodes in the nodeset, and a boolean flag
+if a node was created.
+
+This function returns a C<struct guestfs_int_bool *>.
+I<The caller must call C<guestfs_free_int_bool> after use.>.
+
+=head2 guestfs_aug_defvar
+
+ int guestfs_aug_defvar (guestfs_h *handle,
+               const char *name,
+               const char *expr);
+
+Defines an Augeas variable C<name> whose value is the result
+of evaluating C<expr>.  If C<expr> is NULL, then C<name> is
+undefined.
+
+On success this returns the number of nodes in C<expr>, or
+C<0> if C<expr> evaluates to something which is not a nodeset.
+
+On error this function returns -1.
+
+=head2 guestfs_aug_get
+
+ char *guestfs_aug_get (guestfs_h *handle,
+               const char *path);
+
+Look up the value associated with C<path>.  If C<path>
+matches exactly one node, the C<value> is returned.
+
+This function returns a string or NULL on error.
+I<The caller must free the returned string after use>.
+
+=head2 guestfs_aug_init
+
+ int guestfs_aug_init (guestfs_h *handle,
+               const char *root,
+               int flags);
+
+Create a new Augeas handle for editing configuration files.
+If there was any previous Augeas handle associated with this
+guestfs session, then it is closed.
+
+You must call this before using any other C<guestfs_aug_*>
+commands.
+
+C<root> is the filesystem root.  C<root> must not be NULL,
+use C</> instead.
+
+The flags are the same as the flags defined in
+E<lt>augeas.hE<gt>, the logical I<or> of the following
+integers:
+
+=over 4
+
+=item 1 C<AUG_SAVE_BACKUP>
+
+Keep the original file with a C<.augsave> extension.
+
+=item 2 C<AUG_SAVE_NEWFILE>
+
+Save changes into a file with extension C<.augnew>, and
+do not overwrite original.  Overrides C<AUG_SAVE_BACKUP>.
+
+=item 4 C<AUG_TYPE_CHECK>
+
+Typecheck lenses (can be expensive).
+
+=item 8 C<AUG_NO_STDINC>
+
+Do not use standard load path for modules.
+
+=item 16 C<AUG_SAVE_NOOP>
+
+Make save a no-op, just record what would have been changed.
+
+=item 32 C<AUG_NO_LOAD>
+
+Do not load the tree in C<guestfs_aug_init>.
+
+=back
+
+To close the handle, you can call C<guestfs_aug_close>.
+
+To find out more about Augeas, see L<http://augeas.net/>.
+
+This function returns 0 on success or -1 on error.
+
+=head2 guestfs_aug_insert
+
+ int guestfs_aug_insert (guestfs_h *handle,
+               const char *path,
+               const char *label,
+               int before);
+
+Create a new sibling C<label> for C<path>, inserting it into
+the tree before or after C<path> (depending on the boolean
+flag C<before>).
+
+C<path> must match exactly one existing node in the tree, and
+C<label> must be a label, ie. not contain C</>, C<*> or end
+with a bracketed index C<[N]>.
+
+This function returns 0 on success or -1 on error.
+
+=head2 guestfs_aug_load
+
+ int guestfs_aug_load (guestfs_h *handle);
+
+Load files into the tree.
+
+See C<aug_load> in the Augeas documentation for the full gory
+details.
+
+This function returns 0 on success or -1 on error.
+
+=head2 guestfs_aug_match
+
+ char **guestfs_aug_match (guestfs_h *handle,
+               const char *path);
+
+Returns a list of paths which match the path expression C<path>.
+The returned paths are sufficiently qualified so that they match
+exactly one node in the current tree.
+
+This function returns a NULL-terminated array of strings
+(like L<environ(3)>), or NULL if there was an error.
+I<The caller must free the strings and the array after use>.
+
+=head2 guestfs_aug_mv
+
+ int guestfs_aug_mv (guestfs_h *handle,
+               const char *src,
+               const char *dest);
+
+Move the node C<src> to C<dest>.  C<src> must match exactly
+one node.  C<dest> is overwritten if it exists.
+
+This function returns 0 on success or -1 on error.
+
+=head2 guestfs_aug_rm
+
+ int guestfs_aug_rm (guestfs_h *handle,
+               const char *path);
+
+Remove C<path> and all of its children.
+
+On success this returns the number of entries which were removed.
+
+On error this function returns -1.
+
+=head2 guestfs_aug_save
+
+ int guestfs_aug_save (guestfs_h *handle);
+
+This writes all pending changes to disk.
+
+The flags which were passed to C<guestfs_aug_init> affect exactly
+how files are saved.
+
+This function returns 0 on success or -1 on error.
+
+=head2 guestfs_aug_set
+
+ int guestfs_aug_set (guestfs_h *handle,
+               const char *path,
+               const char *val);
+
+Set the value associated with C<path> to C<value>.
+
+This function returns 0 on success or -1 on error.
+
 =head2 guestfs_cat
 
  char *guestfs_cat (guestfs_h *handle,
@@ -193,7 +390,7 @@ I<The caller must free the strings and the array after use>.
 List all the logical volumes detected.  This is the equivalent
 of the L<lvs(8)> command.  The "full" version includes all fields.
 
-This function returns a C<struct guestfs_lvm_lv_list>.
+This function returns a C<struct guestfs_lvm_lv_list *>.
 I<The caller must call C<guestfs_free_lvm_lv_list> after use.>.
 
 =head2 guestfs_mount
@@ -244,7 +441,7 @@ I<The caller must free the strings and the array after use>.
 List all the physical volumes detected.  This is the equivalent
 of the L<pvs(8)> command.  The "full" version includes all fields.
 
-This function returns a C<struct guestfs_lvm_pv_list>.
+This function returns a C<struct guestfs_lvm_pv_list *>.
 I<The caller must call C<guestfs_free_lvm_pv_list> after use.>.
 
 =head2 guestfs_read_lines
@@ -352,7 +549,7 @@ I<The caller must free the strings and the array after use>.
 List all the volumes groups detected.  This is the equivalent
 of the L<vgs(8)> command.  The "full" version includes all fields.
 
-This function returns a C<struct guestfs_lvm_vg_list>.
+This function returns a C<struct guestfs_lvm_vg_list *>.
 I<The caller must call C<guestfs_free_lvm_vg_list> after use.>.
 
 =head2 guestfs_wait_ready
index bc611ef..4e55988 100644 (file)
@@ -15,7 +15,8 @@ BuildRoot:   %{_tmppath}/%{name}-%{version}-%{release}-root
 # Basic build requirements:
 BuildRequires: /usr/bin/pod2man
 BuildRequires: /usr/bin/pod2text
-BuildRequires: febootstrap
+BuildRequires: febootstrap >= 1.5
+BuildRequires: augeas-devel
 
 # If you want to build the bindings for different languages:
 BuildRequires: ocaml
index f25e7ce..4579e90 100755 (executable)
@@ -25,7 +25,7 @@ set -e
 # larger.
 debug=yes
 
-modules="-i kernel -i bash -i coreutils -i lvm2 -i ntfs-3g -i util-linux-ng -i MAKEDEV -i net-tools"
+modules="-i kernel -i bash -i coreutils -i lvm2 -i ntfs-3g -i util-linux-ng -i MAKEDEV -i net-tools -i augeas-libs"
 
 if [ "x$debug" = "xyes" ]; then
     modules="$modules -i module-init-tools -i procps -i strace -i iputils"
@@ -38,7 +38,7 @@ rm -f $output
 rm -f $koutput
 
 # Create the basic initramfs.
-@FEBOOTSTRAP@ $modules @REPO@ initramfs @MIRROR@
+@FEBOOTSTRAP@ $modules -u @UPDATES@ @REPO@ initramfs @MIRROR@
 
 # /sysroot is where the guest root filesystem will be mounted.
 mkdir initramfs/sysroot
index 2504b45..6487861 100644 (file)
@@ -112,3 +112,15 @@ external pvs_full : t -> lvm_pv array = "ocaml_guestfs_pvs_full"
 external vgs_full : t -> lvm_vg array = "ocaml_guestfs_vgs_full"
 external lvs_full : t -> lvm_lv array = "ocaml_guestfs_lvs_full"
 external read_lines : t -> string -> string array = "ocaml_guestfs_read_lines"
+external aug_init : t -> string -> int -> unit = "ocaml_guestfs_aug_init"
+external aug_close : t -> unit = "ocaml_guestfs_aug_close"
+external aug_defvar : t -> string -> string option -> int = "ocaml_guestfs_aug_defvar"
+external aug_defnode : t -> string -> string -> string -> int * bool = "ocaml_guestfs_aug_defnode"
+external aug_get : t -> string -> string = "ocaml_guestfs_aug_get"
+external aug_set : t -> string -> string -> unit = "ocaml_guestfs_aug_set"
+external aug_insert : t -> string -> string -> bool -> unit = "ocaml_guestfs_aug_insert"
+external aug_rm : t -> string -> int = "ocaml_guestfs_aug_rm"
+external aug_mv : t -> string -> string -> unit = "ocaml_guestfs_aug_mv"
+external aug_match : t -> string -> string array = "ocaml_guestfs_aug_match"
+external aug_save : t -> unit = "ocaml_guestfs_aug_save"
+external aug_load : t -> unit = "ocaml_guestfs_aug_load"
index 177f09e..b1452ab 100644 (file)
@@ -175,3 +175,39 @@ val lvs_full : t -> lvm_lv array
 val read_lines : t -> string -> string array
 (** read file as lines *)
 
+val aug_init : t -> string -> int -> unit
+(** create a new Augeas handle *)
+
+val aug_close : t -> unit
+(** close the current Augeas handle *)
+
+val aug_defvar : t -> string -> string option -> int
+(** define an Augeas variable *)
+
+val aug_defnode : t -> string -> string -> string -> int * bool
+(** define an Augeas node *)
+
+val aug_get : t -> string -> string
+(** look up the value of an Augeas path *)
+
+val aug_set : t -> string -> string -> unit
+(** set Augeas path to value *)
+
+val aug_insert : t -> string -> string -> bool -> unit
+(** insert a sibling Augeas node *)
+
+val aug_rm : t -> string -> int
+(** remove an Augeas path *)
+
+val aug_mv : t -> string -> string -> unit
+(** move Augeas node *)
+
+val aug_match : t -> string -> string array
+(** return Augeas nodes which match path *)
+
+val aug_save : t -> unit
+(** write all pending Augeas changes to disk *)
+
+val aug_load : t -> unit
+(** load files into the tree *)
+
index 80a891e..f21d63e 100644 (file)
@@ -456,7 +456,7 @@ ocaml_guestfs_get_autosync (value gv)
   if (r == -1)
     ocaml_guestfs_raise_error (g, "get_autosync");
 
-  rv = r ? Val_true : Val_false;
+  rv = Val_bool (r);
   CAMLreturn (rv);
 }
 
@@ -501,7 +501,7 @@ ocaml_guestfs_get_verbose (value gv)
   if (r == -1)
     ocaml_guestfs_raise_error (g, "get_verbose");
 
-  rv = r ? Val_true : Val_false;
+  rv = Val_bool (r);
   CAMLreturn (rv);
 }
 
@@ -868,3 +868,292 @@ ocaml_guestfs_read_lines (value gv, value pathv)
   CAMLreturn (rv);
 }
 
+CAMLprim value
+ocaml_guestfs_aug_init (value gv, value rootv, value flagsv)
+{
+  CAMLparam3 (gv, rootv, flagsv);
+  CAMLlocal1 (rv);
+
+  guestfs_h *g = Guestfs_val (gv);
+  if (g == NULL)
+    caml_failwith ("aug_init: used handle after closing it");
+
+  const char *root = String_val (rootv);
+  int flags = Int_val (flagsv);
+  int r;
+
+  caml_enter_blocking_section ();
+  r = guestfs_aug_init (g, root, flags);
+  caml_leave_blocking_section ();
+  if (r == -1)
+    ocaml_guestfs_raise_error (g, "aug_init");
+
+  rv = Val_unit;
+  CAMLreturn (rv);
+}
+
+CAMLprim value
+ocaml_guestfs_aug_close (value gv)
+{
+  CAMLparam1 (gv);
+  CAMLlocal1 (rv);
+
+  guestfs_h *g = Guestfs_val (gv);
+  if (g == NULL)
+    caml_failwith ("aug_close: used handle after closing it");
+
+  int r;
+
+  caml_enter_blocking_section ();
+  r = guestfs_aug_close (g);
+  caml_leave_blocking_section ();
+  if (r == -1)
+    ocaml_guestfs_raise_error (g, "aug_close");
+
+  rv = Val_unit;
+  CAMLreturn (rv);
+}
+
+CAMLprim value
+ocaml_guestfs_aug_defvar (value gv, value namev, value exprv)
+{
+  CAMLparam3 (gv, namev, exprv);
+  CAMLlocal1 (rv);
+
+  guestfs_h *g = Guestfs_val (gv);
+  if (g == NULL)
+    caml_failwith ("aug_defvar: used handle after closing it");
+
+  const char *name = String_val (namev);
+  const char *expr =
+    exprv != Val_int (0) ? String_val (Field (exprv, 0)) : NULL;
+  int r;
+
+  caml_enter_blocking_section ();
+  r = guestfs_aug_defvar (g, name, expr);
+  caml_leave_blocking_section ();
+  if (r == -1)
+    ocaml_guestfs_raise_error (g, "aug_defvar");
+
+  rv = Val_int (r);
+  CAMLreturn (rv);
+}
+
+CAMLprim value
+ocaml_guestfs_aug_defnode (value gv, value namev, value exprv, value valv)
+{
+  CAMLparam4 (gv, namev, exprv, valv);
+  CAMLlocal1 (rv);
+
+  guestfs_h *g = Guestfs_val (gv);
+  if (g == NULL)
+    caml_failwith ("aug_defnode: used handle after closing it");
+
+  const char *name = String_val (namev);
+  const char *expr = String_val (exprv);
+  const char *val = String_val (valv);
+  struct guestfs_int_bool *r;
+
+  caml_enter_blocking_section ();
+  r = guestfs_aug_defnode (g, name, expr, val);
+  caml_leave_blocking_section ();
+  if (r == NULL)
+    ocaml_guestfs_raise_error (g, "aug_defnode");
+
+  rv = caml_alloc (2, 0);
+  Store_field (rv, 0, Val_int (r->i));
+  Store_field (rv, 1, Val_bool (r->b));
+  guestfs_free_int_bool (r);
+  CAMLreturn (rv);
+}
+
+CAMLprim value
+ocaml_guestfs_aug_get (value gv, value pathv)
+{
+  CAMLparam2 (gv, pathv);
+  CAMLlocal1 (rv);
+
+  guestfs_h *g = Guestfs_val (gv);
+  if (g == NULL)
+    caml_failwith ("aug_get: used handle after closing it");
+
+  const char *path = String_val (pathv);
+  char *r;
+
+  caml_enter_blocking_section ();
+  r = guestfs_aug_get (g, path);
+  caml_leave_blocking_section ();
+  if (r == NULL)
+    ocaml_guestfs_raise_error (g, "aug_get");
+
+  rv = caml_copy_string (r);
+  free (r);
+  CAMLreturn (rv);
+}
+
+CAMLprim value
+ocaml_guestfs_aug_set (value gv, value pathv, value valv)
+{
+  CAMLparam3 (gv, pathv, valv);
+  CAMLlocal1 (rv);
+
+  guestfs_h *g = Guestfs_val (gv);
+  if (g == NULL)
+    caml_failwith ("aug_set: used handle after closing it");
+
+  const char *path = String_val (pathv);
+  const char *val = String_val (valv);
+  int r;
+
+  caml_enter_blocking_section ();
+  r = guestfs_aug_set (g, path, val);
+  caml_leave_blocking_section ();
+  if (r == -1)
+    ocaml_guestfs_raise_error (g, "aug_set");
+
+  rv = Val_unit;
+  CAMLreturn (rv);
+}
+
+CAMLprim value
+ocaml_guestfs_aug_insert (value gv, value pathv, value labelv, value beforev)
+{
+  CAMLparam4 (gv, pathv, labelv, beforev);
+  CAMLlocal1 (rv);
+
+  guestfs_h *g = Guestfs_val (gv);
+  if (g == NULL)
+    caml_failwith ("aug_insert: used handle after closing it");
+
+  const char *path = String_val (pathv);
+  const char *label = String_val (labelv);
+  int before = Bool_val (beforev);
+  int r;
+
+  caml_enter_blocking_section ();
+  r = guestfs_aug_insert (g, path, label, before);
+  caml_leave_blocking_section ();
+  if (r == -1)
+    ocaml_guestfs_raise_error (g, "aug_insert");
+
+  rv = Val_unit;
+  CAMLreturn (rv);
+}
+
+CAMLprim value
+ocaml_guestfs_aug_rm (value gv, value pathv)
+{
+  CAMLparam2 (gv, pathv);
+  CAMLlocal1 (rv);
+
+  guestfs_h *g = Guestfs_val (gv);
+  if (g == NULL)
+    caml_failwith ("aug_rm: used handle after closing it");
+
+  const char *path = String_val (pathv);
+  int r;
+
+  caml_enter_blocking_section ();
+  r = guestfs_aug_rm (g, path);
+  caml_leave_blocking_section ();
+  if (r == -1)
+    ocaml_guestfs_raise_error (g, "aug_rm");
+
+  rv = Val_int (r);
+  CAMLreturn (rv);
+}
+
+CAMLprim value
+ocaml_guestfs_aug_mv (value gv, value srcv, value destv)
+{
+  CAMLparam3 (gv, srcv, destv);
+  CAMLlocal1 (rv);
+
+  guestfs_h *g = Guestfs_val (gv);
+  if (g == NULL)
+    caml_failwith ("aug_mv: used handle after closing it");
+
+  const char *src = String_val (srcv);
+  const char *dest = String_val (destv);
+  int r;
+
+  caml_enter_blocking_section ();
+  r = guestfs_aug_mv (g, src, dest);
+  caml_leave_blocking_section ();
+  if (r == -1)
+    ocaml_guestfs_raise_error (g, "aug_mv");
+
+  rv = Val_unit;
+  CAMLreturn (rv);
+}
+
+CAMLprim value
+ocaml_guestfs_aug_match (value gv, value pathv)
+{
+  CAMLparam2 (gv, pathv);
+  CAMLlocal1 (rv);
+
+  guestfs_h *g = Guestfs_val (gv);
+  if (g == NULL)
+    caml_failwith ("aug_match: used handle after closing it");
+
+  const char *path = String_val (pathv);
+  int i;
+  char **r;
+
+  caml_enter_blocking_section ();
+  r = guestfs_aug_match (g, path);
+  caml_leave_blocking_section ();
+  if (r == NULL)
+    ocaml_guestfs_raise_error (g, "aug_match");
+
+  rv = caml_copy_string_array ((const char **) r);
+  for (i = 0; r[i] != NULL; ++i) free (r[i]);
+  free (r);
+  CAMLreturn (rv);
+}
+
+CAMLprim value
+ocaml_guestfs_aug_save (value gv)
+{
+  CAMLparam1 (gv);
+  CAMLlocal1 (rv);
+
+  guestfs_h *g = Guestfs_val (gv);
+  if (g == NULL)
+    caml_failwith ("aug_save: used handle after closing it");
+
+  int r;
+
+  caml_enter_blocking_section ();
+  r = guestfs_aug_save (g);
+  caml_leave_blocking_section ();
+  if (r == -1)
+    ocaml_guestfs_raise_error (g, "aug_save");
+
+  rv = Val_unit;
+  CAMLreturn (rv);
+}
+
+CAMLprim value
+ocaml_guestfs_aug_load (value gv)
+{
+  CAMLparam1 (gv);
+  CAMLlocal1 (rv);
+
+  guestfs_h *g = Guestfs_val (gv);
+  if (g == NULL)
+    caml_failwith ("aug_load: used handle after closing it");
+
+  int r;
+
+  caml_enter_blocking_section ();
+  r = guestfs_aug_load (g);
+  caml_leave_blocking_section ();
+  if (r == -1)
+    ocaml_guestfs_raise_error (g, "aug_load");
+
+  rv = Val_unit;
+  CAMLreturn (rv);
+}
+
index 3cc4775..99eb319 100644 (file)
@@ -485,3 +485,141 @@ PREINIT:
       }
       free (lines);
 
+void
+aug_init (g, root, flags)
+      guestfs_h *g;
+      char *root;
+      int flags;
+ PPCODE:
+      if (guestfs_aug_init (g, root, flags) == -1)
+        croak ("aug_init: %s", last_error);
+
+void
+aug_close (g)
+      guestfs_h *g;
+ PPCODE:
+      if (guestfs_aug_close (g) == -1)
+        croak ("aug_close: %s", last_error);
+
+SV *
+aug_defvar (g, name, expr)
+      guestfs_h *g;
+      char *name;
+      char *expr;
+PREINIT:
+      int nrnodes;
+   CODE:
+      nrnodes = guestfs_aug_defvar (g, name, expr);
+      if (nrnodes == -1)
+        croak ("aug_defvar: %s", last_error);
+      RETVAL = newSViv (nrnodes);
+ OUTPUT:
+      RETVAL
+
+void
+aug_defnode (g, name, expr, val)
+      guestfs_h *g;
+      char *name;
+      char *expr;
+      char *val;
+PREINIT:
+      struct guestfs_int_bool *r;
+ PPCODE:
+      r = guestfs_aug_defnode (g, name, expr, val);
+      if (r == NULL)
+        croak ("aug_defnode: %s", last_error);
+      EXTEND (SP, 2);
+      PUSHs (sv_2mortal (newSViv (r->i)));
+      PUSHs (sv_2mortal (newSViv (r->b)));
+      guestfs_free_int_bool (r);
+
+SV *
+aug_get (g, path)
+      guestfs_h *g;
+      char *path;
+PREINIT:
+      char *val;
+   CODE:
+      val = guestfs_aug_get (g, path);
+      if (val == NULL)
+        croak ("aug_get: %s", last_error);
+      RETVAL = newSVpv (val, 0);
+      free (val);
+ OUTPUT:
+      RETVAL
+
+void
+aug_set (g, path, val)
+      guestfs_h *g;
+      char *path;
+      char *val;
+ PPCODE:
+      if (guestfs_aug_set (g, path, val) == -1)
+        croak ("aug_set: %s", last_error);
+
+void
+aug_insert (g, path, label, before)
+      guestfs_h *g;
+      char *path;
+      char *label;
+      int before;
+ PPCODE:
+      if (guestfs_aug_insert (g, path, label, before) == -1)
+        croak ("aug_insert: %s", last_error);
+
+SV *
+aug_rm (g, path)
+      guestfs_h *g;
+      char *path;
+PREINIT:
+      int nrnodes;
+   CODE:
+      nrnodes = guestfs_aug_rm (g, path);
+      if (nrnodes == -1)
+        croak ("aug_rm: %s", last_error);
+      RETVAL = newSViv (nrnodes);
+ OUTPUT:
+      RETVAL
+
+void
+aug_mv (g, src, dest)
+      guestfs_h *g;
+      char *src;
+      char *dest;
+ PPCODE:
+      if (guestfs_aug_mv (g, src, dest) == -1)
+        croak ("aug_mv: %s", last_error);
+
+void
+aug_match (g, path)
+      guestfs_h *g;
+      char *path;
+PREINIT:
+      char **matches;
+      int i, n;
+ PPCODE:
+      matches = guestfs_aug_match (g, path);
+      if (matches == NULL)
+        croak ("aug_match: %s", last_error);
+      for (n = 0; matches[n] != NULL; ++n) /**/;
+      EXTEND (SP, n);
+      for (i = 0; i < n; ++i) {
+        PUSHs (sv_2mortal (newSVpv (matches[i], 0)));
+        free (matches[i]);
+      }
+      free (matches);
+
+void
+aug_save (g)
+      guestfs_h *g;
+ PPCODE:
+      if (guestfs_aug_save (g) == -1)
+        croak ("aug_save: %s", last_error);
+
+void
+aug_load (g)
+      guestfs_h *g;
+ PPCODE:
+      if (guestfs_aug_load (g) == -1)
+        croak ("aug_load: %s", last_error);
+
index 7706ae4..2941466 100644 (file)
@@ -112,6 +112,134 @@ image).
 
 This is equivalent to the qemu parameter C<-drive file=filename>.
 
+=item $h->aug_close ();
+
+Close the current Augeas handle and free up any resources
+used by it.  After calling this, you have to call
+C<$h-E<gt>aug_init> again before you can use any other
+Augeas functions.
+
+=item ($nrnodes, $created) = $h->aug_defnode (name, expr, val);
+
+Defines a variable C<name> whose value is the result of
+evaluating C<expr>.
+
+If C<expr> evaluates to an empty nodeset, a node is created,
+equivalent to calling C<$h-E<gt>aug_set> C<expr>, C<value>.
+C<name> will be the nodeset containing that single node.
+
+On success this returns a pair containing the
+number of nodes in the nodeset, and a boolean flag
+if a node was created.
+
+=item $nrnodes = $h->aug_defvar (name, expr);
+
+Defines an Augeas variable C<name> whose value is the result
+of evaluating C<expr>.  If C<expr> is NULL, then C<name> is
+undefined.
+
+On success this returns the number of nodes in C<expr>, or
+C<0> if C<expr> evaluates to something which is not a nodeset.
+
+=item $val = $h->aug_get (path);
+
+Look up the value associated with C<path>.  If C<path>
+matches exactly one node, the C<value> is returned.
+
+=item $h->aug_init (root, flags);
+
+Create a new Augeas handle for editing configuration files.
+If there was any previous Augeas handle associated with this
+guestfs session, then it is closed.
+
+You must call this before using any other C<$h-E<gt>aug_*>
+commands.
+
+C<root> is the filesystem root.  C<root> must not be NULL,
+use C</> instead.
+
+The flags are the same as the flags defined in
+E<lt>augeas.hE<gt>, the logical I<or> of the following
+integers:
+
+=over 4
+
+=item 1 C<AUG_SAVE_BACKUP>
+
+Keep the original file with a C<.augsave> extension.
+
+=item 2 C<AUG_SAVE_NEWFILE>
+
+Save changes into a file with extension C<.augnew>, and
+do not overwrite original.  Overrides C<AUG_SAVE_BACKUP>.
+
+=item 4 C<AUG_TYPE_CHECK>
+
+Typecheck lenses (can be expensive).
+
+=item 8 C<AUG_NO_STDINC>
+
+Do not use standard load path for modules.
+
+=item 16 C<AUG_SAVE_NOOP>
+
+Make save a no-op, just record what would have been changed.
+
+=item 32 C<AUG_NO_LOAD>
+
+Do not load the tree in C<$h-E<gt>aug_init>.
+
+=back
+
+To close the handle, you can call C<$h-E<gt>aug_close>.
+
+To find out more about Augeas, see L<http://augeas.net/>.
+
+=item $h->aug_insert (path, label, before);
+
+Create a new sibling C<label> for C<path>, inserting it into
+the tree before or after C<path> (depending on the boolean
+flag C<before>).
+
+C<path> must match exactly one existing node in the tree, and
+C<label> must be a label, ie. not contain C</>, C<*> or end
+with a bracketed index C<[N]>.
+
+=item $h->aug_load ();
+
+Load files into the tree.
+
+See C<aug_load> in the Augeas documentation for the full gory
+details.
+
+=item @matches = $h->aug_match (path);
+
+Returns a list of paths which match the path expression C<path>.
+The returned paths are sufficiently qualified so that they match
+exactly one node in the current tree.
+
+=item $h->aug_mv (src, dest);
+
+Move the node C<src> to C<dest>.  C<src> must match exactly
+one node.  C<dest> is overwritten if it exists.
+
+=item $nrnodes = $h->aug_rm (path);
+
+Remove C<path> and all of its children.
+
+On success this returns the number of entries which were removed.
+
+=item $h->aug_save ();
+
+This writes all pending changes to disk.
+
+The flags which were passed to C<$h-E<gt>aug_init> affect exactly
+how files are saved.
+
+=item $h->aug_set (path, val);
+
+Set the value associated with C<path> to C<value>.
+
 =item $content = $h->cat (path);
 
 Return the contents of the file named C<path>.
index af19fda..3f42c39 100755 (executable)
@@ -32,17 +32,25 @@ and ret =
      * indication, ie. 0 or -1.
      *)
   | Err
+    (* "Int" as a return value means an int which is -1 for error
+     * or any value >= 0 on success.
+     *)
+  | RInt of string
     (* "RBool" is a bool return value which can be true/false or
      * -1 for error.
      *)
   | RBool of string
     (* "RConstString" is a string that refers to a constant value.
-     * Try to avoid using this.
+     * Try to avoid using this.  In particular you cannot use this
+     * for values returned from the daemon, because there is no
+     * thread-safe way to return them in the C API.
      *)
   | RConstString of string
     (* "RString" and "RStringList" are caller-frees. *)
   | RString of string
   | RStringList of string
+    (* Some limited tuples are possible: *)
+  | RIntBool of string * string
     (* LVM PVs, VGs and LVs. *)
   | RPVList of string
   | RVGList of string
@@ -52,10 +60,12 @@ and args =
   | P0
   | P1 of argt
   | P2 of argt * argt
+  | P3 of argt * argt * argt
 and argt =
   | String of string   (* const char *name, cannot be NULL *)
   | OptString of string        (* const char *name, may be NULL *)
   | Bool of string     (* boolean *)
+  | Int of string      (* int (smallish ints, signed, <= 31 bits) *)
 
 type flags =
   | ProtocolLimitWarning  (* display warning about protocol size limits *)
@@ -323,6 +333,146 @@ Note that this function cannot correctly handle binary files
 (specifically, files containing C<\\0> character which is treated
 as end of line).  For those you need to use the C<guestfs_read_file>
 function which has a more complex interface.");
+
+  ("aug_init", (Err, P2 (String "root", Int "flags")), 16, [],
+   "create a new Augeas handle",
+   "\
+Create a new Augeas handle for editing configuration files.
+If there was any previous Augeas handle associated with this
+guestfs session, then it is closed.
+
+You must call this before using any other C<guestfs_aug_*>
+commands.
+
+C<root> is the filesystem root.  C<root> must not be NULL,
+use C</> instead.
+
+The flags are the same as the flags defined in
+E<lt>augeas.hE<gt>, the logical I<or> of the following
+integers:
+
+=over 4
+
+=item 1 C<AUG_SAVE_BACKUP>
+
+Keep the original file with a C<.augsave> extension.
+
+=item 2 C<AUG_SAVE_NEWFILE>
+
+Save changes into a file with extension C<.augnew>, and
+do not overwrite original.  Overrides C<AUG_SAVE_BACKUP>.
+
+=item 4 C<AUG_TYPE_CHECK>
+
+Typecheck lenses (can be expensive).
+
+=item 8 C<AUG_NO_STDINC>
+
+Do not use standard load path for modules.
+
+=item 16 C<AUG_SAVE_NOOP>
+
+Make save a no-op, just record what would have been changed.
+
+=item 32 C<AUG_NO_LOAD>
+
+Do not load the tree in C<guestfs_aug_init>.
+
+=back
+
+To close the handle, you can call C<guestfs_aug_close>.
+
+To find out more about Augeas, see L<http://augeas.net/>.");
+
+  ("aug_close", (Err, P0), 26, [],
+   "close the current Augeas handle",
+   "\
+Close the current Augeas handle and free up any resources
+used by it.  After calling this, you have to call
+C<guestfs_aug_init> again before you can use any other
+Augeas functions.");
+
+  ("aug_defvar", (RInt "nrnodes", P2 (String "name", OptString "expr")), 17, [],
+   "define an Augeas variable",
+   "\
+Defines an Augeas variable C<name> whose value is the result
+of evaluating C<expr>.  If C<expr> is NULL, then C<name> is
+undefined.
+
+On success this returns the number of nodes in C<expr>, or
+C<0> if C<expr> evaluates to something which is not a nodeset.");
+
+  ("aug_defnode", (RIntBool ("nrnodes", "created"), P3 (String "name", String "expr", String "val")), 18, [],
+   "define an Augeas node",
+   "\
+Defines a variable C<name> whose value is the result of
+evaluating C<expr>.
+
+If C<expr> evaluates to an empty nodeset, a node is created,
+equivalent to calling C<guestfs_aug_set> C<expr>, C<value>.
+C<name> will be the nodeset containing that single node.
+
+On success this returns a pair containing the
+number of nodes in the nodeset, and a boolean flag
+if a node was created.");
+
+  ("aug_get", (RString "val", P1 (String "path")), 19, [],
+   "look up the value of an Augeas path",
+   "\
+Look up the value associated with C<path>.  If C<path>
+matches exactly one node, the C<value> is returned.");
+
+  ("aug_set", (Err, P2 (String "path", String "val")), 20, [],
+   "set Augeas path to value",
+   "\
+Set the value associated with C<path> to C<value>.");
+
+  ("aug_insert", (Err, P3 (String "path", String "label", Bool "before")), 21, [],
+   "insert a sibling Augeas node",
+   "\
+Create a new sibling C<label> for C<path>, inserting it into
+the tree before or after C<path> (depending on the boolean
+flag C<before>).
+
+C<path> must match exactly one existing node in the tree, and
+C<label> must be a label, ie. not contain C</>, C<*> or end
+with a bracketed index C<[N]>.");
+
+  ("aug_rm", (RInt "nrnodes", P1 (String "path")), 22, [],
+   "remove an Augeas path",
+   "\
+Remove C<path> and all of its children.
+
+On success this returns the number of entries which were removed.");
+
+  ("aug_mv", (Err, P2 (String "src", String "dest")), 23, [],
+   "move Augeas node",
+   "\
+Move the node C<src> to C<dest>.  C<src> must match exactly
+one node.  C<dest> is overwritten if it exists.");
+
+  ("aug_match", (RStringList "matches", P1 (String "path")), 24, [],
+   "return Augeas nodes which match path",
+   "\
+Returns a list of paths which match the path expression C<path>.
+The returned paths are sufficiently qualified so that they match
+exactly one node in the current tree.");
+
+  ("aug_save", (Err, P0), 25, [],
+   "write all pending Augeas changes to disk",
+   "\
+This writes all pending changes to disk.
+
+The flags which were passed to C<guestfs_aug_init> affect exactly
+how files are saved.");
+
+  ("aug_load", (Err, P0), 27, [],
+   "load files into the tree",
+   "\
+Load files into the tree.
+
+See C<aug_load> in the Augeas documentation for the full gory
+details.");
 ]
 
 let all_functions = non_daemon_functions @ daemon_functions
@@ -465,18 +615,25 @@ let iter_args f = function
   | P0 -> ()
   | P1 arg1 -> f arg1
   | P2 (arg1, arg2) -> f arg1; f arg2
+  | P3 (arg1, arg2, arg3) -> f arg1; f arg2; f arg3
 
 let iteri_args f = function
   | P0 -> ()
   | P1 arg1 -> f 0 arg1
   | P2 (arg1, arg2) -> f 0 arg1; f 1 arg2
+  | P3 (arg1, arg2, arg3) -> f 0 arg1; f 1 arg2; f 2 arg3
 
 let map_args f = function
   | P0 -> []
   | P1 arg1 -> [f arg1]
-  | P2 (arg1, arg2) -> [f arg1; f arg2]
+  | P2 (arg1, arg2) ->
+      let n1 = f arg1 in let n2 = f arg2 in [n1; n2]
+  | P3 (arg1, arg2, arg3) ->
+      let n1 = f arg1 in let n2 = f arg2 in let n3 = f arg3 in [n1; n2; n3]
+
+let nr_args = function | P0 -> 0 | P1 _ -> 1 | P2 _ -> 2 | P3 _ -> 3
 
-let nr_args = function | P0 -> 0 | P1 _ -> 1 | P2 _ -> 2
+let name_of_argt = function String n | OptString n | Bool n | Int n -> n
 
 (* Check function names etc. for consistency. *)
 let check_functions () =
@@ -583,6 +740,8 @@ and generate_actions_pod () =
       (match fst style with
        | Err ->
           pr "This function returns 0 on success or -1 on error.\n\n"
+       | RInt _ ->
+          pr "On error this function returns -1.\n\n"
        | RBool _ ->
           pr "This function returns a C truth value on success or -1 on error.\n\n"
        | RConstString _ ->
@@ -595,14 +754,17 @@ I<The caller must free the returned string after use>.\n\n"
           pr "This function returns a NULL-terminated array of strings
 (like L<environ(3)>), or NULL if there was an error.
 I<The caller must free the strings and the array after use>.\n\n"
+       | RIntBool _ ->
+          pr "This function returns a C<struct guestfs_int_bool *>.
+I<The caller must call C<guestfs_free_int_bool> after use.>.\n\n"
        | RPVList _ ->
-          pr "This function returns a C<struct guestfs_lvm_pv_list>.
+          pr "This function returns a C<struct guestfs_lvm_pv_list *>.
 I<The caller must call C<guestfs_free_lvm_pv_list> after use.>.\n\n"
        | RVGList _ ->
-          pr "This function returns a C<struct guestfs_lvm_vg_list>.
+          pr "This function returns a C<struct guestfs_lvm_vg_list *>.
 I<The caller must call C<guestfs_free_lvm_vg_list> after use.>.\n\n"
        | RLVList _ ->
-          pr "This function returns a C<struct guestfs_lvm_lv_list>.
+          pr "This function returns a C<struct guestfs_lvm_lv_list *>.
 I<The caller must call C<guestfs_free_lvm_lv_list> after use.>.\n\n"
       );
       if List.mem ProtocolLimitWarning flags then
@@ -676,21 +838,26 @@ and generate_xdr () =
   List.iter (
     fun(shortname, style, _, _, _, _) ->
       let name = "guestfs_" ^ shortname in
-      pr "/* %s */\n\n" name;
+
       (match snd style with
        | P0 -> ()
        | args ->
           pr "struct %s_args {\n" name;
           iter_args (
             function
-            | String name -> pr "  string %s<>;\n" name
-            | OptString name -> pr "  string *%s<>;\n" name
-            | Bool name -> pr "  bool %s;\n" name
+            | String n -> pr "  string %s<>;\n" n
+            | OptString n -> pr "  str *%s;\n" n
+            | Bool n -> pr "  bool %s;\n" n
+            | Int n -> pr "  int %s;\n" n
           ) args;
           pr "};\n\n"
       );
       (match fst style with
        | Err -> ()
+       | RInt n ->
+          pr "struct %s_ret {\n" name;
+          pr "  int %s;\n" n;
+          pr "};\n\n"
        | RBool n ->
           pr "struct %s_ret {\n" name;
           pr "  bool %s;\n" n;
@@ -705,6 +872,11 @@ and generate_xdr () =
           pr "struct %s_ret {\n" name;
           pr "  str %s<>;\n" n;
           pr "};\n\n"
+       | RIntBool (n,m) ->
+          pr "struct %s_ret {\n" name;
+          pr "  int %s;\n" n;
+          pr "  bool %s;\n" m;
+          pr "};\n\n"
        | RPVList n ->
           pr "struct %s_ret {\n" name;
           pr "  guestfs_lvm_int_pv_list %s;\n" n;
@@ -788,6 +960,13 @@ and generate_structs_h () =
    * must be identical to what rpcgen / the RFC defines.
    *)
 
+  (* guestfs_int_bool structure. *)
+  pr "struct guestfs_int_bool {\n";
+  pr "  int32_t i;\n";
+  pr "  int32_t b;\n";
+  pr "};\n";
+  pr "\n";
+
   (* LVM public structures. *)
   List.iter (
     function
@@ -838,7 +1017,9 @@ and generate_client_actions () =
        | Err -> ()
        | RConstString _ ->
           failwithf "RConstString cannot be returned from a daemon function"
+       | RInt _
        | RBool _ | RString _ | RStringList _
+       | RIntBool _
        | RPVList _ | RVGList _ | RLVList _ ->
           pr "  struct %s_ret ret;\n" name
       );
@@ -865,7 +1046,9 @@ and generate_client_actions () =
        | Err -> ()
        | RConstString _ ->
           failwithf "RConstString cannot be returned from a daemon function"
+       | RInt _
        | RBool _ | RString _ | RStringList _
+       | RIntBool _
        | RPVList _ | RVGList _ | RLVList _ ->
            pr "  if (!xdr_%s_ret (xdr, &rv->ret)) {\n" name;
            pr "    error (g, \"%s: failed to parse reply\");\n" name;
@@ -884,10 +1067,11 @@ and generate_client_actions () =
 
       let error_code =
        match fst style with
-       | Err | RBool _ -> "-1"
+       | Err | RInt _ | RBool _ -> "-1"
        | RConstString _ ->
            failwithf "RConstString cannot be returned from a daemon function"
-       | RString _ | RStringList _ | RPVList _ | RVGList _ | RLVList _ ->
+       | RString _ | RStringList _ | RIntBool _
+       | RPVList _ | RVGList _ | RLVList _ ->
            "NULL" in
 
       pr "{\n";
@@ -917,12 +1101,14 @@ and generate_client_actions () =
        | args ->
           iter_args (
             function
-            | String name ->
-                pr "  args.%s = (char *) %s;\n" name name
-            | OptString name ->
-                pr "  args.%s = %s ? *%s : NULL;\n" name name name
-            | Bool name ->
-                pr "  args.%s = %s;\n" name name
+            | String n ->
+                pr "  args.%s = (char *) %s;\n" n n
+            | OptString n ->
+                pr "  args.%s = %s ? (char **) &%s : NULL;\n" n n n
+            | Bool n ->
+                pr "  args.%s = %s;\n" n n
+            | Int n ->
+                pr "  args.%s = %s;\n" n n
           ) args;
           pr "  serial = dispatch (g, GUESTFS_PROC_%s,\n"
             (String.uppercase shortname);
@@ -958,6 +1144,7 @@ and generate_client_actions () =
 
       (match fst style with
        | Err -> pr "  return 0;\n"
+       | RInt n
        | RBool n -> pr "  return rv.ret.%s;\n" n
        | RConstString _ ->
           failwithf "RConstString cannot be returned from a daemon function"
@@ -971,6 +1158,9 @@ and generate_client_actions () =
             n n;
           pr "  rv.ret.%s.%s_val[rv.ret.%s.%s_len] = NULL;\n" n n n n;
           pr "  return rv.ret.%s.%s_val;\n" n n
+       | RIntBool _ ->
+          pr "  /* caller with free this */\n";
+          pr "  return safe_memdup (g, &rv.ret, sizeof (rv.ret));\n"
        | RPVList n ->
           pr "  /* caller will free this */\n";
           pr "  return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n
@@ -995,7 +1185,8 @@ and generate_daemon_actions_h () =
   List.iter (
     fun (name, style, _, _, _, _) ->
        generate_prototype
-         ~single_line:true ~newline:true ~in_daemon:true ("do_" ^ name) style;
+         ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
+         name style;
   ) daemon_functions
 
 (* Generate the server-side stubs. *)
@@ -1024,12 +1215,13 @@ and generate_daemon_actions () =
       pr "{\n";
       let error_code =
        match fst style with
-       | Err -> pr "  int r;\n"; "-1"
+       | Err | RInt _ -> pr "  int r;\n"; "-1"
        | RBool _ -> pr "  int r;\n"; "-1"
        | RConstString _ ->
            failwithf "RConstString cannot be returned from a daemon function"
        | RString _ -> pr "  char *r;\n"; "NULL"
        | RStringList _ -> pr "  char **r;\n"; "NULL"
+       | RIntBool _ -> pr "  guestfs_%s_ret *r;\n" name; "NULL"
        | RPVList _ -> pr "  guestfs_lvm_int_pv_list *r;\n"; "NULL"
        | RVGList _ -> pr "  guestfs_lvm_int_vg_list *r;\n"; "NULL"
        | RLVList _ -> pr "  guestfs_lvm_int_lv_list *r;\n"; "NULL" in
@@ -1040,9 +1232,10 @@ and generate_daemon_actions () =
           pr "  struct guestfs_%s_args args;\n" name;
           iter_args (
             function
-            | String name
-            | OptString name -> pr "  const char *%s;\n" name
-            | Bool name -> pr "  int %s;\n" name
+            | String n
+            | OptString n -> pr "  const char *%s;\n" n
+            | Bool n -> pr "  int %s;\n" n
+            | Int n -> pr "  int %s;\n" n
           ) args
       );
       pr "\n";
@@ -1053,14 +1246,15 @@ and generate_daemon_actions () =
           pr "  memset (&args, 0, sizeof args);\n";
           pr "\n";
           pr "  if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
-          pr "    reply_with_error (\"%s: daemon failed to decode procedure arguments\");\n" name;
+          pr "    reply_with_error (\"%%s: daemon failed to decode procedure arguments\", \"%s\");\n" name;
           pr "    return;\n";
           pr "  }\n";
           iter_args (
             function
-            | String name -> pr "  %s = args.%s;\n" name name
-            | OptString name -> pr "  %s = args.%s;\n" name name (* XXX? *)
-            | Bool name -> pr "  %s = args.%s;\n" name name
+            | String n -> pr "  %s = args.%s;\n" n n
+            | OptString n -> pr "  %s = args.%s ? *args.%s : NULL;\n" n n n
+            | Bool n -> pr "  %s = args.%s;\n" n n
+            | Int n -> pr "  %s = args.%s;\n" n n
           ) args;
           pr "\n"
       );
@@ -1076,6 +1270,10 @@ and generate_daemon_actions () =
 
       (match fst style with
        | Err -> pr "  reply (NULL, NULL);\n"
+       | RInt n ->
+          pr "  struct guestfs_%s_ret ret;\n" name;
+          pr "  ret.%s = r;\n" n;
+          pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name
        | RBool n ->
           pr "  struct guestfs_%s_ret ret;\n" name;
           pr "  ret.%s = r;\n" n;
@@ -1093,20 +1291,23 @@ and generate_daemon_actions () =
           pr "  ret.%s.%s_val = r;\n" n n;
           pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name;
           pr "  free_strings (r);\n"
+       | RIntBool _ ->
+          pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name;
+          pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name
        | RPVList n ->
           pr "  struct guestfs_%s_ret ret;\n" name;
           pr "  ret.%s = *r;\n" n;
-          pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name;
+          pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name;
           pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name
        | RVGList n ->
           pr "  struct guestfs_%s_ret ret;\n" name;
           pr "  ret.%s = *r;\n" n;
-          pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name;
+          pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name;
           pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name
        | RLVList n ->
           pr "  struct guestfs_%s_ret ret;\n" name;
           pr "  ret.%s = *r;\n" n;
-          pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name;
+          pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name;
           pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name
       );
 
@@ -1348,12 +1549,7 @@ and generate_fish_cmds () =
        | P0 -> name2
        | args ->
            sprintf "%s <%s>"
-             name2 (
-               String.concat "> <" (
-                 map_args (function
-                           | String n | OptString n | Bool n -> n) args
-               )
-             ) in
+             name2 (String.concat "> <" (map_args name_of_argt args)) in
 
       let warnings =
        if List.mem ProtocolLimitWarning flags then
@@ -1429,19 +1625,22 @@ FTP."
       pr "{\n";
       (match fst style with
        | Err
+       | RInt _
        | RBool _ -> pr "  int r;\n"
        | RConstString _ -> pr "  const char *r;\n"
        | RString _ -> pr "  char *r;\n"
        | RStringList _ -> pr "  char **r;\n"
+       | RIntBool _ -> pr "  struct guestfs_int_bool *r;\n"
        | RPVList _ -> pr "  struct guestfs_lvm_pv_list *r;\n"
        | RVGList _ -> pr "  struct guestfs_lvm_vg_list *r;\n"
        | RLVList _ -> pr "  struct guestfs_lvm_lv_list *r;\n"
       );
       iter_args (
        function
-       | String name -> pr "  const char *%s;\n" name
-       | OptString name -> pr "  const char *%s;\n" name
-       | Bool name -> pr "  int %s;\n" name
+       | String n -> pr "  const char *%s;\n" n
+       | OptString n -> pr "  const char *%s;\n" n
+       | Bool n -> pr "  int %s;\n" n
+       | Int n -> pr "  int %s;\n" n
       ) (snd style);
 
       (* Check and convert parameters. *)
@@ -1461,6 +1660,8 @@ FTP."
                name i i
          | Bool name ->
              pr "  %s = is_true (argv[%d]) ? 1 : 0;\n" name i
+         | Int name ->
+             pr "  %s = atoi (argv[%d]);\n" name i
       ) (snd style);
 
       (* Call C API function. *)
@@ -1474,6 +1675,10 @@ FTP."
       (* Check return value for errors and display command results. *)
       (match fst style with
        | Err -> pr "  return r;\n"
+       | RInt _ ->
+          pr "  if (r == -1) return -1;\n";
+          pr "  if (r) printf (\"%%d\\n\", r);\n";
+          pr "  return 0;\n"
        | RBool _ ->
           pr "  if (r == -1) return -1;\n";
           pr "  if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
@@ -1492,6 +1697,12 @@ FTP."
           pr "  print_strings (r);\n";
           pr "  free_strings (r);\n";
           pr "  return 0;\n"
+       | RIntBool _ ->
+          pr "  if (r == NULL) return -1;\n";
+          pr "  printf (\"%%d, %%s\\n\", r->i,\n";
+          pr "    r->b ? \"true\" : \"false\");\n";
+          pr "  guestfs_free_int_bool (r);\n";
+          pr "  return 0;\n"
        | RPVList _ ->
           pr "  if (r == NULL) return -1;\n";
           pr "  print_pv_list (r);\n";
@@ -1565,6 +1776,7 @@ and generate_fish_actions_pod () =
        | String n -> pr " %s" n
        | OptString n -> pr " %s" n
        | Bool _ -> pr " true|false"
+       | Int n -> pr " %s" n
       ) (snd style);
       pr "\n";
       pr "\n";
@@ -1574,15 +1786,20 @@ and generate_fish_actions_pod () =
 (* Generate a C function prototype. *)
 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
     ?(single_line = false) ?(newline = false) ?(in_daemon = false)
+    ?(prefix = "")
     ?handle name style =
   if extern then pr "extern ";
   if static then pr "static ";
   (match fst style with
    | Err -> pr "int "
+   | RInt _ -> pr "int "
    | RBool _ -> pr "int "
    | RConstString _ -> pr "const char *"
    | RString _ -> pr "char *"
    | RStringList _ -> pr "char **"
+   | RIntBool _ ->
+       if not in_daemon then pr "struct guestfs_int_bool *"
+       else pr "guestfs_%s_ret *" name
    | RPVList _ ->
        if not in_daemon then pr "struct guestfs_lvm_pv_list *"
        else pr "guestfs_lvm_int_pv_list *"
@@ -1593,24 +1810,29 @@ and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
        if not in_daemon then pr "struct guestfs_lvm_lv_list *"
        else pr "guestfs_lvm_int_lv_list *"
   );
-  pr "%s (" name;
-  let comma = ref false in
-  (match handle with
-   | None -> ()
-   | Some handle -> pr "guestfs_h *%s" handle; comma := true
-  );
-  let next () =
-    if !comma then (
-      if single_line then pr ", " else pr ",\n\t\t"
+  pr "%s%s (" prefix name;
+  if handle = None && nr_args (snd style) = 0 then
+    pr "void"
+  else (
+    let comma = ref false in
+    (match handle with
+     | None -> ()
+     | Some handle -> pr "guestfs_h *%s" handle; comma := true
     );
-    comma := true
-  in
-  iter_args (
-    function
-    | String name -> next (); pr "const char *%s" name
-    | OptString name -> next (); pr "const char *%s" name
-    | Bool name -> next (); pr "int %s" name
-  ) (snd style);
+    let next () =
+      if !comma then (
+       if single_line then pr ", " else pr ",\n\t\t"
+      );
+      comma := true
+    in
+    iter_args (
+      function
+      | String n -> next (); pr "const char *%s" n
+      | OptString n -> next (); pr "const char *%s" n
+      | Bool n -> next (); pr "int %s" n
+      | Int n -> next (); pr "int %s" n
+    ) (snd style);
+  );
   pr ")";
   if semicolon then pr ";";
   if newline then pr "\n"
@@ -1628,9 +1850,10 @@ and generate_call_args ?handle style =
       if !comma then pr ", ";
       comma := true;
       match arg with
-      | String name -> pr "%s" name
-      | OptString name -> pr "%s" name
-      | Bool name -> pr "%s" name
+      | String n -> pr "%s" n
+      | OptString n -> pr "%s" n
+      | Bool n -> pr "%s" n
+      | Int n -> pr "%s" n
   ) (snd style);
   pr ")"
 
@@ -1779,15 +2002,13 @@ and generate_ocaml_c () =
       pr "CAMLprim value\n";
       pr "ocaml_guestfs_%s (value gv" name;
       iter_args (
-       function
-       | String n | OptString n | Bool n -> pr ", value %sv" n
+       fun arg -> pr ", value %sv" (name_of_argt arg)
       ) (snd style);
       pr ")\n";
       pr "{\n";
       pr "  CAMLparam%d (gv" (1 + (nr_args (snd style)));
       iter_args (
-       function
-       | String n | OptString n | Bool n -> pr ", %sv" n
+       fun arg -> pr ", %sv" (name_of_argt arg)
       ) (snd style);
       pr ");\n";
       pr "  CAMLlocal1 (rv);\n";
@@ -1808,10 +2029,13 @@ and generate_ocaml_c () =
              n n
        | Bool n ->
            pr "  int %s = Bool_val (%sv);\n" n n
+       | Int n ->
+           pr "  int %s = Int_val (%sv);\n" n n
       ) (snd style);
       let error_code =
        match fst style with
        | Err -> pr "  int r;\n"; "-1"
+       | RInt _ -> pr "  int r;\n"; "-1"
        | RBool _ -> pr "  int r;\n"; "-1"
        | RConstString _ -> pr "  const char *r;\n"; "NULL"
        | RString _ -> pr "  char *r;\n"; "NULL"
@@ -1819,6 +2043,9 @@ and generate_ocaml_c () =
            pr "  int i;\n";
            pr "  char **r;\n";
            "NULL"
+       | RIntBool _ ->
+           pr "  struct guestfs_int_bool *r;\n";
+           "NULL"
        | RPVList _ ->
            pr "  struct guestfs_lvm_pv_list *r;\n";
            "NULL"
@@ -1841,7 +2068,8 @@ and generate_ocaml_c () =
 
       (match fst style with
        | Err -> pr "  rv = Val_unit;\n"
-       | RBool _ -> pr "  rv = r ? Val_true : Val_false;\n"
+       | RInt _ -> pr "  rv = Val_int (r);\n"
+       | RBool _ -> pr "  rv = Val_bool (r);\n"
        | RConstString _ -> pr "  rv = caml_copy_string (r);\n"
        | RString _ ->
           pr "  rv = caml_copy_string (r);\n";
@@ -1850,6 +2078,11 @@ and generate_ocaml_c () =
           pr "  rv = caml_copy_string_array ((const char **) r);\n";
           pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
           pr "  free (r);\n"
+       | RIntBool _ ->
+          pr "  rv = caml_alloc (2, 0);\n";
+          pr "  Store_field (rv, 0, Val_int (r->i));\n";
+          pr "  Store_field (rv, 1, Val_bool (r->b));\n";
+          pr "  guestfs_free_int_bool (r);\n";
        | RPVList _ ->
           pr "  rv = copy_lvm_pv_list (r);\n";
           pr "  guestfs_free_lvm_pv_list (r);\n";
@@ -1890,13 +2123,16 @@ and generate_ocaml_prototype ?(is_external = false) name style =
     | String _ -> pr "string -> "
     | OptString _ -> pr "string option -> "
     | Bool _ -> pr "bool -> "
+    | Int _ -> pr "int -> "
   ) (snd style);
   (match fst style with
    | Err -> pr "unit" (* all errors are turned into exceptions *)
+   | RInt _ -> pr "int"
    | RBool _ -> pr "bool"
    | RConstString _ -> pr "string"
    | RString _ -> pr "string"
    | RStringList _ -> pr "string array"
+   | RIntBool _ -> pr "int * bool"
    | RPVList _ -> pr "lvm_pv array"
    | RVGList _ -> pr "lvm_vg array"
    | RLVList _ -> pr "lvm_lv array"
@@ -1987,10 +2223,12 @@ DESTROY (g)
     fun (name, style, _, _, _, _) ->
       (match fst style with
        | Err -> pr "void\n"
+       | RInt _ -> pr "SV *\n"
        | RBool _ -> pr "SV *\n"
        | RConstString _ -> pr "SV *\n"
        | RString _ -> pr "SV *\n"
        | RStringList _
+       | RIntBool _
        | RPVList _ | RVGList _ | RLVList _ ->
           pr "void\n" (* all lists returned implictly on the stack *)
       );
@@ -2004,6 +2242,7 @@ DESTROY (g)
        | String n -> pr "      char *%s;\n" n
        | OptString n -> pr "      char *%s;\n" n
        | Bool n -> pr "      int %s;\n" n
+       | Int n -> pr "      int %s;\n" n
       ) (snd style);
       (* Code. *)
       (match fst style with
@@ -2013,21 +2252,22 @@ DESTROY (g)
           generate_call_args ~handle:"g" style;
           pr " == -1)\n";
           pr "        croak (\"%s: %%s\", last_error);\n" name
-       | RConstString n ->
+       | RInt n
+       | RBool n ->
           pr "PREINIT:\n";
-          pr "      const char *%s;\n" n;
+          pr "      int %s;\n" n;
           pr "   CODE:\n";
           pr "      %s = guestfs_%s " n name;
           generate_call_args ~handle:"g" style;
           pr ";\n";
-          pr "      if (%s == NULL)\n" n;
+          pr "      if (%s == -1)\n" n;
           pr "        croak (\"%s: %%s\", last_error);\n" name;
-          pr "      RETVAL = newSVpv (%s, 0);\n" n;
+          pr "      RETVAL = newSViv (%s);\n" n;
           pr " OUTPUT:\n";
           pr "      RETVAL\n"
-       | RString n ->
+       | RConstString n ->
           pr "PREINIT:\n";
-          pr "      char *%s;\n" n;
+          pr "      const char *%s;\n" n;
           pr "   CODE:\n";
           pr "      %s = guestfs_%s " n name;
           generate_call_args ~handle:"g" style;
@@ -2035,19 +2275,19 @@ DESTROY (g)
           pr "      if (%s == NULL)\n" n;
           pr "        croak (\"%s: %%s\", last_error);\n" name;
           pr "      RETVAL = newSVpv (%s, 0);\n" n;
-          pr "      free (%s);\n" n;
           pr " OUTPUT:\n";
           pr "      RETVAL\n"
-       | RBool n ->
+       | RString n ->
           pr "PREINIT:\n";
-          pr "      int %s;\n" n;
+          pr "      char *%s;\n" n;
           pr "   CODE:\n";
           pr "      %s = guestfs_%s " n name;
           generate_call_args ~handle:"g" style;
           pr ";\n";
-          pr "      if (%s == -1)\n" n;
+          pr "      if (%s == NULL)\n" n;
           pr "        croak (\"%s: %%s\", last_error);\n" name;
-          pr "      RETVAL = newSViv (%s);\n" n;
+          pr "      RETVAL = newSVpv (%s, 0);\n" n;
+          pr "      free (%s);\n" n;
           pr " OUTPUT:\n";
           pr "      RETVAL\n"
        | RStringList n ->
@@ -2067,6 +2307,19 @@ DESTROY (g)
           pr "        free (%s[i]);\n" n;
           pr "      }\n";
           pr "      free (%s);\n" n;
+       | RIntBool _ ->
+          pr "PREINIT:\n";
+          pr "      struct guestfs_int_bool *r;\n";
+          pr " PPCODE:\n";
+          pr "      r = guestfs_%s " name;
+          generate_call_args ~handle:"g" style;
+          pr ";\n";
+          pr "      if (r == NULL)\n";
+          pr "        croak (\"%s: %%s\", last_error);\n" name;
+          pr "      EXTEND (SP, 2);\n";
+          pr "      PUSHs (sv_2mortal (newSViv (r->i)));\n";
+          pr "      PUSHs (sv_2mortal (newSViv (r->b)));\n";
+          pr "      guestfs_free_int_bool (r);\n";
        | RPVList n ->
           generate_perl_lvm_code "pv" pv_cols name style n;
        | RVGList n ->
@@ -2236,8 +2489,10 @@ and generate_perl_prototype name style =
   (match fst style with
    | Err -> ()
    | RBool n
+   | RInt n
    | RConstString n
    | RString n -> pr "$%s = " n
+   | RIntBool (n, m) -> pr "($%s, $%s) = " n m
    | RStringList n
    | RPVList n
    | RVGList n
@@ -2249,10 +2504,7 @@ and generate_perl_prototype name style =
     fun arg ->
       if !comma then pr ", ";
       comma := true;
-      match arg with
-      | String n -> pr "%s" n
-      | OptString n -> pr "%s" n
-      | Bool n -> pr "%s" n
+      pr "%s" (name_of_argt arg)
   ) (snd style);
   pr ");"
 
index ebde5fc..0bb868c 100644 (file)
@@ -1111,3 +1111,865 @@ char **guestfs_read_lines (guestfs_h *g,
   return rv.ret.lines.lines_val;
 }
 
+struct aug_init_rv {
+  int cb_done;  /* flag to indicate callback was called */
+  struct guestfs_message_header hdr;
+  struct guestfs_message_error err;
+};
+
+static void aug_init_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+  struct aug_init_rv *rv = (struct aug_init_rv *) data;
+
+  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+    error (g, "guestfs_aug_init: failed to parse reply header");
+    return;
+  }
+  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+      error (g, "guestfs_aug_init: failed to parse reply error");
+      return;
+    }
+    goto done;
+  }
+ done:
+  rv->cb_done = 1;
+  main_loop.main_loop_quit (g);
+}
+
+int guestfs_aug_init (guestfs_h *g,
+               const char *root,
+               int flags)
+{
+  struct guestfs_aug_init_args args;
+  struct aug_init_rv rv;
+  int serial;
+
+  if (g->state != READY) {
+    error (g, "guestfs_aug_init called from the wrong state, %d != READY",
+      g->state);
+    return -1;
+  }
+
+  memset (&rv, 0, sizeof rv);
+
+  args.root = (char *) root;
+  args.flags = flags;
+  serial = dispatch (g, GUESTFS_PROC_AUG_INIT,
+                     (xdrproc_t) xdr_guestfs_aug_init_args, (char *) &args);
+  if (serial == -1)
+    return -1;
+
+  rv.cb_done = 0;
+  g->reply_cb_internal = aug_init_cb;
+  g->reply_cb_internal_data = &rv;
+  main_loop.main_loop_run (g);
+  g->reply_cb_internal = NULL;
+  g->reply_cb_internal_data = NULL;
+  if (!rv.cb_done) {
+    error (g, "guestfs_aug_init failed, see earlier error messages");
+    return -1;
+  }
+
+  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_AUG_INIT, serial) == -1)
+    return -1;
+
+  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", rv.err.error);
+    return -1;
+  }
+
+  return 0;
+}
+
+struct aug_close_rv {
+  int cb_done;  /* flag to indicate callback was called */
+  struct guestfs_message_header hdr;
+  struct guestfs_message_error err;
+};
+
+static void aug_close_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+  struct aug_close_rv *rv = (struct aug_close_rv *) data;
+
+  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+    error (g, "guestfs_aug_close: failed to parse reply header");
+    return;
+  }
+  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+      error (g, "guestfs_aug_close: failed to parse reply error");
+      return;
+    }
+    goto done;
+  }
+ done:
+  rv->cb_done = 1;
+  main_loop.main_loop_quit (g);
+}
+
+int guestfs_aug_close (guestfs_h *g)
+{
+  struct aug_close_rv rv;
+  int serial;
+
+  if (g->state != READY) {
+    error (g, "guestfs_aug_close called from the wrong state, %d != READY",
+      g->state);
+    return -1;
+  }
+
+  memset (&rv, 0, sizeof rv);
+
+  serial = dispatch (g, GUESTFS_PROC_AUG_CLOSE, NULL, NULL);
+  if (serial == -1)
+    return -1;
+
+  rv.cb_done = 0;
+  g->reply_cb_internal = aug_close_cb;
+  g->reply_cb_internal_data = &rv;
+  main_loop.main_loop_run (g);
+  g->reply_cb_internal = NULL;
+  g->reply_cb_internal_data = NULL;
+  if (!rv.cb_done) {
+    error (g, "guestfs_aug_close failed, see earlier error messages");
+    return -1;
+  }
+
+  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_AUG_CLOSE, serial) == -1)
+    return -1;
+
+  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", rv.err.error);
+    return -1;
+  }
+
+  return 0;
+}
+
+struct aug_defvar_rv {
+  int cb_done;  /* flag to indicate callback was called */
+  struct guestfs_message_header hdr;
+  struct guestfs_message_error err;
+  struct guestfs_aug_defvar_ret ret;
+};
+
+static void aug_defvar_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+  struct aug_defvar_rv *rv = (struct aug_defvar_rv *) data;
+
+  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+    error (g, "guestfs_aug_defvar: failed to parse reply header");
+    return;
+  }
+  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+      error (g, "guestfs_aug_defvar: failed to parse reply error");
+      return;
+    }
+    goto done;
+  }
+  if (!xdr_guestfs_aug_defvar_ret (xdr, &rv->ret)) {
+    error (g, "guestfs_aug_defvar: failed to parse reply");
+    return;
+  }
+ done:
+  rv->cb_done = 1;
+  main_loop.main_loop_quit (g);
+}
+
+int guestfs_aug_defvar (guestfs_h *g,
+               const char *name,
+               const char *expr)
+{
+  struct guestfs_aug_defvar_args args;
+  struct aug_defvar_rv rv;
+  int serial;
+
+  if (g->state != READY) {
+    error (g, "guestfs_aug_defvar called from the wrong state, %d != READY",
+      g->state);
+    return -1;
+  }
+
+  memset (&rv, 0, sizeof rv);
+
+  args.name = (char *) name;
+  args.expr = expr ? (char **) &expr : NULL;
+  serial = dispatch (g, GUESTFS_PROC_AUG_DEFVAR,
+                     (xdrproc_t) xdr_guestfs_aug_defvar_args, (char *) &args);
+  if (serial == -1)
+    return -1;
+
+  rv.cb_done = 0;
+  g->reply_cb_internal = aug_defvar_cb;
+  g->reply_cb_internal_data = &rv;
+  main_loop.main_loop_run (g);
+  g->reply_cb_internal = NULL;
+  g->reply_cb_internal_data = NULL;
+  if (!rv.cb_done) {
+    error (g, "guestfs_aug_defvar failed, see earlier error messages");
+    return -1;
+  }
+
+  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_AUG_DEFVAR, serial) == -1)
+    return -1;
+
+  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", rv.err.error);
+    return -1;
+  }
+
+  return rv.ret.nrnodes;
+}
+
+struct aug_defnode_rv {
+  int cb_done;  /* flag to indicate callback was called */
+  struct guestfs_message_header hdr;
+  struct guestfs_message_error err;
+  struct guestfs_aug_defnode_ret ret;
+};
+
+static void aug_defnode_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+  struct aug_defnode_rv *rv = (struct aug_defnode_rv *) data;
+
+  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+    error (g, "guestfs_aug_defnode: failed to parse reply header");
+    return;
+  }
+  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+      error (g, "guestfs_aug_defnode: failed to parse reply error");
+      return;
+    }
+    goto done;
+  }
+  if (!xdr_guestfs_aug_defnode_ret (xdr, &rv->ret)) {
+    error (g, "guestfs_aug_defnode: failed to parse reply");
+    return;
+  }
+ done:
+  rv->cb_done = 1;
+  main_loop.main_loop_quit (g);
+}
+
+struct guestfs_int_bool *guestfs_aug_defnode (guestfs_h *g,
+               const char *name,
+               const char *expr,
+               const char *val)
+{
+  struct guestfs_aug_defnode_args args;
+  struct aug_defnode_rv rv;
+  int serial;
+
+  if (g->state != READY) {
+    error (g, "guestfs_aug_defnode called from the wrong state, %d != READY",
+      g->state);
+    return NULL;
+  }
+
+  memset (&rv, 0, sizeof rv);
+
+  args.name = (char *) name;
+  args.expr = (char *) expr;
+  args.val = (char *) val;
+  serial = dispatch (g, GUESTFS_PROC_AUG_DEFNODE,
+                     (xdrproc_t) xdr_guestfs_aug_defnode_args, (char *) &args);
+  if (serial == -1)
+    return NULL;
+
+  rv.cb_done = 0;
+  g->reply_cb_internal = aug_defnode_cb;
+  g->reply_cb_internal_data = &rv;
+  main_loop.main_loop_run (g);
+  g->reply_cb_internal = NULL;
+  g->reply_cb_internal_data = NULL;
+  if (!rv.cb_done) {
+    error (g, "guestfs_aug_defnode failed, see earlier error messages");
+    return NULL;
+  }
+
+  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_AUG_DEFNODE, serial) == -1)
+    return NULL;
+
+  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", rv.err.error);
+    return NULL;
+  }
+
+  /* caller with free this */
+  return safe_memdup (g, &rv.ret, sizeof (rv.ret));
+}
+
+struct aug_get_rv {
+  int cb_done;  /* flag to indicate callback was called */
+  struct guestfs_message_header hdr;
+  struct guestfs_message_error err;
+  struct guestfs_aug_get_ret ret;
+};
+
+static void aug_get_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+  struct aug_get_rv *rv = (struct aug_get_rv *) data;
+
+  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+    error (g, "guestfs_aug_get: failed to parse reply header");
+    return;
+  }
+  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+      error (g, "guestfs_aug_get: failed to parse reply error");
+      return;
+    }
+    goto done;
+  }
+  if (!xdr_guestfs_aug_get_ret (xdr, &rv->ret)) {
+    error (g, "guestfs_aug_get: failed to parse reply");
+    return;
+  }
+ done:
+  rv->cb_done = 1;
+  main_loop.main_loop_quit (g);
+}
+
+char *guestfs_aug_get (guestfs_h *g,
+               const char *path)
+{
+  struct guestfs_aug_get_args args;
+  struct aug_get_rv rv;
+  int serial;
+
+  if (g->state != READY) {
+    error (g, "guestfs_aug_get called from the wrong state, %d != READY",
+      g->state);
+    return NULL;
+  }
+
+  memset (&rv, 0, sizeof rv);
+
+  args.path = (char *) path;
+  serial = dispatch (g, GUESTFS_PROC_AUG_GET,
+                     (xdrproc_t) xdr_guestfs_aug_get_args, (char *) &args);
+  if (serial == -1)
+    return NULL;
+
+  rv.cb_done = 0;
+  g->reply_cb_internal = aug_get_cb;
+  g->reply_cb_internal_data = &rv;
+  main_loop.main_loop_run (g);
+  g->reply_cb_internal = NULL;
+  g->reply_cb_internal_data = NULL;
+  if (!rv.cb_done) {
+    error (g, "guestfs_aug_get failed, see earlier error messages");
+    return NULL;
+  }
+
+  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_AUG_GET, serial) == -1)
+    return NULL;
+
+  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", rv.err.error);
+    return NULL;
+  }
+
+  return rv.ret.val; /* caller will free */
+}
+
+struct aug_set_rv {
+  int cb_done;  /* flag to indicate callback was called */
+  struct guestfs_message_header hdr;
+  struct guestfs_message_error err;
+};
+
+static void aug_set_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+  struct aug_set_rv *rv = (struct aug_set_rv *) data;
+
+  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+    error (g, "guestfs_aug_set: failed to parse reply header");
+    return;
+  }
+  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+      error (g, "guestfs_aug_set: failed to parse reply error");
+      return;
+    }
+    goto done;
+  }
+ done:
+  rv->cb_done = 1;
+  main_loop.main_loop_quit (g);
+}
+
+int guestfs_aug_set (guestfs_h *g,
+               const char *path,
+               const char *val)
+{
+  struct guestfs_aug_set_args args;
+  struct aug_set_rv rv;
+  int serial;
+
+  if (g->state != READY) {
+    error (g, "guestfs_aug_set called from the wrong state, %d != READY",
+      g->state);
+    return -1;
+  }
+
+  memset (&rv, 0, sizeof rv);
+
+  args.path = (char *) path;
+  args.val = (char *) val;
+  serial = dispatch (g, GUESTFS_PROC_AUG_SET,
+                     (xdrproc_t) xdr_guestfs_aug_set_args, (char *) &args);
+  if (serial == -1)
+    return -1;
+
+  rv.cb_done = 0;
+  g->reply_cb_internal = aug_set_cb;
+  g->reply_cb_internal_data = &rv;
+  main_loop.main_loop_run (g);
+  g->reply_cb_internal = NULL;
+  g->reply_cb_internal_data = NULL;
+  if (!rv.cb_done) {
+    error (g, "guestfs_aug_set failed, see earlier error messages");
+    return -1;
+  }
+
+  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_AUG_SET, serial) == -1)
+    return -1;
+
+  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", rv.err.error);
+    return -1;
+  }
+
+  return 0;
+}
+
+struct aug_insert_rv {
+  int cb_done;  /* flag to indicate callback was called */
+  struct guestfs_message_header hdr;
+  struct guestfs_message_error err;
+};
+
+static void aug_insert_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+  struct aug_insert_rv *rv = (struct aug_insert_rv *) data;
+
+  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+    error (g, "guestfs_aug_insert: failed to parse reply header");
+    return;
+  }
+  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+      error (g, "guestfs_aug_insert: failed to parse reply error");
+      return;
+    }
+    goto done;
+  }
+ done:
+  rv->cb_done = 1;
+  main_loop.main_loop_quit (g);
+}
+
+int guestfs_aug_insert (guestfs_h *g,
+               const char *path,
+               const char *label,
+               int before)
+{
+  struct guestfs_aug_insert_args args;
+  struct aug_insert_rv rv;
+  int serial;
+
+  if (g->state != READY) {
+    error (g, "guestfs_aug_insert called from the wrong state, %d != READY",
+      g->state);
+    return -1;
+  }
+
+  memset (&rv, 0, sizeof rv);
+
+  args.path = (char *) path;
+  args.label = (char *) label;
+  args.before = before;
+  serial = dispatch (g, GUESTFS_PROC_AUG_INSERT,
+                     (xdrproc_t) xdr_guestfs_aug_insert_args, (char *) &args);
+  if (serial == -1)
+    return -1;
+
+  rv.cb_done = 0;
+  g->reply_cb_internal = aug_insert_cb;
+  g->reply_cb_internal_data = &rv;
+  main_loop.main_loop_run (g);
+  g->reply_cb_internal = NULL;
+  g->reply_cb_internal_data = NULL;
+  if (!rv.cb_done) {
+    error (g, "guestfs_aug_insert failed, see earlier error messages");
+    return -1;
+  }
+
+  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_AUG_INSERT, serial) == -1)
+    return -1;
+
+  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", rv.err.error);
+    return -1;
+  }
+
+  return 0;
+}
+
+struct aug_rm_rv {
+  int cb_done;  /* flag to indicate callback was called */
+  struct guestfs_message_header hdr;
+  struct guestfs_message_error err;
+  struct guestfs_aug_rm_ret ret;
+};
+
+static void aug_rm_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+  struct aug_rm_rv *rv = (struct aug_rm_rv *) data;
+
+  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+    error (g, "guestfs_aug_rm: failed to parse reply header");
+    return;
+  }
+  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+      error (g, "guestfs_aug_rm: failed to parse reply error");
+      return;
+    }
+    goto done;
+  }
+  if (!xdr_guestfs_aug_rm_ret (xdr, &rv->ret)) {
+    error (g, "guestfs_aug_rm: failed to parse reply");
+    return;
+  }
+ done:
+  rv->cb_done = 1;
+  main_loop.main_loop_quit (g);
+}
+
+int guestfs_aug_rm (guestfs_h *g,
+               const char *path)
+{
+  struct guestfs_aug_rm_args args;
+  struct aug_rm_rv rv;
+  int serial;
+
+  if (g->state != READY) {
+    error (g, "guestfs_aug_rm called from the wrong state, %d != READY",
+      g->state);
+    return -1;
+  }
+
+  memset (&rv, 0, sizeof rv);
+
+  args.path = (char *) path;
+  serial = dispatch (g, GUESTFS_PROC_AUG_RM,
+                     (xdrproc_t) xdr_guestfs_aug_rm_args, (char *) &args);
+  if (serial == -1)
+    return -1;
+
+  rv.cb_done = 0;
+  g->reply_cb_internal = aug_rm_cb;
+  g->reply_cb_internal_data = &rv;
+  main_loop.main_loop_run (g);
+  g->reply_cb_internal = NULL;
+  g->reply_cb_internal_data = NULL;
+  if (!rv.cb_done) {
+    error (g, "guestfs_aug_rm failed, see earlier error messages");
+    return -1;
+  }
+
+  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_AUG_RM, serial) == -1)
+    return -1;
+
+  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", rv.err.error);
+    return -1;
+  }
+
+  return rv.ret.nrnodes;
+}
+
+struct aug_mv_rv {
+  int cb_done;  /* flag to indicate callback was called */
+  struct guestfs_message_header hdr;
+  struct guestfs_message_error err;
+};
+
+static void aug_mv_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+  struct aug_mv_rv *rv = (struct aug_mv_rv *) data;
+
+  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+    error (g, "guestfs_aug_mv: failed to parse reply header");
+    return;
+  }
+  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+      error (g, "guestfs_aug_mv: failed to parse reply error");
+      return;
+    }
+    goto done;
+  }
+ done:
+  rv->cb_done = 1;
+  main_loop.main_loop_quit (g);
+}
+
+int guestfs_aug_mv (guestfs_h *g,
+               const char *src,
+               const char *dest)
+{
+  struct guestfs_aug_mv_args args;
+  struct aug_mv_rv rv;
+  int serial;
+
+  if (g->state != READY) {
+    error (g, "guestfs_aug_mv called from the wrong state, %d != READY",
+      g->state);
+    return -1;
+  }
+
+  memset (&rv, 0, sizeof rv);
+
+  args.src = (char *) src;
+  args.dest = (char *) dest;
+  serial = dispatch (g, GUESTFS_PROC_AUG_MV,
+                     (xdrproc_t) xdr_guestfs_aug_mv_args, (char *) &args);
+  if (serial == -1)
+    return -1;
+
+  rv.cb_done = 0;
+  g->reply_cb_internal = aug_mv_cb;
+  g->reply_cb_internal_data = &rv;
+  main_loop.main_loop_run (g);
+  g->reply_cb_internal = NULL;
+  g->reply_cb_internal_data = NULL;
+  if (!rv.cb_done) {
+    error (g, "guestfs_aug_mv failed, see earlier error messages");
+    return -1;
+  }
+
+  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_AUG_MV, serial) == -1)
+    return -1;
+
+  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", rv.err.error);
+    return -1;
+  }
+
+  return 0;
+}
+
+struct aug_match_rv {
+  int cb_done;  /* flag to indicate callback was called */
+  struct guestfs_message_header hdr;
+  struct guestfs_message_error err;
+  struct guestfs_aug_match_ret ret;
+};
+
+static void aug_match_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+  struct aug_match_rv *rv = (struct aug_match_rv *) data;
+
+  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+    error (g, "guestfs_aug_match: failed to parse reply header");
+    return;
+  }
+  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+      error (g, "guestfs_aug_match: failed to parse reply error");
+      return;
+    }
+    goto done;
+  }
+  if (!xdr_guestfs_aug_match_ret (xdr, &rv->ret)) {
+    error (g, "guestfs_aug_match: failed to parse reply");
+    return;
+  }
+ done:
+  rv->cb_done = 1;
+  main_loop.main_loop_quit (g);
+}
+
+char **guestfs_aug_match (guestfs_h *g,
+               const char *path)
+{
+  struct guestfs_aug_match_args args;
+  struct aug_match_rv rv;
+  int serial;
+
+  if (g->state != READY) {
+    error (g, "guestfs_aug_match called from the wrong state, %d != READY",
+      g->state);
+    return NULL;
+  }
+
+  memset (&rv, 0, sizeof rv);
+
+  args.path = (char *) path;
+  serial = dispatch (g, GUESTFS_PROC_AUG_MATCH,
+                     (xdrproc_t) xdr_guestfs_aug_match_args, (char *) &args);
+  if (serial == -1)
+    return NULL;
+
+  rv.cb_done = 0;
+  g->reply_cb_internal = aug_match_cb;
+  g->reply_cb_internal_data = &rv;
+  main_loop.main_loop_run (g);
+  g->reply_cb_internal = NULL;
+  g->reply_cb_internal_data = NULL;
+  if (!rv.cb_done) {
+    error (g, "guestfs_aug_match failed, see earlier error messages");
+    return NULL;
+  }
+
+  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_AUG_MATCH, serial) == -1)
+    return NULL;
+
+  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", rv.err.error);
+    return NULL;
+  }
+
+  /* caller will free this, but we need to add a NULL entry */
+  rv.ret.matches.matches_val =    safe_realloc (g, rv.ret.matches.matches_val,
+                  sizeof (char *) * (rv.ret.matches.matches_len + 1));
+  rv.ret.matches.matches_val[rv.ret.matches.matches_len] = NULL;
+  return rv.ret.matches.matches_val;
+}
+
+struct aug_save_rv {
+  int cb_done;  /* flag to indicate callback was called */
+  struct guestfs_message_header hdr;
+  struct guestfs_message_error err;
+};
+
+static void aug_save_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+  struct aug_save_rv *rv = (struct aug_save_rv *) data;
+
+  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+    error (g, "guestfs_aug_save: failed to parse reply header");
+    return;
+  }
+  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+      error (g, "guestfs_aug_save: failed to parse reply error");
+      return;
+    }
+    goto done;
+  }
+ done:
+  rv->cb_done = 1;
+  main_loop.main_loop_quit (g);
+}
+
+int guestfs_aug_save (guestfs_h *g)
+{
+  struct aug_save_rv rv;
+  int serial;
+
+  if (g->state != READY) {
+    error (g, "guestfs_aug_save called from the wrong state, %d != READY",
+      g->state);
+    return -1;
+  }
+
+  memset (&rv, 0, sizeof rv);
+
+  serial = dispatch (g, GUESTFS_PROC_AUG_SAVE, NULL, NULL);
+  if (serial == -1)
+    return -1;
+
+  rv.cb_done = 0;
+  g->reply_cb_internal = aug_save_cb;
+  g->reply_cb_internal_data = &rv;
+  main_loop.main_loop_run (g);
+  g->reply_cb_internal = NULL;
+  g->reply_cb_internal_data = NULL;
+  if (!rv.cb_done) {
+    error (g, "guestfs_aug_save failed, see earlier error messages");
+    return -1;
+  }
+
+  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_AUG_SAVE, serial) == -1)
+    return -1;
+
+  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", rv.err.error);
+    return -1;
+  }
+
+  return 0;
+}
+
+struct aug_load_rv {
+  int cb_done;  /* flag to indicate callback was called */
+  struct guestfs_message_header hdr;
+  struct guestfs_message_error err;
+};
+
+static void aug_load_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+  struct aug_load_rv *rv = (struct aug_load_rv *) data;
+
+  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+    error (g, "guestfs_aug_load: failed to parse reply header");
+    return;
+  }
+  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+      error (g, "guestfs_aug_load: failed to parse reply error");
+      return;
+    }
+    goto done;
+  }
+ done:
+  rv->cb_done = 1;
+  main_loop.main_loop_quit (g);
+}
+
+int guestfs_aug_load (guestfs_h *g)
+{
+  struct aug_load_rv rv;
+  int serial;
+
+  if (g->state != READY) {
+    error (g, "guestfs_aug_load called from the wrong state, %d != READY",
+      g->state);
+    return -1;
+  }
+
+  memset (&rv, 0, sizeof rv);
+
+  serial = dispatch (g, GUESTFS_PROC_AUG_LOAD, NULL, NULL);
+  if (serial == -1)
+    return -1;
+
+  rv.cb_done = 0;
+  g->reply_cb_internal = aug_load_cb;
+  g->reply_cb_internal_data = &rv;
+  main_loop.main_loop_run (g);
+  g->reply_cb_internal = NULL;
+  g->reply_cb_internal_data = NULL;
+  if (!rv.cb_done) {
+    error (g, "guestfs_aug_load failed, see earlier error messages");
+    return -1;
+  }
+
+  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_AUG_LOAD, serial) == -1)
+    return -1;
+
+  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", rv.err.error);
+    return -1;
+  }
+
+  return 0;
+}
+
index a84488d..eeb6903 100644 (file)
@@ -46,3 +46,15 @@ extern struct guestfs_lvm_pv_list *guestfs_pvs_full (guestfs_h *handle);
 extern struct guestfs_lvm_vg_list *guestfs_vgs_full (guestfs_h *handle);
 extern struct guestfs_lvm_lv_list *guestfs_lvs_full (guestfs_h *handle);
 extern char **guestfs_read_lines (guestfs_h *handle, const char *path);
+extern int guestfs_aug_init (guestfs_h *handle, const char *root, int flags);
+extern int guestfs_aug_close (guestfs_h *handle);
+extern int guestfs_aug_defvar (guestfs_h *handle, const char *name, const char *expr);
+extern struct guestfs_int_bool *guestfs_aug_defnode (guestfs_h *handle, const char *name, const char *expr, const char *val);
+extern char *guestfs_aug_get (guestfs_h *handle, const char *path);
+extern int guestfs_aug_set (guestfs_h *handle, const char *path, const char *val);
+extern int guestfs_aug_insert (guestfs_h *handle, const char *path, const char *label, int before);
+extern int guestfs_aug_rm (guestfs_h *handle, const char *path);
+extern int guestfs_aug_mv (guestfs_h *handle, const char *src, const char *dest);
+extern char **guestfs_aug_match (guestfs_h *handle, const char *path);
+extern int guestfs_aug_save (guestfs_h *handle);
+extern int guestfs_aug_load (guestfs_h *handle);
index 45ce131..b3751cd 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+struct guestfs_int_bool {
+  int32_t i;
+  int32_t b;
+};
+
 struct guestfs_lvm_pv {
   char *pv_name;
   char pv_uuid[32]; /* this is NOT nul-terminated, be careful when printing */
index 7f0f821..cab264a 100644 (file)
@@ -1271,6 +1271,12 @@ check_reply_header (guestfs_h *g,
  * generator.ml.
  */
 void
+guestfs_free_int_bool (struct guestfs_int_bool *x)
+{
+  free (x);
+}
+
+void
 guestfs_free_lvm_pv_list (struct guestfs_lvm_pv_list *x)
 {
   xdr_free ((xdrproc_t) xdr_guestfs_lvm_int_pv_list, (char *) x);
index 1ed066e..c677730 100644 (file)
@@ -45,6 +45,7 @@ extern guestfs_abort_cb guestfs_get_out_of_memory_handler (guestfs_h *g);
 #include <guestfs-structs.h>
 #include <guestfs-actions.h>
 
+extern void guestfs_free_int_bool (struct guestfs_int_bool *);
 extern void guestfs_free_lvm_pv_list (struct guestfs_lvm_pv_list *);
 extern void guestfs_free_lvm_vg_list (struct guestfs_lvm_vg_list *);
 extern void guestfs_free_lvm_lv_list (struct guestfs_lvm_lv_list *);
index 31034e5..a573728 100644 (file)
@@ -363,6 +363,165 @@ xdr_guestfs_read_lines_ret (XDR *xdrs, guestfs_read_lines_ret *objp)
 }
 
 bool_t
+xdr_guestfs_aug_init_args (XDR *xdrs, guestfs_aug_init_args *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_string (xdrs, &objp->root, ~0))
+                return FALSE;
+        if (!xdr_int (xdrs, &objp->flags))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_guestfs_aug_defvar_args (XDR *xdrs, guestfs_aug_defvar_args *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_string (xdrs, &objp->name, ~0))
+                return FALSE;
+        if (!xdr_pointer (xdrs, (char **)&objp->expr, sizeof (str), (xdrproc_t) xdr_str))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_guestfs_aug_defvar_ret (XDR *xdrs, guestfs_aug_defvar_ret *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_int (xdrs, &objp->nrnodes))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_guestfs_aug_defnode_args (XDR *xdrs, guestfs_aug_defnode_args *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_string (xdrs, &objp->name, ~0))
+                return FALSE;
+        if (!xdr_string (xdrs, &objp->expr, ~0))
+                return FALSE;
+        if (!xdr_string (xdrs, &objp->val, ~0))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_guestfs_aug_defnode_ret (XDR *xdrs, guestfs_aug_defnode_ret *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_int (xdrs, &objp->nrnodes))
+                return FALSE;
+        if (!xdr_bool (xdrs, &objp->created))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_guestfs_aug_get_args (XDR *xdrs, guestfs_aug_get_args *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_string (xdrs, &objp->path, ~0))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_guestfs_aug_get_ret (XDR *xdrs, guestfs_aug_get_ret *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_string (xdrs, &objp->val, ~0))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_guestfs_aug_set_args (XDR *xdrs, guestfs_aug_set_args *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_string (xdrs, &objp->path, ~0))
+                return FALSE;
+        if (!xdr_string (xdrs, &objp->val, ~0))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_guestfs_aug_insert_args (XDR *xdrs, guestfs_aug_insert_args *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_string (xdrs, &objp->path, ~0))
+                return FALSE;
+        if (!xdr_string (xdrs, &objp->label, ~0))
+                return FALSE;
+        if (!xdr_bool (xdrs, &objp->before))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_guestfs_aug_rm_args (XDR *xdrs, guestfs_aug_rm_args *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_string (xdrs, &objp->path, ~0))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_guestfs_aug_rm_ret (XDR *xdrs, guestfs_aug_rm_ret *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_int (xdrs, &objp->nrnodes))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_guestfs_aug_mv_args (XDR *xdrs, guestfs_aug_mv_args *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_string (xdrs, &objp->src, ~0))
+                return FALSE;
+        if (!xdr_string (xdrs, &objp->dest, ~0))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_guestfs_aug_match_args (XDR *xdrs, guestfs_aug_match_args *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_string (xdrs, &objp->path, ~0))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_guestfs_aug_match_ret (XDR *xdrs, guestfs_aug_match_ret *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_array (xdrs, (char **)&objp->matches.matches_val, (u_int *) &objp->matches.matches_len, ~0,
+               sizeof (str), (xdrproc_t) xdr_str))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
 xdr_guestfs_procedure (XDR *xdrs, guestfs_procedure *objp)
 {
        register int32_t *buf;
index a2bf0c1..9412986 100644 (file)
@@ -204,6 +204,88 @@ struct guestfs_read_lines_ret {
 };
 typedef struct guestfs_read_lines_ret guestfs_read_lines_ret;
 
+struct guestfs_aug_init_args {
+       char *root;
+       int flags;
+};
+typedef struct guestfs_aug_init_args guestfs_aug_init_args;
+
+struct guestfs_aug_defvar_args {
+       char *name;
+       str *expr;
+};
+typedef struct guestfs_aug_defvar_args guestfs_aug_defvar_args;
+
+struct guestfs_aug_defvar_ret {
+       int nrnodes;
+};
+typedef struct guestfs_aug_defvar_ret guestfs_aug_defvar_ret;
+
+struct guestfs_aug_defnode_args {
+       char *name;
+       char *expr;
+       char *val;
+};
+typedef struct guestfs_aug_defnode_args guestfs_aug_defnode_args;
+
+struct guestfs_aug_defnode_ret {
+       int nrnodes;
+       bool_t created;
+};
+typedef struct guestfs_aug_defnode_ret guestfs_aug_defnode_ret;
+
+struct guestfs_aug_get_args {
+       char *path;
+};
+typedef struct guestfs_aug_get_args guestfs_aug_get_args;
+
+struct guestfs_aug_get_ret {
+       char *val;
+};
+typedef struct guestfs_aug_get_ret guestfs_aug_get_ret;
+
+struct guestfs_aug_set_args {
+       char *path;
+       char *val;
+};
+typedef struct guestfs_aug_set_args guestfs_aug_set_args;
+
+struct guestfs_aug_insert_args {
+       char *path;
+       char *label;
+       bool_t before;
+};
+typedef struct guestfs_aug_insert_args guestfs_aug_insert_args;
+
+struct guestfs_aug_rm_args {
+       char *path;
+};
+typedef struct guestfs_aug_rm_args guestfs_aug_rm_args;
+
+struct guestfs_aug_rm_ret {
+       int nrnodes;
+};
+typedef struct guestfs_aug_rm_ret guestfs_aug_rm_ret;
+
+struct guestfs_aug_mv_args {
+       char *src;
+       char *dest;
+};
+typedef struct guestfs_aug_mv_args guestfs_aug_mv_args;
+
+struct guestfs_aug_match_args {
+       char *path;
+};
+typedef struct guestfs_aug_match_args guestfs_aug_match_args;
+
+struct guestfs_aug_match_ret {
+       struct {
+               u_int matches_len;
+               str *matches_val;
+       } matches;
+};
+typedef struct guestfs_aug_match_ret guestfs_aug_match_ret;
+
 enum guestfs_procedure {
        GUESTFS_PROC_MOUNT = 1,
        GUESTFS_PROC_SYNC = 2,
@@ -220,7 +302,19 @@ enum guestfs_procedure {
        GUESTFS_PROC_VGS_FULL = 13,
        GUESTFS_PROC_LVS_FULL = 14,
        GUESTFS_PROC_READ_LINES = 15,
-       GUESTFS_PROC_dummy = 15 + 1,
+       GUESTFS_PROC_AUG_INIT = 16,
+       GUESTFS_PROC_AUG_CLOSE = 26,
+       GUESTFS_PROC_AUG_DEFVAR = 17,
+       GUESTFS_PROC_AUG_DEFNODE = 18,
+       GUESTFS_PROC_AUG_GET = 19,
+       GUESTFS_PROC_AUG_SET = 20,
+       GUESTFS_PROC_AUG_INSERT = 21,
+       GUESTFS_PROC_AUG_RM = 22,
+       GUESTFS_PROC_AUG_MV = 23,
+       GUESTFS_PROC_AUG_MATCH = 24,
+       GUESTFS_PROC_AUG_SAVE = 25,
+       GUESTFS_PROC_AUG_LOAD = 27,
+       GUESTFS_PROC_dummy = 27 + 1,
 };
 typedef enum guestfs_procedure guestfs_procedure;
 #define GUESTFS_MESSAGE_MAX 4194304
@@ -283,6 +377,20 @@ extern  bool_t xdr_guestfs_vgs_full_ret (XDR *, guestfs_vgs_full_ret*);
 extern  bool_t xdr_guestfs_lvs_full_ret (XDR *, guestfs_lvs_full_ret*);
 extern  bool_t xdr_guestfs_read_lines_args (XDR *, guestfs_read_lines_args*);
 extern  bool_t xdr_guestfs_read_lines_ret (XDR *, guestfs_read_lines_ret*);
+extern  bool_t xdr_guestfs_aug_init_args (XDR *, guestfs_aug_init_args*);
+extern  bool_t xdr_guestfs_aug_defvar_args (XDR *, guestfs_aug_defvar_args*);
+extern  bool_t xdr_guestfs_aug_defvar_ret (XDR *, guestfs_aug_defvar_ret*);
+extern  bool_t xdr_guestfs_aug_defnode_args (XDR *, guestfs_aug_defnode_args*);
+extern  bool_t xdr_guestfs_aug_defnode_ret (XDR *, guestfs_aug_defnode_ret*);
+extern  bool_t xdr_guestfs_aug_get_args (XDR *, guestfs_aug_get_args*);
+extern  bool_t xdr_guestfs_aug_get_ret (XDR *, guestfs_aug_get_ret*);
+extern  bool_t xdr_guestfs_aug_set_args (XDR *, guestfs_aug_set_args*);
+extern  bool_t xdr_guestfs_aug_insert_args (XDR *, guestfs_aug_insert_args*);
+extern  bool_t xdr_guestfs_aug_rm_args (XDR *, guestfs_aug_rm_args*);
+extern  bool_t xdr_guestfs_aug_rm_ret (XDR *, guestfs_aug_rm_ret*);
+extern  bool_t xdr_guestfs_aug_mv_args (XDR *, guestfs_aug_mv_args*);
+extern  bool_t xdr_guestfs_aug_match_args (XDR *, guestfs_aug_match_args*);
+extern  bool_t xdr_guestfs_aug_match_ret (XDR *, guestfs_aug_match_ret*);
 extern  bool_t xdr_guestfs_procedure (XDR *, guestfs_procedure*);
 extern  bool_t xdr_guestfs_message_direction (XDR *, guestfs_message_direction*);
 extern  bool_t xdr_guestfs_message_status (XDR *, guestfs_message_status*);
@@ -315,6 +423,20 @@ extern bool_t xdr_guestfs_vgs_full_ret ();
 extern bool_t xdr_guestfs_lvs_full_ret ();
 extern bool_t xdr_guestfs_read_lines_args ();
 extern bool_t xdr_guestfs_read_lines_ret ();
+extern bool_t xdr_guestfs_aug_init_args ();
+extern bool_t xdr_guestfs_aug_defvar_args ();
+extern bool_t xdr_guestfs_aug_defvar_ret ();
+extern bool_t xdr_guestfs_aug_defnode_args ();
+extern bool_t xdr_guestfs_aug_defnode_ret ();
+extern bool_t xdr_guestfs_aug_get_args ();
+extern bool_t xdr_guestfs_aug_get_ret ();
+extern bool_t xdr_guestfs_aug_set_args ();
+extern bool_t xdr_guestfs_aug_insert_args ();
+extern bool_t xdr_guestfs_aug_rm_args ();
+extern bool_t xdr_guestfs_aug_rm_ret ();
+extern bool_t xdr_guestfs_aug_mv_args ();
+extern bool_t xdr_guestfs_aug_match_args ();
+extern bool_t xdr_guestfs_aug_match_ret ();
 extern bool_t xdr_guestfs_procedure ();
 extern bool_t xdr_guestfs_message_direction ();
 extern bool_t xdr_guestfs_message_status ();
index c00c4c4..eb3045e 100644 (file)
@@ -85,23 +85,15 @@ struct guestfs_lvm_int_lv {
 
 typedef struct guestfs_lvm_int_lv guestfs_lvm_int_lv_list<>;
 
-/* guestfs_mount */
-
 struct guestfs_mount_args {
   string device<>;
   string mountpoint<>;
 };
 
-/* guestfs_sync */
-
-/* guestfs_touch */
-
 struct guestfs_touch_args {
   string path<>;
 };
 
-/* guestfs_cat */
-
 struct guestfs_cat_args {
   string path<>;
 };
@@ -110,8 +102,6 @@ struct guestfs_cat_ret {
   string content<>;
 };
 
-/* guestfs_ll */
-
 struct guestfs_ll_args {
   string directory<>;
 };
@@ -120,8 +110,6 @@ struct guestfs_ll_ret {
   string listing<>;
 };
 
-/* guestfs_ls */
-
 struct guestfs_ls_args {
   string directory<>;
 };
@@ -130,56 +118,38 @@ struct guestfs_ls_ret {
   str listing<>;
 };
 
-/* guestfs_list_devices */
-
 struct guestfs_list_devices_ret {
   str devices<>;
 };
 
-/* guestfs_list_partitions */
-
 struct guestfs_list_partitions_ret {
   str partitions<>;
 };
 
-/* guestfs_pvs */
-
 struct guestfs_pvs_ret {
   str physvols<>;
 };
 
-/* guestfs_vgs */
-
 struct guestfs_vgs_ret {
   str volgroups<>;
 };
 
-/* guestfs_lvs */
-
 struct guestfs_lvs_ret {
   str logvols<>;
 };
 
-/* guestfs_pvs_full */
-
 struct guestfs_pvs_full_ret {
   guestfs_lvm_int_pv_list physvols;
 };
 
-/* guestfs_vgs_full */
-
 struct guestfs_vgs_full_ret {
   guestfs_lvm_int_vg_list volgroups;
 };
 
-/* guestfs_lvs_full */
-
 struct guestfs_lvs_full_ret {
   guestfs_lvm_int_lv_list logvols;
 };
 
-/* guestfs_read_lines */
-
 struct guestfs_read_lines_args {
   string path<>;
 };
@@ -188,6 +158,71 @@ struct guestfs_read_lines_ret {
   str lines<>;
 };
 
+struct guestfs_aug_init_args {
+  string root<>;
+  int flags;
+};
+
+struct guestfs_aug_defvar_args {
+  string name<>;
+  str *expr;
+};
+
+struct guestfs_aug_defvar_ret {
+  int nrnodes;
+};
+
+struct guestfs_aug_defnode_args {
+  string name<>;
+  string expr<>;
+  string val<>;
+};
+
+struct guestfs_aug_defnode_ret {
+  int nrnodes;
+  bool created;
+};
+
+struct guestfs_aug_get_args {
+  string path<>;
+};
+
+struct guestfs_aug_get_ret {
+  string val<>;
+};
+
+struct guestfs_aug_set_args {
+  string path<>;
+  string val<>;
+};
+
+struct guestfs_aug_insert_args {
+  string path<>;
+  string label<>;
+  bool before;
+};
+
+struct guestfs_aug_rm_args {
+  string path<>;
+};
+
+struct guestfs_aug_rm_ret {
+  int nrnodes;
+};
+
+struct guestfs_aug_mv_args {
+  string src<>;
+  string dest<>;
+};
+
+struct guestfs_aug_match_args {
+  string path<>;
+};
+
+struct guestfs_aug_match_ret {
+  str matches<>;
+};
+
 enum guestfs_procedure {
   GUESTFS_PROC_MOUNT = 1,
   GUESTFS_PROC_SYNC = 2,
@@ -204,6 +239,18 @@ enum guestfs_procedure {
   GUESTFS_PROC_VGS_FULL = 13,
   GUESTFS_PROC_LVS_FULL = 14,
   GUESTFS_PROC_READ_LINES = 15,
+  GUESTFS_PROC_AUG_INIT = 16,
+  GUESTFS_PROC_AUG_CLOSE = 26,
+  GUESTFS_PROC_AUG_DEFVAR = 17,
+  GUESTFS_PROC_AUG_DEFNODE = 18,
+  GUESTFS_PROC_AUG_GET = 19,
+  GUESTFS_PROC_AUG_SET = 20,
+  GUESTFS_PROC_AUG_INSERT = 21,
+  GUESTFS_PROC_AUG_RM = 22,
+  GUESTFS_PROC_AUG_MV = 23,
+  GUESTFS_PROC_AUG_MATCH = 24,
+  GUESTFS_PROC_AUG_SAVE = 25,
+  GUESTFS_PROC_AUG_LOAD = 27,
   GUESTFS_PROC_dummy
 };