Permalink
Browse files

Re-implement terminal functions through cgo

This fixes exec and other functions on ppc64el.

Closes #1621

Signed-off-by: Stéphane Graber <stgraber@ubuntu.com>
  • Loading branch information...
1 parent 0582583 commit 3cd9adce8d3dafc679f5ef19a5cb3a4410e19208 @stgraber stgraber committed Feb 19, 2016
Showing with 141 additions and 19 deletions.
  1. +4 −4 lxc/config.go
  2. +7 −7 lxc/exec.go
  3. +2 −3 lxc/file.go
  4. +2 −2 lxc/image.go
  5. +3 −3 lxc/profile.go
  6. +1 −0 lxc/remote.go
  7. +79 −0 shared/termios/termios.go
  8. +43 −0 shared/termios/termios_windows.go
View
@@ -10,13 +10,13 @@ import (
"syscall"
"github.com/olekukonko/tablewriter"
- "golang.org/x/crypto/ssh/terminal"
"gopkg.in/yaml.v2"
"github.com/lxc/lxd"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/gnuflag"
"github.com/lxc/lxd/shared/i18n"
+ "github.com/lxc/lxd/shared/termios"
)
type configCmd struct {
@@ -106,7 +106,7 @@ func (c *configCmd) doSet(config *lxd.Config, args []string, unset bool) error {
key := args[2]
value := args[3]
- if !terminal.IsTerminal(int(syscall.Stdin)) && value == "-" {
+ if !termios.IsTerminal(int(syscall.Stdin)) && value == "-" {
buf, err := ioutil.ReadAll(os.Stdin)
if err != nil {
return fmt.Errorf(i18n.G("Can't read from stdin: %s"), err)
@@ -446,7 +446,7 @@ func (c *configCmd) run(config *lxd.Config, args []string) error {
func (c *configCmd) doContainerConfigEdit(client *lxd.Client, cont string) error {
// If stdin isn't a terminal, read text from it
- if !terminal.IsTerminal(int(syscall.Stdin)) {
+ if !termios.IsTerminal(int(syscall.Stdin)) {
contents, err := ioutil.ReadAll(os.Stdin)
if err != nil {
return err
@@ -509,7 +509,7 @@ func (c *configCmd) doContainerConfigEdit(client *lxd.Client, cont string) error
func (c *configCmd) doDaemonConfigEdit(client *lxd.Client) error {
// If stdin isn't a terminal, read text from it
- if !terminal.IsTerminal(int(syscall.Stdin)) {
+ if !termios.IsTerminal(int(syscall.Stdin)) {
contents, err := ioutil.ReadAll(os.Stdin)
if err != nil {
return err
View
@@ -9,12 +9,12 @@ import (
"syscall"
"github.com/gorilla/websocket"
- "golang.org/x/crypto/ssh/terminal"
"github.com/lxc/lxd"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/gnuflag"
"github.com/lxc/lxd/shared/i18n"
+ "github.com/lxc/lxd/shared/termios"
)
type envFlag []string
@@ -54,7 +54,7 @@ func (c *execCmd) flags() {
}
func (c *execCmd) sendTermSize(control *websocket.Conn) error {
- width, height, err := terminal.GetSize(int(syscall.Stdout))
+ width, height, err := termios.GetSize(int(syscall.Stdout))
if err != nil {
return err
}
@@ -118,16 +118,16 @@ func (c *execCmd) run(config *lxd.Config, args []string) error {
} else if c.modeFlag == "non-interactive" {
interactive = false
} else {
- interactive = terminal.IsTerminal(cfd)
+ interactive = termios.IsTerminal(cfd)
}
- var oldttystate *terminal.State
+ var oldttystate *termios.State
if interactive {
- oldttystate, err = terminal.MakeRaw(cfd)
+ oldttystate, err = termios.MakeRaw(cfd)
if err != nil {
return err
}
- defer terminal.Restore(cfd, oldttystate)
+ defer termios.Restore(cfd, oldttystate)
}
handler := c.controlSocketHandler
@@ -149,7 +149,7 @@ func (c *execCmd) run(config *lxd.Config, args []string) error {
* Additionally, since os.Exit() exits without running deferred
* functions, we restore the terminal explicitly.
*/
- terminal.Restore(cfd, oldttystate)
+ termios.Restore(cfd, oldttystate)
}
/* we get the result of waitpid() here so we need to transform it */
View
@@ -11,12 +11,11 @@ import (
"strings"
"syscall"
- "golang.org/x/crypto/ssh/terminal"
-
"github.com/lxc/lxd"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/gnuflag"
"github.com/lxc/lxd/shared/i18n"
+ "github.com/lxc/lxd/shared/termios"
)
type fileCmd struct {
@@ -231,7 +230,7 @@ func (c *fileCmd) edit(config *lxd.Config, args []string) error {
}
// If stdin isn't a terminal, read text from it
- if !terminal.IsTerminal(int(syscall.Stdin)) {
+ if !termios.IsTerminal(int(syscall.Stdin)) {
return c.push(config, append([]string{os.Stdin.Name()}, args[0]))
}
View
@@ -10,13 +10,13 @@ import (
"syscall"
"github.com/olekukonko/tablewriter"
- "golang.org/x/crypto/ssh/terminal"
"gopkg.in/yaml.v2"
"github.com/lxc/lxd"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/gnuflag"
"github.com/lxc/lxd/shared/i18n"
+ "github.com/lxc/lxd/shared/termios"
)
type SortImage [][]string
@@ -588,7 +588,7 @@ func (c *imageCmd) showAliases(aliases shared.ImageAliases) error {
func (c *imageCmd) doImageEdit(client *lxd.Client, image string) error {
// If stdin isn't a terminal, read text from it
- if !terminal.IsTerminal(int(syscall.Stdin)) {
+ if !termios.IsTerminal(int(syscall.Stdin)) {
contents, err := ioutil.ReadAll(os.Stdin)
if err != nil {
return err
View
@@ -7,12 +7,12 @@ import (
"strings"
"syscall"
- "golang.org/x/crypto/ssh/terminal"
"gopkg.in/yaml.v2"
"github.com/lxc/lxd"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/i18n"
+ "github.com/lxc/lxd/shared/termios"
)
type profileCmd struct {
@@ -143,7 +143,7 @@ func (c *profileCmd) doProfileCreate(client *lxd.Client, p string) error {
func (c *profileCmd) doProfileEdit(client *lxd.Client, p string) error {
// If stdin isn't a terminal, read text from it
- if !terminal.IsTerminal(int(syscall.Stdin)) {
+ if !termios.IsTerminal(int(syscall.Stdin)) {
contents, err := ioutil.ReadAll(os.Stdin)
if err != nil {
return err
@@ -313,7 +313,7 @@ func (c *profileCmd) doProfileSet(client *lxd.Client, p string, args []string) e
value = args[1]
}
- if !terminal.IsTerminal(int(syscall.Stdin)) && value == "-" {
+ if !termios.IsTerminal(int(syscall.Stdin)) && value == "-" {
buf, err := ioutil.ReadAll(os.Stdin)
if err != nil {
return fmt.Errorf("Can't read from stdin: %s", err)
View
@@ -13,6 +13,7 @@ import (
"strings"
"github.com/olekukonko/tablewriter"
+
"golang.org/x/crypto/ssh/terminal"
"github.com/lxc/lxd"
View
@@ -0,0 +1,79 @@
+// +build !windows
+
+package termios
+
+import (
+ "syscall"
+ "unsafe"
+
+ "github.com/lxc/lxd/shared"
+)
+
+// #include <termios.h>
+import "C"
+
+type State struct {
+ Termios syscall.Termios
+}
+
+func IsTerminal(fd int) bool {
+ _, err := GetState(fd)
+ return err == nil
+}
+
+func GetState(fd int) (*State, error) {
+ termios := syscall.Termios{}
+
+ ret, err := C.tcgetattr(C.int(fd), (*C.struct_termios)(unsafe.Pointer(&termios)))
+ if ret != 0 {
+ return nil, err.(syscall.Errno)
+ }
+
+ state := State{}
+ state.Termios = termios
+
+ return &state, nil
+}
+
+func GetSize(fd int) (int, int, error) {
+ var dimensions [4]uint16
+
+ if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&dimensions)), 0, 0, 0); err != 0 {
+ return -1, -1, err
+ }
+
+ return int(dimensions[1]), int(dimensions[0]), nil
+}
+
+func MakeRaw(fd int) (*State, error) {
+ var err error
+ var oldState, newState *State
+
+ oldState, err = GetState(fd)
+ if err != nil {
+ return nil, err
+ }
+
+ err = shared.DeepCopy(&oldState, &newState)
+ if err != nil {
+ return nil, err
+ }
+
+ C.cfmakeraw((*C.struct_termios)(unsafe.Pointer(&newState.Termios)))
+
+ err = Restore(fd, newState)
+ if err != nil {
+ return nil, err
+ }
+
+ return oldState, nil
+}
+
+func Restore(fd int, state *State) error {
+ ret, err := C.tcsetattr(C.int(fd), C.TCSANOW, (*C.struct_termios)(unsafe.Pointer(&state.Termios)))
+ if ret != 0 {
+ return err.(syscall.Errno)
+ }
+
+ return nil
+}
@@ -0,0 +1,43 @@
+// +build windows
+
+package termios
+
+import (
+ "golang.org/x/crypto/ssh/terminal"
+)
+
+type State terminal.State
+
+func IsTerminal(fd int) bool {
+ return terminal.IsTerminal(fd)
+}
+
+func GetState(fd int) (*State, error) {
+ state, err := terminal.GetState(fd)
+ if err != nil {
+ return nil, err
+ }
+
+ currentState := State(*state)
+ return &currentState, nil
+}
+
+func GetSize(fd int) (int, int, error) {
+ return terminal.GetSize(fd)
+}
+
+func MakeRaw(fd int) (*State, error) {
+ state, err := terminal.MakeRaw(fd)
+ if err != nil {
+ return nil, err
+ }
+
+ oldState := State(*state)
+ return &oldState, nil
+}
+
+func Restore(fd int, state *State) error {
+ newState := terminal.State(*state)
+
+ return terminal.Restore(fd, &newState)
+}

0 comments on commit 3cd9adc

Please sign in to comment.