[lvm-devel] [PATCH 1/2] lvm.c: Don't use GNU readline when no tty
Tony Asleson
tasleson at redhat.com
Fri Jan 8 21:37:16 UTC 2016
If you use lvm shell and write requests to STDIN and read from STDOUT over a
pipe you will find that the GNU readline library echos STDIN to STDOUT.
This wouldn't be so much of an issue if that's all it did, but it also
injects ' \r' (seemingly random) into STDOUT when echoing longer requests.
strace snippet from lvm shell:
...
read(0, "/", 1) = 1
write(1, "/", 1) = 1
read(0, "s", 1) = 1
write(1, "s \r", 3) = 3
read(0, "d", 1) = 1
write(1, "d", 1) = 1
...
This patch removes the calls to GNU readline when STDIN is not a tty as
readline functionality is not needed or wanted in this use case.
Signed-off-by: Tony Asleson <tasleson at redhat.com>
---
tools/lvm.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++---------
1 files changed, 47 insertions(+), 9 deletions(-)
diff --git a/tools/lvm.c b/tools/lvm.c
index 63cc0b4..2f3b911 100644
--- a/tools/lvm.c
+++ b/tools/lvm.c
@@ -181,22 +181,56 @@ static void _write_history(void)
log_very_verbose("Couldn't write history to %s.", hist_file);
}
+static char *_fetchline(const char *prompt)
+{
+ char *line = NULL;
+ size_t allocated_size = 0;
+
+ fprintf(stdout, "%s", prompt);
+ fflush(stdout);
+
+ if (getline(&line, &allocated_size, stdin) == -1) {
+ free(line);
+ line = NULL;
+ }
+
+ if (line) {
+ size_t l = strlen(line);
+
+ /* Mimic same behavior as readline, remove trailing \n if present */
+ if (l) {
+ l--;
+ if (line[l] == '\n')
+ line[l] = '\0';
+ }
+ }
+ return line;
+}
+
+typedef char *(*fetch_line_fp)(const char *);
+
int lvm_shell(struct cmd_context *cmd, struct cmdline_context *cmdline)
{
- int argc, ret;
+ int argc, ret = 0;
char *input = NULL, *args[MAX_ARGS], **argv;
+ int tty = 0;
+ fetch_line_fp get_next_line = _fetchline;
- rl_readline_name = "lvm";
- rl_attempted_completion_function = (rl_completion_func_t *) _completion;
+ tty = isatty(STDIN_FILENO);
- _read_history(cmd);
+ if (tty) {
+ rl_readline_name = "lvm";
+ rl_attempted_completion_function = (rl_completion_func_t *) _completion;
+ _read_history(cmd);
+ get_next_line = readline;
+ }
_cmdline = cmdline;
_cmdline->interactive = 1;
while (1) {
free(input);
- input = readline("lvm> ");
+ input = get_next_line("lvm> ");
/* EOF */
if (!input) {
@@ -209,7 +243,8 @@ int lvm_shell(struct cmd_context *cmd, struct cmdline_context *cmdline)
if (!*input)
continue;
- add_history(input);
+ if (tty)
+ add_history(input);
argv = args;
@@ -230,7 +265,8 @@ int lvm_shell(struct cmd_context *cmd, struct cmdline_context *cmdline)
continue;
if (!strcmp(argv[0], "quit") || !strcmp(argv[0], "exit")) {
- remove_history(history_length - 1);
+ if (tty)
+ remove_history(history_length - 1);
log_error("Exiting.");
break;
}
@@ -240,11 +276,13 @@ int lvm_shell(struct cmd_context *cmd, struct cmdline_context *cmdline)
log_error("No such command '%s'. Try 'help'.",
argv[0]);
- if ((ret != ECMD_PROCESSED) && !error_message_produced()) {
+ if ((ret != ECMD_PROCESSED) && !error_message_produced()) {
log_debug(INTERNAL_ERROR "Failed command did not use log_error");
log_error("Command failed with status code %d.", ret);
}
- _write_history();
+
+ if (tty)
+ _write_history();
}
free(input);
--
1.7.1
More information about the lvm-devel
mailing list