summaryrefslogtreecommitdiffstats
path: root/src/os/executable_path.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/os/executable_path.go')
-rw-r--r--src/os/executable_path.go104
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]
+}