mirror of
https://git.proxmox.com/git/mirror_lxc
synced 2025-06-05 11:38:52 +00:00
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:
parent
2b3b608310
commit
b0a33c1eb6
@ -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
|
||||
|
@ -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
162
doc/lxc-console.sgml.in
Normal 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:
|
||||
-->
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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
243
src/lxc/af_unix.c
Normal 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
31
src/lxc/af_unix.h
Normal 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);
|
||||
|
@ -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
71
src/lxc/console.c
Normal 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;
|
||||
}
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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",
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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
178
src/lxc/mainloop.c
Normal 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
45
src/lxc/mainloop.h
Normal 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);
|
@ -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");
|
||||
|
236
src/lxc/start.c
236
src/lxc/start.c
@ -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));
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user