lxc-start -c makes the named file/device the container's console, but using
this with a regular file in order to get a log of the console output does
not work very well if you also want to login on the console. This change
implements an additional option (-L) to simply log the console's output to
a file.

Both options can be used separately or together. For example to get a usable
console and log: lxc-start -n name -c /dev/tty8 -L console.log

The console state is cleaned up more when lxc_delete_console is called, and
some of the clean up paths in lxc_create_console were fixed.

The lxc_priv and lxc_unpriv macros were modified to make use of gcc's local
label feature so they can be expanded more than once in the same function.

Signed-off-by: Dwight Engen <dwight.en...@oracle.com>
---
 doc/lxc-start.sgml.in | 28 ++++++++++------
 src/lxc/arguments.h   |  1 +
 src/lxc/caps.h        | 12 ++++---
 src/lxc/conf.c        |  2 ++
 src/lxc/conf.h        |  2 ++
 src/lxc/console.c     | 58 +++++++++++++++++++++++++++-----
 src/lxc/lxc_start.c   | 91 ++++++++++++++++++++++++++++++---------------------
 7 files changed, 134 insertions(+), 60 deletions(-)

diff --git a/doc/lxc-start.sgml.in b/doc/lxc-start.sgml.in
index 5c98a25..e4036f4 100644
--- a/doc/lxc-start.sgml.in
+++ b/doc/lxc-start.sgml.in
@@ -51,7 +51,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
02111-1307 USA
       <command>lxc-start</command>
       <arg choice="req">-n <replaceable>name</replaceable></arg>
       <arg choice="opt">-f <replaceable>config_file</replaceable></arg>
-      <arg choice="opt">-c <replaceable>console_file</replaceable></arg>
+      <arg choice="opt">-c <replaceable>console_device</replaceable></arg>
+      <arg choice="opt">-L <replaceable>console_logfile</replaceable></arg>
       <arg choice="opt">-d</arg>
       <arg choice="opt">-p <replaceable>pid_file</replaceable></arg>
       <arg choice="opt">-s KEY=VAL</arg>
@@ -76,11 +77,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
02111-1307 USA
       defined, the default isolation is used.
     </para>
     <para>
-      The orphan process group
-      and daemon are not supported by this command, use
-      the <command>lxc-execute</command> command instead.
-    </para>
-    <para>
       If no command is specified, <command>lxc-start</command> will
       use the default
       <command>"/sbin/init"</command> command to run a system
@@ -139,13 +135,25 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
02111-1307 USA
       <varlistentry>
        <term>
          <option>-c,
-         --console <replaceable>console_file</replaceable></option>
+         --console <replaceable>console_device</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+           Specify a device to use for the container's console, for example
+            /dev/tty8. If this option is not specified the current terminal
+            will be used unless <option>-d</option> is specified.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>-L,
+         --console-log <replaceable>console_logfile</replaceable></option>
        </term>
        <listitem>
          <para>
-           Specify a file to output the container console. If the
-           option is not specified the output will go the terminal
-           except if the <option>-d</option> is specified.
+           Specify a file to log the container's console output to.
          </para>
        </listitem>
       </varlistentry>
