Apple2-IO-RPi/RaspberryPi/apple2driver/handlers/shell.go

114 lines
2.2 KiB
Go
Executable File

// Copyright Terence J. Boldt (c)2020-2024
// Use of this source code is governed by an MIT
// license that can be found in the LICENSE file.
// This file contains the handler for executing Linux shell
package handlers
import (
"fmt"
"io"
"os"
"os/exec"
"github.com/creack/pty"
)
// ShellCommand handles requests for the Apple II executing a Linux shell
func ShellCommand() {
fmt.Printf("Shell started\n")
cmd := exec.Command("bash", "-i")
cmd.Env = append(os.Environ(),
"TERM=vt100",
"LINES=24",
"COLUMNS=79",
)
var ws pty.Winsize
ws.Cols = 79
ws.Rows = 24
ws.X = 0
ws.Y = 0
ptmx, _ := pty.StartWithSize(cmd, &ws)
defer func() { _ = ptmx.Close() }()
outputComplete := make(chan bool)
inputComplete := make(chan bool)
userCancelled := make(chan bool)
go ptyIn(ptmx, outputComplete, inputComplete, userCancelled)
go ptyOut(ptmx, outputComplete, userCancelled)
for {
select {
case <-outputComplete:
fmt.Printf("Shell output complete\n")
outputComplete <- true
ptmx.Close()
cmd.Wait()
comm.WriteByte(0)
return
case <-userCancelled:
fmt.Printf("User cancelled, killing process\n")
ptmx.Close()
cmd.Process.Kill()
comm.WriteByte(0)
return
case <-inputComplete:
fmt.Printf("Shell input complete\n")
ptmx.Close()
cmd.Wait()
comm.WriteByte(0)
return
}
}
}
func ptyOut(stdout io.ReadCloser, outputComplete chan bool, userCancelled chan bool) {
for {
select {
case <-userCancelled:
fmt.Printf("User Cancelled stdout\n")
stdout.Close()
return
default:
bb := make([]byte, 1)
n, err := stdout.Read(bb)
if err != nil {
stdout.Close()
outputComplete <- true
fmt.Printf("stdout closed\n")
return
} else if n > 0 {
b := bb[0]
comm.SendCharacter(b)
}
}
}
}
func ptyIn(stdin io.WriteCloser, done chan bool, inputComplete chan bool, userCancelled chan bool) {
for {
select {
case <-done:
stdin.Close()
inputComplete <- true
fmt.Printf("stdin closed\n")
return
default:
s, err := comm.ReadCharacter()
if err == nil {
if s == string(byte(0x00)) {
stdin.Close()
userCancelled <- true
fmt.Printf("\nUser cancelled stdin\n")
return
}
io.WriteString(stdin, string(s))
}
}
}
}