osext_sysctl.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  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 !go1.8,darwin !go1.8,freebsd openbsd
  5. package osext
  6. import (
  7. "os"
  8. "os/exec"
  9. "path/filepath"
  10. "runtime"
  11. "syscall"
  12. "unsafe"
  13. )
  14. var initCwd, initCwdErr = os.Getwd()
  15. func executable() (string, error) {
  16. var mib [4]int32
  17. switch runtime.GOOS {
  18. case "freebsd":
  19. mib = [4]int32{1 /* CTL_KERN */, 14 /* KERN_PROC */, 12 /* KERN_PROC_PATHNAME */, -1}
  20. case "darwin":
  21. mib = [4]int32{1 /* CTL_KERN */, 38 /* KERN_PROCARGS */, int32(os.Getpid()), -1}
  22. case "openbsd":
  23. mib = [4]int32{1 /* CTL_KERN */, 55 /* KERN_PROC_ARGS */, int32(os.Getpid()), 1 /* KERN_PROC_ARGV */}
  24. }
  25. n := uintptr(0)
  26. // Get length.
  27. _, _, errNum := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, 0, uintptr(unsafe.Pointer(&n)), 0, 0)
  28. if errNum != 0 {
  29. return "", errNum
  30. }
  31. if n == 0 { // This shouldn't happen.
  32. return "", nil
  33. }
  34. buf := make([]byte, n)
  35. _, _, errNum = syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&n)), 0, 0)
  36. if errNum != 0 {
  37. return "", errNum
  38. }
  39. if n == 0 { // This shouldn't happen.
  40. return "", nil
  41. }
  42. var execPath string
  43. switch runtime.GOOS {
  44. case "openbsd":
  45. // buf now contains **argv, with pointers to each of the C-style
  46. // NULL terminated arguments.
  47. var args []string
  48. argv := uintptr(unsafe.Pointer(&buf[0]))
  49. Loop:
  50. for {
  51. argp := *(**[1 << 20]byte)(unsafe.Pointer(argv))
  52. if argp == nil {
  53. break
  54. }
  55. for i := 0; uintptr(i) < n; i++ {
  56. // we don't want the full arguments list
  57. if string(argp[i]) == " " {
  58. break Loop
  59. }
  60. if argp[i] != 0 {
  61. continue
  62. }
  63. args = append(args, string(argp[:i]))
  64. n -= uintptr(i)
  65. break
  66. }
  67. if n < unsafe.Sizeof(argv) {
  68. break
  69. }
  70. argv += unsafe.Sizeof(argv)
  71. n -= unsafe.Sizeof(argv)
  72. }
  73. execPath = args[0]
  74. // There is no canonical way to get an executable path on
  75. // OpenBSD, so check PATH in case we are called directly
  76. if execPath[0] != '/' && execPath[0] != '.' {
  77. execIsInPath, err := exec.LookPath(execPath)
  78. if err == nil {
  79. execPath = execIsInPath
  80. }
  81. }
  82. default:
  83. for i, v := range buf {
  84. if v == 0 {
  85. buf = buf[:i]
  86. break
  87. }
  88. }
  89. execPath = string(buf)
  90. }
  91. var err error
  92. // execPath will not be empty due to above checks.
  93. // Try to get the absolute path if the execPath is not rooted.
  94. if execPath[0] != '/' {
  95. execPath, err = getAbs(execPath)
  96. if err != nil {
  97. return execPath, err
  98. }
  99. }
  100. // For darwin KERN_PROCARGS may return the path to a symlink rather than the
  101. // actual executable.
  102. if runtime.GOOS == "darwin" {
  103. if execPath, err = filepath.EvalSymlinks(execPath); err != nil {
  104. return execPath, err
  105. }
  106. }
  107. return execPath, nil
  108. }
  109. func getAbs(execPath string) (string, error) {
  110. if initCwdErr != nil {
  111. return execPath, initCwdErr
  112. }
  113. // The execPath may begin with a "../" or a "./" so clean it first.
  114. // Join the two paths, trailing and starting slashes undetermined, so use
  115. // the generic Join function.
  116. return filepath.Join(initCwd, filepath.Clean(execPath)), nil
  117. }