Skip to content

Commit fd36b54

Browse files
committed
helper/wrappedstreams: get original console input/output on Windows
Fixes hashicorp#10266 panicwrap was using Extrafiles to get the original standard streams for `terraform console`. This doesn't work on Windows. Instead, we must use the Win32 APIs to get the exact handles.
1 parent 50c1e87 commit fd36b54

5 files changed

Lines changed: 87 additions & 9 deletions

File tree

‎helper/wrappedstreams/streams.go‎

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,15 @@ func Stderr() *os.File {
3838
return stderr
3939
}
4040

41-
// These are the wrapped streams. There doesn't appear to be a negative
42-
// impact of opening these files even if the file descriptor doesn't exist.
41+
// These are the wrapped standard streams. These are setup by the
42+
// platform specific code in initPlatform.
4343
var (
44-
wrappedStdin = os.NewFile(uintptr(3), "stdin")
45-
wrappedStdout = os.NewFile(uintptr(4), "stdout")
46-
wrappedStderr = os.NewFile(uintptr(5), "stderr")
44+
wrappedStdin *os.File
45+
wrappedStdout *os.File
46+
wrappedStderr *os.File
4747
)
48+
49+
func init() {
50+
// Initialize the platform-specific code
51+
initPlatform()
52+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// +build !windows
2+
3+
package wrappedstreams
4+
5+
import (
6+
"os"
7+
)
8+
9+
func initPlatform() {
10+
// The standard streams are passed in via extra file descriptors.
11+
wrappedStdin = os.NewFile(uintptr(3), "stdin")
12+
wrappedStdout = os.NewFile(uintptr(4), "stdout")
13+
wrappedStderr = os.NewFile(uintptr(5), "stderr")
14+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// +build windows
2+
3+
package wrappedstreams
4+
5+
import (
6+
"log"
7+
"os"
8+
"syscall"
9+
)
10+
11+
func initPlatform() {
12+
wrappedStdin = openConsole("CONIN$", os.Stdin)
13+
wrappedStdout = openConsole("CONOUT$", os.Stdout)
14+
wrappedStderr = wrappedStdout
15+
}
16+
17+
// openConsole opens a console handle, using a backup if it fails.
18+
// This is used to get the exact console handle instead of the redirected
19+
// handles from panicwrap.
20+
func openConsole(name string, backup *os.File) *os.File {
21+
// Convert to UTF16
22+
path, err := syscall.UTF16PtrFromString(name)
23+
if err != nil {
24+
log.Printf("[ERROR] wrappedstreams: %s", err)
25+
return backup
26+
}
27+
28+
// Determine the share mode
29+
var shareMode uint32
30+
switch name {
31+
case "CONIN$":
32+
shareMode = syscall.FILE_SHARE_READ
33+
case "CONOUT$":
34+
shareMode = syscall.FILE_SHARE_WRITE
35+
}
36+
37+
// Get the file
38+
h, err := syscall.CreateFile(
39+
path,
40+
syscall.GENERIC_READ|syscall.GENERIC_WRITE,
41+
shareMode,
42+
nil,
43+
syscall.OPEN_EXISTING,
44+
0, 0)
45+
if err != nil {
46+
log.Printf("[ERROR] wrappedstreams: %s", err)
47+
return backup
48+
}
49+
50+
// Create the Go file
51+
return os.NewFile(uintptr(h), name)
52+
}

‎vendor/github.com/mitchellh/panicwrap/panicwrap.go‎

Lines changed: 8 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎vendor/vendor.json‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1915,10 +1915,10 @@
19151915
"revision": "314aad379a39f6ad5bcca278e6757d9abbb3a52e"
19161916
},
19171917
{
1918-
"checksumSHA1": "wqU8bs9c+xm0f07t6ajQFWYS+rE=",
1918+
"checksumSHA1": "kTntIB9SdU1NsCqKwDkUr99qaj0=",
19191919
"path": "github.com/mitchellh/panicwrap",
1920-
"revision": "168f3680ad986108df63bae07da2978f51c4ac8e",
1921-
"revisionTime": "2016-11-14T06:37:33Z"
1920+
"revision": "fde185d0dfb5ecac6e6b201e8855da798ebcd76f",
1921+
"revisionTime": "2016-11-21T18:34:54Z"
19221922
},
19231923
{
19241924
"path": "github.com/mitchellh/prefixedio",

0 commit comments

Comments
 (0)