Home | History | Annotate | Download | only in exec
      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 // +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
      6 
      7 package exec
      8 
      9 import (
     10 	"errors"
     11 	"os"
     12 	"strings"
     13 )
     14 
     15 // ErrNotFound is the error resulting if a path search failed to find an executable file.
     16 var ErrNotFound = errors.New("executable file not found in $PATH")
     17 
     18 func findExecutable(file string) error {
     19 	d, err := os.Stat(file)
     20 	if err != nil {
     21 		return err
     22 	}
     23 	if m := d.Mode(); !m.IsDir() && m&0111 != 0 {
     24 		return nil
     25 	}
     26 	return os.ErrPermission
     27 }
     28 
     29 // LookPath searches for an executable binary named file
     30 // in the directories named by the PATH environment variable.
     31 // If file contains a slash, it is tried directly and the PATH is not consulted.
     32 // The result may be an absolute path or a path relative to the current directory.
     33 func LookPath(file string) (string, error) {
     34 	// NOTE(rsc): I wish we could use the Plan 9 behavior here
     35 	// (only bypass the path if file begins with / or ./ or ../)
     36 	// but that would not match all the Unix shells.
     37 
     38 	if strings.Contains(file, "/") {
     39 		err := findExecutable(file)
     40 		if err == nil {
     41 			return file, nil
     42 		}
     43 		return "", &Error{file, err}
     44 	}
     45 	pathenv := os.Getenv("PATH")
     46 	if pathenv == "" {
     47 		return "", &Error{file, ErrNotFound}
     48 	}
     49 	for _, dir := range strings.Split(pathenv, ":") {
     50 		if dir == "" {
     51 			// Unix shell semantics: path element "" means "."
     52 			dir = "."
     53 		}
     54 		path := dir + "/" + file
     55 		if err := findExecutable(path); err == nil {
     56 			return path, nil
     57 		}
     58 	}
     59 	return "", &Error{file, ErrNotFound}
     60 }
     61