[lxc-devel] [lxc/master] [WIP] make lxc-attach use a pty

brauner on Github lxc-bot at linuxcontainers.org
Thu Feb 18 20:46:27 UTC 2016


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 300 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20160218/59246714/attachment.bin>
-------------- next part --------------
From e20ac4ac493b986b8841e2a7e1d5e571d764a069 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at mailbox.org>
Date: Mon, 15 Feb 2016 19:38:32 +0100
Subject: [PATCH 1/5] Make escape sequence to exit tty optional

Signed-off-by: Christian Brauner <christian.brauner at mailbox.org>
---
 src/lxc/console.c | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/src/lxc/console.c b/src/lxc/console.c
index 67e5d0f..59981ae 100644
--- a/src/lxc/console.c
+++ b/src/lxc/console.c
@@ -641,16 +641,19 @@ static int lxc_console_cb_tty_stdin(int fd, uint32_t events, void *cbdata,
 		return 1;
 	}
 
-	/* we want to exit the console with Ctrl+a q */
-	if (c == ts->escape && !ts->saw_escape) {
-		ts->saw_escape = 1;
-		return 0;
-	}
+	if (ts->escape != -1) {
+		/* we want to exit the console with Ctrl+a q */
+		if (c == ts->escape && !ts->saw_escape) {
+			ts->saw_escape = 1;
+			return 0;
+		}
 
-	if (c == 'q' && ts->saw_escape)
-		return 1;
+		if (c == 'q' && ts->saw_escape)
+			return 1;
+
+		ts->saw_escape = 0;
+	}
 
