Skip to content

Commit 49267c6

Browse files
zyvegmontkob
authored andcommitted
Ticket MidnightCommander#4784: extract command pipe reading code into a function to avoid duplication
Signed-off-by: Yury V. Zaytsev <[email protected]>
1 parent db8cffb commit 49267c6

File tree

1 file changed

+68
-81
lines changed

1 file changed

+68
-81
lines changed

src/subshell/common.c

Lines changed: 68 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,66 @@ synchronize (void)
586586
// We can't do any better without modifying the shell(s)
587587
}
588588

589+
/* --------------------------------------------------------------------------------------------- */
590+
/**
591+
* Read data from command pipe with timeout, avoiding possible deadlock with the shell
592+
*
593+
* @param buffer buffer to read data into
594+
* @param buffer_size size of the buffer
595+
* @param bytes_read pointer to store number of bytes read
596+
* @return TRUE if data was successfully read, FALSE otherwise
597+
*/
598+
599+
static gboolean
600+
read_command_buffer_with_timeout (const int nfds, void *buffer, const size_t buffer_size,
601+
ssize_t *bytes_read)
602+
{
603+
fd_set read_set;
604+
605+
struct timeval subshell_prompt_timer = {
606+
.tv_sec = 1,
607+
.tv_usec = 0,
608+
};
609+
610+
while (TRUE)
611+
{
612+
FD_ZERO (&read_set);
613+
FD_SET (command_buffer_pipe[READ], &read_set);
614+
FD_SET (mc_global.tty.subshell_pty, &read_set);
615+
616+
const int rc = select (nfds, &read_set, NULL, NULL, &subshell_prompt_timer);
617+
618+
if (rc == -1)
619+
{
620+
if (errno == EINTR)
621+
continue;
622+
623+
return FALSE;
624+
}
625+
626+
if (rc == 0)
627+
return FALSE;
628+
629+
// Keep reading the pty to avoid possible deadlock with the shell. Throw away the data.
630+
if (FD_ISSET (mc_global.tty.subshell_pty, &read_set))
631+
{
632+
char buf[BUF_SMALL];
633+
read_nonblock (mc_global.tty.subshell_pty, buf, sizeof (buf));
634+
}
635+
636+
if (FD_ISSET (command_buffer_pipe[READ], &read_set))
637+
break;
638+
}
639+
640+
*bytes_read = read (command_buffer_pipe[READ], buffer, buffer_size);
641+
642+
// FIXME: what about bytes < 0?
643+
if (*bytes_read == 0 || (size_t) *bytes_read == buffer_size)
644+
return FALSE;
645+
646+
return TRUE;
647+
}
648+
589649
/* --------------------------------------------------------------------------------------------- */
590650
/* Get the contents of the current subshell command line buffer, and */
591651
/* transfer the contents to the panel command prompt. */
@@ -602,8 +662,6 @@ read_command_line_buffer (gboolean test_mode)
602662
.tv_sec = 0,
603663
.tv_usec = 0,
604664
};
605-
int command_buffer_length;
606-
size_t command_buffer_char_length;
607665
int bash_version;
608666
int cursor_position;
609667
int rc;
@@ -614,13 +672,13 @@ read_command_line_buffer (gboolean test_mode)
614672
FD_ZERO (&read_set);
615673
FD_SET (command_buffer_pipe[READ], &read_set);
616674

617-
const int maxfdp = MAX (command_buffer_pipe[READ], mc_global.tty.subshell_pty);
675+
const int nfds = MAX (command_buffer_pipe[READ], mc_global.tty.subshell_pty) + 1;
618676

