runtime: Collect QEMU's stderr

LaunchQemu now connects a pipe to QEMU's stderr and makes it
usable by callers through a Go io.ReadCloser object. As
explained in [0], all messages should be read from the pipe
before calling cmd.Wait : introduce a LogAndWait helper to handle
that.

Fixes #5780

Signed-off-by: Greg Kurz <groug@kaod.org>
This commit is contained in:
Greg Kurz
2023-01-24 16:12:44 +01:00
parent a5319c6be6
commit 39fe4a4b6f
3 changed files with 42 additions and 15 deletions

View File

@@ -32,7 +32,7 @@ func Example() {
// flag.
// It will set up a unix domain socket called /tmp/qmp-socket that we
// can use to manage the instance.
proc, err := qemu.LaunchCustomQemu(context.Background(), "", params, nil, nil, nil)
proc, _, err := qemu.LaunchCustomQemu(context.Background(), "", params, nil, nil, nil)
if err != nil {
panic(err)
}

View File

@@ -16,6 +16,7 @@ package qemu
import (
"context"
"fmt"
"io"
"log"
"os"
"os/exec"
@@ -2985,7 +2986,7 @@ func (config *Config) appendFwCfg(logger QMPLog) {
// The Config parameter contains a set of qemu parameters and settings.
//
// See LaunchCustomQemu for more information.
func LaunchQemu(config Config, logger QMPLog) (*exec.Cmd, error) {
func LaunchQemu(config Config, logger QMPLog) (*exec.Cmd, io.ReadCloser, error) {
config.appendName()
config.appendUUID()
config.appendMachine()
@@ -3008,7 +3009,7 @@ func LaunchQemu(config Config, logger QMPLog) (*exec.Cmd, error) {
config.appendSeccompSandbox()
if err := config.appendCPUs(); err != nil {
return nil, err
return nil, nil, err
}
ctx := config.Ctx
@@ -3039,11 +3040,12 @@ func LaunchQemu(config Config, logger QMPLog) (*exec.Cmd, error) {
//
// This function writes its log output via logger parameter.
//
// The function returns cmd, nil where cmd is a Go exec.Cmd object
// representing the QEMU process if launched successfully. Otherwise
// nil, err where err is a Go error object is returned.
// The function returns cmd, reader, nil where cmd is a Go exec.Cmd object
// representing the QEMU process and reader a Go io.ReadCloser object
// connected to QEMU's stderr, if launched successfully. Otherwise
// nil, nil, err where err is a Go error object is returned.
func LaunchCustomQemu(ctx context.Context, path string, params []string, fds []*os.File,
attr *syscall.SysProcAttr, logger QMPLog) (*exec.Cmd, error) {
attr *syscall.SysProcAttr, logger QMPLog) (*exec.Cmd, io.ReadCloser, error) {
if logger == nil {
logger = qmpNullLogger{}
}
@@ -3061,12 +3063,17 @@ func LaunchCustomQemu(ctx context.Context, path string, params []string, fds []*
cmd.SysProcAttr = attr
reader, err := cmd.StderrPipe()
if err != nil {
logger.Errorf("Unable to connect stderr to a pipe")
return nil, nil, err
}
logger.Infof("launching %s with: %v", path, params)
err := cmd.Start()
err = cmd.Start()
if err != nil {
logger.Errorf("Unable to launch %s: %v", path, err)
return nil, err
return nil, nil, err
}
return cmd, nil
return cmd, reader, nil
}