Skip to content

pkg/streamer, pkg/terminal, pkg/device/ros: handle cursor-up and deliver trailing prompt on EOF - #364

Open
AdamMagued wants to merge 3 commits into
annetutil:mainfrom
AdamMagued:fix/routeros-traceroute-timeout
Open

AdamMagued wants to merge 3 commits into
annetutil:mainfrom
AdamMagued:fix/routeros-traceroute-timeout

Conversation

@AdamMagued

Copy link
Copy Markdown

Fixes issue #322 where RouterOS tool traceroute and ping fail with generic_error when a hop does not answer due to unhandled cursor-up/down sequences, discarded trailing prompt on EOF, early error check in chanReader, and narrow search window.

Comment thread go.mod Outdated
module github.com/annetutil/gnetcli

go 1.25.0
go 1.23

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hw, why?

Comment thread pkg/device/ros/device.go Outdated
// line may be like this "\r\n\r\r\r\r[admin@mk-rb3011-test] > (~1000 space) \r[admin@mk-rb3011-test] > "
hiddenPrompt = `(?P<hidden>\[\S+@\S+\]\s{1,2}(\/[\/\w\s-]+)?(<SAFE)?>\s+)?`
visiblePrompt = `\[(?P<login>\S+)@(?P<hostname>\S+)\]\s{1,2}(?P<cfg_path>\/[\/\w\s-]+)?(<(?P<safe_mode>SAFE))?> $`
visiblePrompt = `\[(?P<login>\S+)@(?P<hostname>[^\]]+)\]\s+(?P<cfg_path>\/[\/\w\s-]+)?(<(?P<safe_mode>SAFE))?>[^\n]*$`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new >[^\n]*$ suffix also matches an incomplete command echo, not just an idle prompt. For example, if the echo arrives in two chunks:

Chunk 1: \r\r[admin@router] > /ip service exp
Chunk 2: ort\r\n

The first chunk is now recognized as a prompt. GenericExecute consumes the matched text and preserves only the bytes before it, losing the command prefix. When the second chunk arrives, the full echo can no longer be reconstructed, and
execution fails with echo read error.

…se echo matches

Signed-off-by: AdamMagued <adamismailmageud@gmail.com>
@AdamMagued

Copy link
Copy Markdown
Author

@gescheit Restored go 1.25.0 in go.mod and refined the RouterOS prompt regex to prevent false matches on split command echoes. All unit tests pass cleanly.

Comment thread pkg/device/ros/device.go Outdated
// line may be like this "\r\n\r\r\r\r[admin@mk-rb3011-test] > (~1000 space) \r[admin@mk-rb3011-test] > "
hiddenPrompt = `(?P<hidden>\[\S+@\S+\]\s{1,2}(\/[\/\w\s-]+)?(<SAFE)?>\s+)?`
visiblePrompt = `\[(?P<login>\S+)@(?P<hostname>\S+)\]\s{1,2}(?P<cfg_path>\/[\/\w\s-]+)?(<(?P<safe_mode>SAFE))?> $`
visiblePrompt = `\[(?P<login>\S+)@(?P<hostname>[^\]]+)\]\s+(?P<cfg_path>\/[\/\w\s-]+)?(<(?P<safe_mode>SAFE))?> *$`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new hostname pattern [^\]]+ also matches CR/LF, so it can consume command output together with the actual prompt.
For example, after the command echo:
[alice@example.net\r\n[admin@router] >

The entire buffer is recognized as a prompt. I reproduced this with the same mock-SSH test on both revisions: base returns "[alice@example.net\n", while this PR returns an empty output with status 0 and no error.

Please exclude CR/LF from the hostname character class and add a command-execution regression test that verifies the output is preserved.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excluded \r and \n from the hostname character class ((?P[^\]\r\n]+)) and added unit and mock-SSH regression tests verifying that bracketed command output preceding the prompt is preserved.

Comment thread pkg/streamer/streamer.go Outdated
}
}
if !ok {
if cfg.regExpr != nil {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this additional EOF match necessary? GenericReadX already checks the expression against buffer before entering the select. When the receive returns ok == false, no new bytes are appended, so matching the same buffer again cannot produce a different result for the standard expressions.

I tested both a prompt already in inBuffer and a prompt queued in the channel before it closes; both scenarios pass on base as well as on this PR.

Could we remove this branch, or add a regression test that fails on base and demonstrates the scenario it fixes?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the redundant EOF match block in GenericReadX.

…F match

Exclude carriage return and line feed from the visiblePrompt hostname regex to prevent consuming command output preceding the prompt. Add unit and mock-SSH regression tests ensuring bracketed output lines are preserved. Remove redundant EOF match block in GenericReadX.

Signed-off-by: Adam Magued <adamismailmageud@gmail.com>
@AdamMagued

Copy link
Copy Markdown
Author

@gescheit Updated with the requested fixes:

  • Excluded \r and \n from the RouterOS hostname character class ((?P<hostname>[^\]\r\n]+)) in visiblePrompt. Added both unit regex tests and a mock-SSH command-execution regression test verifying that bracketed output preceding the prompt is preserved.
  • Removed the redundant EOF match block in GenericReadX under pkg/streamer/streamer.go.

This branch has not been deployed

No deployments
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.

2 participants