summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--daemon/actions.h1
-rw-r--r--daemon/stubs.c29
-rw-r--r--fish/cmds.c24
-rw-r--r--guestfish-actions.pod14
-rw-r--r--guestfs-actions.pod19
-rw-r--r--ocaml/guestfs.ml1
-rw-r--r--ocaml/guestfs.mli3
-rw-r--r--ocaml/guestfs_c_actions.c26
-rw-r--r--perl/Guestfs.xs19
-rw-r--r--perl/lib/Sys/Guestfs.pm12
-rw-r--r--src/guestfs-actions.c78
-rw-r--r--src/guestfs-actions.h1
-rw-r--r--src/guestfs_protocol.c21
-rw-r--r--src/guestfs_protocol.h20
-rw-r--r--src/guestfs_protocol.x11
15 files changed, 278 insertions, 1 deletions
diff --git a/daemon/actions.h b/daemon/actions.h
index 02fe55eb..01fe68d6 100644
--- a/daemon/actions.h
+++ b/daemon/actions.h
@@ -35,3 +35,4 @@ 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_read_lines (const char *path);
diff --git a/daemon/stubs.c b/daemon/stubs.c
index 06a86008..fab115c0 100644
--- a/daemon/stubs.c
+++ b/daemon/stubs.c
@@ -292,6 +292,32 @@ static void lvs_full_stub (XDR *xdr_in)
xdr_free ((xdrproc_t) xdr_guestfs_lvs_full_ret, (char *) &ret);
}
+static void read_lines_stub (XDR *xdr_in)
+{
+ char **r;
+ struct guestfs_read_lines_args args;
+ const char *path;
+
+ 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");
+ return;
+ }
+ path = args.path;
+
+ r = do_read_lines (path);
+ if (r == NULL)
+ /* do_read_lines has already called reply_with_error, so just return */
+ return;
+
+ struct guestfs_read_lines_ret ret;
+ ret.lines.lines_len = count_strings (r);
+ ret.lines.lines_val = r;
+ reply ((xdrproc_t) &xdr_guestfs_read_lines_ret, (char *) &ret);
+ free_strings (r);
+}
+
void dispatch_incoming_message (XDR *xdr_in)
{
switch (proc_nr) {
@@ -337,6 +363,9 @@ void dispatch_incoming_message (XDR *xdr_in)
case GUESTFS_PROC_LVS_FULL:
lvs_full_stub (xdr_in);
break;
+ case GUESTFS_PROC_READ_LINES:
+ read_lines_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 1382e884..aaf97a89 100644
--- a/fish/cmds.c
+++ b/fish/cmds.c
@@ -49,6 +49,7 @@ void list_commands (void)
printf ("%-20s %s\n", "mount", "mount a guest disk at a position in the filesystem");
printf ("%-20s %s\n", "pvs", "list the LVM physical volumes (PVs)");
printf ("%-20s %s\n", "pvs-full", "list the LVM physical volumes (PVs)");
+ printf ("%-20s %s\n", "read-lines", "read file as lines");
printf ("%-20s %s\n", "set-autosync", "set autosync mode");
printf ("%-20s %s\n", "set-path", "set the search path");
printf ("%-20s %s\n", "set-verbose", "set verbose mode");
@@ -136,6 +137,9 @@ void display_command (const char *cmd)
if (strcasecmp (cmd, "lvs_full") == 0 || strcasecmp (cmd, "lvs-full") == 0)
pod2text ("lvs-full - list the LVM logical volumes (LVs)", " lvs-full\n\nList all the logical volumes detected. This is the equivalent\nof the L<lvs(8)> command. The \"full\" version includes all fields.");
else
+ 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
display_builtin_command (cmd);
}
@@ -606,6 +610,23 @@ static int run_lvs_full (const char *cmd, int argc, char *argv[])
return 0;
}
+static int run_read_lines (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_read_lines (g, path);
+ if (r == NULL) return -1;
+ print_strings (r);
+ free_strings (r);
+ return 0;
+}
+
int run_action (const char *cmd, int argc, char *argv[])
{
if (strcasecmp (cmd, "launch") == 0 || strcasecmp (cmd, "run") == 0)
@@ -683,6 +704,9 @@ int run_action (const char *cmd, int argc, char *argv[])
if (strcasecmp (cmd, "lvs_full") == 0 || strcasecmp (cmd, "lvs-full") == 0)
return run_lvs_full (cmd, argc, argv);
else
+ if (strcasecmp (cmd, "read_lines") == 0 || strcasecmp (cmd, "read-lines") == 0)
+ return run_read_lines (cmd, argc, argv);
+ else
{
fprintf (stderr, "%s: unknown command\n", cmd);
return -1;
diff --git a/guestfish-actions.pod b/guestfish-actions.pod
index d1958edf..13e23ae5 100644
--- a/guestfish-actions.pod
+++ b/guestfish-actions.pod
@@ -183,6 +183,20 @@ See also C<pvs_full>.
List all the physical volumes detected. This is the equivalent
of the L<pvs(8)> command. The "full" version includes all fields.
+=head2 read-lines
+
+ read-lines path
+
+Return the contents of the file named C<path>.
+
+The file contents are returned as a list of lines. Trailing
+C<LF> and C<CRLF> character sequences are I<not> returned.
+
+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<read_file>
+function which has a more complex interface.
+
=head2 set-autosync | autosync
set-autosync true|false
diff --git a/guestfs-actions.pod b/guestfs-actions.pod
index b54917e5..fd720f9b 100644
--- a/guestfs-actions.pod
+++ b/guestfs-actions.pod
@@ -247,6 +247,25 @@ of the L<pvs(8)> command. The "full" version includes all fields.
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
+
+ char **guestfs_read_lines (guestfs_h *handle,
+ const char *path);
+
+Return the contents of the file named C<path>.
+
+The file contents are returned as a list of lines. Trailing
+C<LF> and C<CRLF> character sequences are I<not> returned.
+
+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.
+
+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_set_autosync
int guestfs_set_autosync (guestfs_h *handle,
diff --git a/ocaml/guestfs.ml b/ocaml/guestfs.ml
index 3e9f172d..2504b45e 100644
--- a/ocaml/guestfs.ml
+++ b/ocaml/guestfs.ml
@@ -111,3 +111,4 @@ external lvs : t -> string array = "ocaml_guestfs_lvs"
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"
diff --git a/ocaml/guestfs.mli b/ocaml/guestfs.mli
index d1970ede..177f09e8 100644
--- a/ocaml/guestfs.mli
+++ b/ocaml/guestfs.mli
@@ -172,3 +172,6 @@ val vgs_full : t -> lvm_vg array
val lvs_full : t -> lvm_lv array
(** list the LVM logical volumes (LVs) *)
+val read_lines : t -> string -> string array
+(** read file as lines *)
+
diff --git a/ocaml/guestfs_c_actions.c b/ocaml/guestfs_c_actions.c
index 64a590fa..80a891e8 100644
--- a/ocaml/guestfs_c_actions.c
+++ b/ocaml/guestfs_c_actions.c
@@ -842,3 +842,29 @@ ocaml_guestfs_lvs_full (value gv)
CAMLreturn (rv);
}
+CAMLprim value
+ocaml_guestfs_read_lines (value gv, value pathv)
+{
+ CAMLparam2 (gv, pathv);
+ CAMLlocal1 (rv);
+
+ guestfs_h *g = Guestfs_val (gv);
+ if (g == NULL)
+ caml_failwith ("read_lines: used handle after closing it");
+
+ const char *path = String_val (pathv);
+ int i;
+ char **r;
+
+ caml_enter_blocking_section ();
+ r = guestfs_read_lines (g, path);
+ caml_leave_blocking_section ();
+ if (r == NULL)
+ ocaml_guestfs_raise_error (g, "read_lines");
+
+ rv = caml_copy_string_array ((const char **) r);
+ for (i = 0; r[i] != NULL; ++i) free (r[i]);
+ free (r);
+ CAMLreturn (rv);
+}
+
diff --git a/perl/Guestfs.xs b/perl/Guestfs.xs
index fd287e7b..3cc47750 100644
--- a/perl/Guestfs.xs
+++ b/perl/Guestfs.xs
@@ -466,3 +466,22 @@ PREINIT:
}
guestfs_free_lvm_lv_list (logvols);
+void
+read_lines (g, path)
+ guestfs_h *g;
+ char *path;
+PREINIT:
+ char **lines;
+ int i, n;
+ PPCODE:
+ lines = guestfs_read_lines (g, path);
+ if (lines == NULL)
+ croak ("read_lines: %s", last_error);
+ for (n = 0; lines[n] != NULL; ++n) /**/;
+ EXTEND (SP, n);
+ for (i = 0; i < n; ++i) {
+ PUSHs (sv_2mortal (newSVpv (lines[i], 0)));
+ free (lines[i]);
+ }
+ free (lines);
+
diff --git a/perl/lib/Sys/Guestfs.pm b/perl/lib/Sys/Guestfs.pm
index 1798e7b8..7706ae40 100644
--- a/perl/lib/Sys/Guestfs.pm
+++ b/perl/lib/Sys/Guestfs.pm
@@ -244,6 +244,18 @@ See also C<$h-E<gt>pvs_full>.
List all the physical volumes detected. This is the equivalent
of the L<pvs(8)> command. The "full" version includes all fields.
+=item @lines = $h->read_lines (path);
+
+Return the contents of the file named C<path>.
+
+The file contents are returned as a list of lines. Trailing
+C<LF> and C<CRLF> character sequences are I<not> returned.
+
+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<$h-E<gt>read_file>
+function which has a more complex interface.
+
=item $h->set_autosync (autosync);
If C<autosync> is true, this enables autosync. Libguestfs will make a
diff --git a/src/guestfs-actions.c b/src/guestfs-actions.c
index 44d7e1ed..ebde5fca 100644
--- a/src/guestfs-actions.c
+++ b/src/guestfs-actions.c
@@ -1033,3 +1033,81 @@ struct guestfs_lvm_lv_list *guestfs_lvs_full (guestfs_h *g)
return safe_memdup (g, &rv.ret.logvols, sizeof (rv.ret.logvols));
}
+struct read_lines_rv {
+ int cb_done; /* flag to indicate callback was called */
+ struct guestfs_message_header hdr;
+ struct guestfs_message_error err;
+ struct guestfs_read_lines_ret ret;
+};
+
+static void read_lines_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+ struct read_lines_rv *rv = (struct read_lines_rv *) data;
+
+ if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+ error (g, "guestfs_read_lines: failed to parse reply header");
+ return;
+ }
+ if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+ if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+ error (g, "guestfs_read_lines: failed to parse reply error");
+ return;
+ }
+ goto done;
+ }
+ if (!xdr_guestfs_read_lines_ret (xdr, &rv->ret)) {
+ error (g, "guestfs_read_lines: failed to parse reply");
+ return;
+ }
+ done:
+ rv->cb_done = 1;
+ main_loop.main_loop_quit (g);
+}
+
+char **guestfs_read_lines (guestfs_h *g,
+ const char *path)
+{
+ struct guestfs_read_lines_args args;
+ struct read_lines_rv rv;
+ int serial;
+
+ if (g->state != READY) {
+ error (g, "guestfs_read_lines 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_READ_LINES,
+ (xdrproc_t) xdr_guestfs_read_lines_args, (char *) &args);
+ if (serial == -1)
+ return NULL;
+
+ rv.cb_done = 0;
+ g->reply_cb_internal = read_lines_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_read_lines failed, see earlier error messages");
+ return NULL;
+ }
+
+ if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_READ_LINES, 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.lines.lines_val = safe_realloc (g, rv.ret.lines.lines_val,
+ sizeof (char *) * (rv.ret.lines.lines_len + 1));
+ rv.ret.lines.lines_val[rv.ret.lines.lines_len] = NULL;
+ return rv.ret.lines.lines_val;
+}
+
diff --git a/src/guestfs-actions.h b/src/guestfs-actions.h
index 4b65f3cd..a84488d6 100644
--- a/src/guestfs-actions.h
+++ b/src/guestfs-actions.h
@@ -45,3 +45,4 @@ extern char **guestfs_lvs (guestfs_h *handle);
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);
diff --git a/src/guestfs_protocol.c b/src/guestfs_protocol.c
index 2a194a71..31034e54 100644
--- a/src/guestfs_protocol.c
+++ b/src/guestfs_protocol.c
@@ -342,6 +342,27 @@ xdr_guestfs_lvs_full_ret (XDR *xdrs, guestfs_lvs_full_ret *objp)
}
bool_t
+xdr_guestfs_read_lines_args (XDR *xdrs, guestfs_read_lines_args *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_string (xdrs, &objp->path, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_read_lines_ret (XDR *xdrs, guestfs_read_lines_ret *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_array (xdrs, (char **)&objp->lines.lines_val, (u_int *) &objp->lines.lines_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 9a7187dd..a2bf0c13 100644
--- a/src/guestfs_protocol.h
+++ b/src/guestfs_protocol.h
@@ -191,6 +191,19 @@ struct guestfs_lvs_full_ret {
};
typedef struct guestfs_lvs_full_ret guestfs_lvs_full_ret;
+struct guestfs_read_lines_args {
+ char *path;
+};
+typedef struct guestfs_read_lines_args guestfs_read_lines_args;
+
+struct guestfs_read_lines_ret {
+ struct {
+ u_int lines_len;
+ str *lines_val;
+ } lines;
+};
+typedef struct guestfs_read_lines_ret guestfs_read_lines_ret;
+
enum guestfs_procedure {
GUESTFS_PROC_MOUNT = 1,
GUESTFS_PROC_SYNC = 2,
@@ -206,7 +219,8 @@ enum guestfs_procedure {
GUESTFS_PROC_PVS_FULL = 12,
GUESTFS_PROC_VGS_FULL = 13,
GUESTFS_PROC_LVS_FULL = 14,
- GUESTFS_PROC_dummy = 14 + 1,
+ GUESTFS_PROC_READ_LINES = 15,
+ GUESTFS_PROC_dummy = 15 + 1,
};
typedef enum guestfs_procedure guestfs_procedure;
#define GUESTFS_MESSAGE_MAX 4194304
@@ -267,6 +281,8 @@ extern bool_t xdr_guestfs_lvs_ret (XDR *, guestfs_lvs_ret*);
extern bool_t xdr_guestfs_pvs_full_ret (XDR *, guestfs_pvs_full_ret*);
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_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*);
@@ -297,6 +313,8 @@ extern bool_t xdr_guestfs_lvs_ret ();
extern bool_t xdr_guestfs_pvs_full_ret ();
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_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 b2fe5351..c00c4c4d 100644
--- a/src/guestfs_protocol.x
+++ b/src/guestfs_protocol.x
@@ -178,6 +178,16 @@ struct guestfs_lvs_full_ret {
guestfs_lvm_int_lv_list logvols;
};
+/* guestfs_read_lines */
+
+struct guestfs_read_lines_args {
+ string path<>;
+};
+
+struct guestfs_read_lines_ret {
+ str lines<>;
+};
+
enum guestfs_procedure {
GUESTFS_PROC_MOUNT = 1,
GUESTFS_PROC_SYNC = 2,
@@ -193,6 +203,7 @@ enum guestfs_procedure {
GUESTFS_PROC_PVS_FULL = 12,
GUESTFS_PROC_VGS_FULL = 13,
GUESTFS_PROC_LVS_FULL = 14,
+ GUESTFS_PROC_READ_LINES = 15,
GUESTFS_PROC_dummy
};