aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config/config.go71
-rw-r--r--csource/common.go2
-rw-r--r--executor/common.h2
-rw-r--r--syz-manager/manager.go1
-rw-r--r--tools/syz-repro/repro.go1
-rw-r--r--vm/adb/adb.go6
-rw-r--r--vm/console.go (renamed from vm/adb/console.go)35
-rw-r--r--vm/odroid/odroid.go368
-rw-r--r--vm/vm.go38
9 files changed, 470 insertions, 54 deletions
diff --git a/config/config.go b/config/config.go
index 410d9c663..aae8de35b 100644
--- a/config/config.go
+++ b/config/config.go
@@ -56,6 +56,13 @@ type Config struct {
Machine_Type string // GCE machine type (e.g. "n1-highcpu-2")
+ Odroid_Host_Addr string // ip address of the host machine
+ Odroid_Slave_Addr string // ip address of the Odroid board
+ Odroid_Console string // console device name (e.g. "/dev/ttyUSB0")
+ Odroid_Hub_Bus int // host USB bus number for the USB hub
+ Odroid_Hub_Device int // host USB device number for the USB hub
+ Odroid_Hub_Port int // port on the USB hub to which Odroid is connected
+
Cover bool // use kcov coverage (default: true)
Leak bool // do memory leak checking
Reproduce bool // reproduce, localize and minimize crashers (on by default)
@@ -138,6 +145,28 @@ func parse(data []byte) (*Config, map[int]bool, error) {
return nil, nil, fmt.Errorf("machine_type parameter is empty (required for gce)")
}
fallthrough
+ case "odroid":
+ if cfg.Count != 1 {
+ return nil, nil, fmt.Errorf("no support for multiple Odroid devices yet, count should be 1")
+ }
+ if cfg.Odroid_Host_Addr == "" {
+ return nil, nil, fmt.Errorf("config param odroid_host_addr is empty")
+ }
+ if cfg.Odroid_Slave_Addr == "" {
+ return nil, nil, fmt.Errorf("config param odroid_slave_addr is empty")
+ }
+ if cfg.Odroid_Console == "" {
+ return nil, nil, fmt.Errorf("config param odroid_console is empty")
+ }
+ if cfg.Odroid_Hub_Bus == 0 {
+ return nil, nil, fmt.Errorf("config param odroid_hub_bus is empty")
+ }
+ if cfg.Odroid_Hub_Device == 0 {
+ return nil, nil, fmt.Errorf("config param odroid_hub_device is empty")
+ }
+ if cfg.Odroid_Hub_Port == 0 {
+ return nil, nil, fmt.Errorf("config param odroid_hub_port is empty")
+ }
default:
if cfg.Count <= 0 || cfg.Count > 1000 {
return nil, nil, fmt.Errorf("invalid config param count: %v, want (1, 1000]", cfg.Count)
@@ -308,21 +337,27 @@ func CreateVMConfig(cfg *Config, index int) (*vm.Config, error) {
return nil, fmt.Errorf("failed to create instance temp dir: %v", err)
}
vmCfg := &vm.Config{
- Name: fmt.Sprintf("%v-%v-%v", cfg.Type, cfg.Name, index),
- Index: index,
- Workdir: workdir,
- Bin: cfg.Bin,
- BinArgs: cfg.Bin_Args,
- Kernel: cfg.Kernel,
- Cmdline: cfg.Cmdline,
- Image: cfg.Image,
- Initrd: cfg.Initrd,
- Sshkey: cfg.Sshkey,
- Executor: filepath.Join(cfg.Syzkaller, "bin", "syz-executor"),
- Cpu: cfg.Cpu,
- Mem: cfg.Mem,
- Debug: cfg.Debug,
- MachineType: cfg.Machine_Type,
+ Name: fmt.Sprintf("%v-%v-%v", cfg.Type, cfg.Name, index),
+ Index: index,
+ Workdir: workdir,
+ Bin: cfg.Bin,
+ BinArgs: cfg.Bin_Args,
+ Kernel: cfg.Kernel,
+ Cmdline: cfg.Cmdline,
+ Image: cfg.Image,
+ Initrd: cfg.Initrd,
+ Sshkey: cfg.Sshkey,
+ Executor: filepath.Join(cfg.Syzkaller, "bin", "syz-executor"),
+ Cpu: cfg.Cpu,
+ Mem: cfg.Mem,
+ Debug: cfg.Debug,
+ MachineType: cfg.Machine_Type,
+ OdroidHostAddr: cfg.Odroid_Host_Addr,
+ OdroidSlaveAddr: cfg.Odroid_Slave_Addr,
+ OdroidConsole: cfg.Odroid_Console,
+ OdroidHubBus: cfg.Odroid_Hub_Bus,
+ OdroidHubDevice: cfg.Odroid_Hub_Device,
+ OdroidHubPort: cfg.Odroid_Hub_Port,
}
if len(cfg.Devices) != 0 {
vmCfg.Device = cfg.Devices[index]
@@ -369,6 +404,12 @@ func checkUnknownFields(data []byte) (string, error) {
"Ignores",
"Initrd",
"Machine_Type",
+ "Odroid_Host_Addr",
+ "Odroid_Slave_Addr",
+ "Odroid_Console",
+ "Odroid_Hub_Bus",
+ "Odroid_Hub_Device",
+ "Odroid_Hub_Port",
}
f := make(map[string]interface{})
if err := json.Unmarshal(data, &f); err != nil {
diff --git a/csource/common.go b/csource/common.go
index fb1f56517..f09cbf24d 100644
--- a/csource/common.go
+++ b/csource/common.go
@@ -1540,7 +1540,7 @@ static int do_sandbox_namespace(int executor_pid, bool enable_tun)
epid = executor_pid;
etun = enable_tun;
mprotect(sandbox_stack, 4096, PROT_NONE);
- return clone(namespace_sandbox_proc, &sandbox_stack[sizeof(sandbox_stack) - 8],
+ return clone(namespace_sandbox_proc, &sandbox_stack[sizeof(sandbox_stack) - 64],
CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWUTS | CLONE_NEWNET, NULL);
}
#endif
diff --git a/executor/common.h b/executor/common.h
index b1084eb0c..4983802f2 100644
--- a/executor/common.h
+++ b/executor/common.h
@@ -633,7 +633,7 @@ static int do_sandbox_namespace(int executor_pid, bool enable_tun)
epid = executor_pid;
etun = enable_tun;
mprotect(sandbox_stack, 4096, PROT_NONE); // to catch stack underflows
- return clone(namespace_sandbox_proc, &sandbox_stack[sizeof(sandbox_stack) - 8],
+ return clone(namespace_sandbox_proc, &sandbox_stack[sizeof(sandbox_stack) - 64],
CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWUTS | CLONE_NEWNET, NULL);
}
#endif
diff --git a/syz-manager/manager.go b/syz-manager/manager.go
index 6806061c3..6bf9d6e9a 100644
--- a/syz-manager/manager.go
+++ b/syz-manager/manager.go
@@ -35,6 +35,7 @@ import (
_ "github.com/google/syzkaller/vm/gce"
_ "github.com/google/syzkaller/vm/kvm"
_ "github.com/google/syzkaller/vm/local"
+ _ "github.com/google/syzkaller/vm/odroid"
_ "github.com/google/syzkaller/vm/qemu"
)
diff --git a/tools/syz-repro/repro.go b/tools/syz-repro/repro.go
index e2e2f6985..841a121d1 100644
--- a/tools/syz-repro/repro.go
+++ b/tools/syz-repro/repro.go
@@ -19,6 +19,7 @@ import (
_ "github.com/google/syzkaller/vm/adb"
_ "github.com/google/syzkaller/vm/gce"
_ "github.com/google/syzkaller/vm/kvm"
+ _ "github.com/google/syzkaller/vm/odroid"
_ "github.com/google/syzkaller/vm/qemu"
)
diff --git a/vm/adb/adb.go b/vm/adb/adb.go
index b8d00ea42..ae67ba182 100644
--- a/vm/adb/adb.go
+++ b/vm/adb/adb.go
@@ -118,7 +118,7 @@ func findConsoleImpl(adb, dev string) (string, error) {
out := new([]byte)
output[con] = out
go func(con string) {
- tty, err := openConsole(con)
+ tty, err := vm.OpenConsole(con)
if err != nil {
errors <- err
return
@@ -342,9 +342,9 @@ func (inst *instance) Run(timeout time.Duration, stop <-chan bool, command strin
var tty io.ReadCloser
var err error
if inst.console == "adb" {
- tty, err = openAdbConsole(inst.cfg.Bin, inst.cfg.Device)
+ tty, err = vm.OpenAdbConsole(inst.cfg.Bin, inst.cfg.Device)
} else {
- tty, err = openConsole(inst.console)
+ tty, err = vm.OpenConsole(inst.console)
}
if err != nil {
return nil, nil, err
diff --git a/vm/adb/console.go b/vm/console.go
index 7fb32c4b9..6dd6a6edf 100644
--- a/vm/adb/console.go
+++ b/vm/console.go
@@ -1,9 +1,9 @@
-// Copyright 2016 syzkaller project authors. All rights reserved.
+// Copyright 2017 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
// +build !ppc64le
-package adb
+package vm
import (
"fmt"
@@ -13,12 +13,11 @@ import (
"syscall"
"unsafe"
- "github.com/google/syzkaller/vm"
- . "golang.org/x/sys/unix"
+ "golang.org/x/sys/unix"
)
// Tested on Suzy-Q and BeagleBone.
-func openConsole(con string) (rc io.ReadCloser, err error) {
+func OpenConsole(con string) (rc io.ReadCloser, err error) {
fd, err := syscall.Open(con, syscall.O_RDONLY|syscall.O_NOCTTY|syscall.O_SYNC, 0)
if err != nil {
return nil, fmt.Errorf("failed to open console file: %v", err)
@@ -28,21 +27,21 @@ func openConsole(con string) (rc io.ReadCloser, err error) {
syscall.Close(fd)
}
}()
- var term Termios
- if _, _, errno := syscall.Syscall(SYS_IOCTL, uintptr(fd), TCGETS2, uintptr(unsafe.Pointer(&term))); errno != 0 {
+ var term unix.Termios
+ if _, _, errno := syscall.Syscall(unix.SYS_IOCTL, uintptr(fd), unix.TCGETS2, uintptr(unsafe.Pointer(&term))); errno != 0 {
return nil, fmt.Errorf("failed to get console termios: %v", errno)
}
// no parity bit, only need 1 stop bit, no hardware flowcontrol
- term.Cflag &^= CBAUD | CSIZE | PARENB | CSTOPB | CRTSCTS
+ term.Cflag &^= unix.CBAUD | unix.CSIZE | unix.PARENB | unix.CSTOPB | unix.CRTSCTS
// ignore modem controls
- term.Cflag |= B115200 | CS8 | CLOCAL | CREAD
+ term.Cflag |= unix.B115200 | unix.CS8 | unix.CLOCAL | unix.CREAD
// setup for non-canonical mode
- term.Iflag &^= IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON
- term.Lflag &^= ECHO | ECHONL | ICANON | ISIG | IEXTEN
- term.Oflag &^= OPOST
- term.Cc[VMIN] = 0
- term.Cc[VTIME] = 10 // 1 second timeout
- if _, _, errno := syscall.Syscall(SYS_IOCTL, uintptr(fd), TCSETS2, uintptr(unsafe.Pointer(&term))); errno != 0 {
+ term.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON
+ term.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN
+ term.Oflag &^= unix.OPOST
+ term.Cc[unix.VMIN] = 0
+ term.Cc[unix.VTIME] = 10 // 1 second timeout
+ if _, _, errno := syscall.Syscall(unix.SYS_IOCTL, uintptr(fd), unix.TCSETS2, uintptr(unsafe.Pointer(&term))); errno != 0 {
return nil, fmt.Errorf("failed to get console termios: %v", errno)
}
tmp := fd
@@ -78,9 +77,9 @@ func (t *tty) Close() error {
return nil
}
-// openAdbConsole provides fallback console output using 'adb shell dmesg -w'.
-func openAdbConsole(bin, dev string) (rc io.ReadCloser, err error) {
- rpipe, wpipe, err := vm.LongPipe()
+// OpenAdbConsole provides fallback console output using 'adb shell dmesg -w'.
+func OpenAdbConsole(bin, dev string) (rc io.ReadCloser, err error) {
+ rpipe, wpipe, err := LongPipe()
if err != nil {
return nil, err
}
diff --git a/vm/odroid/odroid.go b/vm/odroid/odroid.go
new file mode 100644
index 000000000..f99b2a645
--- /dev/null
+++ b/vm/odroid/odroid.go
@@ -0,0 +1,368 @@
+// Copyright 2017 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package odroid
+
+// #cgo pkg-config: libusb-1.0
+// #include <linux/usb/ch9.h>
+// #include <linux/usb/ch11.h>
+// #include <libusb.h>
+import "C"
+
+import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "reflect"
+ "time"
+ "unsafe"
+
+ . "github.com/google/syzkaller/log"
+ "github.com/google/syzkaller/vm"
+)
+
+func init() {
+ vm.Register("odroid", ctor)
+}
+
+type instance struct {
+ cfg *vm.Config
+ closed chan bool
+}
+
+func ctor(cfg *vm.Config) (vm.Instance, error) {
+ inst := &instance{
+ cfg: cfg,
+ closed: make(chan bool),
+ }
+ closeInst := inst
+ defer func() {
+ if closeInst != nil {
+ closeInst.Close()
+ }
+ }()
+ if err := validateConfig(cfg); err != nil {
+ return nil, err
+ }
+ if err := inst.repair(); err != nil {
+ return nil, err
+ }
+
+ // Create working dir if doesn't exist.
+ inst.ssh("mkdir -p /data/")
+
+ // Remove temp files from previous runs.
+ inst.ssh("rm -rf /data/syzkaller-*")
+
+ closeInst = nil
+ return inst, nil
+}
+
+func validateConfig(cfg *vm.Config) error {
+ if _, err := os.Stat(cfg.Sshkey); err != nil {
+ return fmt.Errorf("ssh key '%v' does not exist: %v", cfg.Sshkey, err)
+ }
+ if _, err := os.Stat(cfg.OdroidConsole); err != nil {
+ return fmt.Errorf("console file '%v' does not exist: %v", cfg.OdroidConsole, err)
+ }
+ return nil
+}
+
+func (inst *instance) Forward(port int) (string, error) {
+ return fmt.Sprintf(inst.cfg.OdroidHostAddr+":%v", port), nil
+}
+
+func (inst *instance) ssh(command string) ([]byte, error) {
+ if inst.cfg.Debug {
+ Logf(0, "executing ssh %+v", command)
+ }
+
+ rpipe, wpipe, err := vm.LongPipe()
+ if err != nil {
+ return nil, err
+ }
+
+ args := append(inst.sshArgs("-p"), "root@"+inst.cfg.OdroidSlaveAddr, command)
+ if inst.cfg.Debug {
+ Logf(0, "running command: ssh %#v", args)
+ }
+ cmd := exec.Command("ssh", args...)
+ cmd.Stdout = wpipe
+ cmd.Stderr = wpipe
+ if err := cmd.Start(); err != nil {
+ wpipe.Close()
+ return nil, err
+ }
+ wpipe.Close()
+
+ done := make(chan bool)
+ go func() {
+ select {
+ case <-time.After(time.Minute):
+ if inst.cfg.Debug {
+ Logf(0, "ssh hanged")
+ }
+ cmd.Process.Kill()
+ case <-done:
+ }
+ }()
+ if err := cmd.Wait(); err != nil {
+ close(done)
+ out, _ := ioutil.ReadAll(rpipe)
+ if inst.cfg.Debug {
+ Logf(0, "ssh failed: %v\n%s", err, out)
+ }
+ return nil, fmt.Errorf("ssh %+v failed: %v\n%s", args, err, out)
+ }
+ close(done)
+ if inst.cfg.Debug {
+ Logf(0, "ssh returned")
+ }
+ out, _ := ioutil.ReadAll(rpipe)
+ return out, nil
+}
+
+func switchPortPower(busNum, deviceNum, portNum int, power bool) error {
+ var context *C.libusb_context
+ if err := C.libusb_init(&context); err != 0 {
+ return fmt.Errorf("failed to init libusb: %v\n", err)
+ }
+ defer C.libusb_exit(context)
+
+ var rawList **C.libusb_device
+ numDevices := int(C.libusb_get_device_list(context, &rawList))
+ if numDevices < 0 {
+ return fmt.Errorf("failed to init libusb: %v", numDevices)
+ }
+ defer C.libusb_free_device_list(rawList, 1)
+
+ var deviceList []*C.libusb_device
+ *(*reflect.SliceHeader)(unsafe.Pointer(&deviceList)) = reflect.SliceHeader{
+ Data: uintptr(unsafe.Pointer(rawList)),
+ Len: numDevices,
+ Cap: numDevices,
+ }
+
+ var hub *C.libusb_device
+ for i := 0; i < numDevices; i++ {
+ var desc C.struct_libusb_device_descriptor
+ if err := C.libusb_get_device_descriptor(deviceList[i], &desc); err != 0 {
+ return fmt.Errorf("failed to get device descriptor: %v", err)
+ }
+ if desc.bDeviceClass != C.USB_CLASS_HUB {
+ continue
+ }
+ if C.libusb_get_bus_number(deviceList[i]) != C.uint8_t(busNum) {
+ continue
+ }
+ if C.libusb_get_device_address(deviceList[i]) != C.uint8_t(deviceNum) {
+ continue
+ }
+ hub = deviceList[i]
+ break
+ }
+
+ if hub == nil {
+ return fmt.Errorf("hub not found: bus: %v, device: %v", busNum, deviceNum)
+ }
+
+ var handle *C.libusb_device_handle
+ if err := C.libusb_open(hub, &handle); err != 0 {
+ return fmt.Errorf("failed to open usb device: %v", err)
+ }
+
+ request := C.uint8_t(C.USB_REQ_CLEAR_FEATURE)
+ if power {
+ request = C.uint8_t(C.USB_REQ_SET_FEATURE)
+ }
+ port := C.uint16_t(portNum)
+ timeout := C.uint(1000)
+ if err := C.libusb_control_transfer(handle, C.USB_RT_PORT, request,
+ C.USB_PORT_FEAT_POWER, port, nil, 0, timeout); err < 0 {
+ return fmt.Errorf("failed to send control message: %v\n", err)
+ }
+
+ return nil
+}
+
+func (inst *instance) repair() error {
+ // Try to shutdown gracefully.
+ Logf(1, "odroid: trying to ssh")
+ if err := inst.waitForSsh(10); err == nil {
+ Logf(1, "odroid: ssh succeeded, shutting down now")
+ inst.ssh("shutdown now")
+ if !vm.SleepInterruptible(20 * time.Second) {
+ return fmt.Errorf("shutdown in progress")
+ }
+ } else {
+ Logf(1, "odroid: ssh failed")
+ }
+
+ // Hard reset by turning off and back on power on a hub port.
+ Logf(1, "odroid: hard reset, turning off power")
+ if err := switchPortPower(inst.cfg.OdroidHubBus, inst.cfg.OdroidHubDevice, inst.cfg.OdroidHubPort, false); err != nil {
+ return err
+ }
+ if !vm.SleepInterruptible(5 * time.Second) {
+ return fmt.Errorf("shutdown in progress")
+ }
+ if err := switchPortPower(inst.cfg.OdroidHubBus, inst.cfg.OdroidHubDevice, inst.cfg.OdroidHubPort, true); err != nil {
+ return err
+ }
+
+ // Now wait for boot.
+ Logf(1, "odroid: power back on, waiting for boot")
+ if err := inst.waitForSsh(150); err != nil {
+ return err
+ }
+
+ Logf(1, "odroid: boot succeeded")
+ return nil
+}
+
+func (inst *instance) waitForSsh(timeout int) error {
+ var err error
+ start := time.Now()
+ for {
+ if !vm.SleepInterruptible(time.Second) {
+ return fmt.Errorf("shutdown in progress")
+ }
+ if _, err = inst.ssh("pwd"); err == nil {
+ return nil
+ }
+ if time.Since(start).Seconds() > float64(timeout) {
+ break
+ }
+ }
+ return fmt.Errorf("instance is dead and unrepairable: %v", err)
+}
+
+func (inst *instance) Close() {
+ close(inst.closed)
+ os.RemoveAll(inst.cfg.Workdir)
+}
+
+func (inst *instance) Copy(hostSrc string) (string, error) {
+ basePath := "/data/"
+ vmDst := filepath.Join(basePath, filepath.Base(hostSrc))
+ args := append(inst.sshArgs("-P"), hostSrc, "root@"+inst.cfg.OdroidSlaveAddr+":"+vmDst)
+ cmd := exec.Command("scp", args...)
+ if inst.cfg.Debug {
+ Logf(0, "running command: scp %#v", args)
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stdout
+ }
+ if err := cmd.Start(); err != nil {
+ return "", err
+ }
+ done := make(chan bool)
+ go func() {
+ select {
+ case <-time.After(3 * time.Minute):
+ cmd.Process.Kill()
+ case <-done:
+ }
+ }()
+ err := cmd.Wait()
+ close(done)
+ if err != nil {
+ return "", err
+ }
+ return vmDst, nil
+}
+
+func (inst *instance) Run(timeout time.Duration, stop <-chan bool, command string) (<-chan []byte, <-chan error, error) {
+ tty, err := vm.OpenConsole(inst.cfg.OdroidConsole)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ rpipe, wpipe, err := vm.LongPipe()
+ if err != nil {
+ tty.Close()
+ return nil, nil, err
+ }
+
+ args := append(inst.sshArgs("-p"), "root@"+inst.cfg.OdroidSlaveAddr, "cd /data; "+command)
+ if inst.cfg.Debug {
+ Logf(0, "running command: ssh %#v", args)
+ }
+ cmd := exec.Command("ssh", args...)
+ cmd.Stdout = wpipe
+ cmd.Stderr = wpipe
+ if err := cmd.Start(); err != nil {
+ tty.Close()
+ rpipe.Close()
+ wpipe.Close()
+ return nil, nil, err
+ }
+ wpipe.Close()
+
+ var tee io.Writer
+ if inst.cfg.Debug {
+ tee = os.Stdout
+ }
+ merger := vm.NewOutputMerger(tee)
+ merger.Add("console", tty)
+ merger.Add("ssh", rpipe)
+
+ errc := make(chan error, 1)
+ signal := func(err error) {
+ select {
+ case errc <- err:
+ default:
+ }
+ }
+
+ go func() {
+ select {
+ case <-time.After(timeout):
+ signal(vm.TimeoutErr)
+ case <-stop:
+ signal(vm.TimeoutErr)
+ case <-inst.closed:
+ if inst.cfg.Debug {
+ Logf(0, "instance closed")
+ }
+ signal(fmt.Errorf("instance closed"))
+ case err := <-merger.Err:
+ cmd.Process.Kill()
+ tty.Close()
+ merger.Wait()
+ if cmdErr := cmd.Wait(); cmdErr == nil {
+ // If the command exited successfully, we got EOF error from merger.
+ // But in this case no error has happened and the EOF is expected.
+ err = nil
+ }
+ signal(err)
+ return
+ }
+ cmd.Process.Kill()
+ tty.Close()
+ merger.Wait()
+ cmd.Wait()
+ }()
+ return merger.Output, errc, nil
+}
+
+func (inst *instance) sshArgs(portArg string) []string {
+ args := []string{
+ "-i", inst.cfg.Sshkey,
+ portArg, "22",
+ "-F", "/dev/null",
+ "-o", "ConnectionAttempts=10",
+ "-o", "ConnectTimeout=10",
+ "-o", "BatchMode=yes",
+ "-o", "UserKnownHostsFile=/dev/null",
+ "-o", "IdentitiesOnly=yes",
+ "-o", "StrictHostKeyChecking=no",
+ "-o", "LogLevel=error",
+ }
+ if inst.cfg.Debug {
+ args = append(args, "-v")
+ }
+ return args
+}
diff --git a/vm/vm.go b/vm/vm.go
index 79fdc4f76..2140dc5cf 100644
--- a/vm/vm.go
+++ b/vm/vm.go
@@ -36,22 +36,28 @@ type Instance interface {
}
type Config struct {
- Name string
- Index int
- Workdir string
- Bin string
- BinArgs string
- Initrd string
- Kernel string
- Cmdline string
- Image string
- Sshkey string
- Executor string
- Device string
- MachineType string
- Cpu int
- Mem int
- Debug bool
+ Name string
+ Index int
+ Workdir string
+ Bin string
+ BinArgs string
+ Initrd string
+ Kernel string
+ Cmdline string
+ Image string
+ Sshkey string
+ Executor string
+ Device string
+ MachineType string
+ OdroidHostAddr string
+ OdroidSlaveAddr string
+ OdroidConsole string
+ OdroidHubBus int
+ OdroidHubDevice int
+ OdroidHubPort int
+ Cpu int
+ Mem int
+ Debug bool
}
type ctorFunc func(cfg *Config) (Instance, error)