diff --git a/src/lxc/arguments.h b/src/lxc/arguments.h
index 188c460..5f2ecba 100644
--- a/src/lxc/arguments.h
+++ b/src/lxc/arguments.h
@@ -45,6 +45,7 @@ struct lxc_arguments {
        int daemonize;
        const char *rcfile;
        const char *console;
+       const char *console_log;
        const char *pidfile;
 
        /* for lxc-checkpoint/restart */
diff --git a/src/lxc/caps.h b/src/lxc/caps.h
index 0cf8460..88cf09e 100644
--- a/src/lxc/caps.h
+++ b/src/lxc/caps.h
@@ -33,27 +33,29 @@ extern int lxc_caps_last_cap(void);
 
 #define lxc_priv(__lxc_function)                       \
        ({                                              \
+               __label__ out;                          \
                int __ret, __ret2, __errno = 0;         \
                __ret = lxc_caps_up();                  \
                if (__ret)                              \
-                       goto __out;                     \
+                       goto out;                       \
                __ret = __lxc_function;                 \
                if (__ret)                              \
                        __errno = errno;                \
                __ret2 = lxc_caps_down();               \
-       __out:  __ret ? errno = __errno,__ret : __ret2; \
+       out:    __ret ? errno = __errno,__ret : __ret2; \
        })
 
-#define lxc_unpriv(__lxc_function)             \
+#define lxc_unpriv(__lxc_function)                     \
        ({                                              \
+               __label__ out;                          \
                int __ret, __ret2, __errno = 0;         \
                __ret = lxc_caps_down();                \
                if (__ret)                              \
-                       goto __out;                     \
+                       goto out;                       \
                __ret = __lxc_function;                 \
                if (__ret)                              \
                        __errno = errno;                \
                __ret2 = lxc_caps_up();                 \
-       __out:  __ret ? errno = __errno,__ret : __ret2; \
+       out:    __ret ? errno = __errno,__ret : __ret2; \
        })
 #endif
diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index c82e759..4f041dc 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -2005,6 +2005,8 @@ struct lxc_conf *lxc_conf_init(void)
        memset(new, 0, sizeof(*new));
 
        new->personality = -1;
+       new->console.log_path = NULL;
+       new->console.log_fd = -1;
        new->console.path = NULL;
        new->console.peer = -1;
        new->console.master = -1;
diff --git a/src/lxc/conf.h b/src/lxc/conf.h
index d496916..b576893 100644
--- a/src/lxc/conf.h
+++ b/src/lxc/conf.h
@@ -175,6 +175,8 @@ struct lxc_console {
        int master;
        int peer;
        char *path;
+       char *log_path;
+       int log_fd;
        char name[MAXPATHLEN];
        struct termios *tios;
 };
diff --git a/src/lxc/console.c b/src/lxc/console.c
index 73bec78..cb756f0 100644
--- a/src/lxc/console.c
+++ b/src/lxc/console.c
@@ -195,11 +195,21 @@ int lxc_create_console(struct lxc_conf *conf)
                goto err;
        }
 
+       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;
+       }
+
        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;
+               goto err_close_console_log;
        }
 
        DEBUG("using '%s' as console", console->path);
@@ -212,7 +222,7 @@ int lxc_create_console(struct lxc_conf *conf)
        console->tios = malloc(sizeof(tios));
        if (!console->tios) {
                SYSERROR("failed to allocate memory");
-               goto err;
+               goto err_close_console;
        }
 
        /* Get termios */
@@ -241,26 +251,54 @@ int lxc_create_console(struct lxc_conf *conf)
 
 err_free:
        free(console->tios);
+
+err_close_console:
+       close(console->peer);
+       console->peer = -1;
+
+err_close_console_log:
+       if (console->log_fd >= 0) {
+               close(console->log_fd);
+               console->log_fd = -1;
+       }
+
 err:
        close(console->master);
+       console->master = -1;
+
        close(console->slave);
+       console->slave = -1;
        return -1;
 }
 
-void lxc_delete_console(const struct lxc_console *console)
+void lxc_delete_console(struct lxc_console *console)
 {
        if (console->tios &&
            tcsetattr(console->peer, TCSAFLUSH, console->tios))
                WARN("failed to set old terminal settings");
+       free(console->tios);
+       console->tios = NULL;
+
+       close(console->peer);
+       console->peer = -1;
+
+       if (console->log_fd >= 0) {
+               close(console->log_fd);
+               console->log_fd = -1;
+       }
+
        close(console->master);
+       console->master = -1;
+
        close(console->slave);
+       console->slave = -1;
 }
 
 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;
+       int r,w;
 
        r = read(fd, buf, sizeof(buf));
        if (r < 0) {
@@ -280,10 +318,14 @@ static int console_handler(int fd, void *data, struct 
lxc_epoll_descr *descr)
                return 0;
 
        if (console->peer == fd)
-               r = write(console->master, buf, r);
-       else
-               r = write(console->peer, buf, r);
-
+               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);
+       }
+       if (w != r)
+               WARN("console short write");
        return 0;
 }
 
diff --git a/src/lxc/lxc_start.c b/src/lxc/lxc_start.c
index fb756dd..184fb04 100644
--- a/src/lxc/lxc_start.c
+++ b/src/lxc/lxc_start.c
@@ -54,10 +54,46 @@ lxc_log_define(lxc_start_ui, lxc_start);
 
 static struct lxc_list defines;
 
