2019-04-07 23:15:01 -05:00
|
|
|
package shell
|
|
|
|
|
2019-06-04 22:20:15 -05:00
|
|
|
import "fmt"
|
2019-04-07 23:15:01 -05:00
|
|
|
import "strings"
|
|
|
|
import "time"
|
|
|
|
import "os"
|
|
|
|
import "os/exec"
|
|
|
|
import "bufio"
|
2019-06-04 22:20:15 -05:00
|
|
|
import "bytes"
|
|
|
|
import "io"
|
|
|
|
|
2019-04-07 23:15:01 -05:00
|
|
|
import "github.com/davecgh/go-spew/spew"
|
|
|
|
import "github.com/svent/go-nbreader"
|
|
|
|
|
2019-05-09 19:24:25 -05:00
|
|
|
import log "github.com/sirupsen/logrus"
|
|
|
|
// import "github.com/wercker/journalhook"
|
|
|
|
|
2019-05-09 17:20:26 -05:00
|
|
|
var shellStdout *os.File
|
|
|
|
var shellStderr *os.File
|
|
|
|
|
2019-05-09 19:24:25 -05:00
|
|
|
var spewOn bool = false
|
2019-05-09 20:54:36 -05:00
|
|
|
var msecDelay int = 20 // number of milliseconds to delay between reads with no data
|
2019-05-09 19:24:25 -05:00
|
|
|
|
2019-06-04 22:20:15 -05:00
|
|
|
var buf bytes.Buffer
|
|
|
|
|
2019-04-07 23:15:01 -05:00
|
|
|
func Script(cmds string) int {
|
|
|
|
// split on new lines (while we are at it, handle stupid windows text files
|
|
|
|
lines := strings.Split(strings.Replace(cmds, "\r\n", "\n", -1), "\n")
|
|
|
|
|
|
|
|
for _, line := range lines {
|
|
|
|
line = strings.TrimSpace(line) // this is like 'chomp' in perl
|
2019-05-09 19:24:25 -05:00
|
|
|
log.Println("LINE:", line)
|
2019-04-07 23:15:01 -05:00
|
|
|
time.Sleep(1)
|
2019-04-07 23:16:56 -05:00
|
|
|
Run(line)
|
2019-04-07 23:15:01 -05:00
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2019-05-09 19:24:25 -05:00
|
|
|
/*
|
|
|
|
func UseJournalctl() {
|
|
|
|
journalhook.Enable()
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
func SpewOn() {
|
|
|
|
spewOn = true
|
|
|
|
}
|
|
|
|
|
2019-05-09 20:54:36 -05:00
|
|
|
func SetDelayInMsec(msecs int) {
|
|
|
|
msecDelay = msecs
|
|
|
|
}
|
|
|
|
|
2019-05-09 17:20:26 -05:00
|
|
|
func SetStdout(newout *os.File) {
|
|
|
|
shellStdout = newout
|
|
|
|
}
|
|
|
|
|
|
|
|
func SetStderr(newerr *os.File) {
|
|
|
|
shellStderr = newerr
|
|
|
|
}
|
|
|
|
|
2019-06-04 22:20:15 -05:00
|
|
|
/*
|
|
|
|
func Capture(cmdline string) (int, string) {
|
|
|
|
val, _, _ := Run(cmdline)
|
|
|
|
|
|
|
|
if (val != 0) {
|
|
|
|
log.Println("shell.Capture() ERROR")
|
|
|
|
}
|
|
|
|
|
|
|
|
return val, buf.String()
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
func Run(cmdline string) (int, string, error) {
|
2019-04-07 23:15:01 -05:00
|
|
|
log.Println("START " + cmdline)
|
|
|
|
|
|
|
|
cmd := strings.TrimSpace(cmdline) // this is like 'chomp' in perl
|
|
|
|
cmdArgs := strings.Fields(cmd)
|
|
|
|
if (len(cmdArgs) == 0) {
|
|
|
|
log.Println("END ", cmd)
|
2019-06-04 22:20:15 -05:00
|
|
|
return 0, "", fmt.Errorf("") // nothing to do
|
2019-04-07 23:15:01 -05:00
|
|
|
}
|
|
|
|
if (cmdArgs[0] == "cd") {
|
|
|
|
if (len(cmdArgs) > 1) {
|
|
|
|
log.Println("os.Chdir()", cmd)
|
|
|
|
os.Chdir(cmdArgs[1])
|
|
|
|
}
|
|
|
|
log.Println("END ", cmd)
|
2019-06-04 22:20:15 -05:00
|
|
|
return 0, "", fmt.Errorf("") // nothing to do
|
2019-04-07 23:15:01 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
process := exec.Command(cmdArgs[0], cmdArgs[1:len(cmdArgs)]...)
|
2019-05-09 17:20:26 -05:00
|
|
|
pstdout, _ := process.StdoutPipe()
|
|
|
|
pstderr, _ := process.StderrPipe()
|
|
|
|
|
2019-05-09 19:24:25 -05:00
|
|
|
if (spewOn) {
|
|
|
|
spew.Dump(pstdout)
|
|
|
|
}
|
2019-05-09 17:20:26 -05:00
|
|
|
|
2019-04-07 23:15:01 -05:00
|
|
|
process.Start()
|
|
|
|
|
2019-05-09 17:20:26 -05:00
|
|
|
if (shellStdout == nil) {
|
|
|
|
shellStdout = os.Stdout
|
|
|
|
}
|
|
|
|
|
|
|
|
f := bufio.NewWriter(shellStdout)
|
2019-04-07 23:15:01 -05:00
|
|
|
|
2019-05-09 17:20:26 -05:00
|
|
|
newreader := bufio.NewReader(pstdout)
|
2019-04-07 23:15:01 -05:00
|
|
|
nbr := nbreader.NewNBReader(newreader, 1024)
|
|
|
|
|
2019-05-09 20:54:36 -05:00
|
|
|
tmp := bufio.NewReader(pstderr)
|
|
|
|
go NonBlockingReader(tmp, shellStderr)
|
2019-04-07 23:15:01 -05:00
|
|
|
|
2019-05-09 18:48:53 -05:00
|
|
|
totalCount := 0
|
|
|
|
|
2019-05-09 20:54:36 -05:00
|
|
|
var dead bool = false
|
|
|
|
for (dead == false) {
|
|
|
|
time.Sleep(time.Duration(msecDelay) * time.Millisecond) // only check the buffer 500 times a second
|
2019-04-07 23:15:01 -05:00
|
|
|
// log.Println("sleep done")
|
|
|
|
|
2019-05-09 20:54:36 -05:00
|
|
|
var empty bool = false
|
2019-05-09 18:48:53 -05:00
|
|
|
// tight loop that reads 1K at a time until buffer is empty
|
2019-05-09 20:54:36 -05:00
|
|
|
for (empty == false) {
|
2019-05-09 18:48:53 -05:00
|
|
|
oneByte := make([]byte, 1024)
|
|
|
|
count, err := nbr.Read(oneByte)
|
|
|
|
totalCount += count
|
|
|
|
|
|
|
|
if (err != nil) {
|
2019-05-09 20:54:36 -05:00
|
|
|
log.Println("Read() count = ", count, "err = ", err)
|
2019-05-09 18:48:53 -05:00
|
|
|
oneByte = make([]byte, 1024)
|
|
|
|
count, err = nbr.Read(oneByte)
|
2019-05-09 21:46:27 -05:00
|
|
|
log.Println("STDOUT: count = ", count)
|
|
|
|
f.Write(oneByte[0:count])
|
2019-05-09 18:48:53 -05:00
|
|
|
f.Flush()
|
2019-05-09 20:54:36 -05:00
|
|
|
empty = true
|
|
|
|
dead = true
|
2019-05-09 18:48:53 -05:00
|
|
|
}
|
2019-05-09 21:46:27 -05:00
|
|
|
// f.Write([]byte(string(oneByte)))
|
2019-05-09 18:48:53 -05:00
|
|
|
if (count == 0) {
|
2019-05-09 20:54:36 -05:00
|
|
|
empty = true
|
2019-05-09 21:46:27 -05:00
|
|
|
} else {
|
|
|
|
log.Println("STDOUT: count = ", count)
|
2019-06-04 22:20:15 -05:00
|
|
|
io.WriteString(&buf, string(oneByte))
|
2019-05-09 21:46:27 -05:00
|
|
|
f.Write(oneByte[0:count])
|
|
|
|
f.Flush()
|
2019-05-09 18:48:53 -05:00
|
|
|
}
|
2019-04-07 23:15:01 -05:00
|
|
|
}
|
|
|
|
|
2019-05-09 18:48:53 -05:00
|
|
|
if (totalCount != 0) {
|
2019-05-09 20:54:36 -05:00
|
|
|
log.Println("STDOUT: totalCount = ", totalCount)
|
|
|
|
totalCount = 0
|
2019-04-07 23:15:01 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
err := process.Wait()
|
|
|
|
|
|
|
|
if err != nil {
|
2019-05-09 19:24:25 -05:00
|
|
|
if (spewOn) {
|
|
|
|
spew.Dump(err.(*exec.ExitError))
|
|
|
|
spew.Dump(process.ProcessState)
|
|
|
|
}
|
2019-04-07 23:15:01 -05:00
|
|
|
stuff := err.(*exec.ExitError)
|
|
|
|
log.Println("ERROR ", stuff)
|
|
|
|
log.Println("END ", cmdline)
|
2019-06-04 22:20:15 -05:00
|
|
|
return -1, "", err
|
2019-04-07 23:15:01 -05:00
|
|
|
}
|
2019-06-04 22:20:15 -05:00
|
|
|
// log.Println("shell.Run() END buf =", buf)
|
|
|
|
// log.Println("shell.Run() END string(buf) =", string(buf))
|
|
|
|
// log.Println("shell.Run() END buf.String() =", buf.String())
|
|
|
|
// log.Println("shell.Run() END string(buf.Bytes()) =", string(buf.Bytes()))
|
|
|
|
log.Println("shell.Run() END ", cmdline)
|
|
|
|
return 0, buf.String(), fmt.Errorf("") // nothing to do
|
2019-04-07 23:15:01 -05:00
|
|
|
}
|
2019-04-08 18:43:49 -05:00
|
|
|
|
|
|
|
func Daemon(cmdline string, timeout time.Duration) int {
|
|
|
|
for {
|
|
|
|
Run(cmdline)
|
|
|
|
time.Sleep(timeout)
|
|
|
|
}
|
|
|
|
}
|
2019-05-09 20:54:36 -05:00
|
|
|
|
|
|
|
// pass in two file handles (1 read, 1 write)
|
|
|
|
func NonBlockingReader(buffReader *bufio.Reader, writeFileHandle *os.File) {
|
|
|
|
// newreader := bufio.NewReader(readFileHandle)
|
|
|
|
|
|
|
|
// create a nonblocking GO reader
|
|
|
|
nbr := nbreader.NewNBReader(buffReader, 1024)
|
|
|
|
|
|
|
|
for {
|
|
|
|
// defer buffReader.Close()
|
|
|
|
// defer writeFileHandle.Flush()
|
|
|
|
defer writeFileHandle.Close()
|
|
|
|
totalCount := 0
|
|
|
|
for {
|
|
|
|
oneByte := make([]byte, 1024)
|
|
|
|
count, err := nbr.Read(oneByte)
|
|
|
|
if (err != nil) {
|
|
|
|
log.Println("count, err =", count, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
totalCount += count
|
|
|
|
if (count == 0) {
|
|
|
|
time.Sleep(time.Duration(msecDelay) * time.Millisecond) // without this delay this will peg the CPU
|
|
|
|
if (totalCount != 0) {
|
|
|
|
log.Println("STDERR: totalCount = ", totalCount)
|
|
|
|
totalCount = 0
|
|
|
|
}
|
2019-05-09 21:46:27 -05:00
|
|
|
} else {
|
|
|
|
log.Println("STDERR: count = ", count)
|
|
|
|
writeFileHandle.Write(oneByte[0:count])
|
2019-05-09 20:54:36 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|