Skip to content

Commit

Permalink
helper/wrappedstreams: get original console input/output on Windows
Browse files Browse the repository at this point in the history
Fixes #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.
  • Loading branch information
mitchellh committed Nov 21, 2016
1 parent 50c1e87 commit db8d473
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 9 deletions.
15 changes: 10 additions & 5 deletions helper/wrappedstreams/streams.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,15 @@ func Stderr() *os.File {
return stderr
}

// These are the wrapped streams. There doesn't appear to be a negative
// impact of opening these files even if the file descriptor doesn't exist.
// These are the wrapped standard streams. These are setup by the
// platform specific code in initPlatform.
var (
wrappedStdin = os.NewFile(uintptr(3), "stdin")
wrappedStdout = os.NewFile(uintptr(4), "stdout")
wrappedStderr = os.NewFile(uintptr(5), "stderr")
wrappedStdin *os.File
wrappedStdout *os.File
wrappedStderr *os.File
)

func init() {
// Initialize the platform-specific code
initPlatform()
}
10 changes: 10 additions & 0 deletions helper/wrappedstreams/streams_other.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// +build !windows

package wrappedstreams

func initPlatform() {
// The standard streams are passed in via extra file descriptors.
wrappedStdin = os.NewFile(uintptr(3), "stdin")
wrappedStdout = os.NewFile(uintptr(4), "stdout")
wrappedStderr = os.NewFile(uintptr(5), "stderr")
}
52 changes: 52 additions & 0 deletions helper/wrappedstreams/streams_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// +build windows

package wrappedstreams

import (
"log"
"os"
"syscall"
)

func initPlatform() {
wrappedStdin = openConsole("CONIN$", os.Stdin)
wrappedStdout = openConsole("CONOUT$", os.Stdout)
wrappedStderr = wrappedStdout
}

// openConsole opens a console handle, using a backup if it fails.
// This is used to get the exact console handle instead of the redirected
// handles from panicwrap.
func openConsole(name string, backup *os.File) *os.File {
// Convert to UTF16
path, err := syscall.UTF16PtrFromString(name)
if err != nil {
log.Printf("[ERROR] wrappedstreams: %s", err)
return backup
}

// Determine the share mode
var shareMode uint32
switch name {
case "CONIN$":
shareMode = syscall.FILE_SHARE_READ
case "CONOUT$":
shareMode = syscall.FILE_SHARE_WRITE
}

// Get the file
h, err := syscall.CreateFile(
path,
syscall.GENERIC_READ|syscall.GENERIC_WRITE,
shareMode,
nil,
syscall.OPEN_EXISTING,
0, 0)
if err != nil {
log.Printf("[ERROR] wrappedstreams: %s", err)
return backup
}

// Create the Go file
return os.NewFile(uintptr(h), name)
}
9 changes: 8 additions & 1 deletion vendor/github.com/mitchellh/panicwrap/panicwrap.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions vendor/vendor.json
Original file line number Diff line number Diff line change
Expand Up @@ -1915,10 +1915,10 @@
"revision": "314aad379a39f6ad5bcca278e6757d9abbb3a52e"
},
{
"checksumSHA1": "wqU8bs9c+xm0f07t6ajQFWYS+rE=",
"checksumSHA1": "kTntIB9SdU1NsCqKwDkUr99qaj0=",
"path": "github.com/mitchellh/panicwrap",
"revision": "168f3680ad986108df63bae07da2978f51c4ac8e",
"revisionTime": "2016-11-14T06:37:33Z"
"revision": "fde185d0dfb5ecac6e6b201e8855da798ebcd76f",
"revisionTime": "2016-11-21T18:34:54Z"
},
{
"path": "github.com/mitchellh/prefixedio",
Expand Down

0 comments on commit db8d473

Please sign in to comment.