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