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.
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
) {
17 if len(Args
) == 0 || Args
[0] == "" {
18 return "", ErrNotExist
20 // Args[0] is an absolute path : this is the executable
21 if IsPathSeparator(Args
[0][0]) {
24 for i
:= 1; i
< len(Args
[0]); i
++ {
25 // Args[0] is a relative path : append current directory
26 if IsPathSeparator(Args
[0][i
]) {
30 exePath
= initWd
+ string(PathSeparator
) + Args
[0]
36 err
= isExecutable(exePath
)
40 // File does not exist or is not executable,
41 // this is an unexpected situation !
44 // Search for executable in $PATH
45 for _
, dir
:= range splitPathList(Getenv("PATH")) {
49 if !IsPathSeparator(dir
[0]) {
53 dir
= initWd
+ string(PathSeparator
) + dir
55 exePath
= dir
+ string(PathSeparator
) + Args
[0]
56 err
= isExecutable(exePath
)
60 if err
== ErrPermission
{
64 return "", ErrNotExist
67 // isExecutable returns an error if a given file is not an executable.
68 func isExecutable(path
string) error
{
69 stat
, err
:= Stat(path
)
74 if !mode
.IsRegular() {
77 if (mode
& 0111) != 0 {
83 // splitPathList splits a path list.
84 // This is based on genSplit from strings/strings.go
85 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
:]