|  | // 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] | 
|  | } |