]> Cypherpunks repositories - gostls13.git/commitdiff
os: on OpenBSD implement Executable using Args[0]
authorIan Lance Taylor <iant@golang.org>
Sat, 17 Jun 2017 01:13:13 +0000 (18:13 -0700)
committerIan Lance Taylor <iant@golang.org>
Sat, 17 Jun 2017 03:32:59 +0000 (03:32 +0000)
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>
src/os/executable_path.go [new file with mode: 0644]
src/os/executable_procfs.go
src/os/executable_test.go

diff --git a/src/os/executable_path.go b/src/os/executable_path.go
new file mode 100644 (file)
index 0000000..057e6a7
--- /dev/null
@@ -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]
+}
index 69a70e18df030fe176a3605c64927aa112836fc0..b5fae5904686218373a2cf6bcc7f8fe675b59f82 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build linux netbsd openbsd dragonfly nacl
+// +build linux netbsd dragonfly nacl
 
 package os
 
@@ -23,8 +23,6 @@ var executablePath, executablePathErr = func() (string, error) {
                procfn = "/proc/self/exe"
        case "netbsd":
                procfn = "/proc/curproc/exe"
-       case "openbsd":
-               procfn = "/proc/curproc/file"
        case "dragonfly":
                procfn = "/proc/curproc/file"
        }
index a4d89092ac6f401af62ae2ca592c2032791d8f23..a6aeb0723f9f6d122dd5dfe29f52ce0cba4a8552 100644 (file)
@@ -20,10 +20,6 @@ func TestExecutable(t *testing.T) {
        testenv.MustHaveExec(t) // will also execlude nacl, which doesn't support Executable anyway
        ep, err := os.Executable()
        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)
        }
        // we want fn to be of the form "dir/prog"
@@ -32,6 +28,13 @@ func TestExecutable(t *testing.T) {
        if err != nil {
                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{}
        // make child start with a relative program path
        cmd.Dir = dir