1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

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.
This commit is contained in:
Alasdair G Kergon 2012-08-26 00:19:52 +01:00
parent 3acc85caa8
commit 92330ba9c8
2 changed files with 60 additions and 6 deletions

View File

@ -1,5 +1,6 @@
Version 2.02.98 - Version 2.02.98 -
================================= =================================
Fix setvbuf code by closing and reopening stream before changing buffer.
Disable private buffering when using liblvm. Disable private buffering when using liblvm.
When private stdin/stdout buffering is not used always use silent mode. When private stdin/stdout buffering is not used always use silent mode.
Add log/silent to lvm.conf equivalent to -qq. Add log/silent to lvm.conf equivalent to -qq.

View File

@ -1245,6 +1245,37 @@ static void _init_globals(struct cmd_context *cmd)
init_mirror_in_sync(0); 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 */ /* Entry point */
struct cmd_context *create_toolcontext(unsigned is_long_lived, struct cmd_context *create_toolcontext(unsigned is_long_lived,
const char *system_dir, const char *system_dir,
@ -1252,6 +1283,7 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
unsigned threaded) unsigned threaded)
{ {
struct cmd_context *cmd; struct cmd_context *cmd;
FILE *new_stream;
#ifdef M_MMAP_MAX #ifdef M_MMAP_MAX
mallopt(M_MMAP_MAX, 0); 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."); log_error("Failed to allocate line buffer.");
goto out; goto out;
} }
if ((setvbuf(stdin, cmd->linebuffer, _IOLBF, linebuffer_size) ||
setvbuf(stdout, cmd->linebuffer + linebuffer_size, if (!_reopen_stream(stdin, STDIN_FILENO, "r", "stdin", &new_stream))
_IOLBF, linebuffer_size))) { 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", ""); log_sys_error("setvbuf", "");
goto out; goto out;
} }
@ -1546,6 +1589,7 @@ int refresh_toolcontext(struct cmd_context *cmd)
void destroy_toolcontext(struct cmd_context *cmd) void destroy_toolcontext(struct cmd_context *cmd)
{ {
struct dm_config_tree *cft_cmdline; struct dm_config_tree *cft_cmdline;
FILE *new_stream;
if (cmd->dump_filter) if (cmd->dump_filter)
persistent_filter_dump(cmd->filter, 1); persistent_filter_dump(cmd->filter, 1);
@ -1570,9 +1614,18 @@ void destroy_toolcontext(struct cmd_context *cmd)
if (cmd->linebuffer) { if (cmd->linebuffer) {
/* Reset stream buffering to defaults */ /* Reset stream buffering to defaults */
setlinebuf(stdin); if (_reopen_stream(stdin, STDIN_FILENO, "r", "stdin", &new_stream)) {
fflush(stdout); stdin = new_stream;
setlinebuf(stdout); 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); dm_free(cmd->linebuffer);
} }