diff --git a/qemu.go b/qemu.go index c1f89715d2..869ae3be55 100644 --- a/qemu.go +++ b/qemu.go @@ -46,7 +46,7 @@ type Machine struct { // Device is the qemu device interface. type Device interface { Valid() bool - QemuParams() []string + QemuParams(config *Config) []string } // DeviceDriver is the device driver string. @@ -118,7 +118,7 @@ func (object Object) Valid() bool { } // QemuParams returns the qemu parameters built out of this Object device. -func (object Object) QemuParams() []string { +func (object Object) QemuParams(config *Config) []string { var objectParams []string var deviceParams []string var qemuParams []string @@ -207,7 +207,7 @@ func (fsdev FSDevice) Valid() bool { } // QemuParams returns the qemu parameters built out of this filesystem device. -func (fsdev FSDevice) QemuParams() []string { +func (fsdev FSDevice) QemuParams(config *Config) []string { var fsParams []string var deviceParams []string var qemuParams []string @@ -294,7 +294,7 @@ func appendCharDevice(params []string, cdev CharDevice) ([]string, error) { } // QemuParams returns the qemu parameters built out of this character device. -func (cdev CharDevice) QemuParams() []string { +func (cdev CharDevice) QemuParams(config *Config) []string { var cdevParams []string var deviceParams []string var qemuParams []string @@ -349,7 +349,7 @@ type NetDevice struct { // FDs represents the list of already existing file descriptors to be used. // This is mostly useful for mq support. - FDs []int + FDs []*os.File // VHost enables virtio device emulation from the host kernel instead of from qemu. VHost bool @@ -375,7 +375,7 @@ func (netdev NetDevice) Valid() bool { } // QemuParams returns the qemu parameters built out of this network device. -func (netdev NetDevice) QemuParams() []string { +func (netdev NetDevice) QemuParams(config *Config) []string { var netdevParams []string var deviceParams []string var qemuParams []string @@ -399,7 +399,9 @@ func (netdev NetDevice) QemuParams() []string { if len(netdev.FDs) > 0 { var fdParams []string - for _, fd := range netdev.FDs { + qemuFDs := config.appendFDs(netdev.FDs) + + for _, fd := range qemuFDs { fdParams = append(fdParams, fmt.Sprintf("%d", fd)) } @@ -438,7 +440,7 @@ func (dev SerialDevice) Valid() bool { } // QemuParams returns the qemu parameters built out of this serial device. -func (dev SerialDevice) QemuParams() []string { +func (dev SerialDevice) QemuParams(config *Config) []string { var deviceParams []string var qemuParams []string @@ -503,7 +505,7 @@ func (blkdev BlockDevice) Valid() bool { } // QemuParams returns the qemu parameters built out of this block device. -func (blkdev BlockDevice) QemuParams() []string { +func (blkdev BlockDevice) QemuParams(config *Config) []string { var blkParams []string var deviceParams []string var qemuParams []string @@ -730,12 +732,32 @@ type Config struct { // Knobs is a set of qemu boolean settings. Knobs Knobs - // FDs is a list of open file descriptors to be passed to the spawned qemu process - FDs []*os.File + // fds is a list of open file descriptors to be passed to the spawned qemu process + fds []*os.File qemuParams []string } +// appendFDs append a list of file descriptors to the qemu configuration and +// returns a slice of offset file descriptors that will be seen by the qemu process. +func (config *Config) appendFDs(fds []*os.File) []int { + var fdInts []int + + oldLen := len(config.fds) + + config.fds = append(config.fds, fds...) + + // The magic 3 offset comes from https://golang.org/src/os/exec/exec.go: + // ExtraFiles specifies additional open files to be inherited by the + // new process. It does not include standard input, standard output, or + // standard error. If non-nil, entry i becomes file descriptor 3+i. + for i := range fds { + fdInts = append(fdInts, oldLen+3+i) + } + + return fdInts +} + func (config *Config) appendName() { if config.Name != "" { config.qemuParams = append(config.qemuParams, "-name") @@ -791,7 +813,7 @@ func (config *Config) appendDevices() { continue } - config.qemuParams = append(config.qemuParams, d.QemuParams()...) + config.qemuParams = append(config.qemuParams, d.QemuParams(config)...) } } @@ -929,7 +951,7 @@ func LaunchQemu(config Config, logger QMPLog) (string, error) { config.appendKnobs() config.appendKernel() - return LaunchCustomQemu(config.Ctx, config.Path, config.qemuParams, config.FDs, logger) + return LaunchCustomQemu(config.Ctx, config.Path, config.qemuParams, config.fds, logger) } // LaunchCustomQemu can be used to launch a new qemu instance. diff --git a/qemu_test.go b/qemu_test.go index a5875fe256..647b202a92 100644 --- a/qemu_test.go +++ b/qemu_test.go @@ -17,6 +17,8 @@ package qemu import ( + "io/ioutil" + "os" "strings" "testing" @@ -113,9 +115,15 @@ func TestAppendDeviceFS(t *testing.T) { testAppend(fsdev, deviceFSString, t) } -var deviceNetworkString = "-device virtio-net,netdev=tap0,mac=01:02:de:ad:be:ef -netdev tap,id=tap0,ifname=ceth0,downscript=no,script=no,fds=8:9:10,vhost=on" +var deviceNetworkString = "-device virtio-net,netdev=tap0,mac=01:02:de:ad:be:ef -netdev tap,id=tap0,ifname=ceth0,downscript=no,script=no,fds=3:4,vhost=on" func TestAppendDeviceNetwork(t *testing.T) { + foo, _ := ioutil.TempFile(os.TempDir(), "qemu-ciao-test") + bar, _ := ioutil.TempFile(os.TempDir(), "qemu-ciao-test") + + defer os.Remove(foo.Name()) + defer os.Remove(bar.Name()) + netdev := NetDevice{ Driver: VirtioNet, Type: TAP, @@ -123,7 +131,7 @@ func TestAppendDeviceNetwork(t *testing.T) { IFName: "ceth0", Script: "no", DownScript: "no", - FDs: []int{8, 9, 10}, + FDs: []*os.File{foo, bar}, VHost: true, MACAddress: "01:02:de:ad:be:ef", }