From cd82c9a2eff75c504114dd14495419f00250061f Mon Sep 17 00:00:00 2001 From: Akihiro Suda Date: Wed, 19 May 2021 18:02:47 +0900 Subject: [PATCH] Support non-macOS hosts Tested on Linux. Probably it should work on NetBSD with nvmm as well. Signed-off-by: Akihiro Suda --- .github/workflows/test.yml | 22 ++----- Makefile | 6 +- README.md | 14 ++-- go.mod | 2 +- go.sum | 20 +++++- pkg/cidata/cidata.go | 76 ++++++++++++---------- pkg/iso9660util/iso9660util.go | 63 ++++++++++++++++-- pkg/iso9660util/iso9660util_darwin.go | 58 ----------------- pkg/iso9660util/iso9660util_unsupported.go | 13 ---- pkg/limayaml/validate.go | 11 ++++ pkg/qemu/qemu.go | 40 +++++++++++- pkg/start/start.go | 8 +-- 12 files changed, 188 insertions(+), 145 deletions(-) delete mode 100644 pkg/iso9660util/iso9660util_darwin.go delete mode 100644 pkg/iso9660util/iso9660util_unsupported.go diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 30c138f6293..97d0ebecbf4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,7 +25,7 @@ jobs: ./hack/validate-dco.sh golangci-lint: - runs-on: macos-10.15 + runs-on: ubuntu-20.04 timeout-minutes: 20 steps: - uses: actions/checkout@v2 @@ -37,27 +37,13 @@ jobs: version: v1.35 args: --verbose - unit: - name: Unit tests + tests: + name: Tests runs-on: ${{ matrix.os }} strategy: matrix: os: [macos-10.15, ubuntu-20.04] timeout-minutes: 20 - steps: - - uses: actions/setup-go@v2 - with: - go-version: 1.16.x - - uses: actions/checkout@v2 - with: - fetch-depth: 25 - - name: Unit tests - run: go test -v ./... - - integration: - name: Integration (WIP) - runs-on: macos-10.15 - timeout-minutes: 20 steps: - uses: actions/setup-go@v2 with: @@ -67,6 +53,8 @@ jobs: fetch-depth: 25 - name: Make run: make + - name: Unit tests + run: go test -v ./... artifacts: name: Artifacts diff --git a/Makefile b/Makefile index 735198f29d2..bc70329b4be 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,7 @@ _output/share/lima/lima-guestagent.Linux-aarch64: .PHONY: install install: cp -av _output/* /usr/local/ - if [ ! -e /usr/local/bin/nerdctl ]; then ln -sf nerdctl.lima /usr/local/bin/nerdctl; fi + if [[ $(shell uname -s ) != Linux && ! -e /usr/local/bin/nerdctl ]]; then ln -sf nerdctl.lima /usr/local/bin/nerdctl; fi .PHONY: clean clean: @@ -60,3 +60,7 @@ artifacts: $(TAR) -C _output/ -czvf _artifacts/lima-$(VERSION_TRIMMED)-Darwin-x86_64.tar.gz ./ GOOS=darwin GOARCH=arm64 make clean binaries $(TAR) -C _output -czvf _artifacts/lima-$(VERSION_TRIMMED)-Darwin-arm64.tar.gz ./ + GOOS=linux GOARCH=amd64 make clean binaries + $(TAR) -C _output/ -czvf _artifacts/lima-$(VERSION_TRIMMED)-Linux-x86_64.tar.gz ./ + GOOS=linux GOARCH=arm64 make clean binaries + $(TAR) -C _output/ -czvf _artifacts/lima-$(VERSION_TRIMMED)-Linux-aarch64.tar.gz ./ diff --git a/README.md b/README.md index 3e9bf0a35b1..de1fa0b97dd 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,12 @@ -# Lima: Linux-on-Mac ("macOS subsystem for Linux", "containerd for Mac") +# Lima: Linux virtual machines (on macOS, in most cases) -Lima launches Linux virtual machines on macOS, with automatic file sharing, port forwarding, -and [containerd](https://containerd.io). +Lima launches Linux virtual machines with automatic file sharing, port forwarding, and [containerd](https://containerd.io). Lima can be considered as a some sort of unofficial "macOS subsystem for Linux", or "containerd for Mac". +Lima is expected to be used on macOS hosts, but can be used on Linux hosts as well. +It may work on NetBSD and Windows hosts as well. + ✅ Automatic file sharing ✅ Automatic port forwarding @@ -19,9 +21,9 @@ Lima can be considered as a some sort of unofficial "macOS subsystem for Linux", ✅ Intel on ARM (untested) -✅ Ubuntu +✅ Ubuntu guest -✅ Fedora +✅ Fedora guest Related project: [sshocker (ssh with file sharing and port forwarding)](https://github.com/AkihiroSuda/sshocker) @@ -175,7 +177,7 @@ The current default spec: - Performance optimization - Homebrew - More guest distros -- Linux on Windows/Linux/BSD +- Windows hosts - GUI with system tray icon (Qt or Electron, for portability) - VirtFS to replace the current reverse sshfs (work has to be done on QEMU repo) - [vsock](https://github.com/apple/darwin-xnu/blob/xnu-7195.81.3/bsd/man/man4/vsock.4) to replace SSH (work has to be done on QEMU repo) diff --git a/go.mod b/go.mod index 02f5af30d0b..213a152a82a 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/AkihiroSuda/sshocker v0.1.1-0.20210510144941-56aa3c7472b0 github.com/alessio/shellescape v1.4.1 github.com/containerd/containerd v1.5.0 - github.com/cyphar/filepath-securejoin v0.2.2 + github.com/diskfs/go-diskfs v1.1.2-0.20210512141858-8a6b8b88d14a github.com/docker/go-units v0.4.0 github.com/gorilla/mux v1.8.0 github.com/hashicorp/go-multierror v1.1.1 diff --git a/go.sum b/go.sum index 758d5eba79f..4b0f50c5931 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +4d63.com/gochecknoinits v0.0.0-20200108094044-eb73b47b9fc4/go.mod h1:4o1i5aXtIF5tJFt3UD1knCVmWOXg7fLYdHVu6jeNcnM= bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= @@ -232,7 +233,6 @@ github.com/cybozu-go/log v1.6.0/go.mod h1:2iAEvn2cL5dy/1uP5Jfb0Ao9+DUnDr//V0Bk3W github.com/cybozu-go/netutil v1.2.0/go.mod h1:Wx92iF1dPrtuSzLUMEidtrKTFiDWpLcsYvbQ1lHSmxY= github.com/cybozu-go/usocksd v1.2.0/go.mod h1:nsCvwPP085NIiqt9bS8yW1Sxy3mKwl/eov9Tdu2eKLk= github.com/cybozu-go/well v1.10.0/go.mod h1:OQdjEXQpbG+kSgEF3t3IYUx5y1R4qeBGvzL4gmi61qE= -github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg= github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ= github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s= @@ -246,6 +246,8 @@ github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8l github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/diskfs/go-diskfs v1.1.2-0.20210512141858-8a6b8b88d14a h1:k98u2h2HkKueiYZrPZvfEYxThaCBujQKgKVUO8I5X44= +github.com/diskfs/go-diskfs v1.1.2-0.20210512141858-8a6b8b88d14a/go.mod h1:ZTeTbzixuyfnZW5y5qKMtjV2o+GLLHo1KfMhotJI4Rk= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= @@ -393,6 +395,7 @@ github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsC github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gordonklaus/ineffassign v0.0.0-20190601041439-ed7b1b5ee0f8/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= @@ -426,6 +429,7 @@ github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= +github.com/jgautheron/goconst v0.0.0-20170703170152-9740945f5dcb/go.mod h1:82TxjOpWQiPmywlbIaB2ZkqJoSYJdLGPgAJDvM3PbKc= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= @@ -473,6 +477,7 @@ github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mibk/dupl v1.0.0/go.mod h1:pCr4pNxxIbFGvtyCOi0c7LVjmV6duhKWV+ex5vh38ME= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= @@ -539,6 +544,7 @@ github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtP github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pierrec/lz4 v2.3.0+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -546,6 +552,7 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.12.0 h1:/f3b24xrDhkhddlaobPe2JgBqfdt+gC/NYl0QY9IOuI= github.com/pkg/sftp v1.12.0/go.mod h1:fUqqXB5vEgVCZ131L+9say31RAri6aF6KDViawhxKK8= +github.com/pkg/xattr v0.4.1/go.mod h1:W2cGD0TBEus7MkUgv0tNZ9JutLtVO3cXu+IBRuHqnFs= github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -630,14 +637,17 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stripe/safesql v0.2.0/go.mod h1:q7b2n0JmzM1mVGfcYpanfVb2j23cXZeWFxcILPn3JV4= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tsenart/deadcode v0.0.0-20160724212837-210d2dc333e9/go.mod h1:q+QjxYvZ+fpjMXqs+XEriussHjSYqeXVnAdSV1tkMYk= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= @@ -807,6 +817,7 @@ golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181021155630-eda9bb28ed51/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -826,6 +837,7 @@ golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -853,6 +865,7 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -920,6 +933,7 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200102200121-6de373a2766c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -1055,6 +1069,8 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/djherbis/times.v1 v1.2.0 h1:UCvDKl1L/fmBygl2Y7hubXCnY7t4Yj46ZrBFNUipFbM= +gopkg.in/djherbis/times.v1 v1.2.0/go.mod h1:AQlg6unIsrsCEdQYhTzERy542dz6SFdQFZFv6mUY0P8= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= @@ -1126,6 +1142,8 @@ k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAG k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= +mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/pkg/cidata/cidata.go b/pkg/cidata/cidata.go index dfac32e51b4..49d894e7b0f 100644 --- a/pkg/cidata/cidata.go +++ b/pkg/cidata/cidata.go @@ -1,6 +1,8 @@ package cidata import ( + "bytes" + "io" "io/fs" "os" "os/user" @@ -14,17 +16,17 @@ import ( "github.com/pkg/errors" ) -func GenerateISO9660(name string, y *limayaml.LimaYAML) (*iso9660util.ISO9660, error) { +func GenerateISO9660(isoPath, name string, y *limayaml.LimaYAML) error { if err := limayaml.ValidateRaw(*y); err != nil { - return nil, err + return err } u, err := user.Current() if err != nil { - return nil, err + return err } uid, err := strconv.Atoi(u.Uid) if err != nil { - return nil, err + return err } args := TemplateArgs{ Name: name, @@ -38,60 +40,64 @@ func GenerateISO9660(name string, y *limayaml.LimaYAML) (*iso9660util.ISO9660, e for _, f := range y.Mounts { expanded, err := localpathutil.Expand(f.Location) if err != nil { - return nil, err + return err } args.Mounts = append(args.Mounts, expanded) } if err := ValidateTemplateArgs(args); err != nil { - return nil, err + return err } - userData, err := GenerateUserData(args) - if err != nil { - return nil, err - } + var layout []iso9660util.Entry - metaData, err := GenerateMetaData(args) - if err != nil { - return nil, err + if userData, err := GenerateUserData(args); err != nil { + return err + } else { + layout = append(layout, iso9660util.Entry{ + Path: "user-data", + Reader: bytes.NewReader(userData), + }) } - guestAgentBinaryPath, err := GuestAgentBinaryPath(y.Arch) - if err != nil { - return nil, err + if metaData, err := GenerateMetaData(args); err != nil { + return err + } else { + layout = append(layout, iso9660util.Entry{ + Path: "meta-data", + Reader: bytes.NewReader(metaData), + }) } - iso9660 := &iso9660util.ISO9660{ - Name: "cidata", - FilesFromContent: map[string]string{ - "user-data": string(userData), - "meta-data": string(metaData), - }, - FilesFromHostFilePath: map[string]string{ - "lima-guestagent": guestAgentBinaryPath, - }, + if guestAgentBinary, err := GuestAgentBinary(y.Arch); err != nil { + return err + } else { + defer guestAgentBinary.Close() + layout = append(layout, iso9660util.Entry{ + Path: "lima-guestagent", + Reader: guestAgentBinary, + }) } - return iso9660, nil + return iso9660util.Write(isoPath, "cidata", layout) } -func GuestAgentBinaryPath(arch string) (string, error) { +func GuestAgentBinary(arch string) (io.ReadCloser, error) { if arch == "" { - return "", errors.New("arch must be set") + return nil, errors.New("arch must be set") } self, err := os.Executable() if err != nil { - return "", err + return nil, err } selfSt, err := os.Stat(self) if err != nil { - return "", err + return nil, err } if selfSt.Mode()&fs.ModeSymlink != 0 { self, err = os.Readlink(self) if err != nil { - return "", err + return nil, err } } @@ -109,14 +115,14 @@ func GuestAgentBinaryPath(arch string) (string, error) { filepath.Join(selfDirDir, "share/lima/lima-guestagent.Linux-"+arch), // TODO: support custom path } - for _, f := range candidates { - if _, err := os.Stat(f); err == nil { + for _, candidate := range candidates { + if f, err := os.Open(candidate); err == nil { return f, nil } else if !errors.Is(err, os.ErrNotExist) { - return "", err + return nil, err } } - return "", errors.Errorf("failed to find \"lima-guestagent.Linux-%s\" binary for %q, attempted %v", + return nil, errors.Errorf("failed to find \"lima-guestagent.Linux-%s\" binary for %q, attempted %v", arch, self, candidates) } diff --git a/pkg/iso9660util/iso9660util.go b/pkg/iso9660util/iso9660util.go index a5497f5066a..021e2991cc5 100644 --- a/pkg/iso9660util/iso9660util.go +++ b/pkg/iso9660util/iso9660util.go @@ -1,7 +1,62 @@ package iso9660util -type ISO9660 struct { - Name string // "cidata" - FilesFromContent map[string]string // use string, not []byte, for debug printability - FilesFromHostFilePath map[string]string +import ( + "io" + "os" + "strings" + + "github.com/diskfs/go-diskfs/filesystem" + "github.com/diskfs/go-diskfs/filesystem/iso9660" + "github.com/pkg/errors" +) + +type Entry struct { + Path string + Reader io.Reader +} + +func Write(isoPath, label string, layout []Entry) error { + if err := os.RemoveAll(isoPath); err != nil { + return err + } + + isoFile, err := os.Create(isoPath) + if err != nil { + return err + } + + defer isoFile.Close() + + fs, err := iso9660.Create(isoFile, 0, 0, 0, "") + if err != nil { + return err + } + + for _, f := range layout { + if _, err := WriteFile(fs, f.Path, f.Reader); err != nil { + return err + } + } + + finalizeOptions := iso9660.FinalizeOptions{ + RockRidge: true, + VolumeIdentifier: label, + } + if err := fs.Finalize(finalizeOptions); err != nil { + return err + } + + return isoFile.Close() +} + +func WriteFile(fs filesystem.FileSystem, path string, r io.Reader) (int64, error) { + if strings.Contains(path, "/") || strings.Contains(path, "\\") { + return 0, errors.Errorf("directory not supported yet: %q", path) + } + f, err := fs.OpenFile(path, os.O_CREATE|os.O_RDWR) + if err != nil { + return 0, err + } + defer f.Close() + return io.Copy(f, r) } diff --git a/pkg/iso9660util/iso9660util_darwin.go b/pkg/iso9660util/iso9660util_darwin.go deleted file mode 100644 index a8fd7e0dad3..00000000000 --- a/pkg/iso9660util/iso9660util_darwin.go +++ /dev/null @@ -1,58 +0,0 @@ -package iso9660util - -import ( - "io/ioutil" - "os" - "os/exec" - "strings" - - securejoin "github.com/cyphar/filepath-securejoin" - "github.com/pkg/errors" -) - -func Write(isoFilePath string, iso *ISO9660) error { - td, err := ioutil.TempDir("", "lima-iso9660util") - if err != nil { - return err - } - defer os.RemoveAll(td) - for k, v := range iso.FilesFromContent { - if strings.ToLower(k) != k { - return errors.Errorf("file name must be lower characters, got %q", k) - } - f, err := securejoin.SecureJoin(td, k) - if err != nil { - return err - } - if err := os.WriteFile(f, []byte(v), 0644); err != nil { - return err - } - } - - for k, v := range iso.FilesFromHostFilePath { - if strings.ToLower(k) != k { - return errors.Errorf("file name must be lower characters, got %q", k) - } - f, err := securejoin.SecureJoin(td, k) - if err != nil { - return err - } - cmd := exec.Command("cp", "-a", v, f) - if out, err := cmd.CombinedOutput(); err != nil { - return errors.Wrapf(err, "failed to run %v: %q", cmd.Args, string(out)) - } - } - - if err := os.RemoveAll(isoFilePath); err != nil { - return err - } - - cmd := exec.Command("hdiutil", "makehybrid", "-iso", "-joliet", - "-o", isoFilePath, - "-default-volume-name", iso.Name, - td) - if out, err := cmd.CombinedOutput(); err != nil { - return errors.Wrapf(err, "failed to run %v: %q", cmd.Args, string(out)) - } - return nil -} diff --git a/pkg/iso9660util/iso9660util_unsupported.go b/pkg/iso9660util/iso9660util_unsupported.go deleted file mode 100644 index 37b40dad22f..00000000000 --- a/pkg/iso9660util/iso9660util_unsupported.go +++ /dev/null @@ -1,13 +0,0 @@ -//+build !darwin - -package iso9660util - -import ( - "runtime" - - "github.com/pkg/errors" -) - -func Write(isoFilePath string, iso *ISO9660) error { - return errors.Errorf("unsupported GOOS: %q", runtime.GOOS) -} diff --git a/pkg/limayaml/validate.go b/pkg/limayaml/validate.go index 506f7ecafaa..8e6879afc8a 100644 --- a/pkg/limayaml/validate.go +++ b/pkg/limayaml/validate.go @@ -1,7 +1,9 @@ package limayaml import ( + "fmt" "os" + "os/user" "path/filepath" "strings" @@ -52,6 +54,13 @@ func ValidateRaw(y LimaYAML) error { return errors.Wrapf(err, "field `memory` has an invalid value") } + u, err := user.Current() + if err != nil { + return errors.Wrap(err, "internal error (not an error of YAML)") + } + // reservedHome is the home directory defined in "cidata.iso:/user-data" + reservedHome := fmt.Sprintf("/home/%s.linux", u.Username) + for i, f := range y.Mounts { if !filepath.IsAbs(f.Location) && !strings.HasPrefix(f.Location, "~") { return errors.Errorf("field `mounts[%d].location` must be an absolute path, got %q", @@ -65,6 +74,8 @@ func ValidateRaw(y LimaYAML) error { switch loc { case "/", "/bin", "/dev", "/etc", "/home", "/opt", "/sbin", "/tmp", "/usr", "/var": return errors.Errorf("field `mounts[%d].location` must not be a system path such as /etc or /usr", i) + case reservedHome: + return errors.Errorf("field `mounts[%d].location` is internally reserved", i) } st, err := os.Stat(loc) diff --git a/pkg/qemu/qemu.go b/pkg/qemu/qemu.go index aa7135d2df7..df302f9bb28 100644 --- a/pkg/qemu/qemu.go +++ b/pkg/qemu/qemu.go @@ -119,9 +119,8 @@ func Cmdline(cfg Config) (string, []string, error) { // Firmware if !y.Firmware.LegacyBIOS { - firmware := filepath.Join(exe, - fmt.Sprintf("../../share/qemu/edk2-%s-code.fd", y.Arch)) - if _, err := os.Stat(firmware); err != nil { + firmware, err := getFirmware(exe, y.Arch) + if err != nil { return "", nil, err } args = append(args, "-drive", fmt.Sprintf("if=pflash,format=raw,readonly,file=%s", firmware)) @@ -179,7 +178,42 @@ func getAccel(arch limayaml.Arch) string { return "hvf" case "linux": return "kvm" + case "netbsd": + return "nvmm" // untested + case "windows": + return "whpx" // untested } } return "tcg" } + +func getFirmware(qemuExe string, arch limayaml.Arch) (string, error) { + binDir := filepath.Dir(qemuExe) // "/usr/local/bin" + localDir := filepath.Dir(binDir) // "/usr/local" + + candidates := []string{ + filepath.Join(localDir, fmt.Sprintf("share/qemu/edk2-%s-code.fd", arch)), // macOS (homebrew) + } + + switch arch { + case limayaml.X8664: + // Debian package "ovmf" + candidates = append(candidates, "/usr/share/OVMF/OVMF_CODE.fd") + case limayaml.AARCH64: + // Debian package "qemu-efi-aarch64" + candidates = append(candidates, "/usr/share/qemu-efi-aarch64/QEMU_EFI.fd") + } + + logrus.Debugf("firmware candidates = %v", candidates) + + for _, f := range candidates { + if _, err := os.Stat(f); err == nil { + return f, nil + } + } + + if arch == limayaml.X8664 { + return "", errors.Errorf("could not find firmware for %q (hint: try setting `firmware.legacyBIOS` to `true`)", qemuExe) + } + return "", errors.Errorf("could not find firmware for %q", qemuExe) +} diff --git a/pkg/start/start.go b/pkg/start/start.go index baa65030aed..396082a0c88 100644 --- a/pkg/start/start.go +++ b/pkg/start/start.go @@ -9,7 +9,6 @@ import ( "github.com/AkihiroSuda/lima/pkg/cidata" "github.com/AkihiroSuda/lima/pkg/hostagent" - "github.com/AkihiroSuda/lima/pkg/iso9660util" "github.com/AkihiroSuda/lima/pkg/limayaml" "github.com/AkihiroSuda/lima/pkg/qemu" "github.com/pkg/errors" @@ -17,11 +16,8 @@ import ( ) func Start(ctx context.Context, instName, instDir string, y *limayaml.LimaYAML) error { - cidataISO, err := cidata.GenerateISO9660(instName, y) - if err != nil { - return err - } - if err := iso9660util.Write(filepath.Join(instDir, "cidata.iso"), cidataISO); err != nil { + cidataISOPath := filepath.Join(instDir, "cidata.iso") + if err := cidata.GenerateISO9660(cidataISOPath, instName, y); err != nil { return err } qCfg := qemu.Config{