[lxc-devel] [lxd/master] Send window size initially

tych0 on Github lxc-bot at linuxcontainers.org
Fri Mar 25 19:19:59 UTC 2016


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 301 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20160325/9030c2e7/attachment.bin>
-------------- next part --------------
From a2170a6b96b69bdf30e87f7924a7a1c99f8d9fca Mon Sep 17 00:00:00 2001
From: Tycho Andersen <tycho.andersen at canonical.com>
Date: Fri, 25 Mar 2016 13:15:48 -0600
Subject: [PATCH 1/2] exec: send initial window size

Signed-off-by: Tycho Andersen <tycho.andersen at canonical.com>
---
 client.go             |  3 ++-
 doc/rest-api.md       |  4 +++-
 lxc/exec.go           |  7 ++++++-
 lxd/container_exec.go | 10 ++++++++++
 4 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/client.go b/client.go
index bc4f3fb..e958cf8 100644
--- a/client.go
+++ b/client.go
@@ -1395,7 +1395,8 @@ func (c *Client) Monitor(types []string, handler func(interface{})) error {
 // output is sent to the output buffers.
 func (c *Client) Exec(name string, cmd []string, env map[string]string,
 	stdin io.ReadCloser, stdout io.WriteCloser,
-	stderr io.WriteCloser, controlHandler func(*Client, *websocket.Conn)) (int, error) {
+	stderr io.WriteCloser, controlHandler func(*Client, *websocket.Conn),
+	width int, height int) (int, error) {
 
 	if c.Remote.Public {
 		return -1, fmt.Errorf("This function isn't supported by public remotes.")
diff --git a/doc/rest-api.md b/doc/rest-api.md
index 137455d..af3f368 100644
--- a/doc/rest-api.md
+++ b/doc/rest-api.md
@@ -926,7 +926,9 @@ Input (run bash):
         "command": ["/bin/bash"],       # Command and arguments
         "environment": {},              # Optional extra environment variables to set
         "wait-for-websocket": false,    # Whether to wait for a connection before starting the process
-        "interactive": true             # Whether to allocate a pts device instead of PIPEs
+        "interactive": true,            # Whether to allocate a pts device instead of PIPEs
+        "width": 80,                    # initial width of the terminal (optional)
+        "height": 25,                   # initial height of the terminal (optional)
     }
 
 `wait-for-websocket` indicates whether the operation should block and wait for
diff --git a/lxc/exec.go b/lxc/exec.go
index d218fd5..894cd9d 100644
--- a/lxc/exec.go
+++ b/lxc/exec.go
@@ -137,8 +137,13 @@ func (c *execCmd) run(config *lxd.Config, args []string) error {
 		handler = nil
 	}
 
+	width, height, err := termios.GetSize(int(syscall.Stdout))
+	if err != nil {
+		return err
+	}
+
 	stdout := c.getStdout()
-	ret, err := d.Exec(name, args[1:], env, os.Stdin, stdout, os.Stderr, handler)
+	ret, err := d.Exec(name, args[1:], env, os.Stdin, stdout, os.Stderr, handler, width, height)
 	if err != nil {
 		return err
 	}
diff --git a/lxd/container_exec.go b/lxd/container_exec.go
index 6780089..27c9ea1 100644
--- a/lxd/container_exec.go
+++ b/lxd/container_exec.go
@@ -22,6 +22,8 @@ type commandPostContent struct {
 	WaitForWS   bool              `json:"wait-for-websocket"`
 	Interactive bool              `json:"interactive"`
 	Environment map[string]string `json:"environment"`
+	Width       int               `json:"width"`
+	Height      int               `json:"height"`
 }
 
 func runCommand(container *lxc.Container, command []string, options lxc.AttachOptions) (int, error) {
@@ -46,6 +48,8 @@ type execWs struct {
 	controlConnected chan bool
 	interactive      bool
 	fds              map[int]string
+	width            int
+	height           int
 }
 
 func (s *execWs) Metadata() interface{} {
@@ -112,6 +116,10 @@ func (s *execWs) Do(op *operation) error {
 		s.options.StdinFd = ttys[0].Fd()
 		s.options.StdoutFd = ttys[0].Fd()
 		s.options.StderrFd = ttys[0].Fd()
+
+		if s.width > 0 && s.height > 0 {
+			shared.SetSize(int(ptys[0].Fd()), s.width, s.height)
+		}
 	} else {
 		ttys = make([]*os.File, 3)
 		ptys = make([]*os.File, 3)
@@ -317,6 +325,8 @@ func containerExecPost(d *Daemon, r *http.Request) Response {
 
 		ws.command = post.Command
 		ws.container = c.LXContainerGet()
+		ws.width = post.Width
+		ws.height = post.Height
 
 		resources := map[string][]string{}
 		resources["containers"] = []string{ws.container.Name()}

From cb354a483d3b28b18b810b542cdf0684f1cfd77d Mon Sep 17 00:00:00 2001
From: Tycho Andersen <tycho.andersen at canonical.com>
Date: Fri, 25 Mar 2016 13:16:58 -0600
Subject: [PATCH 2/2] exec client: don't always send window size

Now that we don't rely on the first window size send to set the window
size, let's only send it when there is actually a SIGWINCH.

Signed-off-by: Tycho Andersen <tycho.andersen at canonical.com>
---
 lxc/exec_unix.go | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/lxc/exec_unix.go b/lxc/exec_unix.go
index a4fa8db..9b46add 100644
--- a/lxc/exec_unix.go
+++ b/lxc/exec_unix.go
@@ -23,15 +23,15 @@ func (c *execCmd) controlSocketHandler(d *lxd.Client, control *websocket.Conn) {
 	signal.Notify(ch, syscall.SIGWINCH)
 
 	for {
+		sig := <-ch
+
+		shared.Debugf("Received '%s signal', updating window geometry.", sig)
+
 		err := c.sendTermSize(control)
 		if err != nil {
 			shared.Debugf("error setting term size %s", err)
 			break
 		}
-
-		sig := <-ch
-
-		shared.Debugf("Received '%s signal', updating window geometry.", sig)
 	}
 
 	closeMsg := websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")


More information about the lxc-devel mailing list