github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/os/exec/lp_unix.go (about) 1 // Copyright 2010 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 unix 6 7 package exec 8 9 import ( 10 "errors" 11 "internal/syscall/unix" 12 "io/fs" 13 "os" 14 "path/filepath" 15 "strings" 16 "syscall" 17 ) 18 19 // ErrNotFound is the error resulting if a path search failed to find an executable file. 20 var ErrNotFound = errors.New("executable file not found in $PATH") 21 22 func findExecutable(file string) error { 23 d, err := os.Stat(file) 24 if err != nil { 25 return err 26 } 27 m := d.Mode() 28 if m.IsDir() { 29 return syscall.EISDIR 30 } 31 err = unix.Eaccess(file, unix.X_OK) 32 // ENOSYS means Eaccess is not available or not implemented. 33 // EPERM can be returned by Linux containers employing seccomp. 34 // In both cases, fall back to checking the permission bits. 35 if err == nil || (err != syscall.ENOSYS && err != syscall.EPERM) { 36 return err 37 } 38 if m&0111 != 0 { 39 return nil 40 } 41 return fs.ErrPermission 42 } 43 44 // LookPath searches for an executable named file in the 45 // directories named by the PATH environment variable. 46 // If file contains a slash, it is tried directly and the PATH is not consulted. 47 // Otherwise, on success, the result is an absolute path. 48 // 49 // In older versions of Go, LookPath could return a path relative to the current directory. 50 // As of Go 1.19, LookPath will instead return that path along with an error satisfying 51 // [errors.Is](err, [ErrDot]). See the package documentation for more details. 52 func LookPath(file string) (string, error) { 53 // NOTE(rsc): I wish we could use the Plan 9 behavior here 54 // (only bypass the path if file begins with / or ./ or ../) 55 // but that would not match all the Unix shells. 56 57 if strings.Contains(file, "/") { 58 err := findExecutable(file) 59 if err == nil { 60 return file, nil 61 } 62 return "", &Error{file, err} 63 } 64 path := os.Getenv("PATH") 65 for _, dir := range filepath.SplitList(path) { 66 if dir == "" { 67 // Unix shell semantics: path element "" means "." 68 dir = "." 69 } 70 path := filepath.Join(dir, file) 71 if err := findExecutable(path); err == nil { 72 if !filepath.IsAbs(path) { 73 if execerrdot.Value() != "0" { 74 return path, &Error{file, ErrDot} 75 } 76 execerrdot.IncNonDefault() 77 } 78 return path, nil 79 } 80 } 81 return "", &Error{file, ErrNotFound} 82 } 83 84 // lookExtensions is a no-op on non-Windows platforms, since 85 // they do not restrict executables to specific extensions. 86 func lookExtensions(path, dir string) (string, error) { 87 return path, nil 88 }