tremplin: log LXD's stdout and stderr

LXD usually logs to syslog, but during a panic it only writes
to stderr. Catch the stderr (and stdout for good measure) to
help debugging.

BUG=b:231408845
TEST=cros_workon_make --install --test --board=tatl chromeos-base/tremplin && chromite/contrib/guestos/deploy_to_termina --board tatl dut chromeos-base/tremplin --restart-services

Change-Id: I88e8a3e3a0ddbf6a13fdd2776bbaad8b094c8004
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/tremplin/+/3629843
Reviewed-by: Nicholas Verne <nverne@chromium.org>
Commit-Queue: David Munro <davidmunro@google.com>
Reviewed-by: David Munro <davidmunro@google.com>
Tested-by: David Munro <davidmunro@google.com>
diff --git a/src/chromiumos/tremplin/lxd_helper.go b/src/chromiumos/tremplin/lxd_helper.go
index eafe1ec..fbf88cb 100644
--- a/src/chromiumos/tremplin/lxd_helper.go
+++ b/src/chromiumos/tremplin/lxd_helper.go
@@ -7,6 +7,7 @@
 import (
 	"context"
 	"fmt"
+	"io"
 	"log"
 	"os"
 	"os/exec"
@@ -116,16 +117,57 @@
 	}
 }
 
+func readIntoLog(c chan int, name string, r io.Reader) {
+	defer close(c)
+	buf := make([]byte, 1024)
+	for {
+		n, err := r.Read(buf)
+		if err == io.EOF {
+			return
+		}
+		if err != nil {
+			log.Print(name, " ERROR: ", err)
+			return
+		}
+		if n < 1 {
+			continue
+		}
+		lines := strings.Split(string(buf[:n]), "\n")
+		nl := len(lines)
+		if nl > 1 && lines[nl-1] == "" {
+			lines = lines[:nl-1]
+		}
+		for _, line := range lines {
+			log.Print("lxd ", name, ": ", line)
+		}
+	}
+}
+
 // runLxd launches LXD and blocks until LXD exits. Will set l.process.
 func (l *lxdHelper) runLxd() error {
 	log.Printf("Running %q", strings.Join(lxdCmd, " "))
 	cmd := exec.Command(lxdCmd[0], lxdCmd[1:]...)
-	err := cmd.Start()
-	if err == nil {
-		log.Print("LXD started")
-		l.process = cmd.Process
-		return cmd.Wait()
+	stdout, err := cmd.StdoutPipe()
+	if err != nil {
+		return err
 	}
+	stderr, err := cmd.StderrPipe()
+	if err != nil {
+		return err
+	}
+	wc_stdout := make(chan int)
+	go readIntoLog(wc_stdout, "stdout", stdout)
+	wc_stderr := make(chan int)
+	go readIntoLog(wc_stderr, "stderr", stderr)
+	err = cmd.Start()
+	if err != nil {
+		return err
+	}
+	log.Print("LXD started")
+	l.process = cmd.Process
+	err = cmd.Wait()
+	<-wc_stdout
+	<-wc_stderr
 	return err
 }