@@ -8,29 +8,47 @@ import (
8
8
"fmt"
9
9
"io/fs"
10
10
"os"
11
+ "os/exec"
11
12
"path/filepath"
12
13
"runtime"
14
+ "sync"
13
15
14
16
"github.com/lima-vm/lima/pkg/debugutil"
15
17
"github.com/lima-vm/lima/pkg/limayaml"
16
18
"github.com/sirupsen/logrus"
17
19
)
18
20
19
- func Dir () (string , error ) {
20
- self , err := os .Executable ()
21
- if err != nil {
22
- return "" , err
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
+ //
28
+ // If os.Args[0] is invalid, this function still falls back on os.Executable().
29
+ var executableViaArgs0 = sync .OnceValues (func () (string , error ) {
30
+ if os .Args [0 ] == "" {
31
+ logrus .Warn ("os.Args[0] has not been set" )
32
+ } else {
33
+ executable , err := exec .LookPath (os .Args [0 ])
34
+ if err == nil {
35
+ // LookPath() will add the `.exe` file extension on Windows, but will not return an
36
+ // absolute path if the argument contained any of `:/\` (or just `/` on Unix).
37
+ return filepath .Abs (executable )
38
+ }
39
+ logrus .Warnf ("os.Args[0] is invalid: %v" , err )
23
40
}
24
- selfSt , err := os .Stat (self )
41
+ return os .Executable ()
42
+ })
43
+
44
+ // Dir returns the location of the <PREFIX>/lima/share directory, relative to the location
45
+ // of the current executable. It checks for multiple possible filesystem layouts and returns
46
+ // the first candidate that contains the native guest agent binary.
47
+ func Dir () (string , error ) {
48
+ self , err := executableViaArgs0 ()
25
49
if err != nil {
26
50
return "" , err
27
51
}
28
- if selfSt .Mode ()& fs .ModeSymlink != 0 {
29
- self , err = os .Readlink (self )
30
- if err != nil {
31
- return "" , err
32
- }
33
- }
34
52
35
53
ostype := limayaml .NewOS ("linux" )
36
54
arch := limayaml .NewArch (runtime .GOARCH )
@@ -80,7 +98,7 @@ func Dir() (string, error) {
80
98
ostype , arch , self , gaCandidates )
81
99
}
82
100
83
- // GuestAgentBinary returns the guest agent binary, possibly with ".gz" suffix.
101
+ // GuestAgentBinary returns the absolute path of the guest agent binary, possibly with ".gz" suffix.
84
102
func GuestAgentBinary (ostype limayaml.OS , arch limayaml.Arch ) (string , error ) {
85
103
if ostype == "" {
86
104
return "" , errors .New ("os must be set" )
0 commit comments