github.com/code-reading/golang@v0.0.0-20220303082512-ba5bc0e589a3/go/src/os/executable_path.go (about) 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. 4 5 //go:build aix || openbsd 6 // +build aix openbsd 7 8 package os 9 10 // We query the working directory at init, to use it later to search for the 11 // executable file 12 // errWd will be checked later, if we need to use initWd 13 var initWd, errWd = Getwd() 14 15 func executable() (string, error) { 16 var exePath string 17 if len(Args) == 0 || Args[0] == "" { 18 return "", ErrNotExist 19 } 20 if IsPathSeparator(Args[0][0]) { 21 // Args[0] is an absolute path, so it is the executable. 22 // Note that we only need to worry about Unix paths here. 23 exePath = Args[0] 24 } else { 25 for i := 1; i < len(Args[0]); i++ { 26 if IsPathSeparator(Args[0][i]) { 27 // Args[0] is a relative path: prepend the 28 // initial working directory. 29 if errWd != nil { 30 return "", errWd 31 } 32 exePath = initWd + string(PathSeparator) + Args[0] 33 break 34 } 35 } 36 } 37 if exePath != "" { 38 if err := isExecutable(exePath); err != nil { 39 return "", err 40 } 41 return exePath, nil 42 } 43 // Search for executable in $PATH. 44 for _, dir := range splitPathList(Getenv("PATH")) { 45 if len(dir) == 0 { 46 dir = "." 47 } 48 if !IsPathSeparator(dir[0]) { 49 if errWd != nil { 50 return "", errWd 51 } 52 dir = initWd + string(PathSeparator) + dir 53 } 54 exePath = dir + string(PathSeparator) + Args[0] 55 switch isExecutable(exePath) { 56 case nil: 57 return exePath, nil 58 case ErrPermission: 59 return "", ErrPermission 60 } 61 } 62 return "", ErrNotExist 63 } 64 65 // isExecutable returns an error if a given file is not an executable. 66 func isExecutable(path string) error { 67 stat, err := Stat(path) 68 if err != nil { 69 return err 70 } 71 mode := stat.Mode() 72 if !mode.IsRegular() { 73 return ErrPermission 74 } 75 if (mode & 0111) == 0 { 76 return ErrPermission 77 } 78 return nil 79 } 80 81 // splitPathList splits a path list. 82 // This is based on genSplit from strings/strings.go 83 func splitPathList(pathList string) []string { 84 if pathList == "" { 85 return nil 86 } 87 n := 1 88 for i := 0; i < len(pathList); i++ { 89 if pathList[i] == PathListSeparator { 90 n++ 91 } 92 } 93 start := 0 94 a := make([]string, n) 95 na := 0 96 for i := 0; i+1 <= len(pathList) && na+1 < n; i++ { 97 if pathList[i] == PathListSeparator { 98 a[na] = pathList[start:i] 99 na++ 100 start = i + 1 101 } 102 } 103 a[na] = pathList[start:] 104 return a[:na+1] 105 }