github.com/neugram/ng@v0.0.0-20180309130942-d472ff93d872/eval/shell/exec_bsd.go (about)

     1  // Copyright 2015 The Neugram 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
     6  
     7  package shell
     8  
     9  import (
    10  	"bytes"
    11  	"errors"
    12  	"fmt"
    13  	"os"
    14  	"path/filepath"
    15  	"runtime"
    16  	"syscall"
    17  	"unsafe"
    18  )
    19  
    20  // executable returns the path to the executable of this process.
    21  func executable() (string, error) {
    22  	pid := int32(os.Getpid())
    23  
    24  	// TODO: other BSDs have different sysctls.
    25  	const CTL_KERN = 1
    26  	var cfg [4]int32
    27  	if runtime.GOOS == "darwin" {
    28  		const KERN_PROCARGS = 38 // <sys/sysctl.h>
    29  		cfg = [4]int32{CTL_KERN, KERN_PROCARGS, pid, -1}
    30  	} else {
    31  		panic(fmt.Sprintf("executable: unsupported GOOS: %q", runtime.GOOS))
    32  	}
    33  
    34  	// Get the size of the process args, then take the first of
    35  	// the NUL-separated list.
    36  	var n uintptr
    37  	np := unsafe.Pointer(&n)
    38  	_, _, errno := syscall.Syscall6(
    39  		syscall.SYS___SYSCTL,
    40  		uintptr(unsafe.Pointer(&cfg[0])),
    41  		4, 0, uintptr(np), 0, 0,
    42  	)
    43  	if errno != 0 {
    44  		return "", errno
    45  	}
    46  	if n == 0 {
    47  		return "", errors.New("shell executable: sysctl returned zero size")
    48  	}
    49  	buf := make([]byte, n)
    50  	_, _, errno = syscall.Syscall6(
    51  		syscall.SYS___SYSCTL,
    52  		uintptr(unsafe.Pointer(&cfg[0])),
    53  		4, uintptr(unsafe.Pointer(&buf[0])), uintptr(np), 0, 0,
    54  	)
    55  	if errno != 0 {
    56  		return "", errno
    57  	}
    58  	if i := bytes.IndexByte(buf, 0); i > 0 {
    59  		buf = buf[:i]
    60  	}
    61  	path := string(buf)
    62  	if !filepath.IsAbs(path) {
    63  		path = filepath.Join(initialCwd, string(buf))
    64  	}
    65  	return path, nil
    66  }