aboutsummaryrefslogtreecommitdiffstats
path: root/Godeps/_workspace/src/github.com/kardianos/osext/osext_sysctl.go
blob: b66cac878c4e33d7ba2d4ceaea34b611c15220a6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build darwin freebsd

package osext

import (
    "os"
    "path/filepath"
    "runtime"
    "syscall"
    "unsafe"
)

var initCwd, initCwdErr = os.Getwd()

func executable() (string, error) {
    var mib [4]int32
    switch runtime.GOOS {
    case "freebsd":
        mib = [4]int32{1 /* CTL_KERN */, 14 /* KERN_PROC */, 12 /* KERN_PROC_PATHNAME */, -1}
    case "darwin":
        mib = [4]int32{1 /* CTL_KERN */, 38 /* KERN_PROCARGS */, int32(os.Getpid()), -1}
    }

    n := uintptr(0)
    // Get length.
    _, _, errNum := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, 0, uintptr(unsafe.Pointer(&n)), 0, 0)
    if errNum != 0 {
        return "", errNum
    }
    if n == 0 { // This shouldn't happen.
        return "", nil
    }
    buf := make([]byte, n)
    _, _, errNum = syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&n)), 0, 0)
    if errNum != 0 {
        return "", errNum
    }
    if n == 0 { // This shouldn't happen.
        return "", nil
    }
    for i, v := range buf {
        if v == 0 {
            buf = buf[:i]
            break
        }
    }
    var err error
    execPath := string(buf)
    // execPath will not be empty due to above checks.
    // Try to get the absolute path if the execPath is not rooted.
    if execPath[0] != '/' {
        execPath, err = getAbs(execPath)
        if err != nil {
            return execPath, err
        }
    }
    // For darwin KERN_PROCARGS may return the path to a symlink rather than the
    // actual executable.
    if runtime.GOOS == "darwin" {
        if execPath, err = filepath.EvalSymlinks(execPath); err != nil {
            return execPath, err
        }
    }
    return execPath, nil
}

func getAbs(execPath string) (string, error) {
    if initCwdErr != nil {
        return execPath, initCwdErr
    }
    // The execPath may begin with a "../" or a "./" so clean it first.
    // Join the two paths, trailing and starting slashes undetermined, so use
    // the generic Join function.
    return filepath.Join(initCwd, filepath.Clean(execPath)), nil
}