func tmplStaticVolumes(m Machine) []mountPoint {
	mounts := []mountPoint{}
	for _, mount := range append(m.mounts, m.backend.InitStaticVolumes()...) {
		if mount.static {
			mounts = append(mounts, mount)
		}
	}
	return mounts
}
helper function to return the static volumes from a machine, since the mounts variable is unexported
include the extra static mounts from the backend
package fakemachine
import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"text/template"
	"github.com/go-debos/fakemachine/cpio"
)
func mergedUsrSystem() bool {
	f, _ := os.Lstat("/bin")
	if (f.Mode() & os.ModeSymlink) == os.ModeSymlink {
		return true
	}
	return false
}
func getModData(modname string, fieldname string, kernelRelease string) []string {
	out, err := exec.Command("modinfo", "-k", kernelRelease, modname).Output()
	if err != nil {
		return nil
	}
	var fieldValue []string
	scanner := bufio.NewScanner(strings.NewReader(string(out)))
	scanner.Split(bufio.ScanLines)
	for scanner.Scan() {
		field := strings.Split(strings.TrimSpace(scanner.Text()), ":")
		if strings.TrimSpace(field[0]) == fieldname {
			fieldValue = append(fieldValue, strings.TrimSpace(field[1]))
		}
	}
	return fieldValue
}
func getModPath(modname string, kernelRelease string) string {
	path := getModData(modname, "filename", kernelRelease)
	if len(path) != 0  {
		return path[0]
	}
	return ""
}
func getModDepends(modname string, kernelRelease string) []string {
	deplist := getModData(modname, "depends", kernelRelease)
	var modlist []string
	for _, v := range deplist {
		if  v != "" {
			modlist = append(modlist, strings.Split(v, ",")...)
		}
	}
	return modlist
}
func (m *Machine) copyModules(w *writerhelper.WriterHelper, modname string, copiedModules map[string]bool) error {
	release, _ := m.backend.KernelRelease()
	modpath := getModPath(modname, release)
	if modpath == "" {
		return errors.New("Modules path couldn't be determined")
	}
	if modpath == "(builtin)" || copiedModules[modname] {
		return nil
	}
	prefix := ""
	if mergedUsrSystem() {
		prefix = "/usr"
	}
	if err := w.CopyFile(prefix + modpath); err != nil {
		return err
	}
	copiedModules[modname] = true;
	deplist := getModDepends(modname, release)
	for _, mod := range deplist {
		if err := m.copyModules(w, mod, copiedModules); err != nil {
			return err
		}
	}
	return nil
}
func realDir(path string) (string, error) {
	var p string
	var err error
	if p, err = filepath.Abs(path); err != nil {
		return "", err
	}
	if p, err = filepath.EvalSymlinks(p); err != nil {
		return "", err
	}
	return filepath.Dir(p), nil
}
type mountPoint struct {
	hostDirectory    string
	machineDirectory string
	label            string
	static           bool
}
type image struct {
	path  string
	label string
}
type Machine struct {
	backend  backend
	mounts   []mountPoint
	count    int
	images   []image
	memory   int
	numcpus  int
	showBoot bool
	Environ  []string
	scratchsize int64
	scratchpath string
	scratchfile string
	scratchdev  string
	initrdpath  string
}
func NewMachine() *Machine {
	m, err := NewMachineWithBackend("auto")
	if err != nil {
		panic(err)
	}
	return m
}
func NewMachineWithBackend(backendName string) (*Machine, error) {
	var err error
	m := &Machine{memory: 2048, numcpus: runtime.NumCPU()}
	m.backend, err = newBackend(backendName, m)
	if err != nil {
		return nil, err
	}
	m.addStaticVolume("/usr", "usr")
	if !mergedUsrSystem() {
		m.addStaticVolume("/sbin", "sbin")
		m.addStaticVolume("/bin", "bin")
		m.addStaticVolume("/lib", "lib")
	}
	if _, err := os.Stat("/etc/ca-certificates"); err == nil {
		m.AddVolume("/etc/ca-certificates")
	}
	if _, err := os.Stat("/etc/ssl"); err == nil {
		m.AddVolume("/etc/ssl")
	}
	if _, err := os.Stat("/etc/dbus-1"); err == nil {
		m.AddVolume("/etc/dbus-1")
	}
	if _, err := os.Stat("/etc/alternatives"); err == nil {
		m.AddVolume("/etc/alternatives")
	}
	if _, err := os.Stat("/var/lib/binfmts"); err == nil {
		m.AddVolume("/var/lib/binfmts")
	}
	return m, nil
}
func InMachine() (ret bool) {
	_, ret = os.LookupEnv("IN_FAKE_MACHINE")
	return
}
func Supported() bool {
	_, err := newBackend("auto", nil)
	return err == nil
}
const initScript = `#!/bin/busybox sh
busybox mount -t proc proc /proc
busybox mount -t sysfs none /sys
# probe additional modules
{{ range $m := .Backend.InitModules }}
busybox modprobe {{ $m }}
{{ end }}
# mount static volumes
{{ range $point := StaticVolumes .Machine }}
{{ MountVolume $.Backend $point }}
{{ end }}
exec /lib/systemd/systemd
`
const networkdTemplate = `
[Match]
Name=%[1]s
[Network]
DHCP=ipv4
# Disable link-local address to speedup boot
LinkLocalAddressing=no
IPv6AcceptRA=no
`
const commandWrapper = `#!/bin/sh
/lib/systemd/systemd-networkd-wait-online -q
if [ $? != 0 ]; then
  echo "WARNING: Network setup failed"
  echo "== Journal =="
  journalctl -a --no-pager
  echo "== networkd =="
  networkctl status
  networkctl list
  echo 1 > /run/fakemachine/result
  exit
fi
echo Running '%[2]s' using '%[1]s' backend
%[2]s
echo $? > /run/fakemachine/result
`
const serviceTemplate = `
[Unit]
Description=fakemachine runner
Conflicts=shutdown.target
Before=shutdown.target
Requires=basic.target
Wants=systemd-resolved.service binfmt-support.service systemd-networkd.service
After=basic.target systemd-resolved.service binfmt-support.service systemd-networkd.service
OnFailure=poweroff.target
[Service]
Environment=HOME=/root IN_FAKE_MACHINE=yes %[2]s
WorkingDirectory=-/scratch
ExecStart=/wrapper
ExecStopPost=/bin/sync
ExecStopPost=/bin/systemctl poweroff -ff
Type=idle
TTYPath=%[1]s
StandardInput=tty-force
StandardOutput=inherit
StandardError=inherit
KillMode=process
IgnoreSIGPIPE=no
SendSIGHUP=yes
LimitNOFILE=4096
`
func tmplMountVolume(b backend, m mountPoint) string {
	fsType, options := b.MountParameters(m)
	mntCommand := []string{"busybox", "mount", "-v"}
	mntCommand = append(mntCommand, "-t", fsType)
	if len(options) > 0 {
		mntCommand = append(mntCommand, "-o", strings.Join(options, ","))
	}
	mntCommand = append(mntCommand, m.label)
	mntCommand = append(mntCommand, m.machineDirectory)
	return strings.Join(mntCommand, " ")
}