summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README2
-rw-r--r--configure.ac14
-rw-r--r--daemon/Makefile.am1
-rw-r--r--daemon/actions.h30
-rw-r--r--daemon/augeas.c278
-rw-r--r--daemon/configure.ac7
-rw-r--r--daemon/stubs.c316
-rw-r--r--fish/cmds.c276
-rw-r--r--guestfish-actions.pod152
-rw-r--r--guestfs-actions.pod203
-rw-r--r--libguestfs.spec.in3
-rwxr-xr-xmake-initramfs.sh.in4
-rw-r--r--ocaml/guestfs.ml12
-rw-r--r--ocaml/guestfs.mli36
-rw-r--r--ocaml/guestfs_c_actions.c293
-rw-r--r--perl/Guestfs.xs138
-rw-r--r--perl/lib/Sys/Guestfs.pm128
-rwxr-xr-xsrc/generator.ml410
-rw-r--r--src/guestfs-actions.c862
-rw-r--r--src/guestfs-actions.h12
-rw-r--r--src/guestfs-structs.h5
-rw-r--r--src/guestfs.c6
-rw-r--r--src/guestfs.h1
-rw-r--r--src/guestfs_protocol.c159
-rw-r--r--src/guestfs_protocol.h124
-rw-r--r--src/guestfs_protocol.x107
26 files changed, 3441 insertions, 138 deletions
diff --git a/README b/README
index f90bf462..ecb5362f 100644
--- 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.
diff --git a/configure.ac b/configure.ac
index 0e1df677..7c533eb5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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],
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 4d56034d..bdeeacfe 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -20,6 +20,7 @@ ACLOCAL_AMFLAGS = -I m4
noinst_PROGRAMS = guestfsd
guestfsd_SOURCES = \
actions.h \
+ augeas.c \
daemon.h \
devsparts.c \
file.c \
diff --git a/daemon/actions.h b/daemon/actions.h
index 01fe68d6..6a41c7d0 100644
--- a/daemon/actions.h
+++ b/daemon/actions.h
@@ -22,17 +22,29 @@
#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
index 00000000..2b273875
--- /dev/null
+++ b/daemon/augeas.c
@@ -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;
+}
diff --git a/daemon/configure.ac b/daemon/configure.ac
index af0a78af..7ce03ab5 100644
--- a/daemon/configure.ac
+++ b/daemon/configure.ac
@@ -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])
diff --git a/daemon/stubs.c b/daemon/stubs.c
index fab115c0..38aea33f 100644
--- a/daemon/stubs.c
+++ b/daemon/stubs.c
@@ -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);
}
diff --git a/fish/cmds.c b/fish/cmds.c
index aaf97a89..5c7d5530 100644
--- a/fish/cmds.c
+++ b/fish/cmds.c
@@ -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;
diff --git a/guestfish-actions.pod b/guestfish-actions.pod
index 13e23ae5..00911dbe 100644
--- a/guestfish-actions.pod
+++ b/guestfish-actions.pod
@@ -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
diff --git a/guestfs-actions.pod b/guestfs-actions.pod
index fd720f9b..c5fadcfc 100644
--- a/guestfs-actions.pod
+++ b/guestfs-actions.pod
@@ -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
diff --git a/libguestfs.spec.in b/libguestfs.spec.in
index bc611eff..4e55988e 100644
--- a/libguestfs.spec.in
+++ b/libguestfs.spec.in
@@ -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
diff --git a/make-initramfs.sh.in b/make-initramfs.sh.in
index f25e7ce9..4579e901 100755
--- a/make-initramfs.sh.in
+++ b/make-initramfs.sh.in
@@ -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
diff --git a/ocaml/guestfs.ml b/ocaml/guestfs.ml
index 2504b45e..64878611 100644
--- a/ocaml/guestfs.ml
+++ b/ocaml/guestfs.ml
@@ -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"
diff --git a/ocaml/guestfs.mli b/ocaml/guestfs.mli
index 177f09e8..b1452abe 100644
--- a/ocaml/guestfs.mli
+++ b/ocaml/guestfs.mli
@@ -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 *)
+
diff --git a/ocaml/guestfs_c_actions.c b/ocaml/guestfs_c_actions.c
index 80a891e8..f21d63ec 100644
--- a/ocaml/guestfs_c_actions.c
+++ b/ocaml/guestfs_c_actions.c
@@ -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);
+}
+
diff --git a/perl/Guestfs.xs b/perl/Guestfs.xs
index 3cc47750..99eb3190 100644
--- a/perl/Guestfs.xs
+++ b/perl/Guestfs.xs
@@ -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);
+
diff --git a/perl/lib/Sys/Guestfs.pm b/perl/lib/Sys/Guestfs.pm
index 7706ae40..29414662 100644
--- a/perl/lib/Sys/Guestfs.pm
+++ b/perl/lib/Sys/Guestfs.pm
@@ -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>.
diff --git a/src/generator.ml b/src/generator.ml
index af19fdad..3f42c391 100755
--- a/src/generator.ml
+++ b/src/generator.ml
@@ -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 ");"
diff --git a/src/guestfs-actions.c b/src/guestfs-actions.c
index ebde5fca..0bb868ca 100644
--- a/src/guestfs-actions.c
+++ b/src/guestfs-actions.c
@@ -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;
+}
+
diff --git a/src/guestfs-actions.h b/src/guestfs-actions.h
index a84488d6..eeb69035 100644
--- a/src/guestfs-actions.h
+++ b/src/guestfs-actions.h
@@ -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);
diff --git a/src/guestfs-structs.h b/src/guestfs-structs.h
index 45ce1316..b3751cd5 100644
--- a/src/guestfs-structs.h
+++ b/src/guestfs-structs.h
@@ -19,6 +19,11 @@
* 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 */
diff --git a/src/guestfs.c b/src/guestfs.c
index 7f0f8214..cab264a4 100644
--- a/src/guestfs.c
+++ b/src/guestfs.c
@@ -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);
diff --git a/src/guestfs.h b/src/guestfs.h
index 1ed066e9..c677730a 100644
--- a/src/guestfs.h
+++ b/src/guestfs.h
@@ -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 *);
diff --git a/src/guestfs_protocol.c b/src/guestfs_protocol.c
index 31034e54..a5737288 100644
--- a/src/guestfs_protocol.c
+++ b/src/guestfs_protocol.c
@@ -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;
diff --git a/src/guestfs_protocol.h b/src/guestfs_protocol.h
index a2bf0c13..94129864 100644
--- a/src/guestfs_protocol.h
+++ b/src/guestfs_protocol.h
@@ -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 ();
diff --git a/src/guestfs_protocol.x b/src/guestfs_protocol.x
index c00c4c4d..eb3045e0 100644
--- a/src/guestfs_protocol.x
+++ b/src/guestfs_protocol.x
@@ -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
};