If users *-edit but make a mistake in XML all changes are permanently lost. However, if virsh is not running within a script we can ask user if he wants to re-edit the file and correct the mistakes. --- tools/console.c | 40 ++++++++++++++++++++++------------- tools/console.h | 2 + tools/virsh-edit.c | 38 ++++++++++++++++++++++++++++++---- tools/virsh.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 117 insertions(+), 20 deletions(-) diff --git a/tools/console.c b/tools/console.c index 34fde05..90e54e3 100644 --- a/tools/console.c +++ b/tools/console.c @@ -298,13 +298,36 @@ vshGetEscapeChar(const char *s) return *s; } +int vshMakeStdinRaw(struct termios *ttyattr, bool report_errors) { + struct termios rawattr; + + if (tcgetattr(STDIN_FILENO, ttyattr) < 0) { + if (report_errors) + VIR_ERROR(_("unable to get tty attributes: %s"), + strerror(errno)); + return -1; + } + + rawattr = *ttyattr; + cfmakeraw(&rawattr); + + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &rawattr) < 0) { + if (report_errors) + VIR_ERROR(_("unable to set tty attributes: %s"), + strerror(errno)); + return -1; + } + + return 0; +} + int vshRunConsole(virDomainPtr dom, const char *dev_name, const char *escape_seq, unsigned int flags) { int ret = -1; - struct termios ttyattr, rawattr; + struct termios ttyattr; void (*old_sigquit)(int); void (*old_sigterm)(int); void (*old_sigint)(int); @@ -317,21 +340,8 @@ int vshRunConsole(virDomainPtr dom, result in it being echoed back already), and also ensure Ctrl-C, etc is blocked, and misc other bits */ - if (tcgetattr(STDIN_FILENO, &ttyattr) < 0) { - VIR_ERROR(_("unable to get tty attributes: %s"), - strerror(errno)); - return -1; - } - - rawattr = ttyattr; - cfmakeraw(&rawattr); - - if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &rawattr) < 0) { - VIR_ERROR(_("unable to set tty attributes: %s"), - strerror(errno)); + if (vshMakeStdinRaw(&ttyattr, true) < 0) goto resettty; - } - /* Trap all common signals so that we can safely restore the original terminal settings on STDIN before the diff --git a/tools/console.h b/tools/console.h index 2b5440c..1feea9e 100644 --- a/tools/console.h +++ b/tools/console.h @@ -30,6 +30,8 @@ int vshRunConsole(virDomainPtr dom, const char *escape_seq, unsigned int flags); +int vshMakeStdinRaw(struct termios *ttyattr, bool report_errors); + # endif /* !WIN32 */ #endif /* __VIR_CONSOLE_H__ */ diff --git a/tools/virsh-edit.c b/tools/virsh-edit.c index b50946e..ef47f9d 100644 --- a/tools/virsh-edit.c +++ b/tools/virsh-edit.c @@ -55,6 +55,7 @@ do { char *doc = NULL; char *doc_edited = NULL; char *doc_reread = NULL; + char *msg = NULL; /* Get the XML configuration of the object. */ doc = (EDIT_GET_XML); @@ -66,6 +67,7 @@ do { if (!tmp) goto edit_cleanup; +reedit: /* Start the editor. */ if (editFile(ctl, tmp) == -1) goto edit_cleanup; @@ -80,6 +82,9 @@ do { EDIT_NOT_CHANGED } +redefine: + msg = NULL; + /* Now re-read the object XML. Did someone else change it while * it was being edited? This also catches problems such as us * losing a connection or the object going away. @@ -89,15 +94,38 @@ do { goto edit_cleanup; if (STRNEQ(doc, doc_reread)) { - vshError(ctl, "%s", _("ERROR: the XML configuration " - "was changed by another user")); - goto edit_cleanup; + msg = _("The XML configuration was changed by another user."); + VIR_FREE(doc); + doc = doc_reread; + doc_reread = NULL; } /* Everything checks out, so redefine the object. */ EDIT_FREE - if (!(EDIT_DEFINE)) - goto edit_cleanup; + if (!msg && !(EDIT_DEFINE)) { + msg = _("Failed."); + } + + if (msg) { + int c = vshAskReedit(ctl, msg); + switch (c) { + case 'y': + goto reedit; + break; + + case 'f': + goto redefine; + break; + + case 'n': + goto edit_cleanup; + break; + + default: + vshError(ctl, "%s", msg); + break; + } + } break; diff --git a/tools/virsh.c b/tools/virsh.c index 4af5334..574b92f 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -33,6 +33,7 @@ #include <signal.h> #include <poll.h> #include <strings.h> +#include <termios.h> #include <libxml/parser.h> #include <libxml/tree.h> @@ -654,6 +655,62 @@ vshReconnect(vshControl *ctl) ctl->useSnapshotOld = false; } +/** + * vshAskReedit: + * @msg: Question to ask user + * + * Ask user if he wants to return to previously + * edited file. + * + * Returns 'y' if he wants to + * 'f' if he forcibly wants to + * 'n' if he doesn't want to + * -1 on error + * 0 otherwise + */ +static int +vshAskReedit(vshControl *ctl, const char *msg) +{ +#ifndef WIN32 + int c = -1; + struct termios ttyattr; + + if (!isatty(STDIN_FILENO)) + return -1; + + virshReportError(ctl); + + if (vshMakeStdinRaw(&ttyattr, false) < 0) + return -1; + + while (true) { + /* TRANSLATORS: For now, we aren't using LC_MESSAGES, and the user + * choices really are limited to just 'y', 'n', 'f' and '?' */ + vshPrint(ctl, "\r%s %s", msg, _("Try again? [y,n,f,?]:")); + c = c_tolower(getchar()); + + if (c == '?') { + vshPrint(ctl, "\r\n%s", _("y - yes, start editor again\r\n" + "n - no, throw away my changes\r\n" + "f - force, try to redefine again\r\n" + "? - print this help\r\n")); + continue; + } else if (c == 'y' || c == 'n' || c == 'f') { + break; + } + } + + tcsetattr(STDIN_FILENO, TCSAFLUSH, &ttyattr); + + vshPrint(ctl, "\r\n"); + return c; +#else + vshDebug(ctl, VSH_ERR_WARNING, "%s", _("This function is not " + "supported on WIN32 platform")); + return 0; +#endif +} + /* --------------- * Commands * --------------- -- 1.7.8.5 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list