Maros Zatko
2015-Oct-16 17:05 UTC
[Libguestfs] [PATCH v6 0/2] RFE: journal reader in guestfish
Output is configurable, it's the same format as virt-log has, since both uses same code. First patch moves get_journal_field around and renames it to journal_view and the next one reimplements it a bit and brings it to guestfish. Maros Zatko (2): cat: move get_journal_field to fish/journal.c fish: add journal-view command (RHBZ#988100) .gnulib | 2 +- cat/Makefile.am | 1 + cat/log.c | 114 +--------------------------------- fish/Makefile.am | 1 + fish/journal.c | 151 +++++++++++++++++++++++++++++++++++++++++++++ fish/journal.h | 26 ++++++++ generator/Makefile.am | 6 +- generator/actions.ml | 36 +++++++++++ generator/journalfields.ml | 87 ++++++++++++++++++++++++++ generator/main.ml | 3 + po/POTFILES | 1 + src/guestfs-internal.h | 5 ++ src/proto.c | 14 +++++ 13 files changed, 333 insertions(+), 114 deletions(-) create mode 100644 fish/journal.c create mode 100644 fish/journal.h create mode 100644 generator/journalfields.ml -- 1.9.3
Maros Zatko
2015-Oct-16 17:05 UTC
[Libguestfs] [PATCH v6 1/2] cat: move get_journal_field to fish/journal.c
--- cat/Makefile.am | 1 + cat/log.c | 114 ++--------------------------------------- fish/Makefile.am | 1 + fish/journal.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ fish/journal.h | 26 ++++++++++ 5 files changed, 183 insertions(+), 111 deletions(-) create mode 100644 fish/journal.c create mode 100644 fish/journal.h diff --git a/cat/Makefile.am b/cat/Makefile.am index d0db6fa..d472100 100644 --- a/cat/Makefile.am +++ b/cat/Makefile.am @@ -38,6 +38,7 @@ bin_PROGRAMS = virt-cat virt-filesystems virt-log virt-ls SHARED_SOURCE_FILES = \ ../fish/domain.c \ ../fish/inspect.c \ + ../fish/journal.c \ ../fish/keys.c \ ../fish/options.h \ ../fish/options.c \ diff --git a/cat/log.c b/cat/log.c index 5069398..b092667 100644 --- a/cat/log.c +++ b/cat/log.c @@ -36,6 +36,7 @@ #include "guestfs.h" #include "options.h" +#include "fish/journal.h" /* Currently open libguestfs handle. */ guestfs_h *g; @@ -273,128 +274,19 @@ do_log (void) return 0; } -/* Find the value of the named field from the list of attributes. If - * not found, returns NULL (not an error). If found, returns a - * pointer to the field, and the length of the field. NOTE: The field - * is NOT \0-terminated, so you have to print it using "%.*s". - * - * There may be multiple fields with the same name. In this case, the - * function returns the first entry. - */ -static const char * -get_journal_field (const struct guestfs_xattr_list *xattrs, const char *name, - size_t *len_rtn) -{ - uint32_t i; - - for (i = 0; i < xattrs->len; ++i) { - if (STREQ (name, xattrs->val[i].attrname)) { - *len_rtn = xattrs->val[i].attrval_len; - return xattrs->val[i].attrval; - } - } - - return NULL; /* not found */ -} - -static const char *const log_level_table[] = { - [LOG_EMERG] = "emerg", - [LOG_ALERT] = "alert", - [LOG_CRIT] = "crit", - [LOG_ERR] = "err", - [LOG_WARNING] = "warning", - [LOG_NOTICE] = "notice", - [LOG_INFO] = "info", - [LOG_DEBUG] = "debug" -}; - static int do_log_journal (void) { - int r; - unsigned errors = 0; - if (guestfs_journal_open (g, JOURNAL_DIR) == -1) return -1; - while ((r = guestfs_journal_next (g)) > 0) { - CLEANUP_FREE_XATTR_LIST struct guestfs_xattr_list *xattrs = NULL; - const char *priority_str, *identifier, *comm, *pid, *message; - size_t priority_len, identifier_len, comm_len, pid_len, message_len; - int priority = LOG_INFO; - int64_t ts; - - /* The question is what fields to display. We should probably - * make this configurable, but for now use the "short" format from - * journalctl. (XXX) - */ - - xattrs = guestfs_journal_get (g); - if (xattrs == NULL) - return -1; - - ts = guestfs_journal_get_realtime_usec (g); /* error checked below */ - - priority_str = get_journal_field (xattrs, "PRIORITY", &priority_len); - //hostname = get_journal_field (xattrs, "_HOSTNAME", &hostname_len); - identifier = get_journal_field (xattrs, "SYSLOG_IDENTIFIER", - &identifier_len); - comm = get_journal_field (xattrs, "_COMM", &comm_len); - pid = get_journal_field (xattrs, "_PID", &pid_len); - message = get_journal_field (xattrs, "MESSAGE", &message_len); - - /* Timestamp. */ - if (ts >= 0) { - char buf[64]; - time_t t = ts / 1000000; - struct tm tm; - - if (strftime (buf, sizeof buf, "%b %d %H:%M:%S", - localtime_r (&t, &tm)) <= 0) { - fprintf (stderr, _("%s: could not format journal entry timestamp\n"), - guestfs_int_program_name); - errors++; - continue; - } - fputs (buf, stdout); - } - - /* Hostname. */ - /* We don't print this because it is assumed each line from the - * guest will have the same hostname. (XXX) - */ - //if (hostname) - // printf (" %.*s", (int) hostname_len, hostname); - - /* Identifier. */ - if (identifier) - printf (" %.*s", (int) identifier_len, identifier); - else if (comm) - printf (" %.*s", (int) comm_len, comm); - - /* PID */ - if (pid) - printf ("[%.*s]", (int) pid_len, pid); - - /* Log level. */ - if (priority_str && *priority_str >= '0' && *priority_str <= '7') - priority = *priority_str - '0'; - - printf (" %s:", log_level_table[priority]); - - /* Message. */ - if (message) - printf (" %.*s", (int) message_len, message); - - printf ("\n"); - } - if (r == -1) /* error from guestfs_journal_next */ + if (journal_view () == -1) return -1; if (guestfs_journal_close (g) == -1) return -1; - return errors > 0 ? -1 : 0; + return 0; } static int diff --git a/fish/Makefile.am b/fish/Makefile.am index c4b82ae..e4b4fcf 100644 --- a/fish/Makefile.am +++ b/fish/Makefile.am @@ -94,6 +94,7 @@ guestfish_SOURCES = \ glob.c \ help.c \ hexedit.c \ + journal.c \ lcd.c \ man.c \ more.c \ diff --git a/fish/journal.c b/fish/journal.c new file mode 100644 index 0000000..15d058a --- /dev/null +++ b/fish/journal.c @@ -0,0 +1,152 @@ +/* guestfish - guest filesystem shell + * Copyright (C) 2009-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. + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <inttypes.h> +#include <libintl.h> +#include <time.h> +#include <syslog.h> + +#include "fish.h" +#include "journal.h" + +/* Find the value of the named field from the list of attributes. If + * not found, returns NULL (not an error). If found, returns a + * pointer to the field, and the length of the field. NOTE: The field + * is NOT \0-terminated, so you have to print it using "%.*s". + * + * There may be multiple fields with the same name. In this case, the + * function returns the first entry. + */ +static const char * +get_journal_field (const struct guestfs_xattr_list *xattrs, const char *name, + size_t *len_rtn) +{ + uint32_t i; + + for (i = 0; i < xattrs->len; ++i) { + if (STREQ (name, xattrs->val[i].attrname)) { + *len_rtn = xattrs->val[i].attrval_len; + return xattrs->val[i].attrval; + } + } + + return NULL; /* not found */ +} + +static const char *const log_level_table[] = { + [LOG_EMERG] = "emerg", + [LOG_ALERT] = "alert", + [LOG_CRIT] = "crit", + [LOG_ERR] = "err", + [LOG_WARNING] = "warning", + [LOG_NOTICE] = "notice", + [LOG_INFO] = "info", + [LOG_DEBUG] = "debug" +}; + +int +journal_view (void) +{ + int r; + unsigned errors = 0; + + while ((r = guestfs_journal_next (g)) > 0) { + CLEANUP_FREE_XATTR_LIST struct guestfs_xattr_list *xattrs = NULL; + const char *priority_str, *identifier, *comm, *pid, *message; + size_t priority_len, identifier_len, comm_len, pid_len, message_len; + int priority = LOG_INFO; + int64_t ts; + + /* The question is what fields to display. We should probably + * make this configurable, but for now use the "short" format from + * journalctl. (XXX) + */ + + xattrs = guestfs_journal_get (g); + if (xattrs == NULL) + return -1; + + ts = guestfs_journal_get_realtime_usec (g); /* error checked below */ + + priority_str = get_journal_field (xattrs, "PRIORITY", &priority_len); + //hostname = get_journal_field (xattrs, "_HOSTNAME", &hostname_len); + identifier = get_journal_field (xattrs, "SYSLOG_IDENTIFIER", + &identifier_len); + comm = get_journal_field (xattrs, "_COMM", &comm_len); + pid = get_journal_field (xattrs, "_PID", &pid_len); + message = get_journal_field (xattrs, "MESSAGE", &message_len); + + /* Timestamp. */ + if (ts >= 0) { + char buf[64]; + time_t t = ts / 1000000; + struct tm tm; + + if (strftime (buf, sizeof buf, "%b %d %H:%M:%S", + localtime_r (&t, &tm)) <= 0) { + fprintf (stderr, _("could not format journal entry timestamp\n")); + errors++; + continue; + } + fputs (buf, stdout); + } + + /* Hostname. */ + /* We don't print this because it is assumed each line from the + * guest will have the same hostname. (XXX) + */ + //if (hostname) + // printf (" %.*s", (int) hostname_len, hostname); + + /* Identifier. */ + if (identifier) + printf (" %.*s", (int) identifier_len, identifier); + else if (comm) + printf (" %.*s", (int) comm_len, comm); + + /* PID */ + if (pid) + printf ("[%.*s]", (int) pid_len, pid); + + /* Log level. */ + if (priority_str && *priority_str >= '0' && *priority_str <= '7') + priority = *priority_str - '0'; + + printf (" %s:", log_level_table[priority]); + + /* Message. */ + if (message) + printf (" %.*s", (int) message_len, message); + + printf ("\n"); + } + if (r == -1) /* error from guestfs_journal_next */ + return -1; + + if (guestfs_journal_close (g) == -1) + return -1; + + return errors > 0 ? -1 : 0; +} diff --git a/fish/journal.h b/fish/journal.h new file mode 100644 index 0000000..556324e --- /dev/null +++ b/fish/journal.h @@ -0,0 +1,26 @@ +/* guestfish - guest filesystem shell + * Copyright (C) 2009-2015 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> + +#ifndef JOURNAL_H +#define JOURNAL_H + +/* in journal.c */ +extern int journal_view (void); +#endif /* JOURNAL_H */ -- 1.9.3
Maros Zatko
2015-Oct-16 17:05 UTC
[Libguestfs] [PATCH v6 2/2] fish: add journal-view command (RHBZ#988100)
Let the user view the journald log from a guest, with a format similar to what journalctl uses. Fixes RFE: journal reader in guestfish --- .gnulib | 2 +- cat/log.c | 2 +- fish/journal.c | 133 ++++++++++++++++++++++----------------------- fish/journal.h | 2 +- generator/Makefile.am | 6 +- generator/actions.ml | 36 ++++++++++++ generator/journalfields.ml | 87 +++++++++++++++++++++++++++++ generator/main.ml | 3 + po/POTFILES | 1 + src/guestfs-internal.h | 5 ++ src/proto.c | 14 +++++ 11 files changed, 219 insertions(+), 72 deletions(-) create mode 100644 generator/journalfields.ml diff --git a/.gnulib b/.gnulib index eda101a..3ca9a53 160000 --- a/.gnulib +++ b/.gnulib @@ -1 +1 @@ -Subproject commit eda101a012571c3d043380c959d0aa04de40e721 +Subproject commit 3ca9a533c245fb472b686b30dd9645855f2be3ba diff --git a/cat/log.c b/cat/log.c index b092667..9d61412 100644 --- a/cat/log.c +++ b/cat/log.c @@ -280,7 +280,7 @@ do_log_journal (void) if (guestfs_journal_open (g, JOURNAL_DIR) == -1) return -1; - if (journal_view () == -1) + if (journal_view ("~3axv") == -1) return -1; if (guestfs_journal_close (g) == -1) diff --git a/fish/journal.c b/fish/journal.c index 15d058a..d1ed96c 100644 --- a/fish/journal.c +++ b/fish/journal.c @@ -30,6 +30,7 @@ #include "fish.h" #include "journal.h" +#include "journal-fields.h" /* Find the value of the named field from the list of attributes. If * not found, returns NULL (not an error). If found, returns a @@ -66,87 +67,85 @@ static const char *const log_level_table[] = { [LOG_DEBUG] = "debug" }; +static const char * +lookup_field (char field) +{ + size_t i = 0; + for (i = 0; i < sizeof journal_fields / sizeof *journal_fields; ++i) { + if (field == journal_fields[i].field) + return journal_fields[i].name; + } + return NULL; +} + +/* Fetch and print journal fields in specified order + * default is '~3axv' + */ int -journal_view (void) +journal_view (const char *fields) { - int r; - unsigned errors = 0; + int errors = 0; + guestfs_clear_user_cancelled (g); - while ((r = guestfs_journal_next (g)) > 0) { + while (guestfs_journal_next(g) > 0) { CLEANUP_FREE_XATTR_LIST struct guestfs_xattr_list *xattrs = NULL; - const char *priority_str, *identifier, *comm, *pid, *message; - size_t priority_len, identifier_len, comm_len, pid_len, message_len; - int priority = LOG_INFO; int64_t ts; - - /* The question is what fields to display. We should probably - * make this configurable, but for now use the "short" format from - * journalctl. (XXX) - */ + int priority = LOG_INFO; xattrs = guestfs_journal_get (g); if (xattrs == NULL) return -1; - ts = guestfs_journal_get_realtime_usec (g); /* error checked below */ - - priority_str = get_journal_field (xattrs, "PRIORITY", &priority_len); - //hostname = get_journal_field (xattrs, "_HOSTNAME", &hostname_len); - identifier = get_journal_field (xattrs, "SYSLOG_IDENTIFIER", - &identifier_len); - comm = get_journal_field (xattrs, "_COMM", &comm_len); - pid = get_journal_field (xattrs, "_PID", &pid_len); - message = get_journal_field (xattrs, "MESSAGE", &message_len); - - /* Timestamp. */ - if (ts >= 0) { - char buf[64]; - time_t t = ts / 1000000; - struct tm tm; - - if (strftime (buf, sizeof buf, "%b %d %H:%M:%S", - localtime_r (&t, &tm)) <= 0) { - fprintf (stderr, _("could not format journal entry timestamp\n")); - errors++; - continue; + size_t f_id = 0; + for (f_id = 0; f_id < strlen (fields); ++f_id) { + if (guestfs_is_user_cancelled (g)) + return errors > 0 ? -1 : 0; + + if (fields[f_id] == '~') { + ts = guestfs_journal_get_realtime_usec (g); + /* Timestamp. */ + if (ts >= 0) { + char buf[64]; + time_t t = ts / 1000000; + struct tm tm; + + if (strftime (buf, sizeof buf, "%b %d %H:%M:%S", + localtime_r (&t, &tm)) <= 0) { + fprintf (stderr, _("could not format journal entry timestamp\n")); + errors++; + continue; + } + fputs (buf, stdout); + } } - fputs (buf, stdout); - } - - /* Hostname. */ - /* We don't print this because it is assumed each line from the - * guest will have the same hostname. (XXX) - */ - //if (hostname) - // printf (" %.*s", (int) hostname_len, hostname); - - /* Identifier. */ - if (identifier) - printf (" %.*s", (int) identifier_len, identifier); - else if (comm) - printf (" %.*s", (int) comm_len, comm); - - /* PID */ - if (pid) - printf ("[%.*s]", (int) pid_len, pid); - - /* Log level. */ - if (priority_str && *priority_str >= '0' && *priority_str <= '7') - priority = *priority_str - '0'; - - printf (" %s:", log_level_table[priority]); - - /* Message. */ - if (message) - printf (" %.*s", (int) message_len, message); + const char *field_name, *field_val; + size_t field_len; + field_name = lookup_field (fields[f_id]); + if (field_name != NULL) { + field_val = get_journal_field (xattrs, field_name, &field_len); + if (STREQ (field_name, "PRIORITY")) { + if (field_val && *field_val >= '0' && *field_val <= '7') + priority = *field_val - '0'; + printf (" %s:", log_level_table[priority]); + } else if (field_val) { + printf (" %.*s", (int)field_len, field_val); + } + } else { + fprintf (stderr, _("unknown journal field '%c'\n"), fields[f_id]); + return -1; + } + } printf ("\n"); } - if (r == -1) /* error from guestfs_journal_next */ - return -1; - - if (guestfs_journal_close (g) == -1) - return -1; return errors > 0 ? -1 : 0; } + +int +run_journal_view (const char *cmd, size_t argc, char *argv[]) +{ + if (argc > 0) + return journal_view (argv[0]); + return journal_view ("~3axv"); +} diff --git a/fish/journal.h b/fish/journal.h index 556324e..c76b0f0 100644 --- a/fish/journal.h +++ b/fish/journal.h @@ -22,5 +22,5 @@ #define JOURNAL_H /* in journal.c */ -extern int journal_view (void); +extern int journal_view (const char *fields); #endif /* JOURNAL_H */ diff --git a/generator/Makefile.am b/generator/Makefile.am index a3fe50d..b7e4582 100644 --- a/generator/Makefile.am +++ b/generator/Makefile.am @@ -37,6 +37,7 @@ sources = \ haskell.ml \ java.ml \ lua.ml \ + journalfields.ml \ main.ml \ ocaml.ml \ optgroups.ml \ @@ -60,13 +61,14 @@ sources = \ objects = \ types.cmo \ utils.cmo \ + pr.cmo \ + docstrings.cmo \ + journalfields.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 274ef3f..165edd6 100644 --- a/generator/actions.ml +++ b/generator/actions.ml @@ -3059,6 +3059,22 @@ the default. Else F</var/tmp> is the default." }; Get the directory used by the handle to store the appliance cache." }; { defaults with + name = "clear_user_cancelled"; added = (1, 31, 3); + style = RErr, [], []; + blocking = false; wrapper = false; + shortdesc = "clears user cancellation flag"; + longdesc = "\ +Clears the cancellation flag." }; + + { defaults with + name = "is_user_cancelled"; added = (1, 31, 3); + style = RErr, [], []; + blocking = false; wrapper = false; + shortdesc = "check if current upload or download operation is cancelled"; + longdesc = "\ +Read the cancellation flag." }; + + { defaults with name = "user_cancel"; added = (1, 11, 18); style = RErr, [], []; blocking = false; wrapper = false; @@ -12957,6 +12973,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 L<journalctl(1)>. + +=over + +" +^ (Journalfields.ops_to_pod_string ()) ^ +" +=back + +The default format is C<~3axv>. + +For fields description see L<systemd.journal-fields>(7). + +Use C<guestfs_journal_open> first." }; + + { defaults with name = "lcd"; shortdesc = "change working directory"; longdesc = " lcd directory diff --git a/generator/journalfields.ml b/generator/journalfields.ml new file mode 100644 index 0000000..4746457 --- /dev/null +++ b/generator/journalfields.ml @@ -0,0 +1,87 @@ +(* 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 Docstrings +open Pr + +open Char +open List + +(* Arguments used by journal-view command *) + +type op_type = (char * string) list (* option, option name*) + +let ops = [ + (* 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 ops_to_pod_string () + String.concat "" + (map (fun (a,b) -> "=item " ^ escaped a ^ " " ^ b ^ "\n\n") ops) + +let generate_journal_fields_h () + generate_header CStyle LGPLv2plus; + pr "#include <config.h>\n"; + pr "\n"; + pr "#ifndef JOURNAL_FIELDS_H\n"; + pr "#define JOURNAL_FIELDS_H\n"; + pr "\n"; + pr "static const struct JournalField {\n"; + pr " char field;\n"; + pr " const char *name;\n"; + pr "} journal_fields[] = {\n"; + iter (fun (a,b) -> pr " {'%c', \"%s\"},\n" a b) ops; + pr "};\n\n"; + pr "#endif /* JOURNAL_FIELDS_H */\n" diff --git a/generator/main.ml b/generator/main.ml index 1e0e7d6..b78de0a 100644 --- a/generator/main.ml +++ b/generator/main.ml @@ -46,6 +46,7 @@ open Golang open Bindtests open Errnostring open Customize +open Journalfields 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-fields.h" generate_journal_fields_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 diff --git a/po/POTFILES b/po/POTFILES index cd2c437..6d14181 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -143,6 +143,7 @@ fish/glob.c fish/help.c fish/hexedit.c fish/inspect.c +fish/journal.c fish/keys.c fish/lcd.c fish/man.c diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h index 49da6fe..7b6ccff 100644 --- a/src/guestfs-internal.h +++ b/src/guestfs-internal.h @@ -461,6 +461,11 @@ struct guestfs_h */ int user_cancel; + /* User cancelled transfer. Similar to user_cancel, + * it is cleared after calling guestfs_clear_user_cancelled. + */ + int was_user_cancel; + struct timeval launch_t; /* The time that we called guestfs_launch. */ /* Used by bindtests. */ diff --git a/src/proto.c b/src/proto.c index efe9dfb..f730b15 100644 --- a/src/proto.c +++ b/src/proto.c @@ -872,5 +872,19 @@ int guestfs_user_cancel (guestfs_h *g) { g->user_cancel = 1; + g->was_user_cancel = 1; return 0; } + +int +guestfs_clear_user_cancelled (guestfs_h *g) +{ + g->was_user_cancel = 0; + return 0; +} + +int +guestfs_is_user_cancelled (guestfs_h *g) +{ + return g->was_user_cancel; +} -- 1.9.3