[PATCH rtems6 v2] libmisc/shell: Fix timeout getting terminal size
dufault at hda.com
dufault at hda.com
Wed Jan 24 09:01:33 UTC 2024
From: Peter Dufault <dufault at hda.com>
- Fix detection of timeout in rtems_shell_term_wait_for().
- Use the "termios" VTIME inter-character timeout.
The previous version depends on the BSP clock tick and can be long.
- Add debugging regarding terminal size sequences.
Updates #4763
---
cpukit/libmisc/shell/shell.c | 103 +++++++++++++++++++++++++------------------
1 file changed, 59 insertions(+), 44 deletions(-)
diff --git a/cpukit/libmisc/shell/shell.c b/cpukit/libmisc/shell/shell.c
index 9cefc80..6a9e11e 100644
--- a/cpukit/libmisc/shell/shell.c
+++ b/cpukit/libmisc/shell/shell.c
@@ -40,14 +40,19 @@
#include <assert.h>
#define SHELL_STD_DEBUG 0
+#define SHELL_WINSIZE_DEBUG 0
-#if SHELL_STD_DEBUG
#include <rtems/bspIo.h>
+#define shell_std_debug_(EN, ...) \
+ do { \
+ if (EN) { printk("shell[%08x]: ", rtems_task_self()); printk(__VA_ARGS__); } \
+ } while (0)
+
#define shell_std_debug(...) \
- do { printk("shell[%08x]: ", rtems_task_self()); printk(__VA_ARGS__); } while (0)
-#else
-#define shell_std_debug(...)
-#endif
+ shell_std_debug_(SHELL_STD_DEBUG, __VA_ARGS__)
+
+#define shell_winsize_debug(...) \
+ shell_std_debug_(SHELL_WINSIZE_DEBUG, __VA_ARGS__)
#define SHELL_MAGIC rtems_build_name('S', 'E', 'N', 'V')
@@ -805,28 +810,35 @@ void rtems_shell_print_env(
}
#endif
+/* Window size detection knob.
+ * VTIME timeout in .1 seconds. No way to set without editing.
+ */
+static const int rtems_shell_winsize_vtime = 1;
+
/*
* Wait for the string to return or timeout.
*/
-static bool rtems_shell_term_wait_for(const int fd, const char* str, const int timeout)
+static bool rtems_shell_term_wait_for(const int fd, const char* str)
{
- int msec = timeout;
int i = 0;
- while (msec-- > 0 && str[i] != '\0') {
+ while (str[i] != '\0') {
char ch[2];
- if (read(fd, &ch[0], 1) == 1) {
- fflush(stdout);
+ ssize_t n;
+ if ((n = read(fd, &ch[0], 1)) == 1) {
if (ch[0] != str[i++]) {
+ shell_winsize_debug("Wrong char at char %d.\n", i);
return false;
}
- msec = timeout;
} else {
- usleep(1000);
+ shell_winsize_debug(
+ "%s reading char %d.\n",
+ (n == 0) ? "Timeout" : "Error", i
+ );
+ return false;
}
}
- if (msec == 0) {
- return false;
- }
+
+ shell_winsize_debug("Matched string.\n");
return true;
}
@@ -836,41 +848,43 @@ static bool rtems_shell_term_wait_for(const int fd, const char* str, const int t
static int rtems_shell_term_buffer_until(const int fd,
char* buf,
const int size,
- const char* end,
- const int timeout)
+ const char* end)
{
- int msec = timeout;
int i = 0;
int e = 0;
memset(&buf[0], 0, size);
- while (msec-- > 0 && i < size && end[e] != '\0') {
+ while (i < size && end[e] != '\0') {
char ch[2];
- if (read(fd, &ch[0], 1) == 1) {
- fflush(stdout);
+ ssize_t n;
+ if ( (n = read(fd, &ch[0], 1)) == 1) {
buf[i++] = ch[0];
if (ch[0] == end[e]) {
e++;
} else {
+ shell_winsize_debug("Reset search for end string.\n");
e = 0;
}
- msec = timeout;
} else {
- usleep(1000);
+ /* There is an error or timeout. */
+ shell_winsize_debug(
+ "%s looking for end string \"%s\". Read \"%s\".\n",
+ (n == 0) ? "Timeout" : "Error",
+ end, buf
+ );
+ return -1;
}
}
- if (msec == 0 || end[e] != '\0') {
- return -1;
- }
- i -= e;
+ i -= e; /* Toss away the matched end. */
if (i < size) {
buf[i] = '\0';
}
+ shell_winsize_debug("Found end string \"%s\".\n", end);
return i;
}
/*
- * Determine if the terminal has the row and column values
- * swapped
+ * Determine if this is a version of the "tmux" terminal emulator with
+ * the row and column values swapped
*
* https://github.com/tmux/tmux/issues/3457
*
@@ -878,19 +892,19 @@ static int rtems_shell_term_buffer_until(const int fd,
* in the time it takes to get the fix into code so see if tmux is
* running and which version and work around the bug.
*
- * The terminal device needs to have VMIN=0, and VTIME=0
+ * The terminal device needs to have VMIN=0, and VTIME set to the
+ * desired timeout in .1 seconds.
*/
-static bool rtems_shell_term_row_column_swapped(const int fd, const int timeout) {
+static bool rtems_shell_term_row_column_swapped(const int fd, const int fout) {
char buf[64];
memset(&buf[0], 0, sizeof(buf));
/*
* CSI > Ps q
* Ps = 0 => DCS > | text ST
*/
- fputs("\033[>0q", stdout);
- fflush(stdout);
- if (rtems_shell_term_wait_for(fd, "\033P>|", timeout)) {
- int len = rtems_shell_term_buffer_until(fd, buf, sizeof(buf), "\033\\", timeout);
+ write(fout, "\033[>0q", 5);
+ if (rtems_shell_term_wait_for(fd, "\033P>|")) {
+ int len = rtems_shell_term_buffer_until(fd, buf, sizeof(buf), "\033\\");
if (len > 0) {
if (memcmp(buf, "tmux ", 5) == 0) {
static const char* bad_versions[] = {
@@ -916,8 +930,8 @@ static bool rtems_shell_term_row_column_swapped(const int fd, const int timeout)
static void rtems_shell_winsize( void )
{
const int fd = fileno(stdin);
+ const int fout = fileno(stdout);
struct winsize ws;
- const int timeout = 150;
char buf[64];
bool ok = false;
int lines = 0;
@@ -933,18 +947,19 @@ static void rtems_shell_winsize( void )
if (tcgetattr(fd, &cterm) >= 0) {
struct termios term = cterm;
term.c_cc[VMIN] = 0;
- term.c_cc[VTIME] = 0;
- if (tcsetattr (fd, TCSADRAIN, &term) >= 0) {
+ term.c_cc[VTIME] = rtems_shell_winsize_vtime;
+ if (tcsetattr (fd, TCSAFLUSH, &term) >= 0) {
memset(&buf[0], 0, sizeof(buf));
/*
* https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Miscellaneous
*
* CSI 1 8 t
*/
- fputs("\033[18t", stdout);
- fflush(stdout);
- if (rtems_shell_term_wait_for(fd, "\033[8;", timeout)) {
- int len = rtems_shell_term_buffer_until(fd, buf, sizeof(buf), ";", timeout);
+ if (
+ write(fout, "\033[18t", 5) == 5 &&
+ rtems_shell_term_wait_for(fd, "\033[8;")
+ ) {
+ int len = rtems_shell_term_buffer_until(fd, buf, sizeof(buf), ";");
if (len > 0) {
int i;
lines = 0;
@@ -953,7 +968,7 @@ static void rtems_shell_winsize( void )
lines *= 10;
lines += buf[i++] - '0';
}
- len = rtems_shell_term_buffer_until(fd, buf, sizeof(buf), "t", timeout);
+ len = rtems_shell_term_buffer_until(fd, buf, sizeof(buf), "t");
if (len > 0) {
cols = 0;
i = 0;
@@ -966,7 +981,7 @@ static void rtems_shell_winsize( void )
}
}
}
- if (rtems_shell_term_row_column_swapped(fd, timeout)) {
+ if (ok && rtems_shell_term_row_column_swapped(fd, fout)) {
int tmp = lines;
lines = cols;
cols = tmp;
--
1.8.3.1
More information about the devel
mailing list