osext_sysctl.go 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  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. // +build darwin freebsd
  5. package osext
  6. import (
  7. "os"
  8. "path/filepath"
  9. "runtime"
  10. "syscall"
  11. "unsafe"
  12. )
  13. var initCwd, initCwdErr = os.Getwd()
  14. func executable() (string, error) {
  15. var mib [4]int32
  16. switch runtime.GOOS {
  17. case "freebsd":
  18. mib = [4]int32{1 /* CTL_KERN */, 14 /* KERN_PROC */, 12 /* KERN_PROC_PATHNAME */, -1}
  19. case "darwin":
  20. mib = [4]int32{1 /* CTL_KERN */, 38 /* KERN_PROCARGS */, int32(os.Getpid()), -1}
  21. }
  22. n := uintptr(0)
  23. // Get length.
  24. _, _, errNum := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, 0, uintptr(unsafe.Pointer(&n)), 0, 0)
  25. if errNum != 0 {
  26. return "", errNum
  27. }
  28. if n == 0 { // This shouldn't happen.
  29. return "", nil
  30. }
  31. buf := make([]byte, n)
  32. _, _, errNum = syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&n)), 0, 0)
  33. if errNum != 0 {
  34. return "", errNum
  35. }
  36. if n == 0 { // This shouldn't happen.
  37. return "", nil
  38. }
  39. for i, v := range buf {
  40. if v == 0 {
  41. buf = buf[:i]
  42. break
  43. }
  44. }
  45. var err error
  46. execPath := string(buf)
  47. // execPath will not be empty due to above checks.
  48. // Try to get the absolute path if the execPath is not rooted.
  49. if execPath[0] != '/' {
  50. execPath, err = getAbs(execPath)
  51. if err != nil {
  52. return execPath, err
  53. }
  54. }
  55. // For darwin KERN_PROCARGS may return the path to a symlink rather than the
  56. // actual executable.
  57. if runtime.GOOS == "darwin" {
  58. if execPath, err = filepath.EvalSymlinks(execPath); err != nil {
  59. return execPath, err
  60. }
  61. }
  62. return execPath, nil
  63. }
  64. func getAbs(execPath string) (string, error) {
  65. if initCwdErr != nil {
  66. return execPath, initCwdErr
  67. }
  68. // The execPath may begin with a "../" or a "./" so clean it first.
  69. // Join the two paths, trailing and starting slashes undetermined, so use
  70. // the generic Join function.
  71. return filepath.Join(initCwd, filepath.Clean(execPath)), nil
  72. }