Re: [Libguestfs] [PATCH v5 2/2] fish: add journal-view command (RHBZ#988100)

Pino Toscano
Wed, 02 Sep 2015 10:20:27 -0000

In data lunedì 31 agosto 2015 15:07:37, Maros Zatko ha
scritto:
> Lets user view journald log from VM in a similar format as journalctl
> uses.

"Let the user view the journald log from a guest, with a format similar
to what journalctl uses."

>
> Fixes RFE: journal reader in guestfish
> ---
>  cat/log.c             |  4 +++
>  fish/journal.c        |  3 +-
>  generator/Makefile.am |  6 ++--
>  generator/actions.ml  | 22 ++++++++++++
>  generator/journal.ml  | 97
+++++++++++++++++++++++++++++++++++++++++++++++++++
>  generator/main.ml     |  3 ++
>  6 files changed, 131 insertions(+), 4 deletions(-)
>  create mode 100644 generator/journal.ml
>
> diff --git a/cat/log.c b/cat/log.c
> index f05eae0..157ee55 100644
> --- a/cat/log.c
> +++ b/cat/log.c
> @@ -36,6 +36,7 @@
>
>  #include "guestfs.h"
>  #include "options.h"
> +#include "journal.h"
>
>  /* Currently open libguestfs handle. */
>  guestfs_h *g;
> @@ -279,6 +280,9 @@ do_log_journal (void)
>    if (guestfs_journal_open (g, JOURNAL_DIR) == -1)
>      return -1;
>
> +  if (journal_view ("~3axv") == -1)
> +    return -1;
> +
>    if (guestfs_journal_close (g) == -1)
>      return -1;
>

This should be part of patch #1 if possible.

> diff --git a/fish/journal.c b/fish/journal.c
> index 9afdf60..579a1d1 100644
> --- a/fish/journal.c
> +++ b/fish/journal.c
> @@ -83,9 +83,8 @@ lookup_field (char field)
>  int
>  journal_view (const char *fields)
>  {
> -  int r;
>    int errors = 0;
> -  while ((r = guestfs_journal_next(g)) > 0) {
> +  while (guestfs_journal_next(g) > 0) {
>      CLEANUP_FREE_XATTR_LIST struct guestfs_xattr_list *xattrs = NULL;
>      int64_t ts;
>      int priority = LOG_INFO;

Ditto.

> diff --git a/generator/Makefile.am b/generator/Makefile.am
> index a3fe50d..bd466c2 100644
> --- a/generator/Makefile.am
> +++ b/generator/Makefile.am
> @@ -37,6 +37,7 @@ sources = \
>  	haskell.ml \
>  	java.ml \
>  	lua.ml \
> +	journal.ml \
>  	main.ml \
>  	ocaml.ml \
>  	optgroups.ml \
> @@ -60,13 +61,14 @@ sources = \
>  objects = \
>  	types.cmo \
>  	utils.cmo \
> +	pr.cmo \
> +	docstrings.cmo \
> +	journal.cmo \
>  	actions.cmo \
>  	structs.cmo \
>  	optgroups.cmo \
>  	prepopts.cmo \
>  	events.cmo \
> -	pr.cmo \
> -	docstrings.cmo \
>  	checks.cmo \
>  	c.cmo \
>  	xdr.cmo \
> diff --git a/generator/actions.ml b/generator/actions.ml
> index 13c8bc8..e914fd3 100644
> --- a/generator/actions.ml
> +++ b/generator/actions.ml
> @@ -21,6 +21,8 @@
>  open Types
>  open Utils
>
> +open Journal
> +
>  (* Default settings for all action fields.  So we copy and override
>   * this struct by writing '{ defaults with name = &c }'
>   *)
> @@ -12897,6 +12899,26 @@ environment variable.
>  See also L</hexdump>." };
>
>    { defaults with
> +    name = "journal_view";
> +    shortdesc = "view journald log";
> +    longdesc = "  journal-view [FORMAT]
> +
> +View journald log in format similar to journalctl.

"journalctl" could be linkified, so L<journalctl(1)>.

> +
> +=over
> +
> +"
> +^ (Journal.ops_to_pod_string ()) ^
> +"
> +=back
> +
> +Default format is C<~3axv>

"The default format is C<~3axv>."

> +
> +For fields description see C<man SYSTEMD.JOURNAL-FIELDS>

There's the proper format for linking man pages, so it should be
L<systemd.journal-fields(7)>.

> +
> +Use C<journal-open> first." };

C<guestfs_journal_open> here, so it gets proper linking.

> +
> +  { defaults with
>      name = "lcd";
>      shortdesc = "change working directory";
>      longdesc = " lcd directory
> diff --git a/generator/journal.ml b/generator/journal.ml
> new file mode 100644
> index 0000000..46d93cd
> --- /dev/null
> +++ b/generator/journal.ml
> @@ -0,0 +1,97 @@
> +(* libguestfs
> + * Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
> + *)
> +
> +(* Please read generator/README first. *)
> +
> +open Printf
> +
> +open String
> +open Docstrings
> +open Pr
> +
> +open Char
> +open List

I guess you don't need to open List, if later you always use it like
List.foo.

> +
> +(* Arguments used by journal-view command *)
> +
> +type op_type = Options of (char * string) list;;       (* option, option
name*)

What is Options? I cannot find it neither in the OCaml standard library
nor in the generator own types...

As a style note, usually ;; at the end of top-level statements are not
used in libguestfs' code.

> +let op = Options [
> +  (* Trusted fields *)
> +  ('a', "_PID");
> +  ('b', "_UID");
> +  ('c', "_GID");
> +  ('d', "_COMM");
> +  ('e', "_EXE");
> +  ('f', "_CMDLINE");
> +  ('g', "_CAP_EFFECTIVE");
> +  ('h', "_AUDIT_SESSION");
> +  ('i', "_AUDIT_LOGINUID");
> +  ('j', "_SYSTEMD_CGROUP");
> +  ('k', "_SYSTEMD_SESSION");
> +  ('l', "_SYSTEMD_UNIT");
> +  ('m', "_SYSTEMD_USER_UNIT");
> +  ('n', "_SYSTEMD_OWNER_UID");
> +  ('o', "_SYSTEMD_SLICE");
> +  ('p', "_SELINUX_CONTEXT");
> +  ('q', "_SOURCE_REALTIME_TIMESTAMP");
> +  ('r', "_BOOT_ID");
> +  ('s', "_MACHINE_ID");
> +  ('t', "_HOSTNAME");
> +  ('u', "_TRANSPORT");
> +  (* User fields *)
> +  ('v', "MESSAGE");
> +  ('w', "MESSAGE_ID");
> +  ('x', "PRIORITY");
> +  ('y', "CODE_FILE");
> +  ('z', "CODE_LINE");
> +  ('0', "CODE_FUNC");
> +  ('1', "ERRNO");
> +  ('2', "SYSLOG_FACILITY");
> +  ('3', "SYSLOG_IDENTIFIER");
> +  ('4', "SYSLOG_PID");
> +  ('~', "timestamp")
> +];;
> +
> +let deopt x = match x with Options y -> y;;

Considering you always call deopt on 'op', declaring it as
(char * string) list should be enough, I guess.

> +let string_list_to_string s = List.fold_left (fun a b -> a ^ b)
"" s;;

Using String.concat would make it easier to read/understand... although
seems not used at all.

> +let ops_to_pod_string () > +  List.fold_left (fun a b -> a ^ b)
""

String.concat here would be easier.

> +    (List.map (fun (a,b) -> "=item " ^ escaped a ^ "
" ^ b ^ "\n\n")
> +      (deopt op));;
> +
> +let ops_to_c_array arrname () > +  let decl = "static const char
*const " ^ arrname ^ "[] = {\n" in

Considering it does not change, you could put the array opening and
closing directly in the printed C code.

> +  decl ^ String.concat ",\n"
> +    (List.map (fun (a,b) -> "  \"" ^ escaped a ^
"\", \"" ^ b ^ "\"")
> +      (deopt op)) ^ "\n};";;

IMHO this could be inline in generate_journal_h, just using List.iter
to print each line in the array.

> +let generate_journal_h () > +  generate_header CStyle LGPLv2plus;
> +  pr "#include <config.h>\n";
> +  pr "\n";
> +  pr "#ifndef JOURNAL_H\n";
> +  pr "#define JOURNAL_H\n";
> +  pr "\n";
> +  pr "%s\n" (ops_to_c_array "journal_fields" ());
> +  pr "\n";
> +  pr "/* in journal.c */\n";
> +  pr "extern int journal_view (const char *fields);\n";
> +  pr "#endif /* JOURNAL_H */\n";

The generated code here could be better: instead of generating an array
each field code (as string) and name one after the other, have a list
of structs:

 static const struct JournalField {
   char field;
   const char *name;
 } fields[] = {
   { 'a', "_PID" },
   ...
 };

>From what I see in these patches, it seems like the array with fields
is just an implementation detail of journal_view, and thus not worth
exposing in journal.h. Maybe generate a journal-fields.h (or even .c)
to include directly in journal.c, so journal.h can stay as
non-generated file.

Thanks,
--
Pino Toscano