From c3296ef303e92458bcd57eaafc5caa18cb9fc06e Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 14 Oct 2019 11:17:45 +0200 Subject: [PATCH] term: add IsTerminal function Extracted from golang.org/x/crypto/ssh/terminal The implementation for plan9 is based on IsTerminal from github.com/mattn/go-isatty Change-Id: Id7bf2d6595639ff08e5fd5f786a145d340bbed08 Reviewed-on: https://go-review.googlesource.com/c/term/+/200681 Run-TryBot: Tobias Klauser Reviewed-by: Brad Fitzpatrick --- builders_test.go | 9 --------- go.mod | 2 ++ go.sum | 2 ++ term.go | 12 ++++++++++++ term_aix.go | 11 +++++++++++ term_bsd.go | 13 +++++++++++++ term_linux.go | 11 +++++++++++ term_linux_test.go | 42 ++++++++++++++++++++++++++++++++++++++++++ term_plan9.go | 17 +++++++++++++++++ term_solaris.go | 16 ++++++++++++++++ term_test.go | 26 ++++++++++++++++++++++++++ term_unix.go | 16 ++++++++++++++++ term_windows.go | 15 +++++++++++++++ 13 files changed, 183 insertions(+), 9 deletions(-) delete mode 100644 builders_test.go create mode 100644 go.sum create mode 100644 term.go create mode 100644 term_aix.go create mode 100644 term_bsd.go create mode 100644 term_linux.go create mode 100644 term_linux_test.go create mode 100644 term_plan9.go create mode 100644 term_solaris.go create mode 100644 term_test.go create mode 100644 term_unix.go create mode 100644 term_windows.go diff --git a/builders_test.go b/builders_test.go deleted file mode 100644 index 39500a3..0000000 --- a/builders_test.go +++ /dev/null @@ -1,9 +0,0 @@ -// 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. - -// Temporary file to make the builders happy so there's -// something buildable in this repo. This can be deleted -// when other code is added here. - -package builders_test diff --git a/go.mod b/go.mod index c7216bd..13ae60a 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,5 @@ module golang.org/x/term go 1.11 + +require golang.org/x/sys v0.0.0-20191010194322-b09406accb47 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..9878210 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/term.go b/term.go new file mode 100644 index 0000000..a4f6cd9 --- /dev/null +++ b/term.go @@ -0,0 +1,12 @@ +// Copyright 2019 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 term provides support functions for dealing with terminals, as +// commonly found on UNIX systems. +package term + +// IsTerminal returns whether the given file descriptor is a terminal. +func IsTerminal(fd int) bool { + return isTerminal(fd) +} diff --git a/term_aix.go b/term_aix.go new file mode 100644 index 0000000..ec21c5c --- /dev/null +++ b/term_aix.go @@ -0,0 +1,11 @@ +// Copyright 2019 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 term + +import ( + "golang.org/x/sys/unix" +) + +const ioctlReadTermios = unix.TCGETS diff --git a/term_bsd.go b/term_bsd.go new file mode 100644 index 0000000..04835ed --- /dev/null +++ b/term_bsd.go @@ -0,0 +1,13 @@ +// Copyright 2013 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 darwin dragonfly freebsd netbsd openbsd + +package term + +import ( + "golang.org/x/sys/unix" +) + +const ioctlReadTermios = unix.TIOCGETA diff --git a/term_linux.go b/term_linux.go new file mode 100644 index 0000000..ec21c5c --- /dev/null +++ b/term_linux.go @@ -0,0 +1,11 @@ +// Copyright 2019 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 term + +import ( + "golang.org/x/sys/unix" +) + +const ioctlReadTermios = unix.TCGETS diff --git a/term_linux_test.go b/term_linux_test.go new file mode 100644 index 0000000..5f2443a --- /dev/null +++ b/term_linux_test.go @@ -0,0 +1,42 @@ +// Copyright 2019 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 term_test + +import ( + "io/ioutil" + "os" + "path/filepath" + "testing" + + "golang.org/x/sys/unix" + "golang.org/x/term" +) + +func TestIsTerminalTerm(t *testing.T) { + + dir, err := ioutil.TempDir("", "TestIsTerminalTerm") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + tty := filepath.Join(dir, "tty") + err = unix.Mknod(tty, unix.S_IFCHR, int(unix.Mkdev(5, 0))) + if err == unix.EPERM { + t.Skip("no permission to create terminal file, skipping test") + } else if err != nil { + t.Fatal(err) + } + + file, err := os.Open(tty) + if err != nil { + t.Fatal(err) + } + defer file.Close() + + if !term.IsTerminal(int(file.Fd())) { + t.Fatalf("IsTerminal unexpectedly returned false for terminal file %s", file.Name()) + } +} diff --git a/term_plan9.go b/term_plan9.go new file mode 100644 index 0000000..0e5335f --- /dev/null +++ b/term_plan9.go @@ -0,0 +1,17 @@ +// Copyright 2019 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 term + +import ( + "golang.org/x/sys/plan9" +) + +func isTerminal(fd int) bool { + path, err := plan9.Fd2path(fd) + if err != nil { + return false + } + return path == "/dev/cons" || path == "/mnt/term/dev/cons" +} diff --git a/term_solaris.go b/term_solaris.go new file mode 100644 index 0000000..cd6feae --- /dev/null +++ b/term_solaris.go @@ -0,0 +1,16 @@ +// Copyright 2019 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 aix darwin dragonfly freebsd linux netbsd openbsd + +package term + +import ( + "golang.org/x/sys/unix" +) + +func isTerminal(fd int) bool { + _, err := unix.IoctlGetTermio(fd, unix.TCGETA) + return err == nil +} diff --git a/term_test.go b/term_test.go new file mode 100644 index 0000000..aef6b51 --- /dev/null +++ b/term_test.go @@ -0,0 +1,26 @@ +// Copyright 2019 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 term_test + +import ( + "io/ioutil" + "os" + "testing" + + "golang.org/x/term" +) + +func TestIsTerminalTempFile(t *testing.T) { + file, err := ioutil.TempFile("", "TestIsTerminalTempFile") + if err != nil { + t.Fatal(err) + } + defer os.Remove(file.Name()) + defer file.Close() + + if term.IsTerminal(int(file.Fd())) { + t.Fatalf("IsTerminal unexpectedly returned true for temporary file %s", file.Name()) + } +} diff --git a/term_unix.go b/term_unix.go new file mode 100644 index 0000000..bb770cf --- /dev/null +++ b/term_unix.go @@ -0,0 +1,16 @@ +// Copyright 2019 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 aix darwin dragonfly freebsd linux netbsd openbsd + +package term + +import ( + "golang.org/x/sys/unix" +) + +func isTerminal(fd int) bool { + _, err := unix.IoctlGetTermios(fd, ioctlReadTermios) + return err == nil +} diff --git a/term_windows.go b/term_windows.go new file mode 100644 index 0000000..24f9d6d --- /dev/null +++ b/term_windows.go @@ -0,0 +1,15 @@ +// Copyright 2019 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 term + +import ( + "golang.org/x/sys/windows" +) + +func isTerminal(fd int) bool { + var st uint32 + err := windows.GetConsoleMode(windows.Handle(fd), &st) + return err == nil +}