blob: 3f895d5b3bacbe9d1001e21d1bba1adf9dfb80cb [file] [log] [blame]
Joe Poirierb155a762010-09-12 17:38:36 +10001// 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
Dave Cheney7c8280c2014-02-25 09:47:42 -05005// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
Russ Cox27159562011-09-15 16:48:57 -04006
Joe Poirierb155a762010-09-12 17:38:36 +10007package exec
8
9import (
Russ Coxc2049d22011-11-01 22:04:37 -040010 "errors"
Joe Poirierb155a762010-09-12 17:38:36 +100011 "os"
12 "strings"
13)
14
Rob Pike4e9e9252011-06-03 07:48:06 +100015// ErrNotFound is the error resulting if a path search failed to find an executable file.
Russ Coxc2049d22011-11-01 22:04:37 -040016var ErrNotFound = errors.New("executable file not found in $PATH")
Rob Pike4e9e9252011-06-03 07:48:06 +100017
Russ Coxc2049d22011-11-01 22:04:37 -040018func findExecutable(file string) error {
Joe Poirierb155a762010-09-12 17:38:36 +100019 d, err := os.Stat(file)
20 if err != nil {
Rob Pike4e9e9252011-06-03 07:48:06 +100021 return err
Joe Poirierb155a762010-09-12 17:38:36 +100022 }
Russ Cox8dce57e2011-11-30 12:04:16 -050023 if m := d.Mode(); !m.IsDir() && m&0111 != 0 {
Rob Pike4e9e9252011-06-03 07:48:06 +100024 return nil
25 }
Rob Pike56069f02012-02-17 10:04:29 +110026 return os.ErrPermission
Joe Poirierb155a762010-09-12 17:38:36 +100027}
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.
Rob Pikea41a5bb2013-08-15 14:29:04 +100032// The result may be an absolute path or a path relative to the current directory.
Russ Coxc2049d22011-11-01 22:04:37 -040033func LookPath(file string) (string, error) {
Joe Poirierb155a762010-09-12 17:38:36 +100034 // 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
Brad Fitzpatricke198a502010-11-01 14:32:48 -070038 if strings.Contains(file, "/") {
Rob Pike4e9e9252011-06-03 07:48:06 +100039 err := findExecutable(file)
40 if err == nil {
Joe Poirierb155a762010-09-12 17:38:36 +100041 return file, nil
42 }
Rob Pike4e9e9252011-06-03 07:48:06 +100043 return "", &Error{file, err}
Joe Poirierb155a762010-09-12 17:38:36 +100044 }
45 pathenv := os.Getenv("PATH")
Péter Surányife7dbea2013-02-07 06:41:35 -080046 if pathenv == "" {
47 return "", &Error{file, ErrNotFound}
48 }
Rob Pikeebb15662011-06-28 09:43:14 +100049 for _, dir := range strings.Split(pathenv, ":") {
Joe Poirierb155a762010-09-12 17:38:36 +100050 if dir == "" {
51 // Unix shell semantics: path element "" means "."
52 dir = "."
53 }
Gustavo Niemeyer01a0d392012-01-19 20:17:46 -020054 path := dir + "/" + file
55 if err := findExecutable(path); err == nil {
56 return path, nil
Joe Poirierb155a762010-09-12 17:38:36 +100057 }
58 }
Rob Pike4e9e9252011-06-03 07:48:06 +100059 return "", &Error{file, ErrNotFound}
Joe Poirierb155a762010-09-12 17:38:36 +100060}