diff options
Diffstat (limited to 'src/os/executable_path.go')
-rw-r--r-- | src/os/executable_path.go | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/src/os/executable_path.go b/src/os/executable_path.go new file mode 100644 index 0000000..d6161bc --- /dev/null +++ b/src/os/executable_path.go @@ -0,0 +1,104 @@ +// 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] +} |