@@ -8,29 +8,47 @@ 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- 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 )
2340 }
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 ()
2549 if err != nil {
2650 return "" , err
2751 }
28- if selfSt .Mode ()& fs .ModeSymlink != 0 {
29- self , err = os .Readlink (self )
30- if err != nil {
31- return "" , err
32- }
33- }
3452
3553 ostype := limayaml .NewOS ("linux" )
3654 arch := limayaml .NewArch (runtime .GOARCH )
@@ -80,7 +98,7 @@ func Dir() (string, error) {
8098 ostype , arch , self , gaCandidates )
8199}
82100
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.
84102func GuestAgentBinary (ostype limayaml.OS , arch limayaml.Arch ) (string , error ) {
85103 if ostype == "" {
86104 return "" , errors .New ("os must be set" )
0 commit comments