+static int ensure_path(char **confpath, const char *path)
+{
+       int err = -1, fd;
+       char *fullpath = NULL;
+
+       if (path) {
+               if (access(path, W_OK)) {
+                       fd = creat(path, 0600);
+                       if (fd < 0) {
+                               SYSERROR("failed to create '%s'", path);
+                               goto err;
+                       }
+                       close(fd);
+               }
+
+               fullpath = realpath(path, NULL);
+               if (!fullpath) {
+                       SYSERROR("failed to get the real path of '%s'", path);
+                       goto err;
+               }
+
+               *confpath = strdup(fullpath);
+               if (!*confpath) {
+                       ERROR("failed to dup string '%s'", fullpath);
+                       goto err;
+               }
+       }
+       err = 0;
+
+err:
+       if (fullpath)
+               free(fullpath);
+       return err;
+}
+
 static int my_parser(struct lxc_arguments* args, int c, char* arg)
 {
        switch (c) {
        case 'c': args->console = arg; break;
+       case 'L': args->console_log = arg; break;
        case 'd': args->daemonize = 1; args->close_all_fds = 1; break;
        case 'f': args->rcfile = arg; break;
        case 'C': args->close_all_fds = 1; break;
@@ -72,6 +108,7 @@ static const struct option my_longopts[] = {
        {"rcfile", required_argument, 0, 'f'},
        {"define", required_argument, 0, 's'},
        {"console", required_argument, 0, 'c'},
+       {"console-log", required_argument, 0, 'L'},
        {"close-all-fds", no_argument, 0, 'C'},
        {"pidfile", required_argument, 0, 'p'},
        LXC_COMMON_OPTIONS
@@ -85,15 +122,16 @@ static struct lxc_arguments my_args = {
 lxc-start start COMMAND in specified container NAME\n\
 \n\
 Options :\n\
-  -n, --name=NAME      NAME for name of the container\n\
-  -d, --daemon         daemonize the container\n\
-  -p, --pidfile=FILE   Create a file with the process id\n\
-  -f, --rcfile=FILE    Load configuration file FILE\n\
-  -c, --console=FILE   Set the file output for the container console\n\
-  -C, --close-all-fds  If any fds are inherited, close them\n\
-                       If not specified, exit with failure instead\n\
-                      Note: --daemon implies --close-all-fds\n\
-  -s, --define KEY=VAL Assign VAL to configuration variable KEY\n",
+  -n, --name=NAME        NAME for name of the container\n\
+  -d, --daemon           daemonize the container\n\
+  -p, --pidfile=FILE     Create a file with the process id\n\
+  -f, --rcfile=FILE      Load configuration file FILE\n\
+  -c, --console=FILE     Use specified FILE for the container console\n\
+  -L, --console-log=FILE Log container console output to FILE\n\
+  -C, --close-all-fds    If any fds are inherited, close them\n\
+                         If not specified, exit with failure instead\n\
+                        Note: --daemon implies --close-all-fds\n\
+  -s, --define KEY=VAL   Assign VAL to configuration variable KEY\n",
        .options   = my_longopts,
        .parser    = my_parser,
        .checker   = NULL,
@@ -177,35 +215,14 @@ int main(int argc, char *argv[])
                return err;
        }
 
-       if (my_args.console) {
-
-               char *console, fd;
-
-               if (access(my_args.console, W_OK)) {
-
-                       fd = creat(my_args.console, 0600);
-                       if (fd < 0) {
-                               SYSERROR("failed to touch file '%s'",
-                                        my_args.console);
-                               return err;
-                       }
-                       close(fd);
-               }
-
-               console = realpath(my_args.console, NULL);
-               if (!console) {
-                       SYSERROR("failed to get the real path of '%s'",
-                                my_args.console);
-                       return err;
-               }
-
-               conf->console.path = strdup(console);
-               if (!conf->console.path) {
-                       ERROR("failed to dup string '%s'", console);
-                       return err;
-               }
+       if (ensure_path(&conf->console.path, my_args.console) < 0) {
+               ERROR("failed to ensure console path '%s'", my_args.console);
+               return err;
+       }
 
-               free(console);
+       if (ensure_path(&conf->console.log_path, my_args.console_log) < 0) {
+               ERROR("failed to ensure console log '%s'", my_args.console_log);
+               return err;
        }
 
        if (my_args.pidfile != NULL) {
-- 
1.7.11.7


------------------------------------------------------------------------------
Master Visual Studio, SharePoint, SQL, ASP.NET, C# 2012, HTML5, CSS,
MVC, Windows 8 Apps, JavaScript and much more. Keep your skills current
with LearnDevNow - 3,200 step-by-step video tutorials by Microsoft
MVPs and experts. ON SALE this month only -- learn more at:
http://p.sf.net/sfu/learnmore_122712
_______________________________________________
Lxc-devel mailing list
Lxc-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/lxc-devel

Reply via email to