diff options
| author | Shenghou Ma <minux@golang.org> | 2015-11-01 04:18:58 -0500 |
|---|---|---|
| committer | Brad Fitzpatrick <bradfitz@golang.org> | 2016-11-07 22:34:48 +0000 |
| commit | 2fc67e71af142bfa1e7662a4fde361f43509d2d7 (patch) | |
| tree | 3c3ce17c50bf87dcb7957d49de0cfbe9d219058c /src/os/executable_test.go | |
| parent | 119c30eaf24c3d4f46ba1411f5cddbabb86bd840 (diff) | |
| download | go-2fc67e71af142bfa1e7662a4fde361f43509d2d7.tar.xz | |
os: add Executable() (string, error)
// Executable returns the path name for the executable that started
// the current process. There is no guarantee that the path is still
// pointing to the correct executable. If a symlink was used to start
// the process, depending on the operating system, the result might
// be the symlink or the path it pointed to. If a stable result is
// needed, path/filepath.EvalSymlinks might help.
//
// Executable returns an absolute path unless an error occurred.
//
// The main use case is finding resources located relative to an
// executable.
//
// Executable is not supported on nacl or OpenBSD (unless procfs is
// mounted.)
func Executable() (string, error) {
return executable()
}
Fixes #12773.
Change-Id: I469738d905b12f0b633ea4d88954f8859227a88c
Reviewed-on: https://go-review.googlesource.com/16551
Run-TryBot: Minux Ma <minux@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Diffstat (limited to 'src/os/executable_test.go')
| -rw-r--r-- | src/os/executable_test.go | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/src/os/executable_test.go b/src/os/executable_test.go new file mode 100644 index 0000000000..a4d89092ac --- /dev/null +++ b/src/os/executable_test.go @@ -0,0 +1,87 @@ +// Copyright 2016 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 os_test + +import ( + "fmt" + "internal/testenv" + "os" + osexec "os/exec" + "path/filepath" + "runtime" + "testing" +) + +const executable_EnvVar = "OSTEST_OUTPUT_EXECPATH" + +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" + dir := filepath.Dir(filepath.Dir(ep)) + fn, err := filepath.Rel(dir, ep) + if err != nil { + t.Fatalf("filepath.Rel: %v", err) + } + cmd := &osexec.Cmd{} + // make child start with a relative program path + cmd.Dir = dir + cmd.Path = fn + // forge argv[0] for child, so that we can verify we could correctly + // get real path of the executable without influenced by argv[0]. + cmd.Args = []string{"-", "-test.run=XXXX"} + cmd.Env = append(os.Environ(), fmt.Sprintf("%s=1", executable_EnvVar)) + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("exec(self) failed: %v", err) + } + outs := string(out) + if !filepath.IsAbs(outs) { + t.Fatalf("Child returned %q, want an absolute path", out) + } + if !sameFile(outs, ep) { + t.Fatalf("Child returned %q, not the same file as %q", out, ep) + } +} + +func sameFile(fn1, fn2 string) bool { + fi1, err := os.Stat(fn1) + if err != nil { + return false + } + fi2, err := os.Stat(fn2) + if err != nil { + return false + } + return os.SameFile(fi1, fi2) +} + +func init() { + if e := os.Getenv(executable_EnvVar); e != "" { + // first chdir to another path + dir := "/" + if runtime.GOOS == "windows" { + cwd, err := os.Getwd() + if err != nil { + panic(err) + } + dir = filepath.VolumeName(cwd) + } + os.Chdir(dir) + if ep, err := os.Executable(); err != nil { + fmt.Fprint(os.Stderr, "ERROR: ", err) + } else { + fmt.Fprint(os.Stderr, ep) + } + os.Exit(0) + } +} |
