1 // Copyright 2017 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.
5 //go:build aix || openbsd
9 // We query the working directory at init, to use it later to search for the
11 // errWd will be checked later, if we need to use initWd
12 var initWd, errWd = Getwd()
14 func executable() (string, error) {
16 if len(Args) == 0 || Args[0] == "" {
17 return "", ErrNotExist
19 if IsPathSeparator(Args[0][0]) {
20 // Args[0] is an absolute path, so it is the executable.
21 // Note that we only need to worry about Unix paths here.
24 for i := 1; i < len(Args[0]); i++ {
25 if IsPathSeparator(Args[0][i]) {
26 // Args[0] is a relative path: prepend the
27 // initial working directory.
31 exePath = initWd + string(PathSeparator) + Args[0]
37 if err := isExecutable(exePath); err != nil {
42 // Search for executable in $PATH.
43 for _, dir := range splitPathList(Getenv("PATH")) {
47 if !IsPathSeparator(dir[0]) {
51 dir = initWd + string(PathSeparator) + dir
53 exePath = dir + string(PathSeparator) + Args[0]
54 switch isExecutable(exePath) {
58 return "", ErrPermission
61 return "", ErrNotExist
64 // isExecutable returns an error if a given file is not an executable.
65 func isExecutable(path string) error {
66 stat, err := Stat(path)
71 if !mode.IsRegular() {
74 if (mode & 0111) == 0 {
80 // splitPathList splits a path list.
81 // This is based on genSplit from strings/strings.go
82 func splitPathList(pathList string) []string {
87 for i := 0; i < len(pathList); i++ {
88 if pathList[i] == PathListSeparator {
93 a := make([]string, n)
95 for i := 0; i+1 <= len(pathList) && na+1 < n; i++ {
96 if pathList[i] == PathListSeparator {
97 a[na] = pathList[start:i]
102 a[na] = pathList[start:]