osext_sysctl.go 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  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 startUpcwd, getwdError = 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. _, _, err := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, 0, uintptr(unsafe.Pointer(&n)), 0, 0)
  25. if err != 0 {
  26. return "", err
  27. }
  28. if n == 0 { // shouldn't happen
  29. return "", nil
  30. }
  31. buf := make([]byte, n)
  32. _, _, err = syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&n)), 0, 0)
  33. if err != 0 {
  34. return "", err
  35. }
  36. if n == 0 { // 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 strpath string
  46. if buf[0] != '/' {
  47. var e error
  48. if strpath, e = getAbs(buf); e != nil {
  49. return strpath, e
  50. }
  51. } else {
  52. strpath = string(buf)
  53. }
  54. // darwin KERN_PROCARGS may return the path to a symlink rather than the
  55. // actual executable
  56. if runtime.GOOS == "darwin" {
  57. if strpath, err := filepath.EvalSymlinks(strpath); err != nil {
  58. return strpath, err
  59. }
  60. }
  61. return strpath, nil
  62. }
  63. func getAbs(buf []byte) (string, error) {
  64. if getwdError != nil {
  65. return string(buf), getwdError
  66. } else {
  67. if buf[0] == '.' {
  68. buf = buf[1:]
  69. }
  70. if startUpcwd[len(startUpcwd)-1] != '/' && buf[0] != '/' {
  71. return startUpcwd + "/" + string(buf), nil
  72. }
  73. return startUpcwd + string(buf), nil
  74. }
  75. }