summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlasdair G Kergon <agk@redhat.com>2012-08-26 00:19:52 +0100
committerAlasdair G Kergon <agk@redhat.com>2012-08-26 00:19:52 +0100
commit92330ba9c8e21451f8406377ae4839f397f369a2 (patch)
treea079d36b7a8d13f13e70b4c583eedb9b6ebfeb1a
parent3acc85caa8d313b8c21e4bef7f84601731e74b2b (diff)
downloadlvm2-92330ba9c8e21451f8406377ae4839f397f369a2.zip
lvm2-92330ba9c8e21451f8406377ae4839f397f369a2.tar.gz
lvm2-92330ba9c8e21451f8406377ae4839f397f369a2.tar.xz
setvbuf: close and reopen stream before change
Fix setvbuf code by closing and reopening stream before changing buffer. But we need to review what this code is doing embedded inside a library function rather than the simpler original form being run independently at the top of main() by tools that need it.
-rw-r--r--WHATS_NEW1
-rw-r--r--lib/commands/toolcontext.c65
2 files changed, 60 insertions, 6 deletions
diff --git a/WHATS_NEW b/WHATS_NEW
index acb158b..85f8663 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.98 -
=================================
+ Fix setvbuf code by closing and reopening stream before changing buffer.
Disable private buffering when using liblvm.
When private stdin/stdout buffering is not used always use silent mode.
Add log/silent to lvm.conf equivalent to -qq.
diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c
index 4230624..0ede104 100644
--- a/lib/commands/toolcontext.c
+++ b/lib/commands/toolcontext.c
@@ -1245,6 +1245,37 @@ static void _init_globals(struct cmd_context *cmd)
init_mirror_in_sync(0);
}
+/*
+ * Close and reopen stream on file descriptor fd.
+ */
+static int _reopen_stream(FILE *stream, int fd, const char *mode, const char *name, FILE **new_stream)
+{
+ int fd_copy, new_fd;
+
+ if ((fd_copy = dup(fd)) < 0) {
+ log_sys_error("dup", name);
+ return 0;
+ }
+
+ if (fclose(stream))
+ log_sys_error("fclose", name);
+
+ if ((new_fd = dup2(fd_copy, fd)) < 0)
+ log_sys_error("dup2", name);
+ else if (new_fd != fd)
+ log_error("dup2(%d, %d) returned %d", fd_copy, fd, new_fd);
+
+ if (close(fd_copy) < 0)
+ log_sys_error("close", name);
+
+ if (!(*new_stream = fdopen(fd, mode))) {
+ log_sys_error("fdopen", name);
+ return 0;
+ }
+
+ return 1;
+}
+
/* Entry point */
struct cmd_context *create_toolcontext(unsigned is_long_lived,
const char *system_dir,
@@ -1252,6 +1283,7 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
unsigned threaded)
{
struct cmd_context *cmd;
+ FILE *new_stream;
#ifdef M_MMAP_MAX
mallopt(M_MMAP_MAX, 0);
@@ -1293,9 +1325,20 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
log_error("Failed to allocate line buffer.");
goto out;
}
- if ((setvbuf(stdin, cmd->linebuffer, _IOLBF, linebuffer_size) ||
- setvbuf(stdout, cmd->linebuffer + linebuffer_size,
- _IOLBF, linebuffer_size))) {
+
+ if (!_reopen_stream(stdin, STDIN_FILENO, "r", "stdin", &new_stream))
+ goto_out;
+ stdin = new_stream;
+ if (setvbuf(stdin, cmd->linebuffer, _IOLBF, linebuffer_size)) {
+ log_sys_error("setvbuf", "");
+ goto out;
+ }
+
+ if (!_reopen_stream(stdout, STDOUT_FILENO, "w", "stdout", &new_stream))
+ goto_out;
+ stdout = new_stream;
+ if (setvbuf(stdout, cmd->linebuffer + linebuffer_size,
+ _IOLBF, linebuffer_size)) {
log_sys_error("setvbuf", "");
goto out;
}
@@ -1546,6 +1589,7 @@ int refresh_toolcontext(struct cmd_context *cmd)
void destroy_toolcontext(struct cmd_context *cmd)
{
struct dm_config_tree *cft_cmdline;
+ FILE *new_stream;
if (cmd->dump_filter)
persistent_filter_dump(cmd->filter, 1);
@@ -1570,9 +1614,18 @@ void destroy_toolcontext(struct cmd_context *cmd)
if (cmd->linebuffer) {
/* Reset stream buffering to defaults */
- setlinebuf(stdin);
- fflush(stdout);
- setlinebuf(stdout);
+ if (_reopen_stream(stdin, STDIN_FILENO, "r", "stdin", &new_stream)) {
+ stdin = new_stream;
+ setlinebuf(stdin);
+ } else
+ cmd->linebuffer = NULL; /* Leave buffer in place (deliberate leak) */
+
+ if (_reopen_stream(stdout, STDOUT_FILENO, "w", "stdout", &new_stream)) {
+ stdout = new_stream;
+ setlinebuf(stdout);
+ } else
+ cmd->linebuffer = NULL; /* Leave buffer in place (deliberate leak) */
+
dm_free(cmd->linebuffer);
}