github.com/lovishpuri/go-40569/src@v0.0.0-20230519171745-f8623e7c56cf/os/executable_test.go (about) 1 // Copyright 2016 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 5 package os_test 6 7 import ( 8 "fmt" 9 "internal/testenv" 10 "os" 11 "path/filepath" 12 "runtime" 13 "testing" 14 ) 15 16 const executable_EnvVar = "OSTEST_OUTPUT_EXECPATH" 17 18 func TestExecutable(t *testing.T) { 19 testenv.MustHaveExec(t) 20 t.Parallel() 21 22 ep, err := os.Executable() 23 if err != nil { 24 t.Fatalf("Executable failed: %v", err) 25 } 26 // we want fn to be of the form "dir/prog" 27 dir := filepath.Dir(filepath.Dir(ep)) 28 fn, err := filepath.Rel(dir, ep) 29 if err != nil { 30 t.Fatalf("filepath.Rel: %v", err) 31 } 32 33 cmd := testenv.Command(t, fn, "-test.run=XXXX") 34 // make child start with a relative program path 35 cmd.Dir = dir 36 cmd.Path = fn 37 if runtime.GOOS == "openbsd" || runtime.GOOS == "aix" { 38 // OpenBSD and AIX rely on argv[0] 39 } else { 40 // forge argv[0] for child, so that we can verify we could correctly 41 // get real path of the executable without influenced by argv[0]. 42 cmd.Args[0] = "-" 43 } 44 cmd.Env = append(cmd.Environ(), fmt.Sprintf("%s=1", executable_EnvVar)) 45 out, err := cmd.CombinedOutput() 46 if err != nil { 47 t.Fatalf("exec(self) failed: %v", err) 48 } 49 outs := string(out) 50 if !filepath.IsAbs(outs) { 51 t.Fatalf("Child returned %q, want an absolute path", out) 52 } 53 if !sameFile(outs, ep) { 54 t.Fatalf("Child returned %q, not the same file as %q", out, ep) 55 } 56 } 57 58 func sameFile(fn1, fn2 string) bool { 59 fi1, err := os.Stat(fn1) 60 if err != nil { 61 return false 62 } 63 fi2, err := os.Stat(fn2) 64 if err != nil { 65 return false 66 } 67 return os.SameFile(fi1, fi2) 68 } 69 70 func init() { 71 if e := os.Getenv(executable_EnvVar); e != "" { 72 // first chdir to another path 73 dir := "/" 74 if runtime.GOOS == "windows" { 75 cwd, err := os.Getwd() 76 if err != nil { 77 panic(err) 78 } 79 dir = filepath.VolumeName(cwd) 80 } 81 os.Chdir(dir) 82 if ep, err := os.Executable(); err != nil { 83 fmt.Fprint(os.Stderr, "ERROR: ", err) 84 } else { 85 fmt.Fprint(os.Stderr, ep) 86 } 87 os.Exit(0) 88 } 89 } 90 91 func TestExecutableDeleted(t *testing.T) { 92 testenv.MustHaveGoBuild(t) 93 switch runtime.GOOS { 94 case "windows", "plan9": 95 t.Skipf("%v does not support deleting running binary", runtime.GOOS) 96 case "openbsd", "freebsd", "aix": 97 t.Skipf("%v does not support reading deleted binary name", runtime.GOOS) 98 } 99 t.Parallel() 100 101 dir := t.TempDir() 102 103 src := filepath.Join(dir, "testdel.go") 104 exe := filepath.Join(dir, "testdel.exe") 105 106 err := os.WriteFile(src, []byte(testExecutableDeletion), 0666) 107 if err != nil { 108 t.Fatal(err) 109 } 110 111 out, err := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", exe, src).CombinedOutput() 112 t.Logf("build output:\n%s", out) 113 if err != nil { 114 t.Fatal(err) 115 } 116 117 out, err = testenv.Command(t, exe).CombinedOutput() 118 t.Logf("exec output:\n%s", out) 119 if err != nil { 120 t.Fatal(err) 121 } 122 } 123 124 const testExecutableDeletion = `package main 125 126 import ( 127 "fmt" 128 "os" 129 ) 130 131 func main() { 132 before, err := os.Executable() 133 if err != nil { 134 fmt.Fprintf(os.Stderr, "failed to read executable name before deletion: %v\n", err) 135 os.Exit(1) 136 } 137 138 err = os.Remove(before) 139 if err != nil { 140 fmt.Fprintf(os.Stderr, "failed to remove executable: %v\n", err) 141 os.Exit(1) 142 } 143 144 after, err := os.Executable() 145 if err != nil { 146 fmt.Fprintf(os.Stderr, "failed to read executable name after deletion: %v\n", err) 147 os.Exit(1) 148 } 149 150 if before != after { 151 fmt.Fprintf(os.Stderr, "before and after do not match: %v != %v\n", before, after) 152 os.Exit(1) 153 } 154 } 155 `