Lets user view journald log from VM in a similar format as 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; 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; 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. + +=over + +" +^ (Journal.ops_to_pod_string ()) ^ +" +=back + +Default format is C<~3axv> + +For fields description see C<man SYSTEMD.JOURNAL-FIELDS> + +Use C<journal-open> first." }; + + { 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 + +(* Arguments used by journal-view command *) + +type op_type = Options of (char * string) list;; (* option, option name*) + +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;; + +let string_list_to_string s = List.fold_left (fun a b -> a ^ b) "" s;; + +let ops_to_pod_string () = + List.fold_left (fun a b -> a ^ b) "" + (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 + decl ^ String.concat ",\n" + (List.map (fun (a,b) -> " \"" ^ escaped a ^ "\", \"" ^ b ^ "\"") + (deopt op)) ^ "\n};";; + +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"; diff --git a/generator/main.ml b/generator/main.ml index 1e0e7d6..639920d 100644 --- a/generator/main.ml +++ b/generator/main.ml @@ -46,6 +46,7 @@ open Golang open Bindtests open Errnostring open Customize +open Journal let perror msg = function | Unix_error (err, _, _) -> @@ -212,6 +213,8 @@ Run it from the top source directory using the command output_to "customize/customize-synopsis.pod" generate_customize_synopsis_pod; output_to "customize/customize-options.pod" generate_customize_options_pod; + output_to "fish/journal.h" generate_journal_h; + (* Generate the list of files generated -- last. *) printf "generated %d lines of code\n" (get_lines_generated ()); let files = List.sort compare (get_files_generated ()) in -- 1.9.3