[lxc-devel] [lxd/master] shared: Rewrite OpenPty without cgo

stgraber on Github lxc-bot at linuxcontainers.org
Fri May 8 22:25:48 UTC 2020


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 354 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200508/6ca6a002/attachment.bin>
-------------- next part --------------
From fc0d4c4158413248e940ce602a9080a6d60b256f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Fri, 8 May 2020 18:25:13 -0400
Subject: [PATCH] shared: Rewrite OpenPty without cgo
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 shared/util_linux.go     | 89 ++++++++++++++++++++++++++++++++++++++++
 shared/util_linux_cgo.go | 76 ----------------------------------
 2 files changed, 89 insertions(+), 76 deletions(-)

diff --git a/shared/util_linux.go b/shared/util_linux.go
index ded0dac39e..c739b42058 100644
--- a/shared/util_linux.go
+++ b/shared/util_linux.go
@@ -391,3 +391,92 @@ func DeviceTotalMemory() (int64, error) {
 
 	return -1, fmt.Errorf("Couldn't find MemTotal")
 }
+
+// OpenPty creates a new PTS pair, configures them and returns them.
+func OpenPty(uid, gid int64) (*os.File, *os.File, error) {
+	revert := true
+
+	// Create a PTS pair.
+	master, err := os.OpenFile("/dev/ptmx", os.O_RDWR, 0)
+	if err != nil {
+		return nil, nil, err
+	}
+	defer func() {
+		if revert {
+			master.Close()
+		}
+	}()
+
+	// Get the slave side.
+	id := 0
+	_, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(master.Fd()), unix.TIOCGPTN, uintptr(unsafe.Pointer(&id)))
+	if errno != 0 {
+		return nil, nil, unix.Errno(errno)
+	}
+
+	// Unlock the slave side.
+	val := 0
+	_, _, errno = unix.Syscall(unix.SYS_IOCTL, uintptr(master.Fd()), unix.TIOCSPTLCK, uintptr(unsafe.Pointer(&val)))
+	if errno != 0 {
+		return nil, nil, unix.Errno(errno)
+	}
+
+	// Open the slave.
+	slave, err := os.OpenFile(fmt.Sprintf("/dev/pts/%d", id), os.O_RDWR|unix.O_NOCTTY, 0)
+	if err != nil {
+		return nil, nil, err
+	}
+	defer func() {
+		if revert {
+			slave.Close()
+		}
+	}()
+
+	// Configure both sides
+	for _, entry := range []*os.File{master, slave} {
+		// Get termios.
+		t, err := unix.IoctlGetTermios(int(entry.Fd()), unix.TCGETS)
+		if err != nil {
+			return nil, nil, err
+		}
+
+		// Set flags.
+		t.Cflag |= unix.IMAXBEL
+		t.Cflag |= unix.IUTF8
+		t.Cflag |= unix.BRKINT
+		t.Cflag |= unix.IXANY
+		t.Cflag |= unix.HUPCL
+
+		// Set termios.
+		err = unix.IoctlSetTermios(int(entry.Fd()), unix.TCSETS, t)
+		if err != nil {
+			return nil, nil, err
+		}
+
+		// Set the default window size.
+		sz := &unix.Winsize{
+			Col: 80,
+			Row: 25,
+		}
+
+		err = unix.IoctlSetWinsize(int(entry.Fd()), unix.TIOCSWINSZ, sz)
+		if err != nil {
+			return nil, nil, err
+		}
+
+		// Set CLOEXEC.
+		_, _, errno = unix.Syscall(unix.SYS_FCNTL, uintptr(entry.Fd()), unix.F_SETFD, unix.FD_CLOEXEC)
+		if errno != 0 {
+			return nil, nil, unix.Errno(errno)
+		}
+	}
+
+	// Fix the ownership of the slave side.
+	err = os.Chown(slave.Name(), int(uid), int(gid))
+	if err != nil {
+		return nil, nil, err
+	}
+
+	revert = false
+	return master, slave, nil
+}
diff --git a/shared/util_linux_cgo.go b/shared/util_linux_cgo.go
index bb37c1f33a..e986dce8ee 100644
--- a/shared/util_linux_cgo.go
+++ b/shared/util_linux_cgo.go
@@ -4,7 +4,6 @@
 package shared
 
 import (
-	"errors"
 	"fmt"
 	"io"
 	"os"
@@ -42,63 +41,6 @@ import (
 // This is an adaption from https://codereview.appspot.com/4589049, to be
 // included in the stdlib with the stdlib's license.
 
-void configure_pty(int fd) {
-	struct termios term_settings;
-	struct winsize win;
-
-	if (tcgetattr(fd, &term_settings) < 0) {
-		fprintf(stderr, "Failed to get settings: %s\n", strerror(errno));
-		return;
-	}
-
-	term_settings.c_iflag |= IMAXBEL;
-	term_settings.c_iflag |= IUTF8;
-	term_settings.c_iflag |= BRKINT;
-	term_settings.c_iflag |= IXANY;
-
-	term_settings.c_cflag |= HUPCL;
-
-	if (tcsetattr(fd, TCSANOW, &term_settings) < 0) {
-		fprintf(stderr, "Failed to set settings: %s\n", strerror(errno));
-		return;
-	}
-
-	if (ioctl(fd, TIOCGWINSZ, &win) < 0) {
-		fprintf(stderr, "Failed to get the terminal size: %s\n", strerror(errno));
-		return;
-	}
-
-	win.ws_col = 80;
-	win.ws_row = 25;
-
-	if (ioctl(fd, TIOCSWINSZ, &win) < 0) {
-		fprintf(stderr, "Failed to set the terminal size: %s\n", strerror(errno));
-		return;
-	}
-
-	if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) {
-		fprintf(stderr, "Failed to set FD_CLOEXEC: %s\n", strerror(errno));
-		return;
-	}
-
-	return;
-}
-
-void create_pty(int *master, int *slave, uid_t uid, gid_t gid) {
-	if (openpty(master, slave, NULL, NULL, NULL) < 0) {
-		fprintf(stderr, "Failed to openpty: %s\n", strerror(errno));
-		return;
-	}
-
-	configure_pty(*master);
-	configure_pty(*slave);
-
-	if (fchown(*slave, uid, gid) < 0) {
-		fprintf(stderr, "Warning: error chowning pty to container root\n");
-		fprintf(stderr, "Continuing...\n");
-	}
-}
-
 int get_poll_revents(int lfd, int timeout, int flags, int *revents, int *saved_errno)
 {
 	int ret;
@@ -160,24 +102,6 @@ func GetPollRevents(fd int, timeout int, flags int) (int, int, error) {
 	return int(ret), int(revents), err
 }
 
-func OpenPty(uid, gid int64) (master *os.File, slave *os.File, err error) {
-	fd_master := C.int(-1)
-	fd_slave := C.int(-1)
-	rootUid := C.uid_t(uid)
-	rootGid := C.gid_t(gid)
-
-	C.create_pty(&fd_master, &fd_slave, rootUid, rootGid)
-
-	if fd_master == -1 || fd_slave == -1 {
-		return nil, nil, errors.New("Failed to create a new pts pair")
-	}
-
-	master = os.NewFile(uintptr(fd_master), "master")
-	slave = os.NewFile(uintptr(fd_slave), "slave")
-
-	return master, slave, nil
-}
-
 // UserId is an adaption from https://codereview.appspot.com/4589049.
 func UserId(name string) (int, error) {
 	var pw C.struct_passwd


More information about the lxc-devel mailing list