Skip to content

agent: accept CR at the yes/no prompt - #649

Open
michaelpersonal wants to merge 1 commit into
antirez:mainfrom
michaelpersonal:fix/yes-no-prompt-accept-cr
Open

agent: accept CR at the yes/no prompt#649
michaelpersonal wants to merge 1 commit into
antirez:mainfrom
michaelpersonal:fix/yes-no-prompt-accept-cr

Conversation

@michaelpersonal

Copy link
Copy Markdown

Problem

The Save current session? (y/n) prompt can hang. Typing y and pressing Enter
echoes ^M, the prompt never returns, and each further Enter appends another:

Save current session? (y/n) y^M^M^M

Cause

agent_prompt_yes_no_ex() reads with fgets(), which waits for '\n'.

The terminal may still be in linenoise raw mode at that point. editor_stop()
does leave cooked mode via linenoiseEditStop()disableRawMode(), but
linenoiseRestoreRawMode() (driven by raw_mode_needs_restore) can put it back.
Raw mode clears ICRNL in linenoiseMakeRawMode(), so Enter arrives as '\r'
and never as '\n' — and fgets() blocks forever.

This is why it is intermittent rather than always reproducible.

Fix

Read the line by hand and terminate on '\r' or '\n'. Correct in both
modes: when ICRNL is enabled the tty has already translated CR, so a lone
'\r' cannot reach the application.

Raw mode also clears ECHO, so in that case neither the answer nor a newline is
echoed and following output runs into the prompt line. The patch emits a newline
itself, but only when ECHO is off, so cooked mode does not gain a blank line.
tcgetattr() fails on a non-tty, which correctly suppresses it for pipes too.

Testing

Driven through a pty on macOS (M5 Max, Metal), answering the save prompt with
CR only, never LF:

  • before — prompt hangs, ^M accumulates, process must be killed
  • after — answer accepted, 0 occurrences of ^M, clean exit

Builds warning-free under the existing -Wall -Wextra -std=c99. Adds
#include <termios.h>.

The "Save current session? (y/n)" prompt can hang: typing y and pressing
Enter echoes ^M and the prompt never returns, so each further Enter appends
another ^M.

agent_prompt_yes_no_ex() reads with fgets(), which waits for '\n'. The
terminal may still be in linenoise raw mode at that point -- editor_stop()
leaves cooked mode via linenoiseEditStop(), but linenoiseRestoreRawMode()
(ds4_agent.c, raw_mode_needs_restore) can put it back -- and raw mode clears
ICRNL in linenoiseMakeRawMode(), so Enter arrives as '\r' and never as '\n'.
fgets then blocks forever.

Read the line by hand and terminate on '\r' or '\n'. This is correct in both
modes: when ICRNL is enabled the tty has already translated CR, so a lone
'\r' cannot reach the application.

Raw mode also clears ECHO, so in that case neither the answer nor a newline
is echoed and the following output runs into the prompt line; emit a newline
ourselves, but only when ECHO is off, so cooked mode does not get a blank
line. tcgetattr() fails on a non-tty, which correctly suppresses it for pipes.

Verified on macOS by driving ds4-agent through a pty and answering the save
prompt with CR only (never LF): before, the prompt hung and echoed ^M; after,
it is accepted and the process exits cleanly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant