diff options
-rw-r--r-- | daemon/actions.h | 1 | ||||
-rw-r--r-- | daemon/stubs.c | 29 | ||||
-rw-r--r-- | fish/cmds.c | 24 | ||||
-rw-r--r-- | guestfish-actions.pod | 14 | ||||
-rw-r--r-- | guestfs-actions.pod | 19 | ||||
-rw-r--r-- | ocaml/guestfs.ml | 1 | ||||
-rw-r--r-- | ocaml/guestfs.mli | 3 | ||||
-rw-r--r-- | ocaml/guestfs_c_actions.c | 26 | ||||
-rw-r--r-- | perl/Guestfs.xs | 19 | ||||
-rw-r--r-- | perl/lib/Sys/Guestfs.pm | 12 | ||||
-rw-r--r-- | src/guestfs-actions.c | 78 | ||||
-rw-r--r-- | src/guestfs-actions.h | 1 | ||||
-rw-r--r-- | src/guestfs_protocol.c | 21 | ||||
-rw-r--r-- | src/guestfs_protocol.h | 20 | ||||
-rw-r--r-- | src/guestfs_protocol.x | 11 |
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 }; |