Skip to content

Commit 4fad10d

Browse files
committed
Locate the limactl executable via os.Args[0] instead of os.Executable()
We need the symlink directory to find the the ../share/lima directory relative to it. os.Executable() uses /proc/self/exe on Linux and returns the symlink target, which will break things with a Homebrew installation. This commit also removes the dead code that pretends to resolve any symlinks. It never worked because it called os.Stat() instead of os.Lstat(). If it had worked, then code would have been broken on macOS too. Signed-off-by: Jan Dubois <jan.dubois@suse.com>
1 parent ca17b25 commit 4fad10d

File tree

1 file changed

+21
-10
lines changed

1 file changed

+21
-10
lines changed

pkg/usrlocalsharelima/usrlocalsharelima.go

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,29 +8,40 @@ import (
88
"fmt"
99
"io/fs"
1010
"os"
11+
"os/exec"
1112
"path/filepath"
1213
"runtime"
14+
"sync"
1315

1416
"github.com/lima-vm/lima/pkg/debugutil"
1517
"github.com/lima-vm/lima/pkg/limayaml"
1618
"github.com/sirupsen/logrus"
1719
)
1820

19-
func Dir() (string, error) {
20-
self, err := os.Executable()
21+
// executableViaArgs0 returns the absolute path to the executable used to start this process.
22+
// It will also append the file extension on Windows, if necessary.
23+
// This function is different from os.Executable(), which will use /proc/self/exe on Linux
24+
// and therefore will resolve any symlink used to locate the executable. This function will
25+
// return the symlink instead because we want to locate ../share/lima relative to the location
26+
// of the symlink, and not the actual executable. This is important when using Homebrew.
27+
var executableViaArgs0 = sync.OnceValues(func() (string, error) {
28+
executable, err := exec.LookPath(os.Args[0])
2129
if err != nil {
2230
return "", err
2331
}
24-
selfSt, err := os.Stat(self)
32+
// LookPath() will add the `.exe` file extension on Windows, but will not return an
33+
// absolute path if the argument contained any of `:/\` (or just `/` on Unix).
34+
return filepath.Abs(executable)
35+
})
36+
37+
// Dir returns the location of the <PREFIX>/lima/share directory, relative to the location
38+
// of the current executable. It checks for multiple possible filesystem layouts and returns
39+
// the first candidate that contains the native guest agent binary.
40+
func Dir() (string, error) {
41+
self, err := executableViaArgs0()
2542
if err != nil {
2643
return "", err
2744
}
28-
if selfSt.Mode()&fs.ModeSymlink != 0 {
29-
self, err = os.Readlink(self)
30-
if err != nil {
31-
return "", err
32-
}
33-
}
3445

3546
ostype := limayaml.NewOS("linux")
3647
arch := limayaml.NewArch(runtime.GOARCH)
@@ -80,7 +91,7 @@ func Dir() (string, error) {
8091
ostype, arch, self, gaCandidates)
8192
}
8293

83-
// GuestAgentBinary returns the guest agent binary, possibly with ".gz" suffix.
94+
// GuestAgentBinary returns the absolute path of the guest agent binary, possibly with ".gz" suffix.
8495
func GuestAgentBinary(ostype limayaml.OS, arch limayaml.Arch) (string, error) {
8596
if ostype == "" {
8697
return "", errors.New("os must be set")

0 commit comments

Comments
 (0)