blob: d6161bcb08bbecae79f716de1b53acc29ebe3ff2 [file] [log] [blame]
// Copyright 2017 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.
//go:build aix || openbsd
package os
// We query the working directory at init, to use it later to search for the
// executable file
// errWd will be checked later, if we need to use initWd
var initWd, errWd = Getwd()
func executable() (string, error) {
var exePath string
if len(Args) == 0 || Args[0] == "" {
return "", ErrNotExist
}
if IsPathSeparator(Args[0][0]) {
// Args[0] is an absolute path, so it is the executable.
// Note that we only need to worry about Unix paths here.
exePath = Args[0]
} else {
for i := 1; i < len(Args[0]); i++ {
if IsPathSeparator(Args[0][i]) {
// Args[0] is a relative path: prepend the
// initial working directory.
if errWd != nil {
return "", errWd
}
exePath = initWd + string(PathSeparator) + Args[0]
break
}
}
}
if exePath != "" {
if err := isExecutable(exePath); err != nil {
return "", err
}
return exePath, nil
}
// Search for executable in $PATH.
for _, dir := range splitPathList(Getenv("PATH")) {
if len(dir) == 0 {
dir = "."
}
if !IsPathSeparator(dir[0]) {
if errWd != nil {
return "", errWd
}
dir = initWd + string(PathSeparator) + dir
}
exePath = dir + string(PathSeparator) + Args[0]
switch isExecutable(exePath) {
case nil:
return exePath, nil
case ErrPermission:
return "", ErrPermission
}
}
return "", ErrNotExist
}
// isExecutable returns an error if a given file is not an executable.
func isExecutable(path string) error {
stat, err := Stat(path)
if err != nil {
return err
}
mode := stat.Mode()
if !mode.IsRegular() {
return ErrPermission
}
if (mode & 0111) == 0 {
return ErrPermission
}
return nil
}
// splitPathList splits a path list.
// This is based on genSplit from strings/strings.go
func splitPathList(pathList string) []string {
if pathList == "" {
return nil
}
n := 1
for i := 0; i < len(pathList); i++ {
if pathList[i] == PathListSeparator {
n++
}
}
start := 0
a := make([]string, n)
na := 0
for i := 0; i+1 <= len(pathList) && na+1 < n; i++ {
if pathList[i] == PathListSeparator {
a[na] = pathList[start:i]
na++
start = i + 1
}
}
a[na] = pathList[start:]
return a[:na+1]
}