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

256 lines
5.6 KiB
Go
Raw Normal View History

// Copyright Terence J. Boldt (c)2020-2021
// Use of this source code is governed by an MIT
// license that can be found in the LICENSE file.
// This file is contains the handler for executing Linux and internal
// commands
2021-05-30 11:18:39 +00:00
package handlers
import (
2021-10-23 20:39:02 +00:00
"errors"
2021-05-30 11:18:39 +00:00
"fmt"
2021-10-23 20:39:02 +00:00
"io"
2021-05-30 11:18:39 +00:00
"os"
"os/exec"
"strings"
)
var forceLowercase = false
2021-05-30 11:18:39 +00:00
func ExecCommand() {
workingDirectory, err := os.Getwd()
if err != nil {
workingDirectory = "/home"
2021-10-30 11:03:18 +00:00
comm.WriteString("Failed to get current working directory, setting to /home\r")
2021-05-30 11:18:39 +00:00
}
fmt.Printf("Reading command to execute...\n")
2021-10-30 11:03:18 +00:00
linuxCommand, err := comm.ReadString()
if forceLowercase {
linuxCommand = strings.ToLower(linuxCommand)
}
2021-05-30 11:18:39 +00:00
fmt.Printf("Command to run: %s\n", linuxCommand)
if strings.HasPrefix(linuxCommand, "cd ") {
workingDirectory = strings.Replace(linuxCommand, "cd ", "", 1)
err = os.Chdir(workingDirectory)
if err != nil {
2021-10-30 11:03:18 +00:00
comm.WriteString("Failed to set working directory\r")
2021-05-30 11:18:39 +00:00
return
}
2021-10-30 11:03:18 +00:00
comm.WriteString("Working directory set\r")
2021-05-30 11:18:39 +00:00
return
}
if linuxCommand == "a2help" {
2021-10-23 20:39:02 +00:00
a2help()
2021-05-30 11:18:39 +00:00
return
}
if linuxCommand == "A2LOWER" {
2021-10-23 20:39:02 +00:00
a2lower()
2021-09-28 21:47:52 +00:00
return
}
2021-05-30 13:37:00 +00:00
if linuxCommand == "a2wifi" {
2021-10-23 20:39:02 +00:00
a2wifi()
2021-05-30 13:37:00 +00:00
return
}
if linuxCommand == "a2wifi list" {
2021-10-23 20:39:02 +00:00
linuxCommand = a2wifiList()
2021-05-30 13:37:00 +00:00
}
if strings.HasPrefix(linuxCommand, "a2wifi select") {
2021-10-23 20:39:02 +00:00
linuxCommand, err = a2wifiSelect(linuxCommand)
}
if err == nil {
execCommand(linuxCommand, workingDirectory)
2021-05-30 13:37:00 +00:00
}
2021-10-23 20:39:02 +00:00
}
func execCommand(linuxCommand string, workingDirectory string) {
2021-05-30 11:18:39 +00:00
cmd := exec.Command("bash", "-c", linuxCommand)
cmd.Dir = workingDirectory
2021-10-12 01:19:40 +00:00
stdout, err := cmd.StdoutPipe()
2021-10-23 20:39:02 +00:00
stdin, err := cmd.StdinPipe()
2021-10-27 03:13:06 +00:00
stderr, err := cmd.StderrPipe()
2021-10-23 20:39:02 +00:00
2021-05-30 11:18:39 +00:00
if err != nil {
2021-10-12 01:19:40 +00:00
fmt.Printf("Failed to set stdout\n")
2021-10-30 11:03:18 +00:00
comm.WriteString("Failed to set stdout\r")
2021-05-30 11:18:39 +00:00
return
}
2021-10-12 01:19:40 +00:00
fmt.Printf("Command output:\n")
err = cmd.Start()
2021-05-30 11:18:39 +00:00
if err != nil {
2021-10-12 01:19:40 +00:00
fmt.Printf("Failed to start command\n")
2021-10-30 11:03:18 +00:00
comm.WriteString("Failed to start command\r")
2021-05-30 11:18:39 +00:00
return
}
2021-10-12 01:19:40 +00:00
2021-10-23 20:39:02 +00:00
outputComplete := make(chan bool)
inputComplete := make(chan bool)
userCancelled := make(chan bool)
2021-10-27 03:13:06 +00:00
stderrComplete := make(chan bool)
2021-10-23 20:39:02 +00:00
if linuxCommand == "openssl" {
fmt.Printf("\nSending help command...\n")
io.WriteString(stdin, "help\n")
}
go getStdin(stdin, outputComplete, inputComplete, userCancelled)
2021-10-27 03:13:06 +00:00
go getStdout(stdout, outputComplete, userCancelled, stderrComplete)
go getStderr(stderr, userCancelled, stderrComplete)
2021-10-12 01:19:40 +00:00
2021-10-23 20:39:02 +00:00
for {
select {
case <-outputComplete:
outputComplete <- true
case <-userCancelled:
2021-10-30 11:03:18 +00:00
comm.WriteString("^C\r")
2021-10-23 20:39:02 +00:00
cmd.Process.Kill()
return
case <-inputComplete:
cmd.Wait()
2021-10-30 11:03:18 +00:00
comm.WriteByte(0)
2021-10-23 20:39:02 +00:00
return
default:
}
}
}
2021-10-27 03:13:06 +00:00
func getStdout(stdout io.ReadCloser, outputComplete chan bool, userCancelled chan bool, stderrComplete chan bool) {
stderrDone := false
stdoutDone := false
2021-10-23 20:39:02 +00:00
for {
select {
case <-userCancelled:
stdout.Close()
return
2021-10-27 03:13:06 +00:00
case <-stderrComplete:
stderrDone = true
if stdoutDone {
outputComplete <- true
return
}
2021-10-23 20:39:02 +00:00
default:
bb := make([]byte, 1)
n, err := stdout.Read(bb)
2021-10-27 01:29:40 +00:00
if err != nil {
2021-10-23 20:39:02 +00:00
stdout.Close()
2021-10-27 03:13:06 +00:00
stdoutDone = true
if stderrDone {
outputComplete <- true
return
}
2021-10-23 20:39:02 +00:00
}
2021-10-27 01:29:40 +00:00
if n > 0 {
b := bb[0]
sendCharacter(b)
2021-10-12 01:19:40 +00:00
}
2021-10-23 20:39:02 +00:00
}
}
}
2021-10-27 03:13:06 +00:00
func getStderr(stderr io.ReadCloser, userCancelled chan bool, stderrComplete chan bool) {
for {
select {
case <-userCancelled:
stderr.Close()
return
default:
bb := make([]byte, 1)
n, err := stderr.Read(bb)
if err != nil {
stderr.Close()
stderrComplete <- true
return
}
if n > 0 {
sendCharacter(bb[0])
}
}
}
}
2021-10-23 20:39:02 +00:00
func getStdin(stdin io.WriteCloser, done chan bool, inputComplete chan bool, userCancelled chan bool) {
for {
select {
case <-done:
stdin.Close()
inputComplete <- true
return
default:
2021-10-30 11:03:18 +00:00
b, err := comm.ReadByte()
2021-10-23 20:39:02 +00:00
if err == nil {
if b == 3 {
stdin.Close()
userCancelled <- true
return
} else {
if b == 13 {
b = 10
}
fmt.Printf("%c", b)
io.WriteString(stdin, string(b))
}
2021-10-12 01:19:40 +00:00
}
}
}
2021-10-23 20:39:02 +00:00
}
2021-10-12 01:19:40 +00:00
2021-10-23 20:39:02 +00:00
func a2help() {
2021-10-30 11:03:18 +00:00
comm.WriteString("\r" +
2021-10-23 20:39:02 +00:00
"This is a pseudo shell. Each command is executed as a process. The cd command\r" +
"is intercepted and sets the working directory for the next command.\r" +
"\r" +
"Built-in commands:\r" +
"a2help - display this message\r" +
"a2wifi - set up wifi\r" +
"A2LOWER - force lowercase for II+\r" +
"\r")
}
func a2lower() {
forceLowercase = true
2021-10-30 11:03:18 +00:00
comm.WriteString("All commands will be converted to lowercase\r")
2021-10-23 20:39:02 +00:00
}
func a2wifi() {
2021-10-30 11:03:18 +00:00
comm.WriteString("\r" +
2021-10-23 20:39:02 +00:00
"Usage: a2wifi list\r" +
" a2wifi select SSID PASSWORD\r" +
"\r")
}
func a2wifiList() string {
return "sudo iwlist wlan0 scanning | grep ESSID | sed s/.*ESSID://g | sed s/\\\"//g"
}
func a2wifiSelect(linuxCommand string) (string, error) {
params := strings.Fields(linuxCommand)
if len(params) != 4 {
2021-10-30 11:03:18 +00:00
comm.WriteString("\rIncorrect number of parameters. Usage: a2wifi select SSID PASSWORD\r\r")
2021-10-23 20:39:02 +00:00
return "", errors.New("Incorrect number of parameters. Usage: a2wifi select SSID PASSWORD")
}
ssid := params[2]
psk := params[3]
linuxCommand = "printf \"country=ca\\nupdate_config=1\\nctrl_interface=/var/run/wpa_supplicant\\n\\nnetwork={\\n scan_ssid=1\\n ssid=\\\"%s\\\"\n psk=\\\"%s\\\"\\n}\\n\" " +
ssid + " " +
psk + " " +
" > /tmp/wpa_supplicant.conf; " +
"sudo mv /tmp/wpa_supplicant.conf /etc/wpa_supplicant/; " +
"sudo wpa_cli -i wlan0 reconfigure"
return linuxCommand, nil
2021-05-30 11:18:39 +00:00
}
2021-10-27 01:29:40 +00:00
func sendCharacter(b byte) {
fmt.Print(string(b))
if b == 10 { // convert LF to CR for Apple II compatiblity
b = 13
}
if b == 9 { // convert TAB to spaces
b = ' '
b += 128
2021-10-30 11:03:18 +00:00
comm.WriteByte(b)
2021-10-27 01:29:40 +00:00
}
b |= 128
2021-10-30 11:03:18 +00:00
comm.WriteByte(b)
2021-10-27 01:29:40 +00:00
}