-	ts->saw_escape = 0;
 	if (write(ts->masterfd, &c, 1) < 0) {
 		SYSERROR("failed to write");
 		return 1;

From c640645d68fe17b5546c4650c7de678200fe1cd8 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at mailbox.org>
Date: Mon, 15 Feb 2016 19:40:55 +0100
Subject: [PATCH 2/5] Make tty helper functions extern

- lxc_console_cb_tty_stdin()
- lxc_console_cb_tty_master()
- lxc_setup_tios(int fd, struct termios *oldtios);
- lxc_console_winsz(int srcfd, int dstfd);
- lxc_console_cb_sigwinch_fd(int fd, uint32_t events, void *cbdata,
	struct lxc_epoll_descr *descr);
- lxc_tty_state *lxc_console_sigwinch_init(int srcfd, int dstfd);
- lxc_console_sigwinch_fini(struct lxc_tty_state *ts);

Signed-off-by: Christian Brauner <christian.brauner at mailbox.org>
---
 src/lxc/console.c | 40 ++++++++++++++--------------------------
 src/lxc/console.h | 26 ++++++++++++++++++++++++++
 2 files changed, 40 insertions(+), 26 deletions(-)

diff --git a/src/lxc/console.c b/src/lxc/console.c
index 59981ae..5ae8016 100644
--- a/src/lxc/console.c
+++ b/src/lxc/console.c
@@ -36,6 +36,7 @@
 #include "log.h"
 #include "conf.h"
 #include "config.h"
+#include "console.h"
 #include "start.h" 	/* for struct lxc_handler */
 #include "caps.h"
 #include "commands.h"
@@ -55,19 +56,6 @@ lxc_log_define(lxc_console, lxc);
 static struct lxc_list lxc_ttys;
 
 typedef void (*sighandler_t)(int);
-struct lxc_tty_state
-{
-	struct lxc_list node;
-	int stdinfd;
-	int stdoutfd;
-	int masterfd;
-	int escape;
-	int saw_escape;
-	const char *winch_proxy;
-	const char *winch_proxy_lxcpath;
-	int sigfd;
-	sigset_t oldmask;
-};
 
 __attribute__((constructor))
 void lxc_console_init(void)
@@ -80,7 +68,7 @@ void lxc_console_init(void)
  * @srcfd : terminal to get size from (typically a slave pty)
  * @dstfd : terminal to set size on (typically a master pty)
  */
-static void lxc_console_winsz(int srcfd, int dstfd)
+void lxc_console_winsz(int srcfd, int dstfd)
 {
 	struct winsize wsz;
 	if (isatty(srcfd) && ioctl(srcfd, TIOCGWINSZ, &wsz) == 0) {
@@ -110,8 +98,8 @@ void lxc_console_sigwinch(int sig)
 	}
 }
 
-static int lxc_console_cb_sigwinch_fd(int fd, uint32_t events, void *cbdata,
-				      struct lxc_epoll_descr *descr)
+int lxc_console_cb_sigwinch_fd(int fd, uint32_t events, void *cbdata,
+		struct lxc_epoll_descr *descr)
 {
 	struct signalfd_siginfo siginfo;
 	struct lxc_tty_state *ts = cbdata;
@@ -145,7 +133,7 @@ static int lxc_console_cb_sigwinch_fd(int fd, uint32_t events, void *cbdata,
  * prevent lxc_ttys list corruption, but using the fd we can provide the
  * tty_state needed to the callback (lxc_console_cb_sigwinch_fd()).
  */
-static struct lxc_tty_state *lxc_console_sigwinch_init(int srcfd, int dstfd)
+struct lxc_tty_state *lxc_console_sigwinch_init(int srcfd, int dstfd)
 {
 	sigset_t mask;
 	struct lxc_tty_state *ts;
@@ -200,7 +188,7 @@ static struct lxc_tty_state *lxc_console_sigwinch_init(int srcfd, int dstfd)
  * Must be called with process_lock held to protect the lxc_ttys list, or
  * from a non-threaded context.
  */
-static void lxc_console_sigwinch_fini(struct lxc_tty_state *ts)
+void lxc_console_sigwinch_fini(struct lxc_tty_state *ts)
 {
 	if (ts->sigfd >= 0) {
 		close(ts->sigfd);
@@ -302,7 +290,7 @@ int lxc_console_mainloop_add(struct lxc_epoll_descr *descr,
 	return 0;
 }
 
-static int setup_tios(int fd, struct termios *oldtios)
+int lxc_setup_tios(int fd, struct termios *oldtios)
 {
 	struct termios newtios;
 
@@ -382,7 +370,7 @@ static int lxc_console_peer_proxy_alloc(struct lxc_console *console, int sockfd)
 		return -1;
 	}
 
-	if (setup_tios(console->peerpty.slave, &oldtermio) < 0)
+	if (lxc_setup_tios(console->peerpty.slave, &oldtermio) < 0)
 		goto err1;
 
 	ts = lxc_console_sigwinch_init(console->peerpty.master, console->master);
@@ -521,7 +509,7 @@ static void lxc_console_peer_default(struct lxc_console *console)
 		goto err1;
 	}
 
-	if (setup_tios(console->peer, console->tios) < 0)
+	if (lxc_setup_tios(console->peer, console->tios) < 0)
 		goto err2;
 
 	return;
@@ -629,8 +617,8 @@ int lxc_console_set_stdfds(struct lxc_handler *handler)
 	return 0;
 }
 
-static int lxc_console_cb_tty_stdin(int fd, uint32_t events, void *cbdata,
-				    struct lxc_epoll_descr *descr)
+int lxc_console_cb_tty_stdin(int fd, uint32_t events, void *cbdata,
+		struct lxc_epoll_descr *descr)
 {
 	struct lxc_tty_state *ts = cbdata;
 	char c;
@@ -662,8 +650,8 @@ static int lxc_console_cb_tty_stdin(int fd, uint32_t events, void *cbdata,
 	return 0;
 }
 
-static int lxc_console_cb_tty_master(int fd, uint32_t events, void *cbdata,
-				     struct lxc_epoll_descr *descr)
+int lxc_console_cb_tty_master(int fd, uint32_t events, void *cbdata,
+		struct lxc_epoll_descr *descr)
 {
 	struct lxc_tty_state *ts = cbdata;
 	char buf[1024];
@@ -704,7 +692,7 @@ int lxc_console(struct lxc_container *c, int ttynum,
 		return -1;
 	}
 
-	ret = setup_tios(stdinfd, &oldtios);
+	ret = lxc_setup_tios(stdinfd, &oldtios);
 	if (ret) {
 		ERROR("failed to setup tios");
 		return -1;
diff --git a/src/lxc/console.h b/src/lxc/console.h
index 41d53e6..53f5938 100644
--- a/src/lxc/console.h
+++ b/src/lxc/console.h
@@ -24,8 +24,24 @@
 #ifndef __LXC_CONSOLE_H
 #define __LXC_CONSOLE_H
 
+#include "conf.h"
+#include "list.h"
+
 struct lxc_epoll_descr;
 struct lxc_container;
+struct lxc_tty_state
+{
+	struct lxc_list node;
+	int stdinfd;
+	int stdoutfd;
+	int masterfd;
+	int escape;
+	int saw_escape;
+	const char *winch_proxy;
+	const char *winch_proxy_lxcpath;
+	int sigfd;
+	sigset_t oldmask;
+};
 
 extern int  lxc_console_allocate(struct lxc_conf *conf, int sockfd, int *ttynum);
 extern int  lxc_console_create(struct lxc_conf *);
@@ -40,5 +56,15 @@ extern int  lxc_console(struct lxc_container *c, int ttynum,
 extern int  lxc_console_getfd(struct lxc_container *c, int *ttynum,
 			      int *masterfd);
 extern int  lxc_console_set_stdfds(struct lxc_handler *);
+extern int lxc_console_cb_tty_stdin(int fd, uint32_t events, void *cbdata,
+		struct lxc_epoll_descr *descr);
+extern int lxc_console_cb_tty_master(int fd, uint32_t events, void *cbdata,
+		struct lxc_epoll_descr *descr);
+extern int lxc_setup_tios(int fd, struct termios *oldtios);
+extern void lxc_console_winsz(int srcfd, int dstfd);
+extern int lxc_console_cb_sigwinch_fd(int fd, uint32_t events, void *cbdata,
+		struct lxc_epoll_descr *descr);
+extern struct lxc_tty_state *lxc_console_sigwinch_init(int srcfd, int dstfd);
+extern void lxc_console_sigwinch_fini(struct lxc_tty_state *ts);
 
 #endif

From 137866517e1af6e0b336326cdb4aa516b011107b Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at mailbox.org>
Date: Wed, 17 Feb 2016 19:48:54 +0100
Subject: [PATCH 3/5] rewrite lxc_console_set_stdfds

Make lxc_console_set_stdfds useable by other callers that do not have access to
lxc_handler.

Signed-off-by: Christian Brauner <christian.brauner at mailbox.org>
---
 src/lxc/console.c | 15 ++++++---------
 src/lxc/console.h |  2 +-
 src/lxc/start.c   |  2 +-
 3 files changed, 8 insertions(+), 11 deletions(-)

diff --git a/src/lxc/console.c b/src/lxc/console.c
index 5ae8016..1e79ba5 100644
--- a/src/lxc/console.c
+++ b/src/lxc/console.c
@@ -599,19 +599,16 @@ int lxc_console_create(struct lxc_conf *conf)
 	return -1;
 }
 
-int lxc_console_set_stdfds(struct lxc_handler *handler)
+int lxc_console_set_stdfds(int fd)
 {
-	struct lxc_conf *conf = handler->conf;
-	struct lxc_console *console = &conf->console;
-
-	if (console->slave < 0)
+	if (fd < 0)
 		return 0;
 
-	if (dup2(console->slave, 0) < 0 ||
-	    dup2(console->slave, 1) < 0 ||
-	    dup2(console->slave, 2) < 0)
+	if (dup2(fd, 0) < 0 ||
+	    dup2(fd, 1) < 0 ||
+	    dup2(fd, 2) < 0)
 	{
-		SYSERROR("failed to dup console");
+		SYSERROR("failed to dup file descriptor");
 		return -1;
 	}
 	return 0;
diff --git a/src/lxc/console.h b/src/lxc/console.h
index 53f5938..aa6ec7d 100644
--- a/src/lxc/console.h
+++ b/src/lxc/console.h
@@ -55,7 +55,7 @@ extern int  lxc_console(struct lxc_container *c, int ttynum,
 		        int escape);
 extern int  lxc_console_getfd(struct lxc_container *c, int *ttynum,
 			      int *masterfd);
-extern int  lxc_console_set_stdfds(struct lxc_handler *);
+extern int lxc_console_set_stdfds(int fd);
 extern int lxc_console_cb_tty_stdin(int fd, uint32_t events, void *cbdata,
 		struct lxc_epoll_descr *descr);
 extern int lxc_console_cb_tty_master(int fd, uint32_t events, void *cbdata,
diff --git a/src/lxc/start.c b/src/lxc/start.c
index 153b4c4..acf32e4 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -798,7 +798,7 @@ static int do_start(void *data)
 	 * setup on its console ie. the pty allocated in lxc_console_create()
 	 * so make sure that that pty is stdin,stdout,stderr.
 	 */
-	if (lxc_console_set_stdfds(handler) < 0)
+	if (lxc_console_set_stdfds(handler->conf->console.slave) < 0)
 		goto out_warn_father;
 
 	/* If we mounted a temporary proc, then unmount it now */

From 4bc447da4dcba64eb6c5d3b0f32acf407d90a58b Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at mailbox.org>
Date: Thu, 18 Feb 2016 15:20:34 +0100
Subject: [PATCH 4/5] clean exit on EPOLLHUP

Signed-off-by: Christian Brauner <christian.brauner at mailbox.org>
---
 src/lxc/console.c | 25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/src/lxc/console.c b/src/lxc/console.c
index 1e79ba5..7d027a1 100644
--- a/src/lxc/console.c
+++ b/src/lxc/console.c
@@ -22,27 +22,28 @@
  */
 
 #include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
+#include <sys/epoll.h>
 #include <sys/types.h>
 #include <termios.h>
+#include <unistd.h>
 
 #include <lxc/lxccontainer.h>
 
-#include "log.h"
+#include "af_unix.h"
+#include "caps.h"
+#include "commands.h"
 #include "conf.h"
 #include "config.h"
 #include "console.h"
-#include "start.h" 	/* for struct lxc_handler */
-#include "caps.h"
-#include "commands.h"
-#include "mainloop.h"
-#include "af_unix.h"
+#include "log.h"
 #include "lxclock.h"
+#include "mainloop.h"
+#include "start.h" 	/* for struct lxc_handler */
 #include "utils.h"
 
 #if HAVE_PTY_H
@@ -620,6 +621,9 @@ int lxc_console_cb_tty_stdin(int fd, uint32_t events, void *cbdata,
 	struct lxc_tty_state *ts = cbdata;
 	char c;
 
+	if (events & EPOLLHUP)
+		return 1;
+
 	assert(fd == ts->stdinfd);
 	if (read(ts->stdinfd, &c, 1) < 0) {
 		SYSERROR("failed to read");
@@ -654,6 +658,9 @@ int lxc_console_cb_tty_master(int fd, uint32_t events, void *cbdata,
 	char buf[1024];
 	int r,w;
 
+	if (events & EPOLLHUP)
+		return 1;
+
 	assert(fd == ts->masterfd);
 	r = read(fd, buf, sizeof(buf));
 	if (r < 0) {

From ec2214ecbbbada3c04cf1f85ce176755d7f16fc6 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at mailbox.org>
Date: Mon, 15 Feb 2016 22:10:40 +0100
Subject: [PATCH 5/5] make lxc-attach use a pty

Signed-off-by: Christian Brauner <christian.brauner at mailbox.org>
---
 src/lxc/lxc_attach.c | 289 +++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 279 insertions(+), 10 deletions(-)

diff --git a/src/lxc/lxc_attach.c b/src/lxc/lxc_attach.c
index 1c24349..79a405c 100644
--- a/src/lxc/lxc_attach.c
+++ b/src/lxc/lxc_attach.c
@@ -22,19 +22,40 @@
  */
 
 #define _GNU_SOURCE
+#include <errno.h>
+#include <fcntl.h>
+#include <pty.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+#include <unistd.h>
+#include <utmp.h>
+#include <linux/taskstats.h>
+
+#include <sys/ioctl.h>
+#include <sys/epoll.h> /* epoll() */
+
 #include <assert.h>
 #include <sys/wait.h>
 #include <sys/types.h>
 #include <stdlib.h>
+#include <signal.h>
+
+#include <lxc/lxccontainer.h>
 
 #include "attach.h"
+#include "attach_options.h"
 #include "arguments.h"
 #include "config.h"
 #include "confile.h"
+#include "console.h"
+#include "mainloop.h"
 #include "namespace.h"
 #include "caps.h"
 #include "log.h"
+#include "list.h"
 #include "utils.h"
+#include "mainloop.h"
 
 lxc_log_define(lxc_attach_ui, lxc);
 
@@ -186,12 +207,250 @@ Options :\n\
 	.checker  = NULL,
 };
 
+struct wrapargs {
+	lxc_attach_options_t *options;
+	lxc_attach_command_t *command;
+	struct lxc_tty_state *ts;
+	struct lxc_console *console;
+};
+
+static int pty_on_host_callback(void *p)
+{
+	struct wrapargs *wrap = p;
+
+	close(wrap->console->master);
+	setsid();
+	ioctl(wrap->console->slave, TIOCSCTTY, NULL);
+	if (lxc_console_set_stdfds(wrap->console->slave) < 0)
+		return -1;
+
+	if (wrap->command->program)
+		lxc_attach_run_command(wrap->command);
+	else
+		lxc_attach_run_shell(NULL);
+
+	return -1;
+}
+
+/* Minimalistic forkpty() implementation. */
+static pid_t fork_pty(int *master, int *slave)
+{
+	int ret = openpty(master, slave, NULL, NULL, NULL);
+	if (ret < 0)
+		return -1;
+
+	pid_t pid = fork();
+
+	if (pid == 0) {
+		close(*master);
+		setsid();
+		ioctl(*slave, TIOCSCTTY, NULL);
+		if (lxc_console_set_stdfds(*slave) < 0) {
+			close(*slave);
+			return -1;
+		}
+		return 0;
+	}
+
+	close(*slave);
+	return pid;
+}
+
+static int pty_in_container(void *p)
+{
+	int master, ret, slave;
+	int pid = -1;
+	struct wrapargs *args = p;
+
+	if (!isatty(STDIN_FILENO)) {
+		ERROR("stdin is not a tty");
+		return -1;
+	}
+
+	struct termios oldtios;
+	ret = lxc_setup_tios(STDIN_FILENO, &oldtios);
+	if (ret < 0)
+		goto err1;
+
+	pid = fork_pty(&master, &slave);
+	if (pid < 0)
+		goto err1;
+
+	lxc_console_winsz(STDIN_FILENO, master);
+
+	/* child */
+	if (pid == 0) {
+		if (args->command->program)
+			execvp(args->command->program, args->command->argv);
+		else
+			lxc_attach_run_shell(NULL);
+		SYSERROR("Could not run command");
+		return -1;
+	}
+
+	/*
+	 * For future reference: Must use process_lock() when called from a
+	 * threaded context.
+	 */
+	args->ts = lxc_console_sigwinch_init(STDIN_FILENO, master);
+	if (!args->ts) {
+		ret = -1;
+		goto err2;
+	}
+	args->ts->escape = -1;
+	args->ts->stdoutfd = STDOUT_FILENO;
+	args->ts->winch_proxy = NULL;
+
+	struct lxc_epoll_descr descr;
+	ret = lxc_mainloop_open(&descr);
+	if (ret) {
+		ERROR("failed to create mainloop");
+		goto err3;
+	}
+
+	ret = lxc_mainloop_add_handler(&descr, args->ts->sigfd,
+			lxc_console_cb_sigwinch_fd, args->ts);
+	if (ret) {
+		ERROR("failed to add handler for SIGWINCH fd");
+		goto err4;
+	}
+
+	ret = lxc_mainloop_add_handler(&descr, args->ts->stdinfd,
+			lxc_console_cb_tty_stdin, args->ts);
+	if (ret) {
+		ERROR("failed to add handler for stdinfd");
+		goto err4;
+	}
+
+	ret = lxc_mainloop_add_handler(&descr, args->ts->masterfd,
+			lxc_console_cb_tty_master, args->ts);
+	if (ret) {
+		ERROR("failed to add handler for masterfd");
+		goto err4;
+	}
+
+	ret = lxc_mainloop(&descr, -1);
+	if (ret) {
+		ERROR("mainloop returned an error");
+		goto err4;
+	}
+
+err4:
+	lxc_mainloop_close(&descr);
+err3:
+	lxc_console_sigwinch_fini(args->ts);
+err2:
+	close(args->ts->masterfd);
+err1:
+	tcsetattr(STDIN_FILENO, TCSAFLUSH, &oldtios);
+
+	if (pid > 0)
+		ret = lxc_wait_for_pid_status(pid);
+	return ret;
+}
+
+static int pty_on_host(struct lxc_container *c, struct wrapargs *wrap, int *pid)
+{
+	int ret = -1;
+
+	if (!isatty(STDIN_FILENO)) {
+		ERROR("stdin is not a tty");
+		return -1;
+	}
+
+	/* Save old terminal settings. */
+	struct termios oldtios;
+	ret = lxc_setup_tios(STDIN_FILENO, &oldtios);
+	if (ret < 0)
+		goto err1;
+
+	/* Create pty on the host. */
+	struct lxc_conf *conf = c->lxc_conf;
+	if (lxc_console_create(conf) < 0)
+		goto err1;
+
+	/* Install sigwinch handler. */
+	struct lxc_tty_state *ts;
+	ts = lxc_console_sigwinch_init(STDIN_FILENO, conf->console.master);
+	if (!ts) {
+		goto err2;
+	}
+	ts->masterfd = conf->console.master;
+	ts->stdinfd = STDIN_FILENO;
+	ts->stdoutfd = STDOUT_FILENO;
+	ts->escape = -1;
+	ts->winch_proxy = NULL;
+
+	/* Shit ttys to container. */
+	if (ttys_shift_ids(conf) < 0) {
+		ERROR("Failed to shift tty into container");
+		goto err2;
+	}
+
+	/* Get window size from current pty. */
+	lxc_console_winsz(STDIN_FILENO, conf->console.master);
+
+	/* Send wrapper function on its way. */
+	wrap->console = &conf->console;
+	if (c->attach(c, pty_on_host_callback, wrap, wrap->options, pid) < 0)
+		goto err2;
+	close(conf->console.slave); /* Close slave side. */
+
+	struct lxc_epoll_descr descr;
+	ret = lxc_mainloop_open(&descr);
+	if (ret) {
+		ERROR("failed to create mainloop");
+		goto err3;
+	}
+
+	/* Register sigwinch handler in mainloop. */
+	ret = lxc_mainloop_add_handler(&descr, ts->sigfd,
+			lxc_console_cb_sigwinch_fd, ts);
+	if (ret) {
+		ERROR("failed to add handler for SIGWINCH fd");
+		goto err4;
+	}
+
+	ret = lxc_mainloop_add_handler(&descr, ts->stdinfd,
+			lxc_console_cb_tty_stdin, ts);
+	if (ret) {
+		ERROR("failed to add handler for stdinfd");
+		goto err4;
+	}
+
+	ret = lxc_mainloop_add_handler(&descr, ts->masterfd,
+			lxc_console_cb_tty_master, ts);
+	if (ret) {
+		ERROR("failed to add handler for masterfd");
+		goto err4;
+	}
+
+	ret = lxc_mainloop(&descr, -1);
+	if (ret) {
+		ERROR("mainloop returned an error");
+		goto err4;
+	}
+
+	ret = 0;
+
+err4:
+	lxc_mainloop_close(&descr);
+err3:
+	lxc_console_sigwinch_fini(ts);
+err2:
+	lxc_console_delete(&c->lxc_conf->console);
+err1:
+	tcsetattr(STDIN_FILENO, TCSAFLUSH, &oldtios);
+
+	return ret;
+}
+
 int main(int argc, char *argv[])
 {
 	int ret;
 	pid_t pid;
 	lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
-	lxc_attach_command_t command;
+	lxc_attach_command_t command = (lxc_attach_command_t){.program = NULL};
 
 	ret = lxc_caps_init();
 	if (ret)
@@ -220,23 +479,33 @@ int main(int argc, char *argv[])
 	attach_options.extra_env_vars = extra_env;
 	attach_options.extra_keep_env = extra_keep;
 
-	if (my_args.argc) {
-		command.program = my_args.argv[0];
-		command.argv = (char**)my_args.argv;
-		ret = lxc_attach(my_args.name, my_args.lxcpath[0], lxc_attach_run_command, &command, &attach_options, &pid);
-	} else {
-		ret = lxc_attach(my_args.name, my_args.lxcpath[0], lxc_attach_run_shell, NULL, &attach_options, &pid);
+	struct lxc_container *c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
+	if (!c)
+		exit(EXIT_FAILURE);
+
+	struct wrapargs wrap = (struct wrapargs){.command = &command,
+		.options = &attach_options};
+	if (my_args.argc > 0) {
+		wrap.command->program = my_args.argv[0];
+		wrap.command->argv = (char**)my_args.argv;
 	}
 
+	ret = c->attach(c, pty_in_container, &wrap, &attach_options, &pid);
 	if (ret < 0)
-		return 1;
+		ret = pty_on_host(c, &wrap, &pid);
+
+	lxc_container_put(c);
+
+	if (ret < 0)
+		exit(EXIT_FAILURE);
 
 	ret = lxc_wait_for_pid_status(pid);
 	if (ret < 0)
-		return 1;
+		exit(EXIT_FAILURE);
 
 	if (WIFEXITED(ret))
 		return WEXITSTATUS(ret);
 
-	return 1;
+	exit(EXIT_SUCCESS);
 }
+


More information about the lxc-devel mailing list