The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/lxc/pull/1728

This e-mail was sent by the LXC bot, direct replies will not reach the author
unless they happen to be subscribed to this list.

=== Description (from pull-request) ===
Closes #1620.

Signed-off-by: Christian Brauner <[email protected]>
From 154750341d37deeca3a5e65eb60e118e55d03383 Mon Sep 17 00:00:00 2001
From: Christian Brauner <[email protected]>
Date: Wed, 2 Aug 2017 22:21:56 +0200
Subject: [PATCH 1/5] conf: lxc-setup()

non-functional changes

Signed-off-by: Christian Brauner <[email protected]>
---
 src/lxc/conf.c | 156 +++++++++++++++++++++++++++++++++++----------------------
 1 file changed, 97 insertions(+), 59 deletions(-)

diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index 9508f6946..651ba7844 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -4180,51 +4180,62 @@ static int lxc_send_ttys_to_parent(struct lxc_handler 
*handler)
 
 int lxc_setup(struct lxc_handler *handler)
 {
+       int ret;
        const char *name = handler->name;
-       struct lxc_conf *lxc_conf = handler->conf;
        const char *lxcpath = handler->lxcpath;
+       struct lxc_conf *lxc_conf = handler->conf;
 
-       if (do_rootfs_setup(lxc_conf, name, lxcpath) < 0) {
-               ERROR("Error setting up rootfs mount after spawn");
+       ret = do_rootfs_setup(lxc_conf, name, lxcpath);
+       if (ret < 0) {
+               ERROR("Failed to set up rootfs");
                return -1;
        }
 
        if (lxc_conf->inherit_ns_fd[LXC_NS_UTS] == -1) {
-               if (setup_utsname(lxc_conf->utsname)) {
-                       ERROR("failed to setup the utsname for '%s'", name);
+               ret = setup_utsname(lxc_conf->utsname);
+               if (ret < 0) {
+                       ERROR("Failed to set up uts name");
                        return -1;
                }
        }
 
-       if (lxc_setup_networks_in_child_namespaces(lxc_conf,
-                                                  &lxc_conf->network)) {
-               ERROR("failed to setup the network for '%s'", name);
+       ret = lxc_setup_networks_in_child_namespaces(lxc_conf, 
&lxc_conf->network);
+       if (ret < 0) {
+               ERROR("Failed to set up networking");
                return -1;
        }
 
        if (lxc_conf->autodev > 0) {
-               if (mount_autodev(name, &lxc_conf->rootfs, lxcpath)) {
-                       ERROR("failed to mount /dev in the container");
+               ret = mount_autodev(name, &lxc_conf->rootfs, lxcpath);
+               if (ret < 0) {
+                       ERROR("Failed to set up \"/dev\"");
                        return -1;
                }
        }
 
-       /* do automatic mounts (mainly /proc and /sys), but exclude
-        * those that need to wait until other stuff has finished
+       /* Do automatic mounts (mainly /proc and /sys), but exclude those that
+        * need to wait until other stuff has finished.
         */
-       if (lxc_mount_auto_mounts(lxc_conf, lxc_conf->auto_mounts & 
~LXC_AUTO_CGROUP_MASK, handler) < 0) {
-               ERROR("failed to setup the automatic mounts for '%s'", name);
+       ret = lxc_mount_auto_mounts(lxc_conf, lxc_conf->auto_mounts & 
~LXC_AUTO_CGROUP_MASK, handler);
+       if (ret < 0) {
+               ERROR("Failed to set up initial automatic mounts");
                return -1;
        }
 
-       if (setup_mount(lxc_conf, &lxc_conf->rootfs, lxc_conf->fstab, name, 
lxcpath)) {
-               ERROR("failed to setup the mounts for '%s'", name);
+       ret = setup_mount(lxc_conf, &lxc_conf->rootfs, lxc_conf->fstab, name,
+                         lxcpath);
+       if (ret < 0) {
+               ERROR("Failed to set up fstab mounts");
                return -1;
        }
 
-       if (!lxc_list_empty(&lxc_conf->mount_list) && 
setup_mount_entries(lxc_conf, &lxc_conf->rootfs, &lxc_conf->mount_list, name, 
lxcpath)) {
-               ERROR("failed to setup the mount entries for '%s'", name);
-               return -1;
+       if (!lxc_list_empty(&lxc_conf->mount_list)) {
+               ret = setup_mount_entries(lxc_conf, &lxc_conf->rootfs,
+                                         &lxc_conf->mount_list, name, lxcpath);
+               if (ret < 0) {
+                       ERROR("Failed to set up mount entries");
+                       return -1;
+               }
        }
 
        /* Make sure any start hooks are in the container */
@@ -4238,94 +4249,121 @@ int lxc_setup(struct lxc_handler *handler)
         * before, /sys could not have been mounted
         * (is either mounted automatically or via fstab entries)
         */
-       if (lxc_mount_auto_mounts(lxc_conf, lxc_conf->auto_mounts & 
LXC_AUTO_CGROUP_MASK, handler) < 0) {
-               ERROR("failed to setup the automatic mounts for '%s'", name);
+       ret = lxc_mount_auto_mounts(lxc_conf, lxc_conf->auto_mounts & 
LXC_AUTO_CGROUP_MASK, handler);
+       if (ret < 0) {
+               ERROR("Failed to set up remaining automatic mounts");
                return -1;
        }
 
-       if (run_lxc_hooks(name, "mount", lxc_conf, lxcpath, NULL)) {
-               ERROR("failed to run mount hooks for container '%s'.", name);
+       ret = run_lxc_hooks(name, "mount", lxc_conf, lxcpath, NULL);
+       if (ret < 0) {
+               ERROR("Failed to run mount hooks");
                return -1;
        }
 
        if (lxc_conf->autodev > 0) {
-               if (run_lxc_hooks(name, "autodev", lxc_conf, lxcpath, NULL)) {
-                       ERROR("failed to run autodev hooks for container 
'%s'.", name);
+               ret = run_lxc_hooks(name, "autodev", lxc_conf, lxcpath, NULL);
+               if (ret < 0) {
+                       ERROR("Failed to run autodev hooks");
                        return -1;
                }
 
-               if (lxc_fill_autodev(&lxc_conf->rootfs)) {
-                       ERROR("failed to populate /dev in the container");
+               ret = lxc_fill_autodev(&lxc_conf->rootfs);
+               if (ret < 0) {
+                       ERROR("Failed to populate \"/dev\"");
                        return -1;
                }
        }
 
-       if (!lxc_conf->is_execute && lxc_setup_console(&lxc_conf->rootfs, 
&lxc_conf->console, lxc_conf->ttydir)) {
-               ERROR("failed to setup the console for '%s'", name);
-               return -1;
-       }
+       if (!lxc_conf->is_execute) {
+               ret = lxc_setup_console(&lxc_conf->rootfs, &lxc_conf->console,
+                                       lxc_conf->ttydir);
+               if (ret < 0) {
+                       ERROR("Failed to set up console");
+                       return -1;
+               }
 
-       if (!lxc_conf->is_execute && setup_dev_symlinks(&lxc_conf->rootfs)) {
-               ERROR("failed to setup /dev symlinks for '%s'", name);
-               return -1;
+               ret = setup_dev_symlinks(&lxc_conf->rootfs);
+               if (ret < 0) {
+                       ERROR("Failed to setup \"/dev\" symlinks");
+                       return -1;
+               }
        }
 
        /* mount /proc if it's not already there */
-       if (lxc_create_tmp_proc_mount(lxc_conf) < 0) {
-               ERROR("failed to LSM mount proc for '%s'", name);
+       ret = lxc_create_tmp_proc_mount(lxc_conf);
+       if (ret < 0) {
+               ERROR("Failed to create temporary proc mount for LSM");
                return -1;
        }
 
-       if (setup_pivot_root(&lxc_conf->rootfs)) {
-               ERROR("failed to set rootfs for '%s'", name);
+       ret = setup_pivot_root(&lxc_conf->rootfs);
+       if (ret < 0) {
+               ERROR("Failed to set up rootfs");
                return -1;
        }
 
-       if (lxc_setup_devpts(lxc_conf->pts)) {
-               ERROR("failed to setup the new pts instance");
+       ret = lxc_setup_devpts(lxc_conf->pts);
+       if (ret < 0) {
+               ERROR("Failed to set up new devpts instance");
                return -1;
        }
 
-       if (lxc_create_tty(name, lxc_conf)) {
-               ERROR("failed to create the ttys");
+       ret = lxc_create_tty(name, lxc_conf);
+       if (ret < 0) {
+               ERROR("Failed to allocate ttys");
                return -1;
        }
 
-       if (lxc_send_ttys_to_parent(handler) < 0) {
-               ERROR("failure sending console info to parent");
+       ret = lxc_send_ttys_to_parent(handler);
+       if (ret < 0) {
+               ERROR("Failed to send ttys to parent");
                return -1;
        }
 
-       if (!lxc_conf->is_execute && lxc_setup_tty(lxc_conf)) {
-               ERROR("failed to setup the ttys for '%s'", name);
-               return -1;
+       if (!lxc_conf->is_execute) {
+               ret = lxc_setup_tty(lxc_conf);
+               if (ret < 0) {
+                       ERROR("Failed to set up ttys");
+                       return -1;
+               }
        }
 
-       if (lxc_conf->pty_names && setenv("container_ttys", 
lxc_conf->pty_names, 1))
-               SYSERROR("failed to set environment variable for container 
ptys");
+       if (lxc_conf->pty_names) {
+               ret = setenv("container_ttys", lxc_conf->pty_names, 1);
+               if (ret < 0)
+                       SYSERROR("Failed to set environment variable for ptys");
+       }
 
 
-       if (setup_personality(lxc_conf->personality)) {
-               ERROR("failed to setup personality");
+       ret = setup_personality(lxc_conf->personality);
+       if (ret < 0) {
+               ERROR("Failed to setup personality");
                return -1;
        }
 
        if (!lxc_list_empty(&lxc_conf->keepcaps)) {
                if (!lxc_list_empty(&lxc_conf->caps)) {
-                       ERROR("Container requests lxc.cap.drop and 
lxc.cap.keep: either use lxc.cap.drop or lxc.cap.keep, not both.");
+                       ERROR("Container requests lxc.cap.drop and "
+                             "lxc.cap.keep: either use lxc.cap.drop or "
+                             "lxc.cap.keep, not both");
                        return -1;
                }
-               if (dropcaps_except(&lxc_conf->keepcaps)) {
-                       ERROR("failed to keep requested caps");
+
+               ret = dropcaps_except(&lxc_conf->keepcaps);
+               if (ret < 0) {
+                       ERROR("Failed to keep requested capabilities");
+                       return -1;
+               }
+       } else {
+               ret = setup_caps(&lxc_conf->caps);
+               if (ret < 0) {
+                       ERROR("Failed to drop requested capabilities");
                        return -1;
                }
-       } else if (setup_caps(&lxc_conf->caps)) {
-               ERROR("failed to drop capabilities");
-               return -1;
        }
 
-       NOTICE("Container \"%s\" is set up", name);
-
+       NOTICE("Finished setting up container");
        return 0;
 }
 

From 534efb2ce57c426aa5ac583afba8eff0893cdf9a Mon Sep 17 00:00:00 2001
From: Christian Brauner <[email protected]>
Date: Thu, 3 Aug 2017 17:42:00 +0200
Subject: [PATCH 2/5] conf: non-functional changes

Signed-off-by: Christian Brauner <[email protected]>
---
 src/lxc/conf.h | 57 +++++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 37 insertions(+), 20 deletions(-)

diff --git a/src/lxc/conf.h b/src/lxc/conf.h
index 4d3f6d78f..c1c9543ff 100644
--- a/src/lxc/conf.h
+++ b/src/lxc/conf.h
@@ -329,8 +329,10 @@ struct lxc_conf {
        struct lxc_list caps;
        struct lxc_list keepcaps;
        struct lxc_tty_info tty_info;
-       /* Comma-separated list of lxc.tty.max pty names. */
+
+       /* comma-separated list of lxc.tty.max pty names */
        char *pty_names;
+
        struct lxc_console console;
        struct lxc_rootfs rootfs;
        char *ttydir;
@@ -341,24 +343,35 @@ struct lxc_conf {
        unsigned int lsm_aa_allow_incomplete;
        char *lsm_se_context;
        int tmp_umount_proc;
-       char *seccomp;  // filename with the seccomp rules
+       char *seccomp;
 #if HAVE_SCMP_FILTER_CTX
        scmp_filter_ctx seccomp_ctx;
 #endif
        int maincmd_fd;
-       unsigned int autodev;  // if 1, mount and fill a /dev at start
-       int haltsignal; // signal used to halt container
-       int rebootsignal; // signal used to reboot container
-       int stopsignal; // signal used to hard stop container
-       char *rcfile;   // Copy of the top level rcfile we read
-
-       // Logfile and logleve can be set in a container config file.
-       // Those function as defaults.  The defaults can be overriden
-       // by command line.  However we don't want the command line
-       // specified values to be saved on c->save_config().  So we
-       // store the config file specified values here.
-       char *logfile;  // the logfile as specifed in config
-       int loglevel;   // loglevel as specifed in config (if any)
+
+       /* if 1, mount and fill a /dev at start */
+       unsigned int autodev;
+
+       /* signal used to halt container */
+       int haltsignal;
+
+       /* signal used to reboot container */
+       int rebootsignal;
+
+       /* signal used to hard stop container */
+       int stopsignal;
+
+       /* Copy of the top level rcfile we read */
+       char *rcfile;
+
+       /* Logfile and loglevel can be set in a container config file. Those
+        * function as defaults. The defaults can be overriden by command line.
+        * However we don't want the command line specified values to be saved
+        * on c->save_config(). So we store the config file specified values
+        * here.
+        */
+       char *logfile;
+       int loglevel;
        int logfd;
 
        int inherit_ns_fd[LXC_NS_MAX];
@@ -377,11 +390,13 @@ struct lxc_conf {
 
        /* list of included files */
        struct lxc_list includes;
+
        /* config entries which are not "lxc.*" are aliens */
        struct lxc_list aliens;
 
-       /* list of environment variables we'll add to the container when
-        * started */
+       /* List of environment variables we'll add to the container when
+        * started.
+        */
        struct lxc_list environment;
 
        /* text representation of the config file */
@@ -391,8 +406,9 @@ struct lxc_conf {
        /* init command */
        char *init_cmd;
 
-       /* if running in a new user namespace, the UID/GID that init and COMMAND
-        * should run under when using lxc-execute */
+       /* If running in a new user namespace, the UID/GID that init and COMMAND
+        * should run under when using lxc-execute.
+        */
        uid_t init_uid;
        gid_t init_gid;
 
@@ -400,7 +416,8 @@ struct lxc_conf {
        unsigned int ephemeral;
 
        /* The facility to pass to syslog. Let's users establish as what type of
-        * program liblxc is supposed to write to the syslog. */
+        * program liblxc is supposed to write to the syslog.
+        */
        char *syslog;
 
        /* Whether PR_SET_NO_NEW_PRIVS will be set for the container. */

From 1d732b29e33730f5bcf320ebf69b8d07a1212c33 Mon Sep 17 00:00:00 2001
From: Christian Brauner <[email protected]>
Date: Thu, 3 Aug 2017 17:47:54 +0200
Subject: [PATCH 3/5] conf: allocate O_PATH /dev/pts/ptmx file descriptor

Signed-off-by: Christian Brauner <[email protected]>
---
 src/lxc/conf.c  | 30 ++++++++++++++++++++++++++++++
 src/lxc/conf.h  |  7 +++++++
 src/lxc/start.c |  8 ++++++++
 3 files changed, 45 insertions(+)

diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index 651ba7844..72569edea 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -1427,6 +1427,18 @@ static int lxc_setup_devpts(int num_pts)
        return 0;
 }
 
+static int lxc_allocate_dev_ptmx_opath_fd(struct lxc_conf *conf)
+{
+       int fd;
+
+       fd = open("/dev/pts/ptmx", O_PATH);
+       if (fd < 0)
+               return -1;
+
+       conf->dev_ptmx.opath_fd = fd;
+       return 0;
+}
+
 static int setup_personality(int persona)
 {
        #if HAVE_SYS_PERSONALITY_H
@@ -2769,6 +2781,7 @@ struct lxc_conf *lxc_conf_init(void)
         * default to running as UID/GID 0 when using lxc-execute */
        new->init_uid = 0;
        new->init_gid = 0;
+       new->dev_ptmx.opath_fd = -1;
 
        return new;
 }
@@ -4309,6 +4322,21 @@ int lxc_setup(struct lxc_handler *handler)
                return -1;
        }
 
+       /* Allocate "/dev/pts/ptmx" O_PATH file descriptor. */
+       ret = lxc_allocate_dev_ptmx_opath_fd(lxc_conf);
+       if (ret < 0) {
+               ERROR("Failed to allocate \"/dev/pts/ptmx\" file descriptor");
+               return -1;
+       }
+
+       /* Send "/dev/pts/ptmx" O_PATH file descriptor to parent. */
+       ret = lxc_abstract_unix_send_fds(handler->ttysock[0],
+                                        &lxc_conf->dev_ptmx.opath_fd, 1, NULL, 
0);
+       if (ret < 0) {
+               ERROR("Failed to send \"/dev/pts/ptmx\" file descriptor");
+               return -1;
+       }
+
        ret = lxc_create_tty(name, lxc_conf);
        if (ret < 0) {
                ERROR("Failed to allocate ttys");
@@ -4644,6 +4672,8 @@ void lxc_conf_free(struct lxc_conf *conf)
        lxc_clear_aliens(conf);
        lxc_clear_environment(conf);
        lxc_clear_limits(conf, "lxc.prlimit");
+       if (conf->dev_ptmx.opath_fd >= 0)
+               close(conf->dev_ptmx.opath_fd);
        free(conf);
 }
 
diff --git a/src/lxc/conf.h b/src/lxc/conf.h
index c1c9543ff..73b3a0d5a 100644
--- a/src/lxc/conf.h
+++ b/src/lxc/conf.h
@@ -311,6 +311,11 @@ struct saved_nic {
        char *orig_name;
 };
 
+/* O_PATH File descriptor */
+struct lxc_dev_ptmx {
+       int opath_fd;
+};
+
 struct lxc_conf {
        int is_execute;
        char *fstab;
@@ -425,6 +430,8 @@ struct lxc_conf {
 
        /* RLIMIT_* limits */
        struct lxc_list limits;
+
+       struct lxc_dev_ptmx dev_ptmx;
 };
 
 #ifdef HAVE_TLS
diff --git a/src/lxc/start.c b/src/lxc/start.c
index d2a054bfc..7e8156662 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -1419,6 +1419,14 @@ static int lxc_spawn(struct lxc_handler *handler)
        if (lxc_sync_barrier_child(handler, LXC_SYNC_POST_CGROUP))
                return -1;
 
+       /* Receive "/dev/pts/ptmx" O_PATH file descriptor from child. */
+       if (lxc_abstract_unix_recv_fds(handler->ttysock[1],
+                                      &handler->conf->dev_ptmx.opath_fd, 1, 
NULL,
+                                      0) < 0) {
+               ERROR("Failed to send \"/dev/pts/ptmx\" file descriptor");
+               return -1;
+       }
+
        /* Read tty fds allocated by child. */
        if (lxc_recv_ttys_from_child(handler) < 0) {
                ERROR("Failed to receive tty info from child process.");

From 078d81f3418cabc5372e9bf6ec05f5c101e982f5 Mon Sep 17 00:00:00 2001
From: Christian Brauner <[email protected]>
Date: Thu, 3 Aug 2017 19:55:32 +0200
Subject: [PATCH 4/5] commands: non-functional changes

Signed-off-by: Christian Brauner <[email protected]>
---
 src/lxc/commands.c | 30 ++++++++++++++++--------------
 1 file changed, 16 insertions(+), 14 deletions(-)

diff --git a/src/lxc/commands.c b/src/lxc/commands.c
index c6ece2cc7..416388ad8 100644
--- a/src/lxc/commands.c
+++ b/src/lxc/commands.c
@@ -21,33 +21,35 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
-#include <stdio.h>
+#include "config.h"
+
 #include <errno.h>
-#include <unistd.h>
-#include <signal.h>
 #include <fcntl.h>
+#include <malloc.h>
 #include <poll.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/param.h>
 #include <sys/socket.h>
 #include <sys/un.h>
-#include <sys/param.h>
-#include <malloc.h>
-#include <stdlib.h>
 
-#include "log.h"
-#include "lxc.h"
-#include "conf.h"
-#include "start.h"     /* for struct lxc_handler */
-#include "utils.h"
+#include "af_unix.h"
 #include "cgroup.h"
 #include "commands.h"
 #include "commands_utils.h"
-#include "console.h"
+#include "conf.h"
+#include "config.h"
 #include "confile.h"
+#include "console.h"
+#include "log.h"
+#include "lxc.h"
 #include "lxclock.h"
 #include "mainloop.h"
 #include "monitor.h"
-#include "af_unix.h"
-#include "config.h"
+#include "start.h" /* for struct lxc_handler */
+#include "utils.h"
 
 /*
  * This file provides the different functions for clients to

From 6abc60506a94d94a0f56f6730102610cc0b4a009 Mon Sep 17 00:00:00 2001
From: Christian Brauner <[email protected]>
Date: Thu, 3 Aug 2017 19:55:47 +0200
Subject: [PATCH 5/5] commands: add LXC_CMD_OPENPTY

Closes #1620.

Signed-off-by: Christian Brauner <[email protected]>
---
 src/lxc/commands.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/lxc/commands.h |   9 +++++
 src/lxc/conf.c     |   4 +-
 src/lxc/utils.h    |   9 +++++
 4 files changed, 126 insertions(+), 3 deletions(-)

diff --git a/src/lxc/commands.c b/src/lxc/commands.c
index 416388ad8..07113b6e5 100644
--- a/src/lxc/commands.c
+++ b/src/lxc/commands.c
@@ -92,6 +92,7 @@ static const char *lxc_cmd_str(lxc_cmd_t cmd)
                [LXC_CMD_GET_NAME]         = "get_name",
                [LXC_CMD_GET_LXCPATH]      = "get_lxcpath",
                [LXC_CMD_ADD_STATE_CLIENT] = "add_state_client",
+               [LXC_CMD_OPENPTY]          = "openpty",
        };
 
        if (cmd >= LXC_CMD_MAX)
@@ -118,10 +119,15 @@ static const char *lxc_cmd_str(lxc_cmd_t cmd)
  */
 static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd)
 {
-       int ret, rspfd;
+       int ret;
+       int rspfd = -1;
+       int pty_fds[2] = {-1, -1};
        struct lxc_cmd_rsp *rsp = &cmd->rsp;
 
-       ret = lxc_abstract_unix_recv_fds(sock, &rspfd, 1, rsp, sizeof(*rsp));
+       if (cmd->req.cmd == LXC_CMD_OPENPTY)
+               ret = lxc_abstract_unix_recv_fds(sock, pty_fds, 2, rsp, 
sizeof(*rsp));
+       else
+               ret = lxc_abstract_unix_recv_fds(sock, &rspfd, 1, rsp, 
sizeof(*rsp));
        if (ret < 0) {
                WARN("Command %s failed to receive response: %s.",
                     lxc_cmd_str(cmd->req.cmd), strerror(errno));
@@ -147,6 +153,18 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr 
*cmd)
                rspdata->masterfd = rspfd;
                rspdata->ttynum = PTR_TO_INT(rsp->data);
                rsp->data = rspdata;
+       } else if (cmd->req.cmd == LXC_CMD_OPENPTY) {
+               struct lxc_cmd_openpty_rsp_data *openpty_rsp = NULL;
+
+               openpty_rsp = malloc(sizeof(*openpty_rsp));
+               if (!openpty_rsp) {
+                       ERROR("Command %s couldn't allocate response buffer.",
+                                       lxc_cmd_str(cmd->req.cmd));
+                       return -1;
+               }
+               openpty_rsp->master = pty_fds[0];
+               openpty_rsp->slave = pty_fds[1];
+               rsp->data = openpty_rsp;
        }
 
        if (rsp->datalen == 0) {
@@ -934,6 +952,90 @@ static int lxc_cmd_add_state_client_callback(int fd, 
struct lxc_cmd_req *req,
        return lxc_cmd_rsp_send(fd, &rsp);
 }
 
+int lxc_cmd_openpty(const char *name, const char *lxcpath, int *amaster,
+                   int *aslave)
+{
+       int ret, stopped;
+       struct lxc_cmd_rr cmd = {
+           .req = {
+                   .cmd = LXC_CMD_OPENPTY
+           },
+       };
+       struct lxc_cmd_openpty_rsp_data *openpty_rsp;
+
+       ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
+       if (ret < 0)
+               return -1;
+
+       if (cmd.rsp.ret < 0)
+               return -1;
+
+       openpty_rsp = cmd.rsp.data;
+
+       *amaster = openpty_rsp->master;
+       *aslave = openpty_rsp->slave;
+
+       return 0;
+}
+
+static int lxc_cmd_openpty_callback(int fd, struct lxc_cmd_req *req,
+                                   struct lxc_handler *handler)
+{
+       int ret;
+       struct lxc_cmd_rsp rsp;
+       char proc_self_path[LXC_PROC_SELF_LEN];
+       int pty_fds[2] = {-1, -1};
+
+       memset(&rsp, 0, sizeof(rsp));
+
+       ret = snprintf(proc_self_path, LXC_PROC_SELF_LEN, "/proc/self/fd/%d",
+                      handler->conf->dev_ptmx.opath_fd);
+       if (ret < 0 || (size_t)ret >= LXC_PROC_SELF_LEN) {
+               SYSERROR("Failed to create string: %d != %d", ret, 
LXC_PROC_SELF_LEN);
+               return -1;
+       }
+
+       /* open the pseudoterminal master */
+       pty_fds[0] = open(proc_self_path, O_RDWR | O_NOCTTY);
+       if (pty_fds[0] < 0) {
+               ERROR("%s - Failed to open \"%s\"", proc_self_path,
+                     strerror(errno));
+               return -1;
+       }
+
+       ret = grantpt(pty_fds[0]);
+       if (ret < 0) {
+               ERROR("%s - Failed to grant access to slave pseudoterminal",
+                     strerror(errno));
+               close(pty_fds[0]);
+               return -1;
+       }
+
+       ret = unlockpt(pty_fds[0]);
+       if (ret < 0) {
+               ERROR("%s - Failed to unlock slave pseudoterminal",
+                     strerror(errno));
+               close(pty_fds[0]);
+               return -1;
+       }
+
+       pty_fds[1] = ioctl(pty_fds[0], TIOCGPTPEER, O_RDWR | O_NOCTTY);
+       if (pty_fds[1] < 0) {
+               ERROR("%s - Failed to unlock slave pseudoterminal file "
+                     "descriptor", strerror(errno));
+               close(pty_fds[0]);
+               return -1;
+       }
+
+       ret = lxc_abstract_unix_send_fds(fd, pty_fds, 2, NULL, 0);
+       if (ret < 0) {
+               ERROR("Failed to send pseudoterminal file descriptors");
+               return -1;
+       }
+
+       return 0;
+}
+
 static int lxc_cmd_process(int fd, struct lxc_cmd_req *req,
                           struct lxc_handler *handler)
 {
@@ -951,6 +1053,7 @@ static int lxc_cmd_process(int fd, struct lxc_cmd_req *req,
                [LXC_CMD_GET_NAME]         = lxc_cmd_get_name_callback,
                [LXC_CMD_GET_LXCPATH]      = lxc_cmd_get_lxcpath_callback,
                [LXC_CMD_ADD_STATE_CLIENT] = lxc_cmd_add_state_client_callback,
+               [LXC_CMD_OPENPTY]          = lxc_cmd_openpty_callback,
        };
 
        if (req->cmd >= LXC_CMD_MAX) {
diff --git a/src/lxc/commands.h b/src/lxc/commands.h
index 28428c774..4b20f967c 100644
--- a/src/lxc/commands.h
+++ b/src/lxc/commands.h
@@ -48,6 +48,7 @@ typedef enum {
        LXC_CMD_GET_NAME,
        LXC_CMD_GET_LXCPATH,
        LXC_CMD_ADD_STATE_CLIENT,
+       LXC_CMD_OPENPTY,
        LXC_CMD_MAX,
 } lxc_cmd_t;
 
@@ -73,6 +74,11 @@ struct lxc_cmd_console_rsp_data {
        int ttynum;
 };
 
+struct lxc_cmd_openpty_rsp_data {
+       int master;
+       int slave;
+};
+
 extern int lxc_cmd_console_winch(const char *name, const char *lxcpath);
 extern int lxc_cmd_console(const char *name, int *ttynum, int *fd,
                           const char *lxcpath);
@@ -116,4 +122,7 @@ extern int lxc_cmd_mainloop_add(const char *name, struct 
lxc_epoll_descr *descr,
                                    struct lxc_handler *handler);
 extern int lxc_try_cmd(const char *name, const char *lxcpath);
 
+extern int lxc_cmd_openpty(const char *name, const char *lxcpath, int *amaster,
+                          int *aslave);
+
 #endif /* __commands_h */
diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index 72569edea..334cecca7 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -1431,7 +1431,7 @@ static int lxc_allocate_dev_ptmx_opath_fd(struct lxc_conf 
*conf)
 {
        int fd;
 
-       fd = open("/dev/pts/ptmx", O_PATH);
+       fd = open("/dev/ptmx", O_PATH | O_CLOEXEC);
        if (fd < 0)
                return -1;
 
@@ -4332,6 +4332,8 @@ int lxc_setup(struct lxc_handler *handler)
        /* Send "/dev/pts/ptmx" O_PATH file descriptor to parent. */
        ret = lxc_abstract_unix_send_fds(handler->ttysock[0],
                                         &lxc_conf->dev_ptmx.opath_fd, 1, NULL, 
0);
+       close(lxc_conf->dev_ptmx.opath_fd);
+       lxc_conf->dev_ptmx.opath_fd = -1;
        if (ret < 0) {
                ERROR("Failed to send \"/dev/pts/ptmx\" file descriptor");
                return -1;
diff --git a/src/lxc/utils.h b/src/lxc/utils.h
index 4408c6d69..72efc7d79 100644
--- a/src/lxc/utils.h
+++ b/src/lxc/utils.h
@@ -51,6 +51,15 @@
 #define LXC_NUMSTRLEN64 21
 #define LXC_LINELEN 4096
 #define LXC_IDMAPLEN 4096
+/* strlen("/proc/self/") = 11
+ * +
+ * uint64_t_as_string = 21
+ * +
+ * strlen("fd/") = 3;
+ * +
+ * \0
+ */
+#define LXC_PROC_SELF_LEN 36
 
 /* returns 1 on success, 0 if there were any failures */
 extern int lxc_rmdir_onedev(char *path, const char *exclude);
_______________________________________________
lxc-devel mailing list
[email protected]
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to