619677
/* First, flush the command buffer pipe. This pipe shouldn't be written
620678
* to under normal circumstances, but if it somehow does get written
621679
* to, we need to make sure to discard whatever data is there before
622680
* we try to use it. */
623-
while ((rc = select (maxfdp + 1, &read_set, NULL, NULL, &subshell_prompt_timer)) != 0)
681+
while ((rc = select (nfds, &read_set, NULL, NULL, &subshell_prompt_timer)) != 0)
624682
{
625683
if (rc == -1)
626684
{
@@ -642,91 +700,20 @@ read_command_line_buffer (gboolean test_mode)
642700
write_all (mc_global.tty.subshell_pty, ESC_STR SHELL_BUFFER_KEYBINDING,
643701
sizeof (ESC_STR SHELL_BUFFER_KEYBINDING) - 1);
644702

645-
subshell_prompt_timer.tv_sec = 1;
646-
647-
while (TRUE)
648-
{
649-
FD_ZERO (&read_set);
650-
FD_SET (command_buffer_pipe[READ], &read_set);
651-
FD_SET (mc_global.tty.subshell_pty, &read_set);
652-
653-
rc = select (maxfdp + 1, &read_set, NULL, NULL, &subshell_prompt_timer);
654-
655-
if (rc == -1)
656-
{
657-
if (errno == EINTR)
658-
continue;
659-
660-
return FALSE;
661-
}
662-
663-
if (rc == 0)
664-
return FALSE;
665-
666-
if (FD_ISSET (mc_global.tty.subshell_pty, &read_set))
667-
{
668-
/* Keep reading the pty to avoid possible deadlock with the shell. Throw away the data.
669-
*/
670-
char buf[BUF_SMALL];
671-
read_nonblock (mc_global.tty.subshell_pty, buf, sizeof (buf));
672-
}
673-
674-
if (FD_ISSET (command_buffer_pipe[READ], &read_set))
675-
break;
676-
}
677-
678-
bytes =
679-
read (command_buffer_pipe[READ], subshell_command_buffer, sizeof (subshell_command_buffer));
680-
// FIXME: what about bytes < 0?
681-
if (bytes == 0 || (size_t) bytes == sizeof (subshell_command_buffer))
703+
if (!read_command_buffer_with_timeout (nfds, subshell_command_buffer,
704+
sizeof (subshell_command_buffer), &bytes))
682705
return FALSE;
683706

684-
command_buffer_char_length = (size_t) bytes - 1;
707+
const size_t command_buffer_char_length = (size_t) bytes - 1;
685708
subshell_command_buffer[command_buffer_char_length] = '\0';
686-
command_buffer_length = str_length (subshell_command_buffer);
709+
const int command_buffer_length = str_length (subshell_command_buffer);
687710

688711
// get cursor position
689712
write_all (mc_global.tty.subshell_pty, ESC_STR SHELL_CURSOR_KEYBINDING,
690713
sizeof (ESC_STR SHELL_CURSOR_KEYBINDING) - 1);
691714

692-
subshell_prompt_timer.tv_sec = 1;
693-
subshell_prompt_timer.tv_usec = 0;
694-
695-
while (TRUE)
696-
{
697-
FD_ZERO (&read_set);
698-
FD_SET (command_buffer_pipe[READ], &read_set);
699-
FD_SET (mc_global.tty.subshell_pty, &read_set);
700-
701-
rc = select (maxfdp + 1, &read_set, NULL, NULL, &subshell_prompt_timer);
702-
703-
if (rc == -1)
704-
{
705-
if (errno == EINTR)
706-
continue;
707-
708-
return FALSE;
709-
}
710-
711-
if (rc == 0)
712-
return FALSE;
713-
714-
if (FD_ISSET (mc_global.tty.subshell_pty, &read_set))
715-
{
716-
/* Keep reading the pty to avoid possible deadlock with the shell. Throw away the data.
717-
*/
718-
char buf[BUF_SMALL];
719-
read_nonblock (mc_global.tty.subshell_pty, buf, sizeof (buf));
720-
}
721-
722-
if (FD_ISSET (command_buffer_pipe[READ], &read_set))
723-
break;
724-
}
725-
726-
bytes =
727-
read (command_buffer_pipe[READ], subshell_cursor_buffer, sizeof (subshell_cursor_buffer));
728-
// FIXME: what about bytes < 0?
729-
if (bytes == 0)
715+
if (!read_command_buffer_with_timeout (nfds, subshell_cursor_buffer,
716+
sizeof (subshell_cursor_buffer), &bytes))
730717
return FALSE;
731718

732719
subshell_cursor_buffer[(size_t) bytes - 1] = '\0';

0 commit comments

Comments
 (0)