// Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build aix || darwin || dragonfly || freebsd || linux || nacl || netbsd || openbsd || solaris package execpath import ( "os" "path/filepath" "strings" ) func findExecutable(file string) error { d, err := os.Stat(file) if err != nil { return err } if m := d.Mode(); !m.IsDir() && m&0111 != 0 { return nil } return os.ErrPermission } // Look searches for an executable named file, using getenv to look up // environment variables. If getenv is nil, os.Getenv will be used. If file // contains a slash, it is tried directly and getenv will not be called. The // result may be an absolute path or a path relative to the current directory. func Look(file string, getenv func(string) string) (string, error) { if getenv == nil { getenv = os.Getenv } // NOTE(rsc): I wish we could use the Plan 9 behavior here // (only bypass the path if file begins with / or ./ or ../) // but that would not match all the Unix shells. if strings.Contains(file, "/") { err := findExecutable(file) if err == nil { return file, nil } return "", &Error{file, err} } path := getenv("PATH") for _, dir := range filepath.SplitList(path) { if dir == "" { // Unix shell semantics: path element "" means "." dir = "." } path := filepath.Join(dir, file) if err := findExecutable(path); err == nil { return path, nil } } return "", &Error{file, ErrNotFound} }