]> Cypherpunks.ru repositories - gostls13.git/blob - src/os/executable_path.go
cmd/compile/internal/inline: score call sites exposed by inlines
[gostls13.git] / src / os / executable_path.go
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 }