mirror of
https://github.com/gregtwallace/apc-p15-tool.git
synced 2025-01-22 16:14:09 +00:00
703c26bd27
It was possible for scanner.Scan() to block indefinitely if the UPS never returned the expected prompt regex pattern. This could occur with a UPS using a prompt format I'm not aware of, or if the UPS responds in a non-standard way. This change ensures that Scan() is aborted after a fixed amount of blocking time and the shell cmd function accordingly returns an error. Some error messages, comments, and var names are also updated for clarity.
38 lines
1.1 KiB
Go
38 lines
1.1 KiB
Go
package apcssh
|
|
|
|
import (
|
|
"io"
|
|
"regexp"
|
|
)
|
|
|
|
// scanAPCShell is a SplitFunc to capture shell output after each interactive
|
|
// shell command is run
|
|
func scanAPCShell(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
|
// EOF is not an expected response and should error (e.g., when the output pipe
|
|
// gets closed by timeout)
|
|
if atEOF {
|
|
return len(data), dropCR(data), io.ErrUnexpectedEOF
|
|
} else if len(data) == 0 {
|
|
// no data to process, request more data
|
|
return 0, nil, nil
|
|
}
|
|
|
|
// regex for shell prompt (e.g., `apc@apc>`, `apc>`, `some@dev>`, `other123>`, etc.)
|
|
re := regexp.MustCompile(`(\r\n|\r|\n)([A-Za-z0-9.]+@?)?[A-Za-z0-9.]+>`)
|
|
// find match for prompt
|
|
if index := re.FindStringIndex(string(data)); index != nil {
|
|
// advance starts after the prompt; token is everything before the prompt
|
|
return index[1], dropCR(data[0:index[0]]), nil
|
|
}
|
|
|
|
// no match, request more data
|
|
return 0, nil, nil
|
|
}
|
|
|
|
// dropCR drops a terminal \r from the data.
|
|
func dropCR(data []byte) []byte {
|
|
if len(data) > 0 && data[len(data)-1] == '\r' {
|
|
return data[0 : len(data)-1]
|
|
}
|
|
return data
|
|
}
|