The actual behaviour of the console is messy as:
 * it relies on a heuristic (tty or not, rootfs or not, etc ...)
 * the container init stole the tty and we lose the control

The following patch:
 * allocates a tty
 * maps this tty to the container console
 * proxy the io from the console to the file specified in the configuration
 lxc.console=<file>

That allows to specify a file, a fifo, a $(tty), and can be extended with an
uri like file://mypath, net://1.2.3.4:1234, etc ...
That solves the problem with the heuristic and the container does no longer 
stole
our current tty.

Note by default, the console output will go to a blackhole if no configuration 
is
specified making the container showing nothing.

In order to access the console from the tty, use

 lxc-start -n foo -s lxc.console=$(tty)

I propose the make the container to daemonize by default now.

I tried the following:

 in a shell:
  tail --retry -f /var/lib/lxc/foo/console
 in another shell:
  lxc-start -n foo -s lxc.console=$(tty)

Signed-off-by: Daniel Lezcano <dlezc...@fr.ibm.com>
---
 src/lxc/conf.c      |   56 +++++++++++++++++++-----------------
 src/lxc/conf.h      |   30 ++++++++++++++++---
 src/lxc/confile.c   |   20 +++++++++++++
 src/lxc/console.c   |   80 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/lxc/console.h   |   26 ++++++++++++++++
 src/lxc/lxc_start.c |   45 -----------------------------
 src/lxc/start.c     |   78 ++++++++++++--------------------------------------
 7 files changed, 200 insertions(+), 135 deletions(-)

Index: lxc/src/lxc/conf.c
===================================================================
--- lxc.orig/src/lxc/conf.c
+++ lxc/src/lxc/conf.c
@@ -641,41 +641,42 @@ out:
        return 0;
 }
 
-static int setup_console(const char *rootfs, const char *tty)
+static int setup_console(const char *rootfs, const struct lxc_console *console)
 {
-       char console[MAXPATHLEN];
+       char path[MAXPATHLEN];
+       struct stat s;
 
-       snprintf(console, sizeof(console), "%s/dev/console",
-                rootfs ? rootfs : "");
-
-       /* we have the rootfs with /dev/console but no tty
-        * to be used as console, let's remap /dev/console
-        * to /dev/null to avoid to log to the system console
-        */
-       if (rootfs && !tty[0]) {
+       /* We don't have a rootfs, /dev/console will be shared */
+       if (!rootfs)
+               return 0;
 
-               if (!access(console, F_OK)) {
+       snprintf(path, sizeof(path), "%s/dev/console", rootfs);
 
-                       if (mount("/dev/null", console, "none", MS_BIND, 0)) {
-                               SYSERROR("failed to mount '/dev/null'->'%s'",
-                                        console);
-                               return -1;
-                       }
-               }
+       if (access(path, F_OK)) {
+               WARN("rootfs specified but no console found");
+               return 0;
        }
 
-       if (!tty[0])
-               return 0;
+       if (console->peer == -1)
+               INFO("no console output required");
 
-       if (access(console, R_OK|W_OK))
-               return 0;
+       if (stat(path, &s)) {
+               SYSERROR("failed to stat '%s'", path);
+               return -1;
+       }
+
+       if (chmod(console->name, s.st_mode)) {
+               SYSERROR("failed to set mode '0%o' to '%s'",
+                        s.st_mode, console->name);
+               return -1;
+       }
 
-       if (mount(tty, console, "none", MS_BIND, 0)) {
-               ERROR("failed to mount the console");
+       if (mount(console->name, path, "none", MS_BIND, 0)) {
+               ERROR("failed to mount '%s' on '%s'", console->name, path);
                return -1;
        }
 
-       INFO("console '%s' mounted to '%s'", tty, console);
+       INFO("console has been setup");
 
        return 0;
 }
@@ -1073,7 +1074,10 @@ struct lxc_conf *lxc_conf_init(void)
        new->utsname = NULL;
        new->tty = 0;
        new->pts = 0;
-       new->console[0] = '\0';
+       new->console.peer = -1;
+       new->console.master = -1;
+       new->console.slave = -1;
+       new->console.name[0] = '\0';
        lxc_list_init(&new->cgroup);
        lxc_list_init(&new->network);
        lxc_list_init(&new->mount_list);
@@ -1361,7 +1365,7 @@ int lxc_setup(const char *name, struct l
                return -1;
        }
 
-       if (setup_console(lxc_conf->rootfs, lxc_conf->console)) {
+       if (setup_console(lxc_conf->rootfs, &lxc_conf->console)) {
                ERROR("failed to setup the console for '%s'", name);
                return -1;
        }
Index: lxc/src/lxc/conf.h
===================================================================
--- lxc.orig/src/lxc/conf.h
+++ lxc/src/lxc/conf.h
@@ -149,11 +149,31 @@ struct lxc_tty_info {
 };
 
 /*
+ * Defines the structure to store the console information
+ * @peer   : the file descriptor put/get console traffic
+ * @name   : the file name of the slave pty
+ */
+struct lxc_console {
+       int slave;
+       int master;
+       int peer;
+       char name[MAXPATHLEN];
+};
+
+/*
  * Defines the global container configuration
- * @rootfs  : the root directory to run the container
- * @mount   : the list of mount points
- * @network : the network configuration
- * @utsname : the container utsname
+ * @rootfs     : root directory to run the container
+ * @pivotdir   : pivotdir path, if not set default will be used
+ * @mount      : list of mount points
+ * @tty        : numbers of tty
+ * @pts        : new pts instance
+ * @mount_list : list of mount point (alternative to fstab file)
+ * @network    : network configuration
+ * @utsname    : container utsname
+ * @fstab      : path to a fstab file format
+ * @caps       : list of the capabilities
+ * @tty_info   : tty data
+ * @console    : console data
  */
 struct lxc_conf {
        char *rootfs;
@@ -167,7 +187,7 @@ struct lxc_conf {
        struct lxc_list mount_list;
        struct lxc_list caps;
        struct lxc_tty_info tty_info;
-       char console[MAXPATHLEN];
+       struct lxc_console console;
 };
 
 /*
Index: lxc/src/lxc/confile.c
===================================================================
--- lxc.orig/src/lxc/confile.c
+++ lxc/src/lxc/confile.c
@@ -25,6 +25,9 @@
 #include <string.h>
 #include <unistd.h>
 #include <errno.h>
+#include <fcntl.h>
+#include <pty.h>
+#include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/utsname.h>
@@ -59,6 +62,7 @@ static int config_network_mtu(const char
 static int config_network_ipv4(const char *, char *, struct lxc_conf *);
 static int config_network_ipv6(const char *, char *, struct lxc_conf *);
 static int config_cap_drop(const char *, char *, struct lxc_conf *);
+static int config_console(const char *, char *, struct lxc_conf *);
 
 typedef int (*config_cb)(const char *, char *, struct lxc_conf *);
 
@@ -88,6 +92,7 @@ static struct config config[] = {
        { "lxc.network.ipv4",         config_network_ipv4         },
        { "lxc.network.ipv6",         config_network_ipv6         },
        { "lxc.cap.drop",             config_cap_drop             },
+       { "lxc.console",              config_console              },
 };
 
 static const size_t config_size = sizeof(config)/sizeof(struct config);
@@ -615,6 +620,21 @@ static int config_cap_drop(const char *k
        return ret;
 }
 
+static int config_console(const char *key, char *value, struct lxc_conf 
*lxc_conf)
+{
+       int fd;
+
+       fd = open(value, O_CLOEXEC | O_RDWR | O_CREAT | O_APPEND, 0600);
+       if (fd < 0) {
+               SYSERROR("failed to open '%s'", value);
+               return -1;
+       }
+
+       lxc_conf->console.peer = fd;
+
+       return 0;
+}
+
 static int config_rootfs(const char *key, char *value, struct lxc_conf 
*lxc_conf)
 {
        if (strlen(value) >= MAXPATHLEN) {
Index: lxc/src/lxc/console.c
===================================================================
--- lxc.orig/src/lxc/console.c
+++ lxc/src/lxc/console.c
@@ -23,7 +23,9 @@
 
 #include <stdio.h>
 #include <unistd.h>
+#include <fcntl.h>
 #include <errno.h>
+#include <pty.h>
 #include <sys/types.h>
 #include <sys/un.h>
 
@@ -32,6 +34,7 @@
 #include <lxc/start.h>         /* for struct lxc_handler */
 
 #include "commands.h"
+#include "mainloop.h"
 #include "af_unix.h"
 
 lxc_log_define(lxc_console, lxc);
@@ -95,7 +98,7 @@ extern void lxc_console_remove_fd(int fd
 }
 
 extern int lxc_console_callback(int fd, struct lxc_request *request,
-                       struct lxc_handler *handler)
+                               struct lxc_handler *handler)
 {
        int ttynum = request->data;
        struct lxc_tty_info *tty_info = &handler->conf->tty_info;
@@ -135,3 +138,78 @@ out_close:
        return 1;
 }
 
+int lxc_create_console(struct lxc_console *console)
+{
+       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;
+       }
+
+       return 0;
+err:
+       close(console->master);
+       close(console->slave);
+       return -1;
+}
+
+void lxc_delete_console(const struct lxc_console *console)
+{
+       close(console->master);
+       close(console->slave);
+}
+
+static int console_handler(int fd, void *data, struct lxc_epoll_descr *descr)
+{
+       struct lxc_console *console = (struct lxc_console *)data;
+       char buf[1024];
+       int r;
+
+       r = read(fd, buf, sizeof(buf));
+       if (r < 0) {
+               SYSERROR("failed to read");
+               return 1;
+       }
+
+       /* no output for the console, do nothing */
+       if (console->peer == -1)
+               return 0;
+
+       if (console->peer == fd)
+               write(console->master, buf, r);
+       else
+               write(console->peer, buf, r);
+
+       return 0;
+}
+
+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 (lxc_mainloop_add_handler(descr, console->master,
+                                    console_handler, console)) {
+               ERROR("failed to add to mainloop console handler for '%d'",
+                     console->master);
+               return -1;
+       }
+
+       if (console->peer != -1 &&
+           lxc_mainloop_add_handler(descr, console->peer,
+                                    console_handler, console))
+               WARN("console input disabled");
+
+       return 0;
+}
Index: lxc/src/lxc/console.h
===================================================================
--- /dev/null
+++ lxc/src/lxc/console.h
@@ -0,0 +1,26 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2010
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+extern int lxc_create_console(struct lxc_console *);
+extern void lxc_delete_console(struct lxc_console *);
+extern int lxc_console_mainloop_add(struct lxc_epoll_descr *, struct 
lxc_handler *);
Index: lxc/src/lxc/lxc_start.c
===================================================================
--- lxc.orig/src/lxc/lxc_start.c
+++ lxc/src/lxc/lxc_start.c
@@ -43,6 +43,7 @@
 #include "log.h"
 #include "lxc.h"
 #include "conf.h"
+#include "cgroup.h"
 #include "utils.h"
 #include "config.h"
 #include "confile.h"
@@ -87,50 +88,10 @@ Options :\n\
        .daemonize = 0,
 };
 
-static int save_tty(struct termios *tios)
-{
-       if (!isatty(0))
-               return 0;
-
-       if (tcgetattr(0, tios))
-               WARN("failed to get current terminal settings : %s",
-                    strerror(errno));
-
-       return 0;
-}
-
-static int restore_tty(struct termios *tios)
-{
-       struct termios current_tios;
-       void (*oldhandler)(int);
-       int ret;
-
-       if (!isatty(0))
-               return 0;
-
-       if (tcgetattr(0, &current_tios)) {
-               ERROR("failed to get current terminal settings : %s",
-                     strerror(errno));
-               return -1;
-       }
-
-       if (!memcmp(tios, &current_tios, sizeof(*tios)))
-               return 0;
-
-       oldhandler = signal(SIGTTOU, SIG_IGN);
-       ret = tcsetattr(0, TCSADRAIN, tios);
-       if (ret)
-               ERROR("failed to restore terminal attributes");
-       signal(SIGTTOU, oldhandler);
-
-       return ret;
-}
-
 int main(int argc, char *argv[])
 {
        char *const *args;
        int err = -1;
-       struct termios tios;
 
        char *const default_args[] = {
                "/sbin/init",
@@ -213,12 +174,8 @@ int main(int argc, char *argv[])
                }
        }
 
-       save_tty(&tios);
-
        err = lxc_start(my_args.name, args, conf);
 
-       restore_tty(&tios);
-
        return err;
 }
 
Index: lxc/src/lxc/start.c
===================================================================
--- lxc.orig/src/lxc/start.c
+++ lxc/src/lxc/start.c
@@ -88,19 +88,16 @@ int signalfd(int fd, const sigset_t *mas
 #define PR_CAPBSET_DROP 24
 #endif
 
-#include <lxc/log.h>
-#include <lxc/conf.h>
-#include <lxc/confile.h>
-#include <lxc/start.h>
-#include <lxc/utils.h>
-#include <lxc/cgroup.h>
-#include <lxc/monitor.h>
-
+#include "start.h"
+#include "conf.h"
+#include "log.h"
 #include "error.h"
 #include "af_unix.h"
 #include "mainloop.h"
+#include "utils.h"
+#include "monitor.h"
 #include "commands.h"
-
+#include "console.h"
 
 lxc_log_define(lxc_start, lxc);
 
@@ -170,6 +167,11 @@ int lxc_poll(const char *name, struct lx
                goto out_mainloop_open;
        }
 
+       if (lxc_console_mainloop_add(&descr, handler)) {
+               ERROR("failed to add console handler to mainloop");
+               goto out_mainloop_open;
+       }
+
        if (lxc_command_mainloop_add(name, &descr, handler))
                goto out_mainloop_open;
 
@@ -182,50 +184,6 @@ out_sigfd:
        return -1;
 }
 
-static int fdname(int fd, char *name, size_t size)
-{
-       char path[MAXPATHLEN];
-       ssize_t len;
-
-       snprintf(path, MAXPATHLEN, "/proc/self/fd/%d", fd);
-
-       len = readlink(path, name, size);
-       if (len >  0)
-               path[len] = '\0';
-
-       return (len <= 0) ? -1 : 0;
-}
-
-static int console_init(char *console, size_t size)
-{
-       struct stat stat;
-       int i;
-
-       for (i = 0; i < 3; i++) {
-               if (!isatty(i))
-                       continue;
-
-               if (ttyname_r(i, console, size)) {
-                       SYSERROR("failed to retrieve tty name");
-                       return -1;
-               }
-
-               return 0;
-       }
-
-       if (!fstat(0, &stat)) {
-               if (S_ISREG(stat.st_mode) || S_ISCHR(stat.st_mode) ||
-                   S_ISFIFO(stat.st_mode) || S_ISLNK(stat.st_mode))
-                       return fdname(0, console, size);
-       }
-
-       console[0] = '\0';
-
-       DEBUG("console initialized");
-
-       return 0;
-}
-
 struct lxc_handler *lxc_init(const char *name, struct lxc_conf *conf)
 {
        struct lxc_handler *handler;
@@ -244,23 +202,23 @@ struct lxc_handler *lxc_init(const char
                goto out_free;
        }
 
-       if (console_init(conf->console, sizeof(conf->console))) {
-               ERROR("failed to initialize the console");
-               goto out_aborting;
-       }
-
        if (lxc_create_tty(name, conf)) {
                ERROR("failed to create the ttys");
                goto out_aborting;
        }
 
+       if (lxc_create_console(&conf->console)) {
+               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_sigchld_fd(&handler->oldmask);
        if (handler->sigfd < 0) {
                ERROR("failed to set sigchild fd handler");
-               goto out_delete_tty;
+               goto out_delete_console;
        }
 
        /* Avoid signals from terminal */
@@ -270,6 +228,8 @@ struct lxc_handler *lxc_init(const char
        INFO("'%s' is initialized", name);
        return handler;
 
+out_delete_console:
+       lxc_delete_console(&conf->console);
 out_delete_tty:
        lxc_delete_tty(&conf->tty_info);
 out_aborting:


------------------------------------------------------------------------------
The Planet: dedicated and managed hosting, cloud storage, colocation
Stay online with enterprise data centers and the best network in the business
Choose flexible plans and management services without long-term contracts
Personal 24x7 support from experience hosting pros just a phone call away.
http://p.sf.net/sfu/theplanet-com
_______________________________________________
Lxc-devel mailing list
Lxc-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/lxc-devel

Reply via email to