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