[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