Serge Hallyn | 18 Jun 2013 22:01
Favicon

[PATCH] conf.c: always strdup rootfs.mount

The reason is that the generic code which handles reading
lxc.rootfs.mount always frees the old value if not NULL.
So without this setting lxc.rootfs.mount = /mnt causes
segfault.

Signed-off-by: Serge Hallyn <serge.hallyn@...>
---
 src/lxc/conf.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index 6a43aee..a98fbef 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
 <at>  <at>  -2134,7 +2134,7  <at>  <at>  struct lxc_conf *lxc_conf_init(void)
 	new->console.slave = -1;
 	new->console.name[0] = '\0';
 	new->maincmd_fd = -1;
-	new->rootfs.mount = default_rootfs_mount;
+	new->rootfs.mount = strdup(default_rootfs_mount);
 	new->kmsg = 1;
 	lxc_list_init(&new->cgroup);
 	lxc_list_init(&new->network);
 <at>  <at>  -3152,7 +3152,7  <at>  <at>  void lxc_conf_free(struct lxc_conf *conf)
 		return;
 	if (conf->console.path)
 		free(conf->console.path);
-	if (conf->rootfs.mount != default_rootfs_mount)
+	if (conf->rootfs.mount)
 		free(conf->rootfs.mount);
(Continue reading)

Tobias Gruetzmacher | 16 Jun 2013 16:50

Bug? Watching of /run/utmp

Hi,

in src/lxc/lxcutmp.c in function lxc_utmp_mainloop_add, lxc tries to set 
up an inotify watch for /run or /var/run - but only, if I understand the 
check correctly, if /run/utmp or /var/run exist in the container.

Since I mount /run as a tmpfs in the container, this check was never true 
and the inotify watch seems to target /var/run (which is a symlink) and 
never properly picked up utmp. In the end, this prevented containers to 
shutdown properly (only init left, but lxc doesn't kill it). My current 
workaround is a lxc.hook.mount script, which does

  touch "$LXC_ROTFS_MOUNT/run/utmp"

after mounting the tmpfs on /run.

IMHO, the check for path2 (starting at line 315 in lxcutemp.c) should be 
removed.

Greetings, Tobias

--

-- 
GPG-Key 0xE2BEA341 - signed/encrypted mail preferred

------------------------------------------------------------------------------
This SF.net email is sponsored by Windows:

Build for Windows Store.

http://p.sf.net/sfu/windows-dev2dev
(Continue reading)

Serge Hallyn | 14 Jun 2013 05:43
Favicon

[PATCH RFC] introduce lxc.cap.keep

The lxc configuration file currently supports 'lxc.cap.drop', a list of
capabilities to be dropped (using the bounding set) from the container.
The problem with this is that over time new capabilities are added.  So
an older container configuration file may, over time, become insecure.

Walter has in the past suggested replacing lxc.cap.drop with
lxc.cap.preserve, which would have the inverse sense - any capabilities
in that set would be kept, any others would be dropped.

Realistically both have the same problem - the sendmail capabilities
bug proved that running code with unexpectedly dropped privilege can be
dangerous.  This patch gives the admin a choice:  You can use either
lxc.cap.keep or lxc.cap.drop, not both.

Both continue to be ignored if a user namespace is in use.

Signed-off-by: Serge Hallyn <serge.hallyn@...>
---
 doc/lxc.conf.sgml.in |   11 ++++++
 src/lxc/conf.c       |   93 ++++++++++++++++++++++++++++++++++++++++++++++++--
 src/lxc/conf.h       |    5 ++-
 src/lxc/confile.c    |   70 +++++++++++++++++++++++++++++++++++++
 4 files changed, 176 insertions(+), 3 deletions(-)

diff --git a/doc/lxc.conf.sgml.in b/doc/lxc.conf.sgml.in
index 6500e50..7c289a0 100644
--- a/doc/lxc.conf.sgml.in
+++ b/doc/lxc.conf.sgml.in
 <at>  <at>  -771,6 +771,17  <at>  <at>  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 	    </para>
(Continue reading)

Serge Hallyn | 13 Jun 2013 17:09
Favicon

[PATCH] don't set up console for lxc-execute

Currently due to some safety checks for !rootfs.path, lxc-execute works
ok if you do not set lxc.rootfs at all in your lxc.conf. But if you
set lxc.rootfs = '/', then it sets up console, and when you do an
lxc-execute, the console appears hung.

However the lxc.rootfs NULL check was just incidental to not dereference
a NULL pointer.  In fact we should not be setting up a console if the
container isn't running a full-fledged distro with a getty/login
running on the container's /dev/console.

Have lxc_execute() mark in lxc_conf that this is a lxc-execute and not
an lxc-start, and don't set up the console.

The issue is documented at https://sourceforge.net/p/lxc/bugs/67/ .

Signed-off-by: Serge Hallyn <serge.hallyn@...>
---
 src/lxc/conf.c    |  4 ++--
 src/lxc/conf.h    |  1 +
 src/lxc/console.c | 10 ++++++++++
 src/lxc/execute.c |  1 +
 4 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index a4ed218..d3dc9a5 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
 <at>  <at>  -2836,7 +2836,7  <at>  <at>  int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
 		}
 	}
(Continue reading)

Natanael Copa | 12 Jun 2013 11:18

[PATCH] lxc-init: continue even if we fail to mount /dev/mqueue

The 'lxc-init' (a lightweight init process used by lxc-execute in place
of upstart etc) tries to mount /dev/mqueue during startup. If that fails
(for instance due to missing support for mqueue in kernel) then it
aborts execution and returns -1. This is unreasonable as very few
applications actually need /dev/mqueue.

This similar to what we do with /dev/shm.

Signed-off-by: Natanael Copa <ncopa@...>
---
 src/lxc/utils.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/lxc/utils.c b/src/lxc/utils.c
index 6c0f9d0..136f943 100644
--- a/src/lxc/utils.c
+++ b/src/lxc/utils.c
 <at>  <at>  -148,8 +148,9  <at>  <at>  extern int lxc_setup_fs(void)
 		return 0;
 	}

+	/* continue even without posix message queue support */
 	if (mount_fs("mqueue", "/dev/mqueue", "mqueue"))
-		return -1;
+		INFO("failed to mount /dev/mqueue");

 	return 0;
 }
--

-- 
1.8.3.1
(Continue reading)

Song Tan | 10 Jun 2013 22:16
Picon

the implementation of lxc-freeze

Hello everyone,
  I am new to lxc and right now I am trying to find out how the freeze and unfreeze functions are implemented.
  I have read the  freezer.c file in the lxc source, but I still don't quite get it. From my understanding, this should be something about process scheduling but I am not sure.  Could someone explain a little bit about the implementation of freeze and unfreeze tool? Or is there any document I can follow?


Thanks
                         Stan
------------------------------------------------------------------------------
This SF.net email is sponsored by Windows:

Build for Windows Store.

http://p.sf.net/sfu/windows-dev2dev
_______________________________________________
Lxc-devel mailing list
Lxc-devel@...
https://lists.sourceforge.net/lists/listinfo/lxc-devel
Serge Hallyn | 10 Jun 2013 18:52
Favicon

[PATCH] lxc_stop: return success if api_shutdown succeeded


I originally forgot to set ret = 0 if it succeeded, meaning that a
simple 'lxc-stop -n container1' returns failure even though the
stop succeeded.

Signed-off-by: Serge Hallyn <serge.hallyn@...>
---
 src/lxc/lxc_stop.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/lxc/lxc_stop.c b/src/lxc/lxc_stop.c
index 3d42d0e..d7f8d7f 100644
--- a/src/lxc/lxc_stop.c
+++ b/src/lxc/lxc_stop.c
 <at>  <at>  -166,7 +166,8  <at>  <at>  int main(int argc, char *argv[])
 			ret = c->wait(c, "STOPPED", -1) ? 0 : -1;
 		else
 			ret = -1; // fail
-	}
+	} else
+		ret = 0;

 out:
 	lxc_container_put(c);
--

-- 
1.8.1.2

------------------------------------------------------------------------------
This SF.net email is sponsored by Windows:

Build for Windows Store.

http://p.sf.net/sfu/windows-dev2dev
Serge Hallyn | 10 Jun 2013 16:34
Favicon

[PATCH 1/1] conf.c: if we don't specify a rootfs, we still need proc mounted

otherwise we won't be allowed to set an apparmor context (on pid 1)

Signed-off-by: Serge Hallyn <serge.hallyn@...>
---
 src/lxc/conf.c |    8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index a1aee14..4e3d605 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
 <at>  <at>  -2851,9 +2851,11  <at>  <at>  int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
 #if HAVE_APPARMOR /* || HAVE_SMACK || HAVE_SELINUX */
 	INFO("rootfs path is .%s., mount is .%s.", lxc_conf->rootfs.path,
 		lxc_conf->rootfs.mount);
-	if (lxc_conf->rootfs.path == NULL || strlen(lxc_conf->rootfs.path) == 0)
-		mounted = 0;
-	else
+	if (lxc_conf->rootfs.path == NULL || strlen(lxc_conf->rootfs.path) == 0) {
+		if (mount("proc", "/proc", "proc", 0, NULL))
+			return -1;
+		mounted = 1;
+	} else
 		mounted = lsm_mount_proc_if_needed(lxc_conf->rootfs.path, lxc_conf->rootfs.mount);
 	if (mounted == -1) {
 		SYSERROR("failed to mount /proc in the container.");
--

-- 
1.7.9.5

------------------------------------------------------------------------------
How ServiceNow helps IT people transform IT departments:
1. A cloud service to automate IT design, transition and operations
2. Dashboards that offer high-level views of enterprise services
3. A single system of record for all IT processes
http://p.sf.net/sfu/servicenow-d2d-j
Rui Xiang | 8 Jun 2013 12:04
Favicon

[PATCH] lxc-monitord: remove hard code execvp path of lxc-monitord

Sometimes, the path of lxc tools is not '/usr/bin', but
'/usr/local/bin' or other. Then execvp lxc-monitord will fail
in lxc_monitord_spawn.

Signed-off-by: Rui Xiang <rui.xiang@...>
---
 src/lxc/monitor.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/lxc/monitor.c b/src/lxc/monitor.c
index c04bb73..0717344 100644
--- a/src/lxc/monitor.c
+++ b/src/lxc/monitor.c
 <at>  <at>  -210,7 +210,7  <at>  <at>  int lxc_monitord_spawn(const char *lxcpath)
 	char pipefd_str[11];

 	char * const args[] = {
-		"/usr/bin/lxc-monitord",
+		"lxc-monitord",
 		(char *)lxcpath,
 		pipefd_str,
 		NULL,
--

-- 
1.8.2.2

------------------------------------------------------------------------------
How ServiceNow helps IT people transform IT departments:
1. A cloud service to automate IT design, transition and operations
2. Dashboards that offer high-level views of enterprise services
3. A single system of record for all IT processes
http://p.sf.net/sfu/servicenow-d2d-j
Dwight Engen | 7 Jun 2013 18:35
Picon
Favicon

[PATCH] console API improvements

Add a higher level console API that opens a tty/console and runs the
mainloop as well. Rename existing API to console_getfd(). Use these in
the python binding.

Allow attaching a console peer after container bootup, including if the
container was launched with -d. This is made possible by allocation of a
"proxy" pty as the peer when the console is attached to.

Improve handling of SIGWINCH, the pty size will be correctly set at the
beginning of a session and future changes when using the lxc_console() API
will be propagated to it as well.

Refactor some common code between lxc_console.c and console.c. The variable
wait4q (renamed to saw_escape) was static, making the mainloop callback not
safe across threads. This wasn't a problem when the callback was in the
non-threaded lxc-console, but now that it is internal to console.c, we have
to take care of it. This is now contained in a per-tty state structure.

Don't attempt to open /dev/null as the console peer since /dev/null cannot
be added to the mainloop (epoll_ctl() fails with EPERM). This isn't needed
to get the console setup (and the log to work) since the case of not having
a peer at console init time has to be handled to allow for attaching to it
later.

Signed-off-by: Dwight Engen <dwight.engen@...>
---
 doc/lxc-console.sgml.in                  |  11 +-
 src/lxc/commands.c                       |  64 +--
 src/lxc/commands.h                       |   2 +
 src/lxc/conf.c                           |  11 +-
 src/lxc/conf.h                           |   2 +
 src/lxc/console.c                        | 677 +++++++++++++++++++++++++------
 src/lxc/console.h                        |  18 +-
 src/lxc/lxc.h                            |   9 -
 src/lxc/lxc_console.c                    | 189 +--------
 src/lxc/lxccontainer.c                   |  12 +-
 src/lxc/lxccontainer.h                   |  21 +-
 src/lxc/start.c                          |  19 +-
 src/python-lxc/examples/pyconsole-vte.py |  58 +++
 src/python-lxc/examples/pyconsole.py     |  33 ++
 src/python-lxc/lxc.c                     |  46 +++
 src/python-lxc/lxc/__init__.py           |  18 +-
 src/tests/console.c                      |   6 +-
 17 files changed, 827 insertions(+), 369 deletions(-)
 create mode 100755 src/python-lxc/examples/pyconsole-vte.py
 create mode 100755 src/python-lxc/examples/pyconsole.py

diff --git a/doc/lxc-console.sgml.in b/doc/lxc-console.sgml.in
index 9299778..f4737d1 100644
--- a/doc/lxc-console.sgml.in
+++ b/doc/lxc-console.sgml.in
 <at>  <at>  -78,6 +78,12  <at>  <at>  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
     </para>

     <para>
+      A <replaceable>ttynum</replaceable> of 0 may be given to attach
+      to the container's /dev/console instead of its
+      dev/tty&lt;<replaceable>ttynum</replaceable>&gt;.
+    </para>
+
+    <para>
       A keyboard escape sequence may be used to disconnect from the tty
       and quit lxc-console. The default escape sequence is &lt;Ctrl+a q&gt;.
     </para>
 <at>  <at>  -107,8 +113,9  <at>  <at>  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 	</term>
 	<listitem>
 	  <para>
-	    Specify the tty number to connect, if not specified a tty
-	    number will be automatically choosen by the container.
+	    Specify the tty number to connect to or 0 for the console. If not
+	    specified the next available tty number will be automatically
+	    choosen by the container.
 	  </para>
 	</listitem>
       </varlistentry>
diff --git a/src/lxc/commands.c b/src/lxc/commands.c
index b4afc07..b23eb98 100644
--- a/src/lxc/commands.c
+++ b/src/lxc/commands.c
 <at>  <at>  -40,6 +40,7  <at>  <at> 
 #include <lxc/utils.h>

 #include "commands.h"
+#include "console.h"
 #include "confile.h"
 #include "mainloop.h"
 #include "af_unix.h"
 <at>  <at>  -546,6 +547,37  <at>  <at>  static int lxc_cmd_stop_callback(int fd, struct lxc_cmd_req *req,
 }

 /*
+ * lxc_cmd_console_winch: To process as if a SIGWINCH were received
+ *
+ *  <at> name      : name of container to connect to
+ *  <at> lxcpath   : the lxcpath in which the container is running
+ *
+ * Returns 0 on success, < 0 on failure
+ */
+int lxc_cmd_console_winch(const char *name, const char *lxcpath)
+{
+	int ret, stopped = 0;
+	struct lxc_cmd_rr cmd = {
+		.req = { .cmd = LXC_CMD_CONSOLE_WINCH },
+	};
+
+	ret = lxc_cmd(name, &cmd, &stopped, lxcpath);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int lxc_cmd_console_winch_callback(int fd, struct lxc_cmd_req *req,
+					  struct lxc_handler *handler)
+{
+	struct lxc_cmd_rsp rsp = { .data = 0 };
+
+	lxc_console_sigwinch(SIGWINCH);
+	return lxc_cmd_rsp_send(fd, &rsp);
+}
+
+/*
  * lxc_cmd_console: Open an fd to a tty in the container
  *
  *  <at> name           : name of container to connect to
 <at>  <at>  -599,39 +631,21  <at>  <at>  static int lxc_cmd_console_callback(int fd, struct lxc_cmd_req *req,
 				    struct lxc_handler *handler)
 {
 	int ttynum = PTR_TO_INT(req->data);
-	struct lxc_tty_info *tty_info = &handler->conf->tty_info;
+	int masterfd;
 	struct lxc_cmd_rsp rsp;

-	if (ttynum > 0) {
-		if (ttynum > tty_info->nbtty)
-			goto out_close;
-
-		if (tty_info->pty_info[ttynum - 1].busy)
-			goto out_close;
-
-		/* the requested tty is available */
-		goto out_send;
-	}
-
-	/* search for next available tty, fixup index tty1 => [0] */
-	for (ttynum = 1;
-	     ttynum <= tty_info->nbtty && tty_info->pty_info[ttynum - 1].busy;
-	     ttynum++);
-
-	/* we didn't find any available slot for tty */
-	if (ttynum > tty_info->nbtty)
+	masterfd = lxc_console_allocate(handler->conf, fd, &ttynum);
+	if (masterfd < 0)
 		goto out_close;

-out_send:
 	memset(&rsp, 0, sizeof(rsp));
 	rsp.data = INT_TO_PTR(ttynum);
-	if (lxc_af_unix_send_fd(fd, tty_info->pty_info[ttynum - 1].master,
-				&rsp, sizeof(rsp)) < 0) {
+	if (lxc_af_unix_send_fd(fd, masterfd, &rsp, sizeof(rsp)) < 0) {
 		ERROR("failed to send tty to client");
+		lxc_console_free(handler->conf, fd);
 		goto out_close;
 	}

-	tty_info->pty_info[ttynum - 1].busy = fd;
 	return 0;

 out_close:
 <at>  <at>  -650,6 +664,7  <at>  <at>  static int lxc_cmd_process(int fd, struct lxc_cmd_req *req,

 	callback cb[LXC_CMD_MAX] = {
 		[LXC_CMD_CONSOLE]         = lxc_cmd_console_callback,
+		[LXC_CMD_CONSOLE_WINCH]   = lxc_cmd_console_winch_callback,
 		[LXC_CMD_STOP]            = lxc_cmd_stop_callback,
 		[LXC_CMD_GET_STATE]       = lxc_cmd_get_state_callback,
 		[LXC_CMD_GET_INIT_PID]    = lxc_cmd_get_init_pid_callback,
 <at>  <at>  -668,8 +683,7  <at>  <at>  static int lxc_cmd_process(int fd, struct lxc_cmd_req *req,
 static void lxc_cmd_fd_cleanup(int fd, struct lxc_handler *handler,
 			       struct lxc_epoll_descr *descr)
 {
-	extern void lxc_console_remove_fd(int, struct lxc_tty_info *);
-	lxc_console_remove_fd(fd, &handler->conf->tty_info);
+	lxc_console_free(handler->conf, fd);
 	lxc_mainloop_del_handler(descr, fd);
 	close(fd);
 }
diff --git a/src/lxc/commands.h b/src/lxc/commands.h
index c3738cd..46806cb 100644
--- a/src/lxc/commands.h
+++ b/src/lxc/commands.h
 <at>  <at>  -34,6 +34,7  <at>  <at> 

 typedef enum {
 	LXC_CMD_CONSOLE,
+	LXC_CMD_CONSOLE_WINCH,
 	LXC_CMD_STOP,
 	LXC_CMD_GET_STATE,
 	LXC_CMD_GET_INIT_PID,
 <at>  <at>  -65,6 +66,7  <at>  <at>  struct lxc_cmd_console_rsp_data {
 	int ttynum;
 };

+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);
 extern char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath);
diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index a1aee14..9010623 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
 <at>  <at>  -1293,8 +1293,8  <at>  <at>  static int setup_dev_console(const struct lxc_rootfs *rootfs,
 		return 0;
 	}

-	if (console->peer == -1) {
-		INFO("no console output required");
+	if (console->master < 0) {
+		INFO("no console");
 		return 0;
 	}

 <at>  <at>  -1359,8 +1359,8  <at>  <at>  static int setup_ttydir_console(const struct lxc_rootfs *rootfs,
 	if (ret >= 0)
 		close(ret);

-	if (console->peer == -1) {
-		INFO("no console output required");
+	if (console->master < 0) {
+		INFO("no console");
 		return 0;
 	}

 <at>  <at>  -2127,6 +2127,9  <at>  <at>  struct lxc_conf *lxc_conf_init(void)
 	new->console.log_fd = -1;
 	new->console.path = NULL;
 	new->console.peer = -1;
+	new->console.peerpty.busy = -1;
+	new->console.peerpty.master = -1;
+	new->console.peerpty.slave = -1;
 	new->console.master = -1;
 	new->console.slave = -1;
 	new->console.name[0] = '\0';
diff --git a/src/lxc/conf.h b/src/lxc/conf.h
index a2efa7c..434bab8 100644
--- a/src/lxc/conf.h
+++ b/src/lxc/conf.h
 <at>  <at>  -197,6 +197,8  <at>  <at>  struct lxc_console {
 	int slave;
 	int master;
 	int peer;
+	struct lxc_pty_info peerpty;
+	struct lxc_epoll_descr *descr;
 	char *path;
 	char *log_path;
 	int log_fd;
diff --git a/src/lxc/console.c b/src/lxc/console.c
index 93c16b5..4f3e32b 100644
--- a/src/lxc/console.c
+++ b/src/lxc/console.c
 <at>  <at>  -21,6 +21,8  <at>  <at> 
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */

+#include <assert.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 <at>  <at>  -29,6 +31,7  <at>  <at> 
 #include <sys/types.h>
 #include <termios.h>

+#include "lxccontainer.h"
 #include "log.h"
 #include "conf.h"
 #include "config.h"
 <at>  <at>  -37,6 +40,7  <at>  <at> 
 #include "commands.h"
 #include "mainloop.h"
 #include "af_unix.h"
+#include "lxclock.h"

 #if HAVE_PTY_H
 #include <pty.h>
 <at>  <at>  -46,156 +50,431  <at>  <at> 

 lxc_log_define(lxc_console, lxc);

-extern void lxc_console_remove_fd(int fd, struct lxc_tty_info *tty_info)
-{
-	int i;
+static struct lxc_list lxc_ttys;

-	for (i = 0; i < tty_info->nbtty; i++) {
-
-		if (tty_info->pty_info[i].busy != fd)
-			continue;
+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;
+	sighandler_t handler;
+};
+
+__attribute__((constructor))
+void lxc_console_init(void)
+{
+	lxc_list_init(&lxc_ttys);
+}

-		tty_info->pty_info[i].busy = 0;
+/* lxc_console_winsz: propagte winsz from one terminal to another
+ *
+ *  <at> srcfd : terminal to get size from (typically a slave pty)
+ *  <at> dstfd : terminal to set size on (typically a master pty)
+ */
+static void lxc_console_winsz(int srcfd, int dstfd)
+{
+	struct winsize wsz;
+	if (isatty(srcfd) && ioctl(srcfd, TIOCGWINSZ, &wsz) == 0) {
+		DEBUG("set winsz dstfd:%d cols:%d rows:%d", dstfd,
+		      wsz.ws_col, wsz.ws_row);
+		ioctl(dstfd, TIOCSWINSZ, &wsz);
 	}
+}

-	return;
+void lxc_console_sigwinch(int sig)
+{
+	if (process_lock() == 0) {
+		struct lxc_list *it;
+		struct lxc_tty_state *ts;
+
+		lxc_list_for_each(it, &lxc_ttys) {
+			ts = it->elem;
+			lxc_console_winsz(ts->stdinfd, ts->masterfd);
+			if (ts->winch_proxy) {
+				lxc_cmd_console_winch(ts->winch_proxy,
+						      ts->winch_proxy_lxcpath);
+			}
+		}
+		process_unlock();
+	}
 }

-static int get_default_console(char **console)
+/*
+ * lxc_console_sigwinch_init: install SIGWINCH handler
+ *
+ *  <at> srcfd  : src for winsz in SIGWINCH handler
+ *  <at> dstfd  : dst for winsz in SIGWINCH handler
+ *
+ * Returns lxc_tty_state structure on success or NULL on failure
+ *
+ * Must be called with process_lock held to protect the lxc_ttys list, or
+ * from a non-threaded context.
+ */
+static struct lxc_tty_state *lxc_console_sigwinch_init(int srcfd, int dstfd)
 {
-	int fd;
+	sigset_t mask;
+	struct lxc_tty_state *ts;

-	if (!access("/dev/tty", F_OK)) {
-		fd = open("/dev/tty", O_RDWR);
-		if (fd >= 0) {
-			close(fd);
-			*console = strdup("/dev/tty");
-			goto out;
-		}
+	ts = malloc(sizeof(*ts));
+	if (!ts)
+		return NULL;
+
+	memset(ts, 0, sizeof(*ts));
+	ts->stdinfd     = srcfd;
+	ts->masterfd    = dstfd;
+
+	/* add tty to list to be scanned at SIGWINCH time */
+	lxc_list_add_elem(&ts->node, ts);
+	lxc_list_add_tail(&lxc_ttys, &ts->node);
+
+	ts->handler = signal(SIGWINCH, lxc_console_sigwinch);
+	if (ts->handler == SIG_ERR) {
+		SYSERROR("failed to set SIGWINCH handler");
+		goto err1;
 	}

-	if (!access("/dev/null", F_OK)) {
-		*console = strdup("/dev/null");
-		goto out;
+	sigemptyset(&mask);
+	sigaddset(&mask, SIGWINCH);
+	if (sigprocmask(SIG_UNBLOCK, &mask, NULL)) {
+		SYSERROR("failed to unblock SIGWINCH");
+		goto err2;
 	}

-	ERROR("No suitable default console");
+	DEBUG("%d installed SIGWINCH handler", getpid());
+	goto out;
+
+err2:
+	signal(SIGWINCH, ts->handler);
+err1:
+	lxc_list_del(&ts->node);
+	free(ts);
+	ts = NULL;
 out:
-	return *console ? 0 : -1;
+	return ts;
 }

-int lxc_create_console(struct lxc_conf *conf)
+/*
+ * lxc_console_sigwinch_fini: uninstall SIGWINCH handler
+ *
+ *  <at> ts  : the lxc_tty_state returned by lxc_console_sigwinch_init
+ *
+ * Restore the saved signal handler that was in effect at the time
+ * lxc_console_sigwinch_init() was called.
+ *
+ * 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)
 {
-	struct termios tios;
-	struct lxc_console *console = &conf->console;
-	int fd;
+	signal(SIGWINCH, ts->handler);
+	lxc_list_del(&ts->node);
+	free(ts);
+}

-	if (!conf->rootfs.path)
-		return 0;
+static int lxc_console_cb_con(int fd, void *data,
+			      struct lxc_epoll_descr *descr)
+{
+	struct lxc_console *console = (struct lxc_console *)data;
+	char buf[1024];
+	int r,w;

-	if (!console->path && get_default_console(&console->path)) {
-		ERROR("failed to get default console");
-		return -1;
+	w = r = read(fd, buf, sizeof(buf));
+	if (r < 0) {
+		SYSERROR("failed to read");
+		return 1;
 	}

-	if (!strcmp(console->path, "none"))
+	if (!r) {
+		INFO("console client on fd %d has exited", fd);
+		lxc_mainloop_del_handler(descr, fd);
+		close(fd);
 		return 0;
+	}

-	if (openpty(&console->master, &console->slave,
-		    console->name, NULL, NULL)) {
-		SYSERROR("failed to allocate a pty");
-		return -1;
+	if (fd == console->peer)
+		w = write(console->master, buf, r);
+
+	if (fd == console->master) {
+		if (console->log_fd >= 0)
+			w = write(console->log_fd, buf, r);
+
+		if (console->peer >= 0)
+			w = write(console->peer, buf, r);
 	}

-	if (fcntl(console->master, F_SETFD, FD_CLOEXEC)) {
-		SYSERROR("failed to set console master to close-on-exec");
-		goto err;
+	if (w != r)
+		WARN("console short write r:%d w:%d", r, w);
+	return 0;
+}
+
+static void lxc_console_mainloop_add_peer(struct lxc_console *console)
+{
+	if (console->peer >= 0) {
+		if (lxc_mainloop_add_handler(console->descr, console->peer,
+					     lxc_console_cb_con, console))
+			WARN("console peer not added to mainloop");
 	}
+}

-	if (fcntl(console->slave, F_SETFD, FD_CLOEXEC)) {
-		SYSERROR("failed to set console slave to close-on-exec");
-		goto err;
+int lxc_console_mainloop_add(struct lxc_epoll_descr *descr,
+			     struct lxc_handler *handler)
+{
+	struct lxc_conf *conf = handler->conf;
+	struct lxc_console *console = &conf->console;
+
+	if (!conf->rootfs.path) {
+		INFO("no rootfs, no console.");
+		return 0;
 	}

-	if (console->log_path) {
-		fd = lxc_unpriv(open(console->log_path, O_CLOEXEC | O_RDWR | O_CREAT | O_APPEND, 0600));
-		if (fd < 0) {
-			SYSERROR("failed to open '%s'", console->log_path);
-			goto err;
-		}
-		DEBUG("using '%s' as console log", console->log_path);
-		console->log_fd = fd;
+	if (console->master < 0) {
+		INFO("no console");
+		return 0;
 	}

-	fd = lxc_unpriv(open(console->path, O_CLOEXEC | O_RDWR | O_CREAT |
-			     O_APPEND, 0600));
-	if (fd < 0) {
-		SYSERROR("failed to open '%s'", console->path);
-		goto err_close_console_log;
+	if (lxc_mainloop_add_handler(descr, console->master,
+				     lxc_console_cb_con, console)) {
+		ERROR("failed to add to mainloop console handler for '%d'",
+		      console->master);
+		return -1;
 	}

-	DEBUG("using '%s' as console", console->path);
+	/* we cache the descr so that we can add an fd to it when someone
+	 * does attach to it in lxc_console_allocate()
+	 */
+	console->descr = descr;
+	lxc_console_mainloop_add_peer(console);

-	console->peer = fd;
+	return 0;
+}

-	if (!isatty(console->peer))
-		return 0;
+static int setup_tios(int fd, struct termios *oldtios)
+{
+	struct termios newtios;

-	console->tios = malloc(sizeof(tios));
-	if (!console->tios) {
-		SYSERROR("failed to allocate memory");
-		goto err_close_console;
+	if (!isatty(fd)) {
+		ERROR("'%d' is not a tty", fd);
+		return -1;
 	}

-	/* Get termios */
-	if (tcgetattr(console->peer, console->tios)) {
+	/* Get current termios */
+	if (tcgetattr(fd, oldtios)) {
 		SYSERROR("failed to get current terminal settings");
-		goto err_free;
+		return -1;
 	}

-	tios = *console->tios;
+	newtios = *oldtios;

 	/* Remove the echo characters and signal reception, the echo
-	 * will be done below with master proxying */
-	tios.c_iflag &= ~IGNBRK;
-	tios.c_iflag &= BRKINT;
-	tios.c_lflag &= ~(ECHO|ICANON|ISIG);
-	tios.c_cc[VMIN] = 1;
-	tios.c_cc[VTIME] = 0;
+	 * will be done with master proxying */
+	newtios.c_iflag &= ~IGNBRK;
+	newtios.c_iflag &= BRKINT;
+	newtios.c_lflag &= ~(ECHO|ICANON|ISIG);
+	newtios.c_cc[VMIN] = 1;
+	newtios.c_cc[VTIME] = 0;

 	/* Set new attributes */
-	if (tcsetattr(console->peer, TCSAFLUSH, &tios)) {
+	if (tcsetattr(fd, TCSAFLUSH, &newtios)) {
 		ERROR("failed to set new terminal settings");
-		goto err_free;
+		return -1;
 	}

 	return 0;
+}

-err_free:
-	free(console->tios);
-
-err_close_console:
-	close(console->peer);
+static void lxc_console_peer_proxy_free(struct lxc_console *console)
+{
+	close(console->peerpty.master);
+	close(console->peerpty.slave);
+	console->peerpty.master = -1;
+	console->peerpty.slave = -1;
+	console->peerpty.busy = -1;
+	console->peerpty.name[0] = '\0';
 	console->peer = -1;
+}

-err_close_console_log:
-	if (console->log_fd >= 0) {
-		close(console->log_fd);
-		console->log_fd = -1;
+static int lxc_console_peer_proxy_alloc(struct lxc_console *console, int sockfd)
+{
+	struct termios oldtermio;
+
+	if (console->master < 0) {
+		ERROR("console not set up");
+		return -1;
+	}
+	if (console->peerpty.busy != -1 || console->peer != -1) {
+		NOTICE("console already in use");
+		return -1;
 	}

-err:
-	close(console->master);
-	console->master = -1;
+	/* this is the proxy pty that will be given to the client, and that
+	 * the real pty master will send to / recv from
+	 */
+	if (openpty(&console->peerpty.master, &console->peerpty.slave,
+		    console->peerpty.name, NULL, NULL)) {
+		SYSERROR("failed to create proxy pty");
+		return -1;
+	}

-	close(console->slave);
-	console->slave = -1;
+	if (setup_tios(console->peerpty.slave, &oldtermio) < 0)
+		goto err1;
+
+	console->peer = console->peerpty.slave;
+	console->peerpty.busy = sockfd;
+	lxc_console_mainloop_add_peer(console);
+
+	lxc_console_sigwinch_init(console->peerpty.master, console->master);
+	DEBUG("%d %s peermaster:%d sockfd:%d", getpid(), __FUNCTION__, console->peerpty.master, sockfd);
+	return 0;
+
+err1:
+	lxc_console_peer_proxy_free(console);
 	return -1;
 }

-void lxc_delete_console(struct lxc_console *console)
+/* lxc_console_allocate: allocate the console or a tty
+ *
+ *  <at> conf    : the configuration of the container to allocate from
+ *  <at> sockfd  : the socket fd whose remote side when closed, will be an
+ *            indication that the console or tty is no longer in use
+ *  <at> ttyreq  : the tty requested to be opened, -1 for any, 0 for the console
+ */
+int lxc_console_allocate(struct lxc_conf *conf, int sockfd, int *ttyreq)
 {
-	if (console->tios &&
+	int masterfd = -1, ttynum;
+	struct lxc_tty_info *tty_info = &conf->tty_info;
+	struct lxc_console *console = &conf->console;
+
+	process_lock();
+	if (*ttyreq == 0) {
+		if (lxc_console_peer_proxy_alloc(console, sockfd) < 0)
+			goto out;
+		masterfd = console->peerpty.master;
+		goto out;
+	}
+
+	if (*ttyreq > 0) {
+		if (*ttyreq > tty_info->nbtty)
+			goto out;
+
+		if (tty_info->pty_info[*ttyreq - 1].busy)
+			goto out;
+
+		/* the requested tty is available */
+		ttynum = *ttyreq;
+		goto out_tty;
+	}
+
+	/* search for next available tty, fixup index tty1 => [0] */
+	for (ttynum = 1;
+	     ttynum <= tty_info->nbtty && tty_info->pty_info[ttynum - 1].busy;
+	     ttynum++);
+
+	/* we didn't find any available slot for tty */
+	if (ttynum > tty_info->nbtty)
+		goto out;
+
+	*ttyreq = ttynum;
+
+out_tty:
+	tty_info->pty_info[ttynum - 1].busy = sockfd;
+	masterfd = tty_info->pty_info[ttynum - 1].master;
+out:
+	process_unlock();
+	return masterfd;
+}
+
+/* lxc_console_free: mark the console or a tty as unallocated, free any
+ * resources allocated by lxc_console_allocate().
+ *
+ *  <at> conf : the configuration of the container whose tty was closed
+ *  <at> fd   : the socket fd whose remote side was closed, which indicated
+ *         the console or tty is no longer in use. this is used to match
+ *         which console/tty is being freed.
+ */
+void lxc_console_free(struct lxc_conf *conf, int fd)
+{
+	int i;
+	struct lxc_tty_info *tty_info = &conf->tty_info;
+	struct lxc_console *console = &conf->console;
+
+	for (i = 0; i < tty_info->nbtty; i++) {
+		if (tty_info->pty_info[i].busy == fd)
+			tty_info->pty_info[i].busy = 0;
+	}
+
+	if (console->peerpty.busy == fd) {
+		lxc_mainloop_del_handler(console->descr, console->peerpty.slave);
+		lxc_console_peer_proxy_free(console);
+	}
+}
+
+static void lxc_console_peer_default(struct lxc_console *console)
+{
+	struct lxc_tty_state *ts;
+	const char *path = console->path;
+
+	/* if no console was given, try current controlling terminal, there
+	 * won't be one if we were started as a daemon (-d)
+	 */
+	if (!path && !access("/dev/tty", F_OK)) {
+		int fd;
+		fd = open("/dev/tty", O_RDWR);
+		if (fd >= 0) {
+			close(fd);
+			path = "/dev/tty";
+		}
+	}
+
+	if (!path)
+		goto out;
+
+	DEBUG("opening %s for console peer", path);
+	console->peer = lxc_unpriv(open(path, O_CLOEXEC | O_RDWR | O_CREAT |
+					O_APPEND, 0600));
+	if (console->peer < 0)
+		goto out;
+
+	DEBUG("using '%s' as console", path);
+
+	if (!isatty(console->peer))
+		return;
+
+	ts = lxc_console_sigwinch_init(console->peer, console->master);
+	if (!ts)
+		WARN("Unable to install SIGWINCH");
+
+	lxc_console_winsz(console->peer, console->master);
+
+	console->tios = malloc(sizeof(*console->tios));
+	if (!console->tios) {
+		SYSERROR("failed to allocate memory");
+		goto err1;
+	}
+
+	if (setup_tios(console->peer, console->tios) < 0)
+		goto err2;
+
+	return;
+
+err2:
+	free(console->tios);
+	console->tios = NULL;
+err1:
+	close(console->peer);
+	console->peer = -1;
+out:
+	DEBUG("no console peer");
+}
+
+void lxc_console_delete(struct lxc_console *console)
+{
+	if (console->tios && console->peer >= 0 &&
 	    tcsetattr(console->peer, TCSAFLUSH, console->tios))
 		WARN("failed to set old terminal settings");
 	free(console->tios);
 <at>  <at>  -216,73 +495,201  <at>  <at>  void lxc_delete_console(struct lxc_console *console)
 	console->slave = -1;
 }

-static int console_handler(int fd, void *data, struct lxc_epoll_descr *descr)
+int lxc_console_create(struct lxc_conf *conf)
 {
-	struct lxc_console *console = (struct lxc_console *)data;
-	char buf[1024];
-	int r,w;
+	struct lxc_console *console = &conf->console;

-	r = read(fd, buf, sizeof(buf));
-	if (r < 0) {
+	if (!conf->rootfs.path)
+		return 0;
+
+	if (console->path && !strcmp(console->path, "none"))
+		return 0;
+
+	if (openpty(&console->master, &console->slave,
+		    console->name, NULL, NULL)) {
+		SYSERROR("failed to allocate a pty");
+		return -1;
+	}
+
+	if (fcntl(console->master, F_SETFD, FD_CLOEXEC)) {
+		SYSERROR("failed to set console master to close-on-exec");
+		goto err;
+	}
+
+	if (fcntl(console->slave, F_SETFD, FD_CLOEXEC)) {
+		SYSERROR("failed to set console slave to close-on-exec");
+		goto err;
+	}
+
+	lxc_console_peer_default(console);
+
+	if (console->log_path) {
+		console->log_fd = lxc_unpriv(open(console->log_path,
+						  O_CLOEXEC | O_RDWR |
+						  O_CREAT | O_APPEND, 0600));
+		if (console->log_fd < 0) {
+			SYSERROR("failed to open '%s'", console->log_path);
+			goto err;
+		}
+		DEBUG("using '%s' as console log", console->log_path);
+	}
+
+	return 0;
+
+err:
+	lxc_console_delete(console);
+	return -1;
+}
+
+
+
+static int lxc_console_cb_tty_stdin(int fd, void *cbdata,
+				    struct lxc_epoll_descr *descr)
+{
+	struct lxc_tty_state *ts = cbdata;
+	char c;
+
+	assert(fd == ts->stdinfd);
+	if (read(ts->stdinfd, &c, 1) < 0) {
 		SYSERROR("failed to read");
 		return 1;
 	}

-	if (!r) {
-		INFO("console client has exited");
-		lxc_mainloop_del_handler(descr, fd);
-		close(fd);
+	/* we want to exit the console with Ctrl+a q */
+	if (c == ts->escape && !ts->saw_escape) {
+		ts->saw_escape = 1;
 		return 0;
 	}

-	/* no output for the console, do nothing */
-	if (console->peer == -1)
-		return 0;
+	if (c == 'q' && ts->saw_escape)
+		return 1;

-	if (console->peer == fd)
-		w = write(console->master, buf, r);
-	else {
-		w = write(console->peer, buf, r);
-		if (console->log_fd > 0)
-			w = write(console->log_fd, buf, r);
+	ts->saw_escape = 0;
+	if (write(ts->masterfd, &c, 1) < 0) {
+		SYSERROR("failed to write");
+		return 1;
 	}
-	if (w != r)
-		WARN("console short write");
+
 	return 0;
 }

-int lxc_console_mainloop_add(struct lxc_epoll_descr *descr,
-			     struct lxc_handler *handler)
+static int lxc_console_cb_tty_master(int fd, void *cbdata,
+				     struct lxc_epoll_descr *descr)
 {
-	struct lxc_conf *conf = handler->conf;
-	struct lxc_console *console = &conf->console;
+	struct lxc_tty_state *ts = cbdata;
+	char buf[1024];
+	int r,w;

-	if (!conf->rootfs.path) {
-		INFO("no rootfs, no console.");
-		return 0;
+	assert(fd == ts->masterfd);
+	r = read(fd, buf, sizeof(buf));
+	if (r < 0) {
+		SYSERROR("failed to read");
+		return 1;
 	}

-	if (!console->path) {
-		INFO("no console specified");
-		return 0;
+	w = write(ts->stdoutfd, buf, r);
+	if (w < 0 || w != r) {
+		SYSERROR("failed to write");
+		return 1;
 	}

-	if (console->peer == -1) {
-		INFO("no console will be used");
-		return 0;
+	return 0;
+}
+
+int lxc_console_getfd(struct lxc_container *c, int *ttynum, int *masterfd)
+{
+	return lxc_cmd_console(c->name, ttynum, masterfd, c->config_path);
+}
+
+int lxc_console(struct lxc_container *c, int ttynum,
+		int stdinfd, int stdoutfd, int stderrfd,
+		int escape)
+{
+	int ret, ttyfd, masterfd;
+	struct lxc_epoll_descr descr;
+	struct termios oldtios;
+	struct lxc_tty_state *ts;
+
+	if (!isatty(stdinfd)) {
+		ERROR("stdin is not a tty");
+		return -1;
 	}

-	if (lxc_mainloop_add_handler(descr, console->master,
-				     console_handler, console)) {
-		ERROR("failed to add to mainloop console handler for '%d'",
-		      console->master);
+	ret = setup_tios(stdinfd, &oldtios);
+	if (ret) {
+		ERROR("failed to setup tios");
 		return -1;
 	}

-	if (console->peer != -1 &&
-	    lxc_mainloop_add_handler(descr, console->peer,
-				     console_handler, console))
-		WARN("console input disabled");
+	process_lock();
+	ttyfd = lxc_cmd_console(c->name, &ttynum, &masterfd, c->config_path);
+	if (ttyfd < 0) {
+		ret = ttyfd;
+		goto err1;
+	}

-	return 0;
+	fprintf(stderr, "\n"
+			"Connected to tty %1$d\n"
+			"Type <Ctrl+%2$c q> to exit the console, "
+			"<Ctrl+%2$c Ctrl+%2$c> to enter Ctrl+%2$c itself\n",
+			ttynum, 'a' + escape - 1);
+
+	ret = setsid();
+	if (ret)
+		INFO("already group leader");
+
+	ts = lxc_console_sigwinch_init(stdinfd, masterfd);
+	if (!ts) {
+		ret = -1;
+		goto err2;
+	}
+	ts->escape = escape;
+	ts->winch_proxy = c->name;
+	ts->winch_proxy_lxcpath = c->config_path;
+
+	lxc_console_winsz(stdinfd, masterfd);
+	lxc_cmd_console_winch(ts->winch_proxy, ts->winch_proxy_lxcpath);
+
+	ret = lxc_mainloop_open(&descr);
+	if (ret) {
+		ERROR("failed to create mainloop");
+		goto err3;
+	}
+
+	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;
+	}
+
+	process_unlock();
+	ret = lxc_mainloop(&descr, -1);
+	process_lock();
+	if (ret) {
+		ERROR("mainloop returned an error");
+		goto err4;
+	}
+
+	ret = 0;
+
+err4:
+	lxc_mainloop_close(&descr);
+err3:
+	lxc_console_sigwinch_fini(ts);
+err2:
+	close(masterfd);
+	close(ttyfd);
+err1:
+	tcsetattr(stdinfd, TCSAFLUSH, &oldtios);
+	process_unlock();
+
+	return ret;
 }
diff --git a/src/lxc/console.h b/src/lxc/console.h
index c9bf937..1089493 100644
--- a/src/lxc/console.h
+++ b/src/lxc/console.h
 <at>  <at>  -21,6 +21,18  <at>  <at> 
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */

-extern int lxc_create_console(struct lxc_conf *);
-extern void lxc_delete_console(struct lxc_console *);
-extern int lxc_console_mainloop_add(struct lxc_epoll_descr *, struct lxc_handler *);
+struct lxc_epoll_descr;
+struct lxc_container;
+
+extern int  lxc_console_allocate(struct lxc_conf *conf, int sockfd, int *ttynum);
+extern int  lxc_console_create(struct lxc_conf *);
+extern void lxc_console_delete(struct lxc_console *);
+extern void lxc_console_free(struct lxc_conf *conf, int fd);
+
+extern int  lxc_console_mainloop_add(struct lxc_epoll_descr *, struct lxc_handler *);
+extern void lxc_console_sigwinch(int sig);
+extern int  lxc_console(struct lxc_container *c, int ttynum,
+		        int stdinfd, int stdoutfd, int stderrfd,
+		        int escape);
+extern int  lxc_console_getfd(struct lxc_container *c, int *ttynum,
+			      int *masterfd);
diff --git a/src/lxc/lxc.h b/src/lxc/lxc.h
index 8491ff3..67e0d9e 100644
--- a/src/lxc/lxc.h
+++ b/src/lxc/lxc.h
 <at>  <at>  -108,15 +108,6  <at>  <at>  extern int lxc_monitor_read_fdset(fd_set *rfds, int nfds, struct lxc_msg *msg, i
 extern int lxc_monitor_close(int fd);

 /*
- * Show the console of the container.
- *  <at> name : the name of container
- *  <at> tty  : the tty number
- *  <at> fd   : a pointer to a tty file descriptor
- * Returns 0 on sucess, < 0 otherwise
- */
-extern int lxc_console(const char *name, int ttynum, int *fd, const char *lxcpath);
-
-/*
  * Freeze all the tasks running inside the container <name>
  *  <at> name : the container name
  * Returns 0 on success, < 0 otherwise
diff --git a/src/lxc/lxc_console.c b/src/lxc/lxc_console.c
index 52e6988..77afdc1 100644
--- a/src/lxc/lxc_console.c
+++ b/src/lxc/lxc_console.c
 <at>  <at>  -38,6 +38,7  <at>  <at> 
 #include <sys/poll.h>
 #include <sys/ioctl.h>

+#include "../lxc/lxccontainer.h"
 #include "error.h"
 #include "lxc.h"
 #include "log.h"
 <at>  <at>  -87,184 +88,34  <at>  <at>  Options :\n\
 	.escape = 1,
 };

-static int master = -1;
-
-static void winsz(void)
-{
-	struct winsize wsz;
-	if (ioctl(0, TIOCGWINSZ, &wsz) == 0)
-		ioctl(master, TIOCSWINSZ, &wsz);
-}
-
-static void sigwinch(int sig)
-{
-	winsz();
-}
-
-static int setup_tios(int fd, struct termios *newtios, struct termios *oldtios)
-{
-	if (!isatty(fd)) {
-		ERROR("'%d' is not a tty", fd);
-		return -1;
-	}
-
-	/* Get current termios */
-	if (tcgetattr(fd, oldtios)) {
-		SYSERROR("failed to get current terminal settings");
-		return -1;
-	}
-
-	*newtios = *oldtios;
-
-	/* Remove the echo characters and signal reception, the echo
-	 * will be done below with master proxying */
-	newtios->c_iflag &= ~IGNBRK;
-	newtios->c_iflag &= BRKINT;
-	newtios->c_lflag &= ~(ECHO|ICANON|ISIG);
-	newtios->c_cc[VMIN] = 1;
-	newtios->c_cc[VTIME] = 0;
-
-	/* Set new attributes */
-	if (tcsetattr(fd, TCSAFLUSH, newtios)) {
-		ERROR("failed to set new terminal settings");
-		return -1;
-	}
-
-	return 0;
-}
-
-static int stdin_handler(int fd, void *data, struct lxc_epoll_descr *descr)
-{
-	static int wait4q = 0;
-	int *peer = (int *)data;
-	char c;
-
-	if (read(0, &c, 1) < 0) {
-		SYSERROR("failed to read");
-		return 1;
-	}
-
-	/* we want to exit the console with Ctrl+a q */
-	if (c == my_args.escape && !wait4q) {
-		wait4q = !wait4q;
-		return 0;
-	}
-
-	if (c == 'q' && wait4q)
-		return 1;
-
-	wait4q = 0;
-	if (write(*peer, &c, 1) < 0) {
-		SYSERROR("failed to write");
-		return 1;
-	}
-
-	return 0;
-}
-
-static int master_handler(int fd, void *data, struct lxc_epoll_descr *descr)
-{
-	char buf[1024];
-	int *peer = (int *)data;
-	int r,w;
-
-	r = read(fd, buf, sizeof(buf));
-	if (r < 0) {
-		SYSERROR("failed to read");
-		return 1;
-	}
-	w = write(*peer, buf, r);
-	if (w < 0 || w != r) {
-		SYSERROR("failed to write");
-		return 1;
-	}
-
-	return 0;
-}
-
 int main(int argc, char *argv[])
 {
-	int err, ttyfd, std_in = 1;
-	struct lxc_epoll_descr descr;
-	struct termios newtios, oldtios;
+	int ret;
+	struct lxc_container *c;

-	err = lxc_arguments_parse(&my_args, argc, argv);
-	if (err)
-		return -1;
+	ret = lxc_arguments_parse(&my_args, argc, argv);
+	if (ret)
+		return EXIT_FAILURE;

-	err = lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
+	ret = lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
 			   my_args.progname, my_args.quiet, my_args.lxcpath[0]);
-	if (err)
-		return -1;
-
-	err = setup_tios(0, &newtios, &oldtios);
-	if (err) {
-		ERROR("failed to setup tios");
-		return -1;
-	}
-
-	ttyfd = lxc_cmd_console(my_args.name, &my_args.ttynum, &master, my_args.lxcpath[0]);
-	if (ttyfd < 0) {
-		err = ttyfd;
-		goto out;
-	}
-
-	fprintf(stderr, "\n\
-Connected to tty %1$d\n\
-Type <Ctrl+%2$c q> to exit the console, \
-<Ctrl+%2$c Ctrl+%2$c> to enter Ctrl+%2$c itself\n", my_args.ttynum,
-                'a' + my_args.escape - 1);
-
-	err = setsid();
-	if (err)
-		INFO("already group leader");
-
-	if (signal(SIGWINCH, sigwinch) == SIG_ERR) {
-		SYSERROR("failed to set SIGWINCH handler");
-		err = -1;
-		goto out;
-	}
-
-	winsz();
-
-	err = lxc_mainloop_open(&descr);
-	if (err) {
-		ERROR("failed to create mainloop");
-		goto out;
-	}
+	if (ret)
+		return EXIT_FAILURE;

-	err = lxc_mainloop_add_handler(&descr, 0, stdin_handler, &master);
-	if (err) {
-		ERROR("failed to add handler for the stdin");
-		goto out_mainloop_open;
+	c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
+	if (!c) {
+		fprintf(stderr, "System error loading container\n");
+		exit(EXIT_FAILURE);
 	}

-	err = lxc_mainloop_add_handler(&descr, master, master_handler, &std_in);
-	if (err) {
-		ERROR("failed to add handler for the master");
-		goto out_mainloop_open;
+	if (!c->is_running(c)) {
+		fprintf(stderr, "%s is not running\n", my_args.name);
+		exit(EXIT_FAILURE);
 	}

-	err = lxc_mainloop(&descr, -1);
-	if (err) {
-		ERROR("mainloop returned an error");
-		goto out_mainloop_open;
+	ret = c->console(c, my_args.ttynum, 0, 1, 2, my_args.escape);
+	if (ret < 0) {
+		exit(EXIT_FAILURE);
 	}
-
-	close(ttyfd);
-	err =  0;
-
-out_mainloop_open:
-	lxc_mainloop_close(&descr);
-
-out:
-	/* Restore previous terminal parameter */
-	tcsetattr(0, TCSAFLUSH, &oldtios);
-
-	/* Return to line it is */
-	printf("\n");
-
-	close(master);
-
-	return err;
+	return EXIT_SUCCESS;
 }
diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
index c8fc16f..b1a05b4 100644
--- a/src/lxc/lxccontainer.c
+++ b/src/lxc/lxccontainer.c
 <at>  <at>  -31,6 +31,7  <at>  <at> 
 #include "lxccontainer.h"
 #include "conf.h"
 #include "confile.h"
+#include "console.h"
 #include "cgroup.h"
 #include "commands.h"
 #include "version.h"
 <at>  <at>  -350,16 +351,22  <at>  <at>  static bool lxcapi_unfreeze(struct lxc_container *c)
 	return true;
 }

-static int lxcapi_console(struct lxc_container *c, int *ttynum, int *masterfd)
+static int lxcapi_console_getfd(struct lxc_container *c, int *ttynum, int *masterfd)
 {
 	int ttyfd;
 	if (!c)
 		return -1;

-	ttyfd = lxc_cmd_console(c->name, ttynum, masterfd, c->config_path);
+	ttyfd = lxc_console_getfd(c, ttynum, masterfd);
 	return ttyfd;
 }

+static int lxcapi_console(struct lxc_container *c, int ttynum, int stdinfd,
+			  int stdoutfd, int stderrfd, int escape)
+{
+	return lxc_console(c, ttynum, stdinfd, stdoutfd, stderrfd, escape);
+}
+
 static pid_t lxcapi_init_pid(struct lxc_container *c)
 {
 	if (!c)
 <at>  <at>  -2018,6 +2025,7  <at>  <at>  struct lxc_container *lxc_container_new(const char *name, const char *configpath
 	c->freeze = lxcapi_freeze;
 	c->unfreeze = lxcapi_unfreeze;
 	c->console = lxcapi_console;
+	c->console_getfd = lxcapi_console_getfd;
 	c->init_pid = lxcapi_init_pid;
 	c->load_config = lxcapi_load_config;
 	c->want_daemonize = lxcapi_want_daemonize;
diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h
index 5078f03..5449a46 100644
--- a/src/lxc/lxccontainer.h
+++ b/src/lxc/lxccontainer.h
 <at>  <at>  -115,7 +115,7  <at>  <at>  struct lxc_container {
 		const char *lxcpath, int flags, const char *bdevtype,
 		const char *bdevdata, unsigned long newsize, char **hookargs);

-	/* lxcapi_console: allocate a console tty from container  <at> c
+	/* lxcapi_console_getfd: allocate a console tty from container  <at> c
 	 *
 	 *  <at> c        : the running container
 	 *  <at> ttynum   : in : tty number to attempt to allocate or -1 to
 <at>  <at>  -128,7 +128,24  <at>  <at>  struct lxc_container {
 	 * indicate that it is done with the allocated console so that it can
 	 * be allocated by another caller.
 	 */
-	int (*console)(struct lxc_container *c, int *ttynum, int *masterfd);
+	int (*console_getfd)(struct lxc_container *c, int *ttynum, int *masterfd);
+
+	/* lxcapi_console: allocate and run a console tty from container  <at> c
+	 *
+	 *  <at> c        : the running container
+	 *  <at> ttynum   : tty number to attempt to allocate, -1 to
+	 *             allocate the first available tty, or 0 to allocate
+	 *             the console
+	 *  <at> stdinfd  : fd to read input from
+	 *  <at> stdoutfd : fd to write output to
+	 *  <at> stderrfd : fd to write error output to
+	 *  <at> escape   : the escape character (1 == 'a', 2 == 'b', ...)
+	 *
+	 * Returns 0 on success, -1 on failure. This function will not return
+	 * until the console has been exited by the user.
+	 */
+	int (*console)(struct lxc_container *c, int ttynum,
+		       int stdinfd, int stdoutfd, int stderrfd, int escape);

 #if 0
 	bool (*commit_cgroups)(struct lxc_container *c);
diff --git a/src/lxc/start.c b/src/lxc/start.c
index 5092b51..a660ec5 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
 <at>  <at>  -387,25 +387,26  <at>  <at>  struct lxc_handler *lxc_init(const char *name, struct lxc_conf *conf, const char
 		goto out_aborting;
 	}

-	if (lxc_create_console(conf)) {
-		ERROR("failed to create console");
-		goto out_delete_tty;
-	}
-
 	/* the signal fd has to be created before forking otherwise
 	 * if the child process exits before we setup the signal fd,
 	 * the event will be lost and the command will be stuck */
 	handler->sigfd = setup_signal_fd(&handler->oldmask);
 	if (handler->sigfd < 0) {
 		ERROR("failed to set sigchild fd handler");
-		goto out_delete_console;
+		goto out_delete_tty;
+	}
+
+	/* do this after setting up signals since it might unblock SIGWINCH */
+	if (lxc_console_create(conf)) {
+		ERROR("failed to create console");
+		goto out_restore_sigmask;
 	}

 	INFO("'%s' is initialized", name);
 	return handler;

-out_delete_console:
-	lxc_delete_console(&conf->console);
+out_restore_sigmask:
+	sigprocmask(SIG_SETMASK, &handler->oldmask, NULL);
 out_delete_tty:
 	lxc_delete_tty(&conf->tty_info);
 out_aborting:
 <at>  <at>  -436,7 +437,7  <at>  <at>  static void lxc_fini(const char *name, struct lxc_handler *handler)
 	if (sigprocmask(SIG_SETMASK, &handler->oldmask, NULL))
 		WARN("failed to restore sigprocmask");

-	lxc_delete_console(&handler->conf->console);
+	lxc_console_delete(&handler->conf->console);
 	lxc_delete_tty(&handler->conf->tty_info);
 	close(handler->conf->maincmd_fd);
 	handler->conf->maincmd_fd = -1;
diff --git a/src/python-lxc/examples/pyconsole-vte.py b/src/python-lxc/examples/pyconsole-vte.py
new file mode 100755
index 0000000..7926758
--- /dev/null
+++ b/src/python-lxc/examples/pyconsole-vte.py
 <at>  <at>  -0,0 +1,58  <at>  <at> 
+#!/usr/bin/python
+#
+# Example program showing use of console functions in the lxc python binding
+#
+
+import warnings
+warnings.filterwarnings("ignore", "The python-lxc API isn't yet stable")
+
+import gtk
+import vte
+import lxc
+import sys
+
+def gtk_exit_cb(terminal):
+    gtk.main_quit()
+
+def vte_con(ct, ttynum):
+    print("Doing console in a VTE widget...")
+    masterfd = ct.console_getfd(ttynum)
+    term = vte.Terminal()
+    term.set_cursor_blinks(True)
+    term.set_scrollback_lines(1000)
+    term.connect('eof', gtk_exit_cb)
+
+    term.set_pty(masterfd)
+    term.feed_child('\n')
+    #term.feed_child('ps aux\n')
+
+    vscrollbar = gtk.VScrollbar()
+    vscrollbar.set_adjustment(term.get_adjustment())
+
+    hbox = gtk.HBox()
+    hbox.pack_start(term)
+    hbox.pack_start(vscrollbar)
+
+    window = gtk.Window()
+    window.add(hbox)
+    window.connect('delete-event', lambda window, event: gtk.main_quit())
+    window.show_all()
+    gtk.main()
+    print("Console done")
+
+if __name__ == '__main__':
+    ttynum = -1
+    if len(sys.argv) < 2:
+        sys.exit("Usage: %s container-name [ttynum]" % sys.argv[0])
+    if len(sys.argv) > 2:
+        ttynum = int(sys.argv[2])
+
+    ct = lxc.Container(sys.argv[1])
+
+    print("Container:%s tty:%d" % (ct.name, ttynum))
+    if not ct.defined:
+        sys.exit("Container %s not defined" % ct.name)
+    if not ct.running:
+        sys.exit("Container %s not running" % ct.name)
+
+    vte_con(ct, ttynum)
diff --git a/src/python-lxc/examples/pyconsole.py b/src/python-lxc/examples/pyconsole.py
new file mode 100755
index 0000000..4dbcf77
--- /dev/null
+++ b/src/python-lxc/examples/pyconsole.py
 <at>  <at>  -0,0 +1,33  <at>  <at> 
+#!/usr/bin/python
+#
+# Example program showing use of console functions in the lxc python binding
+#
+
+import warnings
+warnings.filterwarnings("ignore", "The python-lxc API isn't yet stable")
+
+import lxc
+import sys
+import time
+
+if __name__ == '__main__':
+    ttynum = -1
+    escape = 1
+    if len(sys.argv) < 2:
+        sys.exit("Usage: %s container-name [ttynum [escape]]" % sys.argv[0])
+    if len(sys.argv) > 2:
+        ttynum = int(sys.argv[2])
+    if len(sys.argv) > 3:
+        escape = ord(sys.argv[3]) - ord('a') + 1
+
+    ct = lxc.Container(sys.argv[1])
+
+    print("Container:%s tty:%d Ctrl-%c q to quit" % (ct.name, ttynum, ord('a') + escape-1))
+    time.sleep(1)
+    if not ct.defined:
+        sys.exit("Container %s not defined" % ct.name)
+    if not ct.running:
+        sys.exit("Container %s not running" % ct.name)
+
+    ct.console(ttynum, 0, 1, 2, escape)
+    print("Console done")
diff --git a/src/python-lxc/lxc.c b/src/python-lxc/lxc.c
index 0b31a37..02428d4 100644
--- a/src/python-lxc/lxc.c
+++ b/src/python-lxc/lxc.c
 <at>  <at>  -638,6 +638,40  <at>  <at>  Container_unfreeze(Container *self, PyObject *args, PyObject *kwds)
 }

 static PyObject *
+Container_console(Container *self, PyObject *args, PyObject *kwds)
+{
+    static char *kwlist[] = {"ttynum", "stdinfd", "stdoutfd", "stderrfd", "escape", NULL};
+    int ttynum = -1, stdinfd = 0, stdoutfd = 1, stderrfd = 2, escape = 1;
+
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, "|iiiii", kwlist,
+                                      &ttynum, &stdinfd, &stdoutfd, &stderrfd,
+                                      &escape))
+        return NULL;
+
+    if (self->container->console(self->container, ttynum,
+				 stdinfd, stdoutfd, stderrfd, escape) == 0) {
+        Py_RETURN_TRUE;
+    }
+    Py_RETURN_FALSE;
+}
+
+static PyObject *
+Container_console_getfd(Container *self, PyObject *args, PyObject *kwds)
+{
+    static char *kwlist[] = {"ttynum", NULL};
+    int ttynum = -1, masterfd;
+
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist, &ttynum))
+        return NULL;
+
+    if (self->container->console_getfd(self->container, &ttynum, &masterfd) < 0) {
+        PyErr_SetString(PyExc_ValueError, "Unable to allocate tty");
+        return NULL;
+    }
+    return PyLong_FromLong(masterfd);
+}
+
+static PyObject *
 Container_wait(Container *self, PyObject *args, PyObject *kwds)
 {
     static char *kwlist[] = {"state", "timeout", NULL};
 <at>  <at>  -804,6 +838,18  <at>  <at>  static PyMethodDef Container_methods[] = {
      "\n"
      "Wait for the container to reach a given state or timeout."
     },
+    {"console", (PyCFunction)Container_console,
+     METH_VARARGS|METH_KEYWORDS,
+     "console(ttynum = -1, stdinfd = 0, stdoutfd = 1, stderrfd = 2, escape = 0) -> boolean\n"
+     "\n"
+     "Attach to container's console."
+    },
+    {"console_getfd", (PyCFunction)Container_console_getfd,
+     METH_VARARGS|METH_KEYWORDS,
+     "console(ttynum = -1) -> boolean\n"
+     "\n"
+     "Attach to container's console."
+    },
     {NULL, NULL, 0, NULL}
 };

diff --git a/src/python-lxc/lxc/__init__.py b/src/python-lxc/lxc/__init__.py
index 2fc907c..fd227d3 100644
--- a/src/python-lxc/lxc/__init__.py
+++ b/src/python-lxc/lxc/__init__.py
 <at>  <at>  -291,19 +291,25  <at>  <at>  class Container(_lxc.Container):
         self.load_config()
         return True

-    def console(self, tty="1"):
+    def console(self, ttynum = -1, stdinfd = 0, stdoutfd = 1, stderrfd = 2, escape = 0):
         """
-            Access the console of a container.
+            Attach to console of running container.
         """

         if not self.running:
             return False

-        if subprocess.call(["lxc-console", "-n", self.name, "-t", "%s" % tty,
-                            "-P", self.get_config_path()],
-                           universal_newlines=True) != 0:
+        return _lxc.Container.console(self, ttynum, stdinfd, stdoutfd, stderrfd, escape)
+
+    def console_getfd(self, ttynum = -1):
+        """
+            Attach to console of running container.
+        """
+
+        if not self.running:
             return False
-        return True
+
+        return _lxc.Container.console_getfd(self, ttynum)

     def get_cgroup_item(self, key):
         """
diff --git a/src/tests/console.c b/src/tests/console.c
index a3e7bca..434f7f2 100644
--- a/src/tests/console.c
+++ b/src/tests/console.c
 <at>  <at>  -61,7 +61,7  <at>  <at>  static int test_console_running_container(struct lxc_container *c)
 		ttynum[i] = ttyfd[i] = masterfd[i] = -1;

 	ttynum[0] = 1;
-	ret = c->console(c, &ttynum[0], &masterfd[0]);
+	ret = c->console_getfd(c, &ttynum[0], &masterfd[0]);
 	if (ret < 0) {
 		TSTERR("console allocate failed");
 		goto err1;
 <at>  <at>  -73,7 +73,7  <at>  <at>  static int test_console_running_container(struct lxc_container *c)
 	}

 	/* attempt to alloc same ttynum */
-	ret = c->console(c, &ttynum[0], &masterfd[1]);
+	ret = c->console_getfd(c, &ttynum[0], &masterfd[1]);
 	if (ret != -1) {
 		TSTERR("console allocate should fail for allocated ttynum %d", ttynum[0]);
 		goto err2;
 <at>  <at>  -86,7 +86,7  <at>  <at>  static int test_console_running_container(struct lxc_container *c)
 	 */
 	for (i = 0; i < 10; i++) {
 		for (nrconsoles = 0; nrconsoles < MAXCONSOLES; nrconsoles++) {
-			ret = c->console(c, &ttynum[nrconsoles], &masterfd[nrconsoles]);
+			ret = c->console_getfd(c, &ttynum[nrconsoles], &masterfd[nrconsoles]);
 			if (ret < 0)
 				break;
 			ttyfd[nrconsoles] = ret;
--

-- 
1.8.1.4

------------------------------------------------------------------------------
How ServiceNow helps IT people transform IT departments:
1. A cloud service to automate IT design, transition and operations
2. Dashboards that offer high-level views of enterprise services
3. A single system of record for all IT processes
http://p.sf.net/sfu/servicenow-d2d-j
Dwight Engen | 7 Jun 2013 16:07
Picon
Favicon

[PATCH] fix check for lock acquired

Signed-off-by: Dwight Engen <dwight.engen@...>
---
 src/lxc/lxccontainer.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
index cf5252b..c8fc16f 100644
--- a/src/lxc/lxccontainer.c
+++ b/src/lxc/lxccontainer.c
 <at>  <at>  -418,7 +418,7  <at>  <at>  static void lxcapi_want_daemonize(struct lxc_container *c)
 {
 	if (!c)
 		return;
-	if (!container_mem_lock(c)) {
+	if (container_mem_lock(c)) {
 		ERROR("Error getting mem lock");
 		return;
 	}
--

-- 
1.8.1.4

------------------------------------------------------------------------------
How ServiceNow helps IT people transform IT departments:
1. A cloud service to automate IT design, transition and operations
2. Dashboards that offer high-level views of enterprise services
3. A single system of record for all IT processes
http://p.sf.net/sfu/servicenow-d2d-j

Gmane