]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
From: Daniel Lezcano <daniel.lezcano@free.fr>
authordlezcano <dlezcano>
Sun, 25 Jan 2009 21:52:38 +0000 (21:52 +0000)
committerdlezcano <dlezcano>
Sun, 25 Jan 2009 21:52:38 +0000 (21:52 +0000)
Console support for the system container.

Signed-off-by: Daniel Lezcano <daniel.lezcano@free.fr>
Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
28 files changed:
configure.in
doc/Makefile.am
doc/lxc-console.sgml.in [new file with mode: 0644]
doc/lxc.conf.sgml.in
doc/lxc.sgml.in
scripts/lxc-debian.in
src/lxc/Makefile.am
src/lxc/af_unix.c [new file with mode: 0644]
src/lxc/af_unix.h [new file with mode: 0644]
src/lxc/checkpoint.c
src/lxc/console.c [new file with mode: 0644]
src/lxc/create.c
src/lxc/destroy.c
src/lxc/error.c
src/lxc/error.h
src/lxc/lxc.h
src/lxc/lxc_conf.c
src/lxc/lxc_conf.h
src/lxc/lxc_config.c
src/lxc/lxc_console.c
src/lxc/lxc_init.c
src/lxc/lxc_lock.c
src/lxc/lxc_start.c
src/lxc/mainloop.c [new file with mode: 0644]
src/lxc/mainloop.h [new file with mode: 0644]
src/lxc/restart.c
src/lxc/start.c
src/lxc/stop.c

index c91177fc341bc0198341356d6aea92fa75a98217..1f7629452da9ccd41a3639cbbb014bb6df12b6b6 100644 (file)
@@ -1,7 +1,7 @@
 #                                               -*- Autoconf -*-
 # Process this file with autoconf to produce a configure script.
 
-AC_INIT([lxc], [0.5.2])
+AC_INIT([lxc], [0.6.0])
 
 AC_CONFIG_SRCDIR([configure.in])
 AC_CONFIG_MACRO_DIR([m4])
@@ -60,6 +60,7 @@ AC_CONFIG_FILES([
        doc/lxc-execute.sgml
        doc/lxc-start.sgml
        doc/lxc-stop.sgml
+       doc/lxc-console.sgml
        doc/lxc-freeze.sgml
        doc/lxc-unfreeze.sgml
        doc/lxc-monitor.sgml
index 2e495967cc7784cb70b1908411b2c5c2f99250e9..46a7dbb96144ed513b5d9260079235330b78aa58 100644 (file)
@@ -8,6 +8,7 @@ man_MANS = \
        lxc-execute.1 \
        lxc-start.1 \
        lxc-stop.1 \
+       lxc-console.1 \
        lxc-freeze.1 \
        lxc-unfreeze.1 \
        lxc-monitor.1 \
diff --git a/doc/lxc-console.sgml.in b/doc/lxc-console.sgml.in
new file mode 100644 (file)
index 0000000..4d06dee
--- /dev/null
@@ -0,0 +1,162 @@
+<!-- 
+
+lxc: linux Container library
+
+(C) Copyright IBM Corp. 2007, 2008
+
+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
+
+-->
+
+<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN">
+
+<refentry>
+
+  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+
+  <refmeta>
+    <refentrytitle>lxc-console</refentrytitle>
+    <manvolnum>1</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>lxc-console</refname>
+
+    <refpurpose>
+      Launch a console for the specified container
+    </refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>lxc-console <replaceable>-n name</replaceable>
+       <replaceable>-t ttynum</replaceable>
+      </command>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>
+      If the tty service has been configured and is available for the
+      container specified as parameter, this command will launch a
+      console allowing to log to the container.
+    </para>
+
+    <para>
+      The available tty are free slots taken by this command. That
+      means if the container has four ttys available and the command
+      has been launched four times taking the different tty, the fifth
+      command will fail because no console will be available. 
+    </para>
+
+    <para>
+      The command will connect to a tty. If the connection is lost or
+      broken, the command can be launched again and regain the tty at
+      the state it was before the disconnection.
+    </para>
+
+  </refsect1>
+
+  <refsect1>
+    <title>Options</title>
+    <variablelist>
+
+      <varlistentry>
+       <term>
+         <option>-n <replaceable>name</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+           Specify the container name to open a console.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>-t <replaceable>ttynum</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+           Specify the tty number to connect.
+         </para>
+       </listitem>
+      </varlistentry>
+
+    </variablelist>
+
+  </refsect1>
+
+  <refsect1>
+    <title>Diagnostic</title>
+
+    <variablelist>
+
+      <varlistentry>
+        <term>tty service denied</term>
+        <listitem>
+          <para>
+           No tty is available or there is not enough privilege to
+           use the console. For example, the container belongs to
+           user "foo" and "bar" is trying to open a console to it.
+          </para>
+        </listitem>
+      </varlistentry>    
+
+    </variablelist>
+
+  </refsect1>
+
+  <refsect1>
+    <title>See Also</title>
+
+    <simpara>    
+      <citerefentry>
+       <refentrytitle><command>lxc.conf</command></refentrytitle>
+       <manvolnum>5</manvolnum>
+      </citerefentry>
+    </simpara>
+
+
+  </refsect1>
+
+  <refsect1>
+    <title>Author</title>
+    <para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para>
+  </refsect1>
+
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
index 6752a4435299d242af5940d7b46dc73744fdf86a..a6166948816ca286eae9184ae901eaf6d7a40233 100644 (file)
@@ -243,6 +243,33 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
     </refsect2>
 
+    <refsect2>
+      <title>Console through the ttys</title>
+      <para>
+       If the container is configured with a root filesystem and the
+       inittab file is setup to launch a getty on the ttys. This
+       option will specify the number of ttys to be available for the
+       container. The number of getty in the inittab file of the
+       container and the number of tty specified in this
+       configuration file should be equal, otherwise the getty will
+       die and respawn indefinitly giving annoying messages on the
+       console.
+      </para>
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>lxc.tty</option>
+         </term>
+         <listitem>
+           <para>
+             Specify the number of tty to make available to the
+             container.
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+    </refsect2>
+
     <refsect2>
       <title>Mount points</title>
       <para>
index 39de600c0b163a6a8db92821513320e9c751d748..2dfd79febfe00b1715e9fb6fd45e49326a9bb237 100644 (file)
@@ -367,6 +367,20 @@ rootfs
       </para>
     </refsect2>
 
+    <refsect2>
+      <title>Connect to an available tty</title>
+      <para>
+       If the container is configured with the ttys, it is possible
+       to access it through them. It is up to the container to
+       provide a set of available tty to be used by the following
+       command. When the tty is lost, it is possible to reconnect it
+       without login again.
+       <programlisting>
+         lxc-console -n foo -t 3
+       </programlisting>
+      </para>
+    </refsect2>
+
     <refsect2>
       <title>Freeze / Unfreeze a container</title>
       <para>
@@ -591,6 +605,11 @@ rootfs
        <manvolnum>1</manvolnum>
       </citerefentry>,
 
+      <citerefentry>
+       <refentrytitle><command>lxc-console</command></refentrytitle>
+       <manvolnum>1</manvolnum>
+      </citerefentry>,
+
       <citerefentry>
        <refentrytitle><command>lxc-monitor</command></refentrytitle>
        <manvolnum>1</manvolnum>
index 55f848886d70c8cf9d86f65c29fb7567b81615d7..fa244ad0f3c02b44d85f094facee1aee3728c218 100755 (executable)
@@ -49,6 +49,10 @@ l6:6:wait:/etc/init.d/rc 6
 # Normally not reached, but fallthrough in case of emergency.
 z6:6:respawn:/sbin/sulogin
 1:2345:respawn:/sbin/getty 38400 console
+c1:12345:respawn:/sbin/getty 38400 tty1 linux
+c2:12345:respawn:/sbin/getty 38400 tty2 linux
+c3:12345:respawn:/sbin/getty 38400 tty3 linux
+c4:12345:respawn:/sbin/getty 38400 tty4 linux
 EOF
 }
 
@@ -107,6 +111,7 @@ EOF
 write_lxc_configuration() {
 cat <<EOF > $CONFFILE
 lxc.utsname = $UTSNAME
+lxc.tty = 4
 lxc.network.type = veth
 lxc.network.flags = up
 lxc.network.link = br0
index e0e5b0e6d1dc913a63d057bd1cbb22ebca8ca36f..677ebe4f663c5e4338b0a86c1b0382de1449bdf6 100644 (file)
@@ -1,4 +1,5 @@
 INCLUDES= -I$(top_srcdir)/src -DLXCPATH="\"$(localstatedir)/lxc\"" -DLXCBINDIR="\"$(bindir)\""
+AM_LDFLAGS= -lutil
 lib_LTLIBRARIES = liblxc.la
 pkginclude_HEADERS = \
                monitor.h \
@@ -18,6 +19,7 @@ liblxc_la_SOURCES = \
        start.c \
        stop.c \
        monitor.c monitor.h \
+       console.c \
        freezer.c \
        checkpoint.c \
        restart.c \
@@ -38,6 +40,9 @@ liblxc_la_SOURCES = \
         rtnl.c rtnl.h \
         genl.c genl.h \
        \
+       mainloop.c mainloop.h \
+       af_unix.c af_unix.h \
+       \
        cr_plugin_columbia.c lxc_plugin.h
 
 liblxc_la_LDFLAGS = -release @PACKAGE_VERSION@
diff --git a/src/lxc/af_unix.c b/src/lxc/af_unix.c
new file mode 100644 (file)
index 0000000..c24df8b
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * 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
+ */
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#define __USE_GNU
+#include <sys/socket.h>
+#undef __USE_GNU
+#include <sys/un.h>
+
+
+int lxc_af_unix_open(const char *path, int type, int flags)
+{
+       int fd;
+       struct sockaddr_un addr;
+
+       if (flags & O_TRUNC)
+               unlink(path);
+
+       fd = socket(PF_UNIX, type, 0);
+       if (fd < 0)
+               return -1;
+
+       memset(&addr, 0, sizeof(addr));
+
+       if (!path)
+               return fd;
+
+       addr.sun_family = AF_UNIX;
+       /* copy entire buffer in case of abstract socket */
+       memcpy(addr.sun_path, path, 
+              path[0]?strlen(path):sizeof(addr.sun_path));
+
+       if (bind(fd, (struct sockaddr *)&addr, sizeof(addr))) {
+               close(fd);
+               return -1;
+       }
+       
+       if (listen(fd, 100)) {
+               close(fd);
+               return -1;
+       }
+
+       return fd;
+}
+
+int lxc_af_unix_close(int fd)
+{
+       struct sockaddr_un addr;
+       socklen_t addrlen;
+       
+       if (!getsockname(fd, (struct sockaddr *)&addr, &addrlen) && 
+           addr.sun_path[0])
+               unlink(addr.sun_path);
+
+       close(fd);
+
+       return 0;
+}
+
+int lxc_af_unix_connect(const char *path)
+{
+       int fd;
+       struct sockaddr_un addr;
+
+       fd = socket(PF_UNIX, SOCK_STREAM, 0);
+       if (fd < 0)
+               return -1;
+
+       memset(&addr, 0, sizeof(addr));
+
+       addr.sun_family = AF_UNIX;
+       /* copy entire buffer in case of abstract socket */
+       memcpy(addr.sun_path, path, 
+              path[0]?strlen(path):sizeof(addr.sun_path));
+
+       if (connect(fd, (struct sockaddr *)&addr, sizeof(addr))) {
+               close(fd);
+               return -1;
+       }
+
+       return fd;
+}
+
+int lxc_af_unix_send_fd(int fd, int sendfd, void *data, size_t size)
+{
+        struct msghdr msg = { 0 };
+        struct iovec iov;
+        struct cmsghdr *cmsg;
+        char cmsgbuf[CMSG_SPACE(sizeof(int))];
+        char buf[1];
+
+        msg.msg_control = cmsgbuf;
+        msg.msg_controllen = sizeof(cmsgbuf);
+
+        cmsg = CMSG_FIRSTHDR(&msg);
+        cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+        cmsg->cmsg_level = SOL_SOCKET;
+        cmsg->cmsg_type = SCM_RIGHTS;
+        *((int *) CMSG_DATA(cmsg)) = sendfd;
+        msg.msg_controllen = cmsg->cmsg_len;
+
+        msg.msg_name = NULL;
+        msg.msg_namelen = 0;
+
+        iov.iov_base = data ? data : buf;
+        iov.iov_len = data ? size : sizeof(buf);
+        msg.msg_iov = &iov;
+        msg.msg_iovlen = 1;
+
+        return sendmsg(fd, &msg, 0);
+}
+
+int lxc_af_unix_recv_fd(int fd, int *recvfd, void *data, size_t size)
+{
+        struct msghdr msg = { 0 };
+        struct iovec iov;
+        struct cmsghdr *cmsg;
+        char cmsgbuf[CMSG_SPACE(sizeof(int))];
+        char buf[1];
+       int ret;
+
+        msg.msg_name = NULL;
+        msg.msg_namelen = 0;
+        msg.msg_control = cmsgbuf;
+        msg.msg_controllen = sizeof(cmsgbuf);
+
+        iov.iov_base = data ? data : buf;
+        iov.iov_len = data ? size : sizeof(buf);
+        msg.msg_iov = &iov;
+        msg.msg_iovlen = 1;
+
+       ret = recvmsg(fd, &msg, 0);
+       if (ret <= 0)
+               goto out;
+
+        cmsg = CMSG_FIRSTHDR(&msg);
+
+       /* if the message is wrong the variable will not be 
+        * filled and the peer will notified about a problem */
+       *recvfd = -1;
+
+        if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(int)) &&
+            cmsg->cmsg_level == SOL_SOCKET &&
+            cmsg->cmsg_type == SCM_RIGHTS) {
+                *recvfd = *((int *) CMSG_DATA(cmsg));
+        }
+out:
+        return ret;
+}
+
+int lxc_af_unix_send_credential(int fd, void *data, size_t size)
+{
+        struct msghdr msg = { 0 };
+        struct iovec iov;
+        struct cmsghdr *cmsg;
+       struct ucred cred = {
+               .pid = getpid(),
+               .uid = getuid(),
+               .gid = getgid(),
+       };
+        char cmsgbuf[CMSG_SPACE(sizeof(cred))];
+        char buf[1];
+
+        msg.msg_control = cmsgbuf;
+        msg.msg_controllen = sizeof(cmsgbuf);
+
+        cmsg = CMSG_FIRSTHDR(&msg);
+        cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
+        cmsg->cmsg_level = SOL_SOCKET;
+        cmsg->cmsg_type = SCM_CREDENTIALS;
+       *((struct ucred *) CMSG_DATA(cmsg)) = cred;
+        msg.msg_controllen = cmsg->cmsg_len;
+
+        msg.msg_name = NULL;
+        msg.msg_namelen = 0;
+
+        iov.iov_base = data ? data : buf;
+        iov.iov_len = data ? size : sizeof(buf);
+        msg.msg_iov = &iov;
+        msg.msg_iovlen = 1;
+
+        return sendmsg(fd, &msg, 0);
+}
+
+int lxc_af_unix_rcv_credential(int fd, void *data, size_t size)
+{
+        struct msghdr msg = { 0 };
+        struct iovec iov;
+        struct cmsghdr *cmsg;
+       struct ucred cred;
+        char cmsgbuf[CMSG_SPACE(sizeof(cred))];
+        char buf[1];
+       int ret;
+
+        msg.msg_name = NULL;
+        msg.msg_namelen = 0;
+        msg.msg_control = cmsgbuf;
+        msg.msg_controllen = sizeof(cmsgbuf);
+
+        iov.iov_base = data ? data : buf;
+        iov.iov_len = data ? size : sizeof(buf);
+        msg.msg_iov = &iov;
+        msg.msg_iovlen = 1;
+
+       ret = recvmsg(fd, &msg, 0);
+       if (ret <= 0)
+               goto out;
+
+        cmsg = CMSG_FIRSTHDR(&msg);
+
+       ret = -1;
+
+        if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)) &&
+            cmsg->cmsg_level == SOL_SOCKET &&
+            cmsg->cmsg_type == SCM_CREDENTIALS) {
+                cred = *((struct ucred *) CMSG_DATA(cmsg));
+               if (cred.uid == getuid() && cred.gid == getgid())
+                       ret = 0;
+        }
+out:
+        return ret;
+}
diff --git a/src/lxc/af_unix.h b/src/lxc/af_unix.h
new file mode 100644 (file)
index 0000000..e1d5db7
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * 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_af_unix_open(const char *path, int type, int flags);
+extern int lxc_af_unix_close(int fd);
+extern int lxc_af_unix_connect(const char *path);
+extern int lxc_af_unix_send_fd(int fd, int sendfd, void *data, size_t size);
+extern int lxc_af_unix_recv_fd(int fd, int *recvfd, void *data, size_t size);
+extern int lxc_af_unix_send_credential(int fd, void *data, size_t size);
+extern int lxc_af_unix_rcv_credential(int fd, void *data, size_t size);
+
index 995de100fbd252ab53e26a210f2c197c7abdc6c4..724c24c60cd6794119aea1ec5cb4e49521f2f83d 100644 (file)
@@ -53,17 +53,17 @@ int lxc_checkpoint(const char *name, const char *statefile,
        lock = lxc_get_lock(name);
        if (lock >= 0) {
                lxc_put_lock(lock);
-               return -LXC_ERROR_EMPTY;
+               return -LXC_ERROR_ESRCH;
        }
 
-       if (lock < 0 && lock != -EWOULDBLOCK)
-               return -LXC_ERROR_LOCK;
+       if (lock < 0 && lock != -LXC_ERROR_EBUSY)
+               return lock;
 
        snprintf(init, MAXPATHLEN, LXCPATH "/%s/init", name);
        fd = open(init, O_RDONLY);
        if (fd < 0) {
                lxc_log_syserror("failed to open init file for %s", name);
-               goto out_unlock;
+               goto out_close;
        }
        
        if (read(fd, val, sizeof(val)) < 0) {
@@ -82,7 +82,5 @@ int lxc_checkpoint(const char *name, const char *statefile,
 
 out_close:
        close(fd);
-out_unlock:
-       lxc_put_lock(lock);
        return ret;
 }
diff --git a/src/lxc/console.c b/src/lxc/console.c
new file mode 100644 (file)
index 0000000..6953b93
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * 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
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/un.h>
+
+#include "lxc_log.h"
+#include "af_unix.h"
+#include "error.h"
+
+extern int lxc_console(const char *name, int ttynum, int *fd)
+{
+       struct sockaddr_un addr = { 0 };
+       int sock, ret = -LXC_ERROR_TTY_EAGAIN;
+
+       snprintf(addr.sun_path, sizeof(addr.sun_path), "@%s", name);
+       addr.sun_path[0] = '\0';
+
+       sock = lxc_af_unix_connect(addr.sun_path);
+       if (sock < 0) {
+               lxc_log_error("failed to connect to the tty service");
+               goto out_err;
+       }
+
+       ret = lxc_af_unix_send_credential(sock, &ttynum, sizeof(ttynum));
+       if (ret < 0) {
+               lxc_log_syserror("failed to send credentials");
+               goto out_err;
+       }
+
+       ret = lxc_af_unix_recv_fd(sock, fd, NULL, 0);
+       if (ret < 0) {
+               lxc_log_error("failed to connect to the tty");
+               goto out_err;
+       }
+
+       if (!ret) {
+               lxc_log_error("tty%d denied by '%s'", ttynum, name);
+               ret = -LXC_ERROR_TTY_DENIED;
+               goto out_err;
+       }
+
+       ret = 0;
+
+out_err:
+       close(sock);
+       return ret;
+}
index 89d46c4469aef4cebe4f8d0ac777377b0889542c..9af6f3800cea6ff646bbea4036885062edc4e4a5 100644 (file)
@@ -99,7 +99,7 @@ int lxc_create(const char *name, struct lxc_conf *conf)
        err = create_lxc_directory(name);
        if (err < 0)
                return err == -EEXIST ?
-                       -LXC_ERROR_ALREADY_EXISTS:LXC_ERROR_INTERNAL;
+                       -LXC_ERROR_EEXIST : LXC_ERROR_INTERNAL;
        
        lock = lxc_get_lock(name);
        if (lock < 0)
index 01b4b43112f44444237d22fa7c7418d7e8799d5c..e96489ff7949bc2391de1e00058835e2db36d03d 100644 (file)
@@ -52,13 +52,8 @@ int lxc_destroy(const char *name)
        char path[MAXPATHLEN];
 
        lock = lxc_get_lock(name);
-       if (lock < 0) {
-               if (lock == -EWOULDBLOCK)
-                       return -LXC_ERROR_BUSY;
-               if (lock == -ENOENT)
-                       return -LXC_ERROR_NOT_FOUND;
-               return -LXC_ERROR_INTERNAL;
-       }
+       if (lock < 0)
+               return lock;
 
        if (lxc_rmstate(name)) {
                lxc_log_error("failed to remove state file for %s", name);
index 8f2dbc8b538b4d793d18a58d609799cd466756a2..4af8d10652e965476549853be70d29e1dac0cda6 100644 (file)
@@ -29,17 +29,18 @@ static const char *const catalogue[] = {
 
        [LXC_ERROR_LOCK] = "Failed to lock the container",
 
-       [LXC_ERROR_EMPTY] = "The container is empty",
-       [LXC_ERROR_ALREADY_EXISTS] = "The container already exists",
-       [LXC_ERROR_BUSY] = "The container is busy",
-       [LXC_ERROR_NOT_FOUND] = "The container was not found",
-       [LXC_ERROR_PERMISSION_DENIED] = "Permission denied",
+       [LXC_ERROR_ESRCH] = "The container is empty",
+       [LXC_ERROR_EEXIST] = "The container already exists",
+       [LXC_ERROR_EBUSY] = "The container is busy",
+       [LXC_ERROR_ENOENT] = "The container was not found",
+       [LXC_ERROR_EACCES] = "Not enough privilege to use the container",
        [LXC_ERROR_WRONG_COMMAND] = "Wrong command",
 
        [LXC_ERROR_CONF_CGROUP] = "Failed to configure the control group",
        [LXC_ERROR_CONF_MOUNT] = "Failed to configure the mount points",
        [LXC_ERROR_CONF_UTSNAME] = "Failed to configure the utsname",
        [LXC_ERROR_CONF_NETWORK] = "Failed to configure the network",
+       [LXC_ERROR_CONF_TTY] = "Failed to configure the tty",
        [LXC_ERROR_CONF_ROOTFS] = "Failed to configure the root fs",
 
        [LXC_ERROR_SETUP_CGROUP] = "Failed to setup the control group",
@@ -47,8 +48,11 @@ static const char *const catalogue[] = {
        [LXC_ERROR_SETUP_UTSNAME] = "Failed to setup the utsname",
        [LXC_ERROR_SETUP_NETWORK] = "Failed to setup the network",
        [LXC_ERROR_SETUP_CONSOLE] = "Failed to setup the console",
+       [LXC_ERROR_SETUP_TTY] = "Failed to setup the tty",
        [LXC_ERROR_SETUP_ROOTFS] = "Failed to setup the root fs",
 
+       [LXC_ERROR_TTY_DENIED] = "tty service denied",
+       [LXC_ERROR_TTY_EAGAIN] = "tty service is not available",
        [LXC_ERROR_INTERNAL] = "Internal system error",
 };
 
index e0296440fcde6d1034eb6b593027abbe1399396a..b79adf6964ee448fc89146f3139da0bb25492e50 100644 (file)
@@ -28,17 +28,18 @@ typedef enum {
 
        LXC_ERROR_LOCK,
 
-       LXC_ERROR_EMPTY,
-       LXC_ERROR_BUSY,
-       LXC_ERROR_ALREADY_EXISTS,
-       LXC_ERROR_NOT_FOUND,
-       LXC_ERROR_PERMISSION_DENIED,
+       LXC_ERROR_ESRCH,
+       LXC_ERROR_EEXIST,
+       LXC_ERROR_EBUSY,
+       LXC_ERROR_ENOENT,
+       LXC_ERROR_EACCES,
        LXC_ERROR_WRONG_COMMAND,
 
        LXC_ERROR_CONF_CGROUP,
        LXC_ERROR_CONF_MOUNT,
        LXC_ERROR_CONF_UTSNAME,
        LXC_ERROR_CONF_NETWORK,
+       LXC_ERROR_CONF_TTY,
        LXC_ERROR_CONF_ROOTFS,
 
        LXC_ERROR_SETUP_CGROUP,
@@ -46,8 +47,11 @@ typedef enum {
        LXC_ERROR_SETUP_UTSNAME,
        LXC_ERROR_SETUP_NETWORK,
        LXC_ERROR_SETUP_CONSOLE,
+       LXC_ERROR_SETUP_TTY,
        LXC_ERROR_SETUP_ROOTFS,
 
+       LXC_ERROR_TTY_DENIED,
+       LXC_ERROR_TTY_EAGAIN,
        LXC_ERROR_INTERNAL,
 
        LXC_LAST_ERROR,
index de8c3533ca44374deadc019fcecd18f6b53e5ff1..1dd74bb507366c6f08072dcbfe57baaa482dfccd 100644 (file)
@@ -40,6 +40,7 @@ extern "C" {
 #include <lxc/lxc_lock.h>
 #include <lxc/lxc_namespace.h>
 #include <lxc/lxc_utils.h>
+#include <lxc/error.h>
 #include <lxc/cgroup.h>
 #include <lxc/monitor.h>
 
@@ -120,7 +121,7 @@ extern int lxc_monitor_close(int fd);
  * @name : the name of container
  * Returns 0 on sucess, < 0 otherwise
  */
-extern int lxc_console(const char *name);
+extern int lxc_console(const char *name, int ttynum, int *fd);
 
 /*
  * Freeze all the tasks running inside the container <name>
index ab3586035576013a6432ff1f07fddc6be4a8e122..826cc96c10b7ba981414473e645e3b049d562815 100644 (file)
@@ -29,6 +29,7 @@
 #include <dirent.h>
 #include <mntent.h>
 #include <unistd.h>
+#include <pty.h>
 
 #include <sys/types.h>
 #include <sys/utsname.h>
@@ -427,6 +428,28 @@ static int configure_cgroup(const char *name, struct lxc_list *cgroup)
        return 0;
 }
 
+static int configure_tty(const char *name, int tty)
+{
+       char path[MAXPATHLEN];
+       char *nbtty;
+       int ret;
+
+       if (asprintf(&nbtty, "%d", tty) < 0) {
+               lxc_log_error("failed to convert tty number");
+               return -1;
+       }
+
+       snprintf(path, MAXPATHLEN, LXCPATH "/%s", name);
+
+       ret = write_info(path, "tty", nbtty);
+       if (ret)
+               lxc_log_error("failed to write the tty info");
+
+       free(nbtty);
+
+       return ret;
+}
+
 static int configure_rootfs(const char *name, const char *rootfs)
 {
        char path[MAXPATHLEN];
@@ -447,7 +470,6 @@ static int configure_rootfs(const char *name, const char *rootfs)
        }
 
        return symlink(absrootfs, path);
-
 }
 
 static int configure_mount(const char *name, const char *fstab)
@@ -647,6 +669,31 @@ static int setup_utsname(const char *name)
        return 0;
 }
 
+static int setup_tty(const char *name, const struct lxc_tty_info *tty_info)
+{
+       char path[MAXPATHLEN];
+       int i;
+
+       for (i = 0; i < tty_info->nbtty; i++) {
+
+               struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
+
+               snprintf(path, MAXPATHLEN, LXCPATH "/%s/rootfs/dev/tty%d", name, i + 1);
+
+               /* At this point I can not use the "access" function 
+                * to check the file is present or not because it fails
+                * with EACCES errno and I don't know why :( */
+                       
+               if (mount(pty_info->name, path, "none", MS_BIND, 0)) {
+                       lxc_log_warning("failed to mount '%s'->'%s'", 
+                                       pty_info->name, path);
+                       continue;
+               }
+       }
+
+       return 0;
+}
+
 static int setup_rootfs(const char *name)
 {
        char path[MAXPATHLEN];
@@ -1067,6 +1114,11 @@ int lxc_configure(const char *name, struct lxc_conf *conf)
                return -LXC_ERROR_CONF_NETWORK;
        }
 
+       if (conf->tty && configure_tty(name, conf->tty)) {
+               lxc_log_error("failed to configure the tty");
+               return -LXC_ERROR_CONF_TTY;
+       }
+
        if (conf->rootfs && configure_rootfs(name, conf->rootfs)) {
                lxc_log_error("failed to configure the rootfs");
                return -LXC_ERROR_CONF_ROOTFS;
@@ -1393,7 +1445,78 @@ int conf_destroy_network(const char *name)
        return 0;
 }
 
-int lxc_setup(const char *name, const char *tty)
+int lxc_create_tty(const char *name, struct lxc_tty_info *tty_info)
+{
+       char path[MAXPATHLEN];
+       char tty[4];
+       int i, ret = -1;
+
+       tty_info->nbtty = 0;
+
+       if (!conf_has_tty(name))
+               return 0;
+
+       if (!conf_has_rootfs(name)) {
+               lxc_log_warning("no rootfs is configured, ignoring ttys");
+               return 0;
+       }
+
+       snprintf(path, MAXPATHLEN, LXCPATH "/%s", name);
+
+       if (read_info(path, "tty", tty, sizeof(tty)) < 0) {
+               lxc_log_syserror("failed to read tty info");
+               goto out;
+       }
+
+       tty_info->nbtty = atoi(tty);
+       tty_info->pty_info = 
+               malloc(sizeof(*tty_info->pty_info)*tty_info->nbtty);
+       
+       if (!tty_info->pty_info) {
+               lxc_log_syserror("failed to allocate pty_info");
+               goto out;
+       }
+
+       for (i = 0; i < tty_info->nbtty; i++) {
+               
+               struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
+
+               if (openpty(&pty_info->master, &pty_info->slave, 
+                           pty_info->name, NULL, NULL)) {
+                       lxc_log_syserror("failed to create pty #%d", i);
+                       goto out_free;
+               }
+
+               pty_info->busy = 0;
+       }
+
+       ret = 0;
+out:
+       return ret;
+
+out_free:
+       free(tty_info->pty_info);
+       goto out;
+}
+
+void lxc_delete_tty(struct lxc_tty_info *tty_info)
+{
+       int i;
+
+       for (i = 0; i < tty_info->nbtty; i++) {
+               struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
+
+               close(pty_info->master);
+               close(pty_info->slave);
+       }
+
+       free(tty_info->pty_info);
+       tty_info->nbtty = 0;
+}
+
+int lxc_setup(const char *name, const char *tty, 
+             const struct lxc_tty_info *tty_info)
+             
 {
        if (conf_has_utsname(name) && setup_utsname(name)) {
                lxc_log_error("failed to setup the utsname for '%s'", name);
@@ -1420,6 +1543,11 @@ int lxc_setup(const char *name, const char *tty)
                return -LXC_ERROR_SETUP_CONSOLE;
        }
 
+       if (tty_info->nbtty && setup_tty(name, tty_info)) {
+               lxc_log_error("failed to setup the ttys for '%s'", name);
+               return -LXC_ERROR_SETUP_TTY;
+       }
+
        if (conf_has_rootfs(name) && setup_rootfs(name)) {
                lxc_log_error("failed to set rootfs for '%s'", name);
                return -LXC_ERROR_SETUP_ROOTFS;
index fe4b80fdff0ee0ac9e008097ac9aa0f58e921c80..708a6ca8edbe1ad863bba99270645df7ab27bf7d 100644 (file)
@@ -24,6 +24,7 @@
 #define _conf_h
 
 #include <netinet/in.h>
+#include <sys/param.h>
 
 enum { 
        EMPTY,
@@ -117,11 +118,36 @@ struct lxc_cgroup {
 struct lxc_conf {
        char *rootfs;
        char *fstab;
+       int tty;
        struct utsname *utsname;
        struct lxc_list cgroup;
        struct lxc_list networks;
 };
 
+/*
+ * Defines a structure containing a pty information for
+ * virtualizing a tty
+ * @name   : the path name of the slave pty side
+ * @master : the file descriptor of the master
+ * @slave  : the file descriptor of the slave
+ */
+struct lxc_pty_info {
+       char name[MAXPATHLEN];
+       int master;
+       int slave;
+       int busy;
+};
+
+/*
+ * Defines the number of tty configured and contains the
+ * instanciated ptys
+ * @nbtty = number of configured ttys
+ */
+struct lxc_tty_info {
+       int nbtty;
+       struct lxc_pty_info *pty_info;
+};
+
 /*
  * Configure the external resources for the container
  */
@@ -136,10 +162,14 @@ extern int conf_create_network(const char *name, pid_t pid);
 
 extern int conf_destroy_network(const char *name);
 
+extern int lxc_create_tty(const char *name, struct lxc_tty_info *tty_info);
+extern void lxc_delete_tty(struct lxc_tty_info *tty_info);
+
 /*
  * Configure the container from inside
  */
-extern int lxc_setup(const char *name, const char *tty);
+extern int lxc_setup(const char *name, const char *tty, 
+                    const struct lxc_tty_info *tty_info);
 
 extern int conf_has(const char *name, const char *info);
 
@@ -148,6 +178,7 @@ extern int conf_has(const char *name, const char *info);
 #define conf_has_utsname(__name) conf_has(__name, "utsname")
 #define conf_has_network(__name) conf_has(__name, "network")
 #define conf_has_console(__name) conf_has(__name, "console")
-#define conf_has_cgroup(__name) conf_has(__name, "cgroup")
+#define conf_has_cgroup(__name)  conf_has(__name, "cgroup")
+#define conf_has_tty(__name)     conf_has(__name, "tty")
 
 #endif
index 10361486d25069128b1c14abc91e2490bf6ddf77..8b83a83d5e3793bb09841c42c3680dc2bfa6a019 100644 (file)
@@ -37,6 +37,7 @@
 typedef int (*file_cb)(char* buffer, void *data);
 typedef int (*config_cb)(const char *, char *, struct lxc_conf *);
 
+static int config_tty(const char *, char *, struct lxc_conf *);
 static int config_cgroup(const char *, char *, struct lxc_conf *);
 static int config_mount(const char *, char *, struct lxc_conf *);
 static int config_rootfs(const char *, char *, struct lxc_conf *);
@@ -56,6 +57,7 @@ struct config {
 
 static struct config config[] = {
 
+       { "lxc.tty",            config_tty            },
        { "lxc.cgroup",         config_cgroup         },
        { "lxc.mount",          config_mount          },
        { "lxc.rootfs",         config_rootfs         },
@@ -417,6 +419,15 @@ static int config_network_ipv6(const char *key, char *value, struct lxc_conf *lx
        return 0;
 }
 
+static int config_tty(const char *key, char *value, struct lxc_conf *lxc_conf)
+{
+       int nbtty = atoi(value);
+
+       lxc_conf->tty = nbtty;
+
+       return 0;
+}
+
 static int config_cgroup(const char *key, char *value, struct lxc_conf *lxc_conf)
 {
        char *token = "lxc.cgroup.";
@@ -580,6 +591,7 @@ int lxc_config_init(struct lxc_conf *conf)
        conf->rootfs = NULL;
        conf->fstab = NULL;
        conf->utsname = NULL;
+       conf->tty = 0;
        lxc_list_init(&conf->cgroup);
        lxc_list_init(&conf->networks);
        return 0;
index b16b29fc0516323aa064561024f6db3f9db49115..6a9881a4f0321b3572d60e184f3c6142cbe75340 100644 (file)
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
+
+#define _GNU_SOURCE
 #include <stdio.h>
+#undef _GNU_SOURCE
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <termios.h>
 #include <unistd.h>
+#include <signal.h>
+#include <libgen.h>
+#include <sys/param.h>
 #include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/poll.h>
 
-#include <lxc/lxc.h>
+#include "error.h"
+#include "lxc.h"
 
-int main(int argc, char *argv[])
+void usage(char *cmd)
 {
-       return 0;
+       fprintf(stderr, "%s <command>\n", basename(cmd));
+       fprintf(stderr, "\t -n <name>   : name of the container\n");
+       fprintf(stderr, "\t -t <tty#>   : tty number\n");
+       _exit(1);
 }
 
+int main(int argc, char *argv[])
+{
+       char opt;
+       char *name = NULL;
+       int ttynum = 0;
+       int nbargs = 0;
+       int master = -1;
+       int wait4q = 0;
+       int err = LXC_ERROR_INTERNAL;
+       struct termios tios, oldtios;
+
+       while ((opt = getopt(argc, argv, "t:n:")) != -1) {
+               switch (opt) {
+               case 'n':
+                       name = optarg;
+                       break;
+               case 't':
+                       ttynum = atoi(optarg);
+                       break;
+               }
+
+               nbargs++;
+       }
+
+       if (!name || !ttynum)
+               usage(argv[0]);
+
+       /* Get current termios */
+       if (tcgetattr(0, &tios)) {
+               lxc_log_error("failed to get current terminal settings");
+               fprintf(stderr, "%s\n", lxc_strerror(err));
+               return 1;
+       }
+
+       oldtios = tios;
+
+       /* 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;
+
+       /* Set new attributes */
+       if (tcsetattr(0, TCSAFLUSH, &tios)) {
+               lxc_log_syserror("failed to set new terminal settings");
+               fprintf(stderr, "%s\n", lxc_strerror(err));
+               return 1;
+       }
+
+       err = lxc_console(name, ttynum, &master);
+       if (err) {
+               fprintf(stderr, "%s\n", lxc_strerror(err));
+               goto out;
+       }
+
+       fprintf(stderr, "\nType <Ctrl+a q> to exit the console\n");
+
+       setsid();
+
+       err = 0;
+
+       /* let's proxy the tty */
+       for (;;) {
+               char c;
+               struct pollfd pfd[2] = {
+                       { .fd = 0,
+                         .events = POLLIN|POLLPRI,
+                         .revents = 0 },
+                       { .fd = master,
+                         .events = POLLIN|POLLPRI,
+                         .revents = 0 },
+               };
+
+               if (poll(pfd, 2, -1) < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       lxc_log_syserror("failed to poll");
+                       goto out_err;
+               }
+               
+               /* read the "stdin" and write that to the master
+                */
+               if (pfd[0].revents & POLLIN) {
+                       read(0, &c, 1);
+
+                       /* we want to exit the console with Ctrl+a q */
+                       if (c == 1) {
+                               wait4q = !wait4q;
+                               continue;
+                       }
+
+                       if (c == 'q' && wait4q)
+                               goto out;
+
+                       wait4q = 0;
+                       write(master, &c, 1);
+               }
+
+               /* other side has closed the connection */
+               if (pfd[1].revents & POLLHUP)
+                       goto out;
+
+               /* read the master and write to "stdout" */
+               if (pfd[1].revents & POLLIN) {
+                       read(master, &c, 1);
+                       printf("%c", c);
+                       fflush(stdout);
+               }
+       }
+out:
+       /* Restore previous terminal parameter */
+       tcsetattr(0, TCSAFLUSH, &oldtios);
+       
+       /* Return to line it is */
+       printf("\n");
+
+       close(master);
+
+       return err;
+
+out_err:
+       fprintf(stderr, "%s\n", lxc_strerror(-LXC_ERROR_INTERNAL));
+       err = 1;
+       goto out;
+}
index e18eaef6f448f8b23e75cc00d2bd15266657cdad..13caec63e73ca54f23ac54d11cb9eeb331fa9ec8 100644 (file)
@@ -25,6 +25,7 @@
 #include <unistd.h>
 #include <stdlib.h>
 #include <errno.h>
+#include <signal.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <sys/mount.h>
@@ -42,7 +43,6 @@ static struct option options[] = {
 int main(int argc, char *argv[])
 {
        pid_t pid;
-
        int nbargs = 0;
        char **aargv;
 
@@ -85,6 +85,8 @@ int main(int argc, char *argv[])
                exit(1);
        }
 
+       
+
        for (;;) {
                int status;
                if (wait(&status) < 0) {
index 0eadfabc24dcfe90fcb9f8a797308a446a841198..a5408d52768363a05f43c3562b860540a05dcd47 100644 (file)
@@ -30,6 +30,7 @@
 #include <sys/file.h>
 #include <sys/param.h>
 
+#include "error.h"
 #include <lxc/lxc.h>
 
 int lxc_get_lock(const char *name)
@@ -38,23 +39,46 @@ int lxc_get_lock(const char *name)
        int fd, ret;
 
        snprintf(lock, MAXPATHLEN, LXCPATH "/%s", name);
+
+       /* need to check access because of cap_dac_override */
+       if (access(lock, R_OK |W_OK | X_OK)) {
+               ret = errno;
+               goto out_err;
+       }
+
        fd = open(lock, O_RDONLY|O_DIRECTORY, S_IRUSR|S_IWUSR);
        if (fd < 0) {
-               ret = -errno;
-               goto out;
+               ret = errno;
+               goto out_err;
        }
 
         fcntl(fd, F_SETFD, FD_CLOEXEC);
 
        if (flock(fd, LOCK_EX|LOCK_NB)) {
-               ret = -errno;
+               ret = errno;
                close(fd);
-               goto out;
+               goto out_err;
        }
 
        ret = fd;
 out:
        return ret;
+
+out_err:
+       switch (ret) {
+       case EWOULDBLOCK:
+               ret = -LXC_ERROR_EBUSY;
+               goto out;
+       case ENOENT:
+               ret = -LXC_ERROR_ENOENT;
+               goto out;
+       case EACCES:
+               ret = -LXC_ERROR_EACCES;
+               goto out;
+       default:
+               ret = -LXC_ERROR_LOCK;
+               goto out;
+       }
 }
 
 void lxc_put_lock(int lock)
index a4f84d1efadc3ca2cc09dca48b84a65b6bca32e5..ed7af47565201238464bcc72afae27b4e5168532 100644 (file)
@@ -24,6 +24,8 @@
 #include <libgen.h>
 #include <unistd.h>
 #include <string.h>
+#include <termios.h>
+#include <errno.h>
 #include <sys/param.h>
 #include <sys/utsname.h>
 #include <sys/types.h>
@@ -46,7 +48,9 @@ int main(int argc, char *argv[])
        char opt;
        char *name = NULL;
        char **args;
-       int err, nbargs = 0;
+       int err = LXC_ERROR_INTERNAL, nbargs = 0;
+       struct termios tios;
+
        char *default_args[] = {
                "/sbin/init",
                '\0',
@@ -72,12 +76,21 @@ int main(int argc, char *argv[])
        if (!name)
                usage(argv[0]);
 
+       if (tcgetattr(0, &tios)) {
+               lxc_log_error("failed to get current terminal settings");
+               fprintf(stderr, "%s\n", lxc_strerror(err));
+               return 1;
+       }
+
        err = lxc_start(name, args);
        if (err) {
                fprintf(stderr, "%s\n", lxc_strerror(err));
-               return 1;
+               err = 1;
        }
 
-       return 0;
+       if (tcsetattr(0, TCSAFLUSH, &tios))
+               lxc_log_syserror("failed to restore terminal attributes");
+
+       return err;
 }
 
diff --git a/src/lxc/mainloop.c b/src/lxc/mainloop.c
new file mode 100644 (file)
index 0000000..d951801
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * 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
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/epoll.h>
+
+#include "mainloop.h"
+
+struct lxc_handler {
+       lxc_mainloop_callback_t callback;
+       int fd;
+       void *data;
+};
+
+int lxc_mainloop(struct lxc_epoll_descr *descr)
+{
+       int i, nfds, triggered;
+       struct lxc_handler *handler;
+
+       for (;;) {
+
+               triggered = 0;
+
+               nfds = epoll_wait(descr->epfd, descr->ev, descr->nfds, -1);
+               if (nfds < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       return -1;
+               }
+
+               for (i = 0; i < descr->nfds; i++) {
+
+                       if (!(descr->ev[i].events & EPOLLIN) &&
+                           !(descr->ev[i].events & EPOLLHUP))
+                               continue;
+
+                       triggered++;
+                       handler = (struct lxc_handler *)descr->ev[i].data.ptr;
+
+                       /* If the handler returns a positive value, exit
+                          the mainloop */
+                       if (handler->callback(handler->fd, handler->data, 
+                                             descr) > 0)
+                               return 0;
+
+                       if (triggered == nfds)
+                               break;
+               }
+
+               if (!descr->nfds)
+                       return 0;
+       }
+}
+
+int lxc_mainloop_add_handler(struct lxc_epoll_descr *descr, int fd, 
+                            lxc_mainloop_callback_t callback, void *data)
+{
+       struct epoll_event *ev;
+       struct lxc_handler *handler;
+       int ret = -1;
+
+       handler = malloc(sizeof(*handler));
+       if (!handler)
+               return -1;
+
+       handler->callback = callback;
+       handler->fd = fd;
+       handler->data = data;
+
+       ev = malloc(sizeof(*descr->ev) * (descr->nfds + 1));
+       if (!ev)
+               goto out_free;
+
+       if (descr->nfds) {
+               memcpy(ev, descr->ev, sizeof(*descr->ev) * (descr->nfds));
+               free(descr->ev);
+       }
+
+       descr->ev = ev;
+       descr->ev[descr->nfds].events = EPOLLIN;
+       descr->ev[descr->nfds].data.ptr = handler;
+
+       ret = epoll_ctl(descr->epfd, EPOLL_CTL_ADD, fd, 
+                       &descr->ev[descr->nfds]);
+
+       descr->nfds++;
+out:
+       return ret;
+
+out_free:
+       free(handler);
+       goto out;
+}
+
+int lxc_mainloop_del_handler(struct lxc_epoll_descr *descr, int fd)
+{
+       struct epoll_event *ev;
+       struct lxc_handler *handler;
+       int i, j, idx = 0;
+
+       for (i = 0; i < descr->nfds; i++) {
+               
+               handler = descr->ev[i].data.ptr;
+
+               if (handler->fd != fd)
+                       continue;
+
+               if (epoll_ctl(descr->epfd, EPOLL_CTL_DEL, fd, NULL))
+                       return -1;
+
+               ev = malloc(sizeof(*ev) * (descr->nfds - 1));
+               if (!ev)
+                       return -1;
+
+               for (j = 0; j < descr->nfds; j++) {
+                       if (i == j)
+                               continue;
+                       ev[idx] = descr->ev[idx];
+                       idx++;
+               }
+
+               free(descr->ev[i].data.ptr);
+               free(descr->ev);
+               descr->ev = ev;
+               descr->nfds--;
+               
+               return 0;
+       }
+
+       return -1;
+}
+
+int lxc_mainloop_open(int size, struct lxc_epoll_descr *descr)
+{
+       descr->nfds = 0;
+       descr->ev = NULL;
+
+       descr->epfd = epoll_create(size);
+       if (descr->epfd < 0)
+               return -1;
+
+       return 0;
+}
+
+int lxc_mainloop_close(struct lxc_epoll_descr *descr)
+{
+       int i;
+
+       for (i = 0; i < descr->nfds; i++)
+               free(descr->ev[i].data.ptr);
+       free(descr->ev);
+
+       return close(descr->epfd);
+}
+
diff --git a/src/lxc/mainloop.h b/src/lxc/mainloop.h
new file mode 100644 (file)
index 0000000..5ee0228
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * 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
+ */
+
+struct epoll_event;
+
+struct lxc_epoll_descr {
+       int epfd;
+       int nfds;
+       struct epoll_event *ev;
+};
+
+typedef int (*lxc_mainloop_callback_t)(int fd, void *data, 
+                                      struct lxc_epoll_descr *descr);
+
+extern int lxc_mainloop(struct lxc_epoll_descr *descr);
+
+extern int lxc_mainloop_add_handler(struct lxc_epoll_descr *descr, int fd,
+                                   lxc_mainloop_callback_t callback, 
+                                   void *data);
+
+extern int lxc_mainloop_del_handler(struct lxc_epoll_descr *descr, int fd);
+
+extern int lxc_mainloop_open(int size, struct lxc_epoll_descr *descr);
+
+extern int lxc_mainloop_close(struct lxc_epoll_descr *descr);
index 38ba092c506d6f24eb72701688fef65c83d9ca8b..bc2329312c430739c679cfd611c44d49484caf8b 100644 (file)
@@ -47,6 +47,7 @@ LXC_TTY_HANDLER(SIGQUIT);
 int lxc_restart(const char *name, const char *statefile,
                unsigned long flags)
 {
+       struct lxc_tty_info tty_info = { 0 };
        char *init = NULL, *val = NULL;
        char tty[MAXPATHLEN];
        int fd, lock, sv[2], sync = 0, err = -1;
@@ -55,13 +56,12 @@ int lxc_restart(const char *name, const char *statefile,
 
        lock = lxc_get_lock(name);
        if (lock < 0)
-               return lock == -EWOULDBLOCK ? 
-                       -LXC_ERROR_BUSY : 
-                       -LXC_ERROR_LOCK;
+               return lock;
 
        /* Begin the set the state to STARTING*/
        if (lxc_setstate(name, STARTING)) {
-               lxc_log_error("failed to set state %s", lxc_state2str(STARTING));
+               lxc_log_error("failed to set state %s", 
+                             lxc_state2str(STARTING));
                goto out;
        }
 
@@ -113,7 +113,7 @@ int lxc_restart(const char *name, const char *statefile,
                }
 
                /* Setup the container, ip, names, utsname, ... */
-               if (lxc_setup(name, tty)) {
+               if (lxc_setup(name, tty, &tty_info)) {
                        lxc_log_error("failed to setup the container");
                        if (write(sv[0], &sync, sizeof(sync)) < 0)
                                lxc_log_syserror("failed to write the socket");
index c539fa94e8c278ec30f22c9546d9ecebd503740e..b7e5870004118bba655d0af22103bbc50070aeb8 100644 (file)
@@ -30,6 +30,8 @@
 #include <errno.h>
 #include <unistd.h>
 #include <signal.h>
+#include <fcntl.h>
+#include <termios.h>
 #include <sys/param.h>
 #include <sys/file.h>
 #include <sys/mount.h>
 #include <sys/prctl.h>
 #include <sys/capability.h>
 #include <sys/wait.h>
+#include <sys/un.h>
+#include <sys/poll.h>
+#include <sys/signalfd.h>
 
 #include "error.h"
+#include "af_unix.h"
+#include "mainloop.h"
 
 #include <lxc/lxc.h>
 
 LXC_TTY_HANDLER(SIGINT);
 LXC_TTY_HANDLER(SIGQUIT);
 
+static int setup_sigchld_fd(sigset_t *oldmask)
+{
+       sigset_t mask;
+       int fd;
+
+       if (sigprocmask(SIG_BLOCK, NULL, &mask)) {
+               lxc_log_syserror("failed to get mask signal");
+               return -1;
+       }
+
+       if (sigaddset(&mask, SIGCHLD) || sigprocmask(SIG_BLOCK, &mask, oldmask)) {
+               lxc_log_syserror("failed to set mask signal");
+               return -1;
+       }
+
+       fd = signalfd(-1, &mask, 0);
+       if (fd < 0) {
+               lxc_log_syserror("failed to create the signal fd");
+               return -1;
+       }
+
+       if (fcntl(fd, F_SETFD, FD_CLOEXEC)) {
+               lxc_log_syserror("failed to set sigfd to close-on-exec");
+               close(fd);
+               return -1;
+       }
+
+       return fd;
+}
+
+static int setup_tty_service(const char *name, int *ttyfd)
+{
+       int fd;
+       struct sockaddr_un addr = { 0 };
+       char *offset = &addr.sun_path[1];
+       
+       strcpy(offset, name);
+       addr.sun_path[0] = '\0';
+
+       fd = lxc_af_unix_open(addr.sun_path, SOCK_STREAM, 0);
+       if (fd < 0)
+               return -1;
+
+       if (fcntl(fd, F_SETFD, FD_CLOEXEC)) {
+               lxc_log_syserror("failed to close-on-exec flag");
+               close(fd);
+               return -1;
+       }
+
+       *ttyfd = fd;
+
+       return 0;
+}
+
+static int sigchld_handler(int fd, void *data, 
+                          struct lxc_epoll_descr *descr)
+{
+       pid_t *pid = data;
+
+       waitpid(*pid, NULL, 0);
+
+       return 1;
+}
+
+static int ttyclient_handler(int fd, void *data,
+                            struct lxc_epoll_descr *descr)
+{
+       int i;
+       struct lxc_tty_info *tty_info = data;
+
+       for (i = 0; i < tty_info->nbtty; i++) {
+
+               if (tty_info->pty_info[i].busy != fd)
+                       continue;
+
+               lxc_mainloop_del_handler(descr, fd);
+               tty_info->pty_info[i].busy = 0;
+               close(fd);
+       }
+
+       return 0;
+}
+
+static int ttyservice_handler(int fd, void *data,
+                             struct lxc_epoll_descr *descr)
+{
+       int conn, ttynum, val = 1, ret = -1;
+       struct lxc_tty_info *tty_info = data;
+       
+       conn = accept(fd, NULL, 0);
+       if (conn < 0) {
+               lxc_log_syserror("failed to accept tty client");
+               return -1;
+       }
+       
+       if (setsockopt(conn, SOL_SOCKET, SO_PASSCRED, &val, sizeof(val))) {
+               lxc_log_syserror("failed to enable credential on socket");
+               goto out_close;
+       }
+
+       if (lxc_af_unix_rcv_credential(conn, &ttynum, sizeof(ttynum)))
+               goto out_close;
+
+       if (ttynum <= 0 || ttynum > tty_info->nbtty)
+               goto out_close;
+
+       /* fixup index array (eg. tty1 is index 0) */
+       ttynum--;
+
+       if (tty_info->pty_info[ttynum].busy)
+               goto out_close;
+
+       if (lxc_af_unix_send_fd(conn, tty_info->pty_info[ttynum].master, 
+                               NULL, 0) < 0) {
+               lxc_log_error("failed to send tty to client");
+               goto out_close;
+       }
+
+       if (lxc_mainloop_add_handler(descr, conn, 
+                                    ttyclient_handler, tty_info)) {
+               lxc_log_error("failed to add tty client handler");
+               goto out_close;
+       }
+
+       tty_info->pty_info[ttynum].busy = conn;
+
+       ret = 0;
+
+out:
+       return ret;
+out_close:
+       close(conn);
+       goto out;
+}
+
+static int mainloop(const char *name, pid_t pid, int sigfd,
+                   const struct lxc_tty_info *tty_info)
+{
+       int nfds, ttyfd = -1, ret = -1;
+       struct lxc_epoll_descr descr;
+
+       if (tty_info->nbtty && setup_tty_service(name, &ttyfd)) {
+               lxc_log_error("failed to create the tty service point");
+               goto out_sigfd;
+       }
+
+       /* sigfd + nb tty + tty service 
+        * if tty is enabled */
+       nfds = tty_info->nbtty + 1 + tty_info->nbtty ? 1 : 0;
+
+       if (lxc_mainloop_open(nfds, &descr)) {
+               lxc_log_error("failed to create mainloop");
+               goto out_ttyfd;
+       }
+
+       if (lxc_mainloop_add_handler(&descr, sigfd, sigchld_handler, &pid)) {
+               lxc_log_error("failed to add handler for the signal");
+               goto out_mainloop_open;
+       }
+
+       if (tty_info->nbtty) {
+               if (lxc_mainloop_add_handler(&descr, ttyfd, 
+                                            ttyservice_handler, 
+                                            (void *)tty_info)) {
+                       lxc_log_error("failed to add handler for the tty");
+                       goto out_mainloop_open;
+               }
+       }
+
+       ret = lxc_mainloop(&descr);
+
+out:
+       return ret;
+
+out_mainloop_open:
+       lxc_mainloop_close(&descr);
+out_ttyfd:
+       close(ttyfd);
+out_sigfd:
+       close(sigfd);
+       goto out;
+}
+
 int lxc_start(const char *name, char *argv[])
 {
+       struct lxc_tty_info tty_info = { 0 };
+       sigset_t oldmask;
        char init[MAXPATHLEN];
        char tty[MAXPATHLEN];
        char *val = NULL;
-       int fd, lock, sv[2], sync = 0, err = -LXC_ERROR_INTERNAL;
+       int fd, sigfd, lock, sv[2], sync = 0, err = -LXC_ERROR_INTERNAL;
        pid_t pid;
        int clone_flags;
 
        lock = lxc_get_lock(name);
-       if (lock < 0) {
-               if (lock == -EWOULDBLOCK)
-                       return -LXC_ERROR_BUSY;
-               if (lock == -ENOENT)
-                       return -LXC_ERROR_NOT_FOUND;
-               return -LXC_ERROR_LOCK;
-       }
+       if (lock < 0)
+               return lock;
 
        /* Begin the set the state to STARTING*/
        if (lxc_setstate(name, STARTING)) {
@@ -74,6 +261,20 @@ int lxc_start(const char *name, char *argv[])
        if (ttyname_r(0, tty, sizeof(tty))) 
                tty[0] = '\0';
 
+       if (lxc_create_tty(name, &tty_info)) {
+               lxc_log_error("failed to create the ttys");
+               goto out;
+       }
+
+       /* 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 */
+       sigfd = setup_sigchld_fd(&oldmask);
+       if (sigfd < 0) {
+               lxc_log_error("failed to set sigchild fd handler");
+               return -1;
+       }
+
        /* Synchro socketpair */
        if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sv)) {
                lxc_log_syserror("failed to create communication socketpair");
@@ -99,6 +300,11 @@ int lxc_start(const char *name, char *argv[])
 
        if (!pid) {
 
+               if (sigprocmask(SIG_SETMASK, &oldmask, NULL)) {
+                       lxc_log_syserror("failed to set sigprocmask");
+                       return -1;
+               }
+
                close(sv[1]);
 
                /* Be sure we don't inherit this after the exec */
@@ -117,7 +323,7 @@ int lxc_start(const char *name, char *argv[])
                }
 
                /* Setup the container, ip, names, utsname, ... */
-               err = lxc_setup(name, tty);
+               err = lxc_setup(name, tty, &tty_info);
                if (err) {
                        lxc_log_error("failed to setup the container");
                        if (write(sv[0], &err, sizeof(err)) < 0)
@@ -201,12 +407,9 @@ int lxc_start(const char *name, char *argv[])
                goto err_state_failed;
        }
 
-wait_again:
-       if (waitpid(pid, NULL, 0) < 0) {
-               if (errno == EINTR) 
-                       goto wait_again;
-               lxc_log_syserror("failed to wait the pid %d", pid);
-               goto err_waitpid_failed;
+       if (mainloop(name, pid, sigfd, &tty_info)) {
+               lxc_log_error("mainloop exited with an error");
+               goto err_mailoop_failed;
        }
 
        if (lxc_setstate(name, STOPPING))
@@ -220,6 +423,7 @@ out:
        if (lxc_setstate(name, STOPPED))
                lxc_log_error("failed to set state %s", lxc_state2str(STOPPED));
 
+       lxc_delete_tty(&tty_info);
        lxc_unlink_nsgroup(name);
        unlink(init);
        free(val);
@@ -240,7 +444,7 @@ err_pipe_write:
                conf_destroy_network(name);
 err_create_network:
 err_pipe_read:
-err_waitpid_failed:
+err_mailoop_failed:
        if (lxc_setstate(name, ABORTING))
                lxc_log_error("failed to set state %s", lxc_state2str(STOPPED));
 
index 4b359152ccb1a4c96af1918e224f1c2217a199da..eb1044ea16f3e4d57dda8e7aa6a5e45707145845 100644 (file)
@@ -31,7 +31,6 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 
-#include "error.h"
 #include <lxc/lxc.h>
 
 #define MAXPIDLEN 20
@@ -46,20 +45,17 @@ int lxc_stop(const char *name)
        lock = lxc_get_lock(name);
        if (lock >= 0) {
                lxc_put_lock(lock);
-               return -LXC_ERROR_EMPTY;
+               return -LXC_ERROR_ESRCH;
        }
 
-       if (lock < 0 && lock != -EWOULDBLOCK) {
-               if (lock == -ENOENT)
-                       return -LXC_ERROR_NOT_FOUND;
-               return -LXC_ERROR_LOCK;
-       }
+       if (lock < 0 && lock != -LXC_ERROR_EBUSY)
+               return lock;
 
        snprintf(init, MAXPATHLEN, LXCPATH "/%s/init", name);
        fd = open(init, O_RDONLY);
        if (fd < 0) {
                lxc_log_syserror("failed to open init file for %s", name);
-               goto out_unlock;
+               goto out_close;
        }
        
        if (read(fd, val, sizeof(val)) < 0) {
@@ -83,7 +79,5 @@ int lxc_stop(const char *name)
 
 out_close:
        close(fd);
-out_unlock:
-       lxc_put_lock(lock);
        return ret;
 }