mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
os: on OpenBSD implement Executable using Args[0]
OpenBSD no longer has procfs. Based on a patch by Matthieu Sarter. Fixes #19453. Change-Id: Ia09d16f8a1cbef2f8cc1c5f49e9c61ec7d026a40 Reviewed-on: https://go-review.googlesource.com/46004 Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
fddc598370
commit
c60d6c0b43
3 changed files with 112 additions and 7 deletions
104
src/os/executable_path.go
Normal file
104
src/os/executable_path.go
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
// +build openbsd
|
||||||
|
|
||||||
|
package os
|
||||||
|
|
||||||
|
// We query the working directory at init, to use it later to search for the
|
||||||
|
// executable file
|
||||||
|
// errWd will be checked later, if we need to use initWd
|
||||||
|
var initWd, errWd = Getwd()
|
||||||
|
|
||||||
|
func executable() (string, error) {
|
||||||
|
var exePath string
|
||||||
|
if len(Args) == 0 || Args[0] == "" {
|
||||||
|
return "", ErrNotExist
|
||||||
|
}
|
||||||
|
if IsPathSeparator(Args[0][0]) {
|
||||||
|
// Args[0] is an absolute path, so it is the executable.
|
||||||
|
// Note that we only need to worry about Unix paths here.
|
||||||
|
exePath = Args[0]
|
||||||
|
} else {
|
||||||
|
for i := 1; i < len(Args[0]); i++ {
|
||||||
|
if IsPathSeparator(Args[0][i]) {
|
||||||
|
// Args[0] is a relative path: prepend the
|
||||||
|
// initial working directory.
|
||||||
|
if errWd != nil {
|
||||||
|
return "", errWd
|
||||||
|
}
|
||||||
|
exePath = initWd + string(PathSeparator) + Args[0]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if exePath != "" {
|
||||||
|
if err := isExecutable(exePath); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return exePath, nil
|
||||||
|
}
|
||||||
|
// Search for executable in $PATH.
|
||||||
|
for _, dir := range splitPathList(Getenv("PATH")) {
|
||||||
|
if len(dir) == 0 {
|
||||||
|
dir = "."
|
||||||
|
}
|
||||||
|
if !IsPathSeparator(dir[0]) {
|
||||||
|
if errWd != nil {
|
||||||
|
return "", errWd
|
||||||
|
}
|
||||||
|
dir = initWd + string(PathSeparator) + dir
|
||||||
|
}
|
||||||
|
exePath = dir + string(PathSeparator) + Args[0]
|
||||||
|
switch isExecutable(exePath) {
|
||||||
|
case nil:
|
||||||
|
return exePath, nil
|
||||||
|
case ErrPermission:
|
||||||
|
return "", ErrPermission
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", ErrNotExist
|
||||||
|
}
|
||||||
|
|
||||||
|
// isExecutable returns an error if a given file is not an executable.
|
||||||
|
func isExecutable(path string) error {
|
||||||
|
stat, err := Stat(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
mode := stat.Mode()
|
||||||
|
if !mode.IsRegular() {
|
||||||
|
return ErrPermission
|
||||||
|
}
|
||||||
|
if (mode & 0111) == 0 {
|
||||||
|
return ErrPermission
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// splitPathList splits a path list.
|
||||||
|
// This is based on genSplit from strings/strings.go
|
||||||
|
func splitPathList(pathList string) []string {
|
||||||
|
if pathList == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
n := 1
|
||||||
|
for i := 0; i < len(pathList); i++ {
|
||||||
|
if pathList[i] == PathListSeparator {
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
start := 0
|
||||||
|
a := make([]string, n)
|
||||||
|
na := 0
|
||||||
|
for i := 0; i+1 <= len(pathList) && na+1 < n; i++ {
|
||||||
|
if pathList[i] == PathListSeparator {
|
||||||
|
a[na] = pathList[start:i]
|
||||||
|
na++
|
||||||
|
start = i + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a[na] = pathList[start:]
|
||||||
|
return a[:na+1]
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build linux netbsd openbsd dragonfly nacl
|
// +build linux netbsd dragonfly nacl
|
||||||
|
|
||||||
package os
|
package os
|
||||||
|
|
||||||
|
|
@ -23,8 +23,6 @@ var executablePath, executablePathErr = func() (string, error) {
|
||||||
procfn = "/proc/self/exe"
|
procfn = "/proc/self/exe"
|
||||||
case "netbsd":
|
case "netbsd":
|
||||||
procfn = "/proc/curproc/exe"
|
procfn = "/proc/curproc/exe"
|
||||||
case "openbsd":
|
|
||||||
procfn = "/proc/curproc/file"
|
|
||||||
case "dragonfly":
|
case "dragonfly":
|
||||||
procfn = "/proc/curproc/file"
|
procfn = "/proc/curproc/file"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,6 @@ func TestExecutable(t *testing.T) {
|
||||||
testenv.MustHaveExec(t) // will also execlude nacl, which doesn't support Executable anyway
|
testenv.MustHaveExec(t) // will also execlude nacl, which doesn't support Executable anyway
|
||||||
ep, err := os.Executable()
|
ep, err := os.Executable()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch goos := runtime.GOOS; goos {
|
|
||||||
case "openbsd": // procfs is not mounted by default
|
|
||||||
t.Skipf("Executable failed on %s: %v, expected", goos, err)
|
|
||||||
}
|
|
||||||
t.Fatalf("Executable failed: %v", err)
|
t.Fatalf("Executable failed: %v", err)
|
||||||
}
|
}
|
||||||
// we want fn to be of the form "dir/prog"
|
// we want fn to be of the form "dir/prog"
|
||||||
|
|
@ -32,6 +28,13 @@ func TestExecutable(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("filepath.Rel: %v", err)
|
t.Fatalf("filepath.Rel: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if runtime.GOOS == "openbsd" {
|
||||||
|
// The rest of the test doesn't work on OpenBSD,
|
||||||
|
// which relies on argv[0].
|
||||||
|
t.Skipf("skipping remainder of test on %s", runtime.GOOS)
|
||||||
|
}
|
||||||
|
|
||||||
cmd := &osexec.Cmd{}
|
cmd := &osexec.Cmd{}
|
||||||
// make child start with a relative program path
|
// make child start with a relative program path
|
||||||
cmd.Dir = dir
|
cmd.Dir = dir
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue