@@ -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