From: Daniel Lezcano <daniel.lezcano@free.fr>

Console support for the system container.

Signed-off-by: Daniel Lezcano <daniel.lezcano@free.fr>
Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
This commit is contained in:
dlezcano 2009-01-25 21:52:38 +00:00
parent 2b3b608310
commit b0a33c1eb6
28 changed files with 1418 additions and 76 deletions

View 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

View 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 \

162
doc/lxc-console.sgml.in Normal file
View File

@ -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:
-->

View 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>

View 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>

View File

@ -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

View 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@

243
src/lxc/af_unix.c Normal file
View File

@ -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;
}

31
src/lxc/af_unix.h Normal file
View File

@ -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);

View 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;
}

71
src/lxc/console.c Normal file
View File

@ -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;
}

View 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)

View 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);

View 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",
};

View 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,

View 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>

View 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;

View 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

View 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;

View File

@ -20,14 +20,158 @@
* 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 <sys/types.h>
#include <lxc/lxc.h>
#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 "error.h"
#include "lxc.h"
void usage(char *cmd)
{
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[])
{
return 0;
}
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;
}

View 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) {

View 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)

View 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]);
err = lxc_start(name, args);
if (err) {
if (tcgetattr(0, &tios)) {
lxc_log_error("failed to get current terminal settings");
fprintf(stderr, "%s\n", lxc_strerror(err));
return 1;
}
return 0;
err = lxc_start(name, args);
if (err) {
fprintf(stderr, "%s\n", lxc_strerror(err));
err = 1;
}
if (tcsetattr(0, TCSAFLUSH, &tios))
lxc_log_syserror("failed to restore terminal attributes");
return err;
}

178
src/lxc/mainloop.c Normal file
View File

@ -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);
}

45
src/lxc/mainloop.h Normal file
View File

@ -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);

View 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");

View 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>
@ -37,31 +39,216 @@
#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));

View 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;
}