|
|
|
|
@@ -56,13 +56,17 @@ func (s *Server) handleTerminalWS(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
var initMsg wsMessage
|
|
|
|
|
_, raw, err := conn.ReadMessage()
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Printf("terminal: read init message failed: %v", err)
|
|
|
|
|
conn.WriteJSON(wsMessage{Type: "error", Data: "failed to read init message"})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
log.Printf("terminal: init message received: %s", string(raw))
|
|
|
|
|
if err := json.Unmarshal(raw, &initMsg); err != nil {
|
|
|
|
|
log.Printf("terminal: unmarshal init message failed: %v", err)
|
|
|
|
|
conn.WriteJSON(wsMessage{Type: "error", Data: "invalid init message"})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
log.Printf("terminal: init type=%q data=%q", initMsg.Type, initMsg.Data)
|
|
|
|
|
|
|
|
|
|
var cmd *exec.Cmd
|
|
|
|
|
|
|
|
|
|
@@ -96,23 +100,26 @@ func (s *Server) handleTerminalWS(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
|
|
|
|
|
cmd = exec.Command("ssh", sshArgs...)
|
|
|
|
|
} else {
|
|
|
|
|
shell := initMsg.Data
|
|
|
|
|
shell := strings.TrimSpace(initMsg.Data)
|
|
|
|
|
log.Printf("terminal: requested shell=%q, trimmed=%q", initMsg.Data, shell)
|
|
|
|
|
if shell == "" {
|
|
|
|
|
shell = detectShell()
|
|
|
|
|
} else {
|
|
|
|
|
if path, err := exec.LookPath(shell); err == nil {
|
|
|
|
|
shell = path
|
|
|
|
|
}
|
|
|
|
|
log.Printf("terminal: auto-detected shell=%q", shell)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Ignore invalid shell paths (e.g., single characters from race condition)
|
|
|
|
|
if len(shell) <= 1 {
|
|
|
|
|
conn.WriteJSON(wsMessage{Type: "error", Data: "invalid shell config"})
|
|
|
|
|
return
|
|
|
|
|
if shell == "" {
|
|
|
|
|
log.Printf("terminal: no shell detected, falling back to /bin/sh")
|
|
|
|
|
shell = "/bin/sh"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if path, err := exec.LookPath(shell); err == nil {
|
|
|
|
|
shell = path
|
|
|
|
|
log.Printf("terminal: resolved shell path=%q", shell)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if _, err := os.Stat(shell); err != nil {
|
|
|
|
|
conn.WriteJSON(wsMessage{Type: "error", Data: fmt.Sprintf("shell not found: %s", shell)})
|
|
|
|
|
log.Printf("terminal: shell stat failed: %v for %q", err, shell)
|
|
|
|
|
conn.WriteJSON(wsMessage{Type: "error", Data: fmt.Sprintf("shell not found: %s (resolved from: %q)", shell, initMsg.Data)})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -131,12 +138,14 @@ func (s *Server) handleTerminalWS(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
|
|
|
|
|
cmd.Env = append(os.Environ(), "TERM=xterm-256color")
|
|
|
|
|
|
|
|
|
|
log.Printf("terminal: starting pty with cmd=%q args=%v", cmd.Path, cmd.Args)
|
|
|
|
|
ptmx, err := pty.Start(cmd)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Printf("pty start: %v", err)
|
|
|
|
|
log.Printf("terminal: pty start failed: %v", err)
|
|
|
|
|
conn.WriteJSON(wsMessage{Type: "error", Data: err.Error()})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
log.Printf("terminal: pty started successfully")
|
|
|
|
|
defer func() {
|
|
|
|
|
ptmx.Close()
|
|
|
|
|
if cmd.Process != nil {
|
|
|
|
|
|