2021-10-30 13:50:00 +00:00
|
|
|
// 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-11-03 09:33:09 +00:00
|
|
|
|
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"
|
|
|
|
)
|
|
|
|
|
2021-09-28 21:34:22 +00:00
|
|
|
var forceLowercase = false
|
|
|
|
|
2021-11-03 09:33:09 +00:00
|
|
|
// ExecCommand handles requests for the Apple II executing Linux commands
|
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()
|
2021-09-28 21:34:22 +00:00
|
|
|
if forceLowercase {
|
|
|
|
linuxCommand = strings.ToLower(linuxCommand)
|
|
|
|
}
|
2021-12-28 21:23:27 +00:00
|
|
|
linuxCommand = strings.Trim(linuxCommand, " ")
|
2021-12-28 21:26:59 +00:00
|
|
|
if linuxCommand == "" {
|
|
|
|
linuxCommand = "a2help"
|
|
|
|
}
|
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
|
|
|
|
}
|
2021-11-27 03:51:52 +00:00
|
|
|
if linuxCommand == "a2lower" {
|
|
|
|
a2lower(false)
|
|
|
|
return
|
|
|
|
}
|
2021-09-28 21:34:22 +00:00
|
|
|
if linuxCommand == "A2LOWER" {
|
2021-11-27 03:51:52 +00:00
|
|
|
a2lower(true)
|
2021-09-28 21:47:52 +00:00
|
|
|
return
|
2021-09-28 21:34:22 +00:00
|
|
|
}
|
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
|
|
|
|
}
|
2021-11-05 19:15:54 +00:00
|
|
|
if linuxCommand == "a2prompt" {
|
|
|
|
prompt := fmt.Sprintf("A2IO:%s ", workingDirectory)
|
|
|
|
comm.WriteString(prompt)
|
|
|
|
return
|
|
|
|
}
|
2021-05-30 13:37:00 +00:00
|
|
|
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-11-05 19:15:54 +00:00
|
|
|
// force the command to combine stderr(2) into stdout(1)
|
|
|
|
linuxCommand += " 2>&1"
|
2021-05-30 11:18:39 +00:00
|
|
|
cmd := exec.Command("bash", "-c", linuxCommand)
|
|
|
|
cmd.Dir = workingDirectory
|
2021-11-11 02:44:28 +00:00
|
|
|
cmd.Env = append(os.Environ(),
|
|
|
|
"TERM=vt100",
|
|
|
|
"LINES=24",
|
|
|
|
"COLUMNS=80",
|
|
|
|
)
|
2021-10-12 01:19:40 +00:00
|
|
|
stdout, err := cmd.StdoutPipe()
|
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-11-05 19:15:54 +00:00
|
|
|
stdin, err := cmd.StdinPipe()
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("Failed to set stdin\n")
|
|
|
|
comm.WriteString("Failed to set stdin\r")
|
|
|
|
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)
|
|
|
|
|
|
|
|
go getStdin(stdin, outputComplete, inputComplete, userCancelled)
|
2021-11-05 19:15:54 +00:00
|
|
|
go getStdout(stdout, outputComplete, userCancelled)
|
2021-10-12 01:19:40 +00:00
|
|
|
|
2021-10-23 20:39:02 +00:00
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-outputComplete:
|
|
|
|
outputComplete <- true
|
2021-11-05 19:15:54 +00:00
|
|
|
cmd.Wait()
|
|
|
|
comm.WriteByte(0)
|
|
|
|
return
|
2021-10-23 20:39:02 +00:00
|
|
|
case <-userCancelled:
|
2021-11-05 19:15:54 +00:00
|
|
|
userCancelled <- true
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-05 19:15:54 +00:00
|
|
|
func getStdout(stdout io.ReadCloser, outputComplete chan bool, userCancelled chan bool) {
|
2021-10-23 20:39:02 +00:00
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-userCancelled:
|
2021-11-25 23:45:56 +00:00
|
|
|
fmt.Printf("User Cancelled stdout\n")
|
2021-10-23 20:39:02 +00:00
|
|
|
stdout.Close()
|
|
|
|
return
|
|
|
|
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-11-05 19:15:54 +00:00
|
|
|
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]
|
2021-11-11 02:44:28 +00:00
|
|
|
comm.SendCharacter(b)
|
2021-10-12 01:19:40 +00:00
|
|
|
}
|
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-11-27 03:51:52 +00:00
|
|
|
b, err := comm.ReadByte()
|
2021-10-23 20:39:02 +00:00
|
|
|
if err == nil {
|
2021-11-27 03:51:52 +00:00
|
|
|
if b == 0x00 || b == 0x03 {
|
2021-10-23 20:39:02 +00:00
|
|
|
stdin.Close()
|
|
|
|
userCancelled <- true
|
2021-11-25 23:45:56 +00:00
|
|
|
fmt.Printf("\nUser cancelled stdin\n")
|
2021-10-23 20:39:02 +00:00
|
|
|
return
|
|
|
|
}
|
2021-11-27 03:51:52 +00:00
|
|
|
bb := make([]byte, 1)
|
|
|
|
stdin.Write(bb)
|
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
|
|
|
"Built-in commands:\r" +
|
2021-11-27 03:51:52 +00:00
|
|
|
"------------------\r" +
|
2021-10-23 20:39:02 +00:00
|
|
|
"a2help - display this message\r" +
|
|
|
|
"a2wifi - set up wifi\r" +
|
|
|
|
"A2LOWER - force lowercase for II+\r" +
|
2021-11-27 03:51:52 +00:00
|
|
|
"a2lower - disable force lowercase for II+\r" +
|
2021-10-23 20:39:02 +00:00
|
|
|
"\r")
|
|
|
|
}
|
|
|
|
|
2021-11-27 03:51:52 +00:00
|
|
|
func a2lower(enable bool) {
|
|
|
|
forceLowercase = enable
|
|
|
|
comm.WriteString(fmt.Sprintf("All commands will be converted to lowercase: %t\r", forceLowercase))
|
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" +
|
2021-12-31 13:43:48 +00:00
|
|
|
" a2wifi select SSID PASSWORD REGION\r" +
|
2021-10-23 20:39:02 +00:00
|
|
|
"\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)
|
2021-12-31 13:43:48 +00:00
|
|
|
if len(params) != 5 {
|
|
|
|
comm.WriteString("\rIncorrect number of parameters. Usage: a2wifi select SSID PASSWORD REGION\r\r")
|
|
|
|
return "", errors.New("Incorrect number of parameters. Usage: a2wifi select SSID PASSWORD REGION")
|
2021-10-23 20:39:02 +00:00
|
|
|
}
|
|
|
|
ssid := params[2]
|
|
|
|
psk := params[3]
|
2021-12-31 13:43:48 +00:00
|
|
|
region := params[4]
|
|
|
|
linuxCommand = "printf \"country=%s\\nupdate_config=1\\nctrl_interface=/var/run/wpa_supplicant\\n\\nnetwork={\\n scan_ssid=1\\n ssid=\\\"%s\\\"\n psk=\\\"%s\\\"\\n}\\n\" " +
|
|
|
|
region + " " +
|
|
|
|
ssid + " " +
|
2021-10-23 20:39:02 +00:00
|
|
|
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
|
|
|
}
|