github.com/RuishanTech/selfupdate@v1.0.0/internal/osext/osext_sysctl.go (about) 1 // Copyright 2012 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build darwin freebsd 6 7 package osext 8 9 import ( 10 "os" 11 "path/filepath" 12 "runtime" 13 "syscall" 14 "unsafe" 15 ) 16 17 var initCwd, initCwdErr = os.Getwd() 18 19 func executable() (string, error) { 20 var mib [4]int32 21 switch runtime.GOOS { 22 case "freebsd": 23 mib = [4]int32{1 /* CTL_KERN */, 14 /* KERN_PROC */, 12 /* KERN_PROC_PATHNAME */, -1} 24 case "darwin": 25 mib = [4]int32{1 /* CTL_KERN */, 38 /* KERN_PROCARGS */, int32(os.Getpid()), -1} 26 } 27 28 n := uintptr(0) 29 // Get length. 30 _, _, errNum := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, 0, uintptr(unsafe.Pointer(&n)), 0, 0) 31 if errNum != 0 { 32 return "", errNum 33 } 34 if n == 0 { // This shouldn't happen. 35 return "", nil 36 } 37 buf := make([]byte, n) 38 _, _, errNum = syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&n)), 0, 0) 39 if errNum != 0 { 40 return "", errNum 41 } 42 if n == 0 { // This shouldn't happen. 43 return "", nil 44 } 45 for i, v := range buf { 46 if v == 0 { 47 buf = buf[:i] 48 break 49 } 50 } 51 var err error 52 execPath := string(buf) 53 // execPath will not be empty due to above checks. 54 // Try to get the absolute path if the execPath is not rooted. 55 if execPath[0] != '/' { 56 execPath, err = getAbs(execPath) 57 if err != nil { 58 return execPath, err 59 } 60 } 61 // For darwin KERN_PROCARGS may return the path to a symlink rather than the 62 // actual executable. 63 if runtime.GOOS == "darwin" { 64 if execPath, err = filepath.EvalSymlinks(execPath); err != nil { 65 return execPath, err 66 } 67 } 68 return execPath, nil 69 } 70 71 func getAbs(execPath string) (string, error) { 72 if initCwdErr != nil { 73 return execPath, initCwdErr 74 } 75 // The execPath may begin with a "../" or a "./" so clean it first. 76 // Join the two paths, trailing and starting slashes undetermined, so use 77 // the generic Join function. 78 return filepath.Join(initCwd, filepath.Clean(execPath)), nil 79 }