aboutsummaryrefslogtreecommitdiff
path: root/src/os/exec
diff options
context:
space:
mode:
authorCarlos Amedee <carlos@golang.org>2026-01-21 15:45:40 -0500
committerCarlos Amedee <carlos@golang.org>2026-01-21 15:56:01 -0500
commiteec3c0ca956803db8a90dfd92ce4ebffebdaf9b4 (patch)
tree14ed37a5aa0fd9e80b547fd43086b2b137457726 /src/os/exec
parent4606a931d2b099f2c5e5619b797352607ee42225 (diff)
parent2baa1d17628bb2f09757617382b1e61f1f9f0ddd (diff)
downloadgo-eec3c0ca956803db8a90dfd92ce4ebffebdaf9b4.tar.xz
[release-branch.go1.26] all: merge master (2baa1d1) into release-branch.go1.26
For #76474. Change-Id: Ic50e288f99b731b62af9aa73ce6721f0f2f3596d
Diffstat (limited to 'src/os/exec')
-rw-r--r--src/os/exec/exec_test.go24
-rw-r--r--src/os/exec/lookpath.go30
-rw-r--r--src/os/exec/lp_plan9.go11
-rw-r--r--src/os/exec/lp_unix.go10
-rw-r--r--src/os/exec/lp_wasm.go2
-rw-r--r--src/os/exec/lp_windows.go26
6 files changed, 48 insertions, 55 deletions
diff --git a/src/os/exec/exec_test.go b/src/os/exec/exec_test.go
index bf2f3da535..2746ad8783 100644
--- a/src/os/exec/exec_test.go
+++ b/src/os/exec/exec_test.go
@@ -1845,23 +1845,13 @@ func TestStart_twice(t *testing.T) {
testenv.MustHaveExec(t)
cmd := exec.Command("/bin/nonesuch")
- for i, want := range []string{
- cond(runtime.GOOS == "windows",
- `exec: "/bin/nonesuch": executable file not found in %PATH%`,
- "fork/exec /bin/nonesuch: no such file or directory"),
- "exec: already started",
- } {
- err := cmd.Start()
- if got := fmt.Sprint(err); got != want {
- t.Errorf("Start call #%d return err %q, want %q", i+1, got, want)
- }
+ if err := cmd.Start(); err == nil {
+ t.Fatalf("running invalid command succeeded")
}
-}
-
-func cond[T any](cond bool, t, f T) T {
- if cond {
- return t
- } else {
- return f
+ err := cmd.Start()
+ got := fmt.Sprint(err)
+ want := "exec: already started"
+ if got != want {
+ t.Fatalf("Start call returned err %q, want %q", got, want)
}
}
diff --git a/src/os/exec/lookpath.go b/src/os/exec/lookpath.go
new file mode 100644
index 0000000000..71f86b994f
--- /dev/null
+++ b/src/os/exec/lookpath.go
@@ -0,0 +1,30 @@
+// Copyright 2026 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.
+
+package exec
+
+// LookPath searches for an executable named file in the current path,
+// following the conventions of the host operating system.
+// If file contains a slash, it is tried directly and the default path is not consulted.
+// Otherwise, on success the result is an absolute path.
+//
+// LookPath returns an error satisfying [errors.Is](err, [ErrDot])
+// if the resolved path is relative to the current directory.
+// See the package documentation for more details.
+//
+// LookPath looks for an executable named file in the
+// directories named by the PATH environment variable,
+// except as described below.
+//
+// - On Windows, the file must have an extension named by
+// the PATHEXT environment variable.
+// When PATHEXT is unset, the file must have
+// a ".com", ".exe", ".bat", or ".cmd" extension.
+// - On Plan 9, LookPath consults the path environment variable.
+// If file begins with "/", "#", "./", or "../", it is tried
+// directly and the path is not consulted.
+// - On Wasm, LookPath always returns an error.
+func LookPath(file string) (string, error) {
+ return lookPath(file)
+}
diff --git a/src/os/exec/lp_plan9.go b/src/os/exec/lp_plan9.go
index f713a6905c..711aad11bd 100644
--- a/src/os/exec/lp_plan9.go
+++ b/src/os/exec/lp_plan9.go
@@ -26,16 +26,7 @@ func findExecutable(file string) error {
return fs.ErrPermission
}
-// LookPath searches for an executable named file in the
-// directories named by the path environment variable.
-// If file begins with "/", "#", "./", or "../", it is tried
-// directly and the path is not consulted.
-// On success, the result is an absolute path.
-//
-// In older versions of Go, LookPath could return a path relative to the current directory.
-// As of Go 1.19, LookPath will instead return that path along with an error satisfying
-// [errors.Is](err, [ErrDot]). See the package documentation for more details.
-func LookPath(file string) (string, error) {
+func lookPath(file string) (string, error) {
if err := validateLookPath(filepath.Clean(file)); err != nil {
return "", &Error{file, err}
}
diff --git a/src/os/exec/lp_unix.go b/src/os/exec/lp_unix.go
index e5fddbafe2..d3b10cc43d 100644
--- a/src/os/exec/lp_unix.go
+++ b/src/os/exec/lp_unix.go
@@ -41,15 +41,7 @@ func findExecutable(file string) error {
return fs.ErrPermission
}
-// LookPath searches for an executable named file in the
-// directories named by the PATH environment variable.
-// If file contains a slash, it is tried directly and the PATH is not consulted.
-// Otherwise, on success, the result is an absolute path.
-//
-// In older versions of Go, LookPath could return a path relative to the current directory.
-// As of Go 1.19, LookPath will instead return that path along with an error satisfying
-// [errors.Is](err, [ErrDot]). See the package documentation for more details.
-func LookPath(file string) (string, error) {
+func lookPath(file string) (string, error) {
// 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.
diff --git a/src/os/exec/lp_wasm.go b/src/os/exec/lp_wasm.go
index 3c819049ba..1de9076e53 100644
--- a/src/os/exec/lp_wasm.go
+++ b/src/os/exec/lp_wasm.go
@@ -17,7 +17,7 @@ var ErrNotFound = errors.New("executable file not found in $PATH")
// directories named by the PATH environment variable.
// If file contains a slash, it is tried directly and the PATH is not consulted.
// The result may be an absolute path or a path relative to the current directory.
-func LookPath(file string) (string, error) {
+func lookPath(file string) (string, error) {
// Wasm can not execute processes, so act as if there are no executables at all.
return "", &Error{file, ErrNotFound}
}
diff --git a/src/os/exec/lp_windows.go b/src/os/exec/lp_windows.go
index 74537dec68..f58aabc19f 100644
--- a/src/os/exec/lp_windows.go
+++ b/src/os/exec/lp_windows.go
@@ -56,22 +56,12 @@ func findExecutable(file string, exts []string) (string, error) {
return "", ErrNotFound
}
-// LookPath searches for an executable named file in the
-// directories named by the PATH environment variable.
-// LookPath also uses PATHEXT environment variable to match
-// a suitable candidate.
-// If file contains a slash, it is tried directly and the PATH is not consulted.
-// Otherwise, on success, the result is an absolute path.
-//
-// In older versions of Go, LookPath could return a path relative to the current directory.
-// As of Go 1.19, LookPath will instead return that path along with an error satisfying
-// [errors.Is](err, [ErrDot]). See the package documentation for more details.
-func LookPath(file string) (string, error) {
+func lookPath(file string) (string, error) {
if err := validateLookPath(file); err != nil {
return "", &Error{file, err}
}
- return lookPath(file, pathExt())
+ return lookPathExts(file, pathExt())
}
// lookExtensions finds windows executable by its dir and path.
@@ -101,17 +91,17 @@ func lookExtensions(path, dir string) (string, error) {
}
}
if dir == "" {
- return lookPath(path, exts)
+ return lookPathExts(path, exts)
}
if filepath.VolumeName(path) != "" {
- return lookPath(path, exts)
+ return lookPathExts(path, exts)
}
if len(path) > 1 && os.IsPathSeparator(path[0]) {
- return lookPath(path, exts)
+ return lookPathExts(path, exts)
}
dirandpath := filepath.Join(dir, path)
// We assume that LookPath will only add file extension.
- lp, err := lookPath(dirandpath, exts)
+ lp, err := lookPathExts(dirandpath, exts)
if err != nil {
return "", err
}
@@ -138,8 +128,8 @@ func pathExt() []string {
return exts
}
-// lookPath implements LookPath for the given PATHEXT list.
-func lookPath(file string, exts []string) (string, error) {
+// lookPathExts implements LookPath for the given PATHEXT list.
+func lookPathExts(file string, exts []string) (string, error) {
if strings.ContainsAny(file, `:\/`) {
f, err := findExecutable(file, exts)
if err == nil {