mirror of
https://git.proxmox.com/git/mirror_lxc
synced 2025-07-15 16:19:18 +00:00
attach: move pty allocation into api
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
This commit is contained in:
parent
79bd76625d
commit
ba2be1a8a6
@ -58,7 +58,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|||||||
<arg choice="opt">-R, --remount-sys-proc</arg>
|
<arg choice="opt">-R, --remount-sys-proc</arg>
|
||||||
<arg choice="opt">--keep-env</arg>
|
<arg choice="opt">--keep-env</arg>
|
||||||
<arg choice="opt">--clear-env</arg>
|
<arg choice="opt">--clear-env</arg>
|
||||||
<arg choice="opt">-L, --pty-log <replaceable>file</replaceable></arg>
|
|
||||||
<arg choice="opt">-v, --set-var <replaceable>variable</replaceable></arg>
|
<arg choice="opt">-v, --set-var <replaceable>variable</replaceable></arg>
|
||||||
<arg choice="opt">--keep-var <replaceable>variable</replaceable></arg>
|
<arg choice="opt">--keep-var <replaceable>variable</replaceable></arg>
|
||||||
<arg choice="opt">-- <replaceable>command</replaceable></arg>
|
<arg choice="opt">-- <replaceable>command</replaceable></arg>
|
||||||
@ -256,22 +255,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
|
||||||
<term>
|
|
||||||
<option>-L, --pty-log <replaceable>file</replaceable></option>
|
|
||||||
</term>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
Specify a file where the output of <command>lxc-attach</command> will be
|
|
||||||
logged.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
<emphasis>Important:</emphasis> When a standard file descriptor
|
|
||||||
does not refer to a pty output produced on it will not be logged.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term>
|
<term>
|
||||||
<option>-v, --set-var <replaceable>variable</replaceable></option>
|
<option>-v, --set-var <replaceable>variable</replaceable></option>
|
||||||
|
231
src/lxc/attach.c
231
src/lxc/attach.c
@ -66,6 +66,7 @@
|
|||||||
#include "lsm/lsm.h"
|
#include "lsm/lsm.h"
|
||||||
#include "lxclock.h"
|
#include "lxclock.h"
|
||||||
#include "lxcseccomp.h"
|
#include "lxcseccomp.h"
|
||||||
|
#include "mainloop.h"
|
||||||
#include "namespace.h"
|
#include "namespace.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
@ -819,12 +820,30 @@ static signed long get_personality(const char *name, const char *lxcpath)
|
|||||||
|
|
||||||
struct attach_clone_payload {
|
struct attach_clone_payload {
|
||||||
int ipc_socket;
|
int ipc_socket;
|
||||||
|
int pty_fd;
|
||||||
lxc_attach_options_t *options;
|
lxc_attach_options_t *options;
|
||||||
struct lxc_proc_context_info *init_ctx;
|
struct lxc_proc_context_info *init_ctx;
|
||||||
lxc_attach_exec_t exec_function;
|
lxc_attach_exec_t exec_function;
|
||||||
void *exec_payload;
|
void *exec_payload;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void lxc_put_attach_clone_payload(struct attach_clone_payload *p)
|
||||||
|
{
|
||||||
|
if (p->ipc_socket >= 0) {
|
||||||
|
shutdown(p->ipc_socket, SHUT_RDWR);
|
||||||
|
close(p->ipc_socket);
|
||||||
|
p->ipc_socket = -EBADF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->pty_fd >= 0) {
|
||||||
|
close(p->pty_fd);
|
||||||
|
p->pty_fd = -EBADF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->init_ctx)
|
||||||
|
lxc_proc_put_context_info(p->init_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
static int attach_child_main(struct attach_clone_payload *payload)
|
static int attach_child_main(struct attach_clone_payload *payload)
|
||||||
{
|
{
|
||||||
int fd, lsm_fd, ret;
|
int fd, lsm_fd, ret;
|
||||||
@ -961,7 +980,8 @@ static int attach_child_main(struct attach_clone_payload *payload)
|
|||||||
}
|
}
|
||||||
shutdown(payload->ipc_socket, SHUT_RDWR);
|
shutdown(payload->ipc_socket, SHUT_RDWR);
|
||||||
close(payload->ipc_socket);
|
close(payload->ipc_socket);
|
||||||
payload->ipc_socket = -1;
|
payload->ipc_socket = -EBADF;
|
||||||
|
lxc_proc_put_context_info(init_ctx);
|
||||||
|
|
||||||
/* The following is done after the communication socket is shut down.
|
/* The following is done after the communication socket is shut down.
|
||||||
* That way, all errors that might (though unlikely) occur up until this
|
* That way, all errors that might (though unlikely) occur up until this
|
||||||
@ -1011,19 +1031,107 @@ static int attach_child_main(struct attach_clone_payload *payload)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options->attach_flags & LXC_ATTACH_ALLOCATE_PTY) {
|
||||||
|
ret = lxc_login_pty(payload->pty_fd);
|
||||||
|
if (ret < 0) {
|
||||||
|
SYSERROR("Failed to prepare pty file descriptor %d", payload->pty_fd);
|
||||||
|
goto on_error;
|
||||||
|
}
|
||||||
|
TRACE("Prepared pty file descriptor %d", payload->pty_fd);
|
||||||
|
}
|
||||||
|
|
||||||
/* We're done, so we can now do whatever the user intended us to do. */
|
/* We're done, so we can now do whatever the user intended us to do. */
|
||||||
rexit(payload->exec_function(payload->exec_payload));
|
rexit(payload->exec_function(payload->exec_payload));
|
||||||
|
|
||||||
on_error:
|
on_error:
|
||||||
if (payload->ipc_socket >= 0) {
|
lxc_put_attach_clone_payload(payload);
|
||||||
shutdown(payload->ipc_socket, SHUT_RDWR);
|
|
||||||
close(payload->ipc_socket);
|
|
||||||
payload->ipc_socket = -1;
|
|
||||||
}
|
|
||||||
lxc_proc_put_context_info(init_ctx);
|
|
||||||
rexit(EXIT_FAILURE);
|
rexit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int lxc_attach_pty(struct lxc_conf *conf, struct lxc_console *pty)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
lxc_pty_init(pty);
|
||||||
|
|
||||||
|
ret = lxc_pty_create(pty);
|
||||||
|
if (ret < 0) {
|
||||||
|
SYSERROR("Failed to create pty");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shift ttys to container. */
|
||||||
|
ret = lxc_pty_map_ids(conf, pty);
|
||||||
|
if (ret < 0) {
|
||||||
|
ERROR("Failed to shift pty");
|
||||||
|
goto on_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
on_error:
|
||||||
|
lxc_console_delete(pty);
|
||||||
|
lxc_pty_conf_free(pty);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lxc_attach_pty_mainloop_init(struct lxc_console *pty,
|
||||||
|
struct lxc_epoll_descr *descr)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = lxc_mainloop_open(descr);
|
||||||
|
if (ret < 0) {
|
||||||
|
ERROR("Failed to create mainloop");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = lxc_console_mainloop_add(descr, pty);
|
||||||
|
if (ret < 0) {
|
||||||
|
ERROR("Failed to add handlers to mainloop");
|
||||||
|
lxc_mainloop_close(descr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void lxc_attach_pty_close_master(struct lxc_console *pty)
|
||||||
|
{
|
||||||
|
if (pty->master < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
close(pty->master);
|
||||||
|
pty->master = -EBADF;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void lxc_attach_pty_close_slave(struct lxc_console *pty)
|
||||||
|
{
|
||||||
|
if (pty->slave < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
close(pty->slave);
|
||||||
|
pty->slave = -EBADF;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void lxc_attach_pty_close_peer(struct lxc_console *pty)
|
||||||
|
{
|
||||||
|
if (pty->peer < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
close(pty->peer);
|
||||||
|
pty->peer = -EBADF;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void lxc_attach_pty_close_log(struct lxc_console *pty)
|
||||||
|
{
|
||||||
|
if (pty->log_fd < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
close(pty->log_fd);
|
||||||
|
pty->log_fd = -EBADF;
|
||||||
|
}
|
||||||
|
|
||||||
int lxc_attach(const char *name, const char *lxcpath,
|
int lxc_attach(const char *name, const char *lxcpath,
|
||||||
lxc_attach_exec_t exec_function, void *exec_payload,
|
lxc_attach_exec_t exec_function, void *exec_payload,
|
||||||
lxc_attach_options_t *options, pid_t *attached_process)
|
lxc_attach_options_t *options, pid_t *attached_process)
|
||||||
@ -1032,8 +1140,9 @@ int lxc_attach(const char *name, const char *lxcpath,
|
|||||||
int ipc_sockets[2];
|
int ipc_sockets[2];
|
||||||
char *cwd, *new_cwd;
|
char *cwd, *new_cwd;
|
||||||
signed long personality;
|
signed long personality;
|
||||||
pid_t attached_pid, expected, init_pid, pid;
|
pid_t attached_pid, init_pid, pid;
|
||||||
struct lxc_proc_context_info *init_ctx;
|
struct lxc_proc_context_info *init_ctx;
|
||||||
|
struct lxc_console pty;
|
||||||
struct attach_clone_payload payload = {0};
|
struct attach_clone_payload payload = {0};
|
||||||
|
|
||||||
ret = access("/proc/self/ns", X_OK);
|
ret = access("/proc/self/ns", X_OK);
|
||||||
@ -1150,6 +1259,18 @@ int lxc_attach(const char *name, const char *lxcpath,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options->attach_flags & LXC_ATTACH_ALLOCATE_PTY) {
|
||||||
|
ret = lxc_attach_pty(init_ctx->container->lxc_conf, &pty);
|
||||||
|
if (ret < 0) {
|
||||||
|
ERROR("Failed to allocate pty");
|
||||||
|
free(cwd);
|
||||||
|
lxc_proc_put_context_info(init_ctx);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pty.log_fd = options->log_fd;
|
||||||
|
}
|
||||||
|
|
||||||
/* Create a socket pair for IPC communication; set SOCK_CLOEXEC in order
|
/* Create a socket pair for IPC communication; set SOCK_CLOEXEC in order
|
||||||
* to make sure we don't irritate other threads that want to fork+exec
|
* to make sure we don't irritate other threads that want to fork+exec
|
||||||
* away
|
* away
|
||||||
@ -1210,13 +1331,16 @@ int lxc_attach(const char *name, const char *lxcpath,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pid) {
|
if (pid) {
|
||||||
|
int ret_parent = -1;
|
||||||
pid_t to_cleanup_pid = pid;
|
pid_t to_cleanup_pid = pid;
|
||||||
|
struct lxc_epoll_descr descr = {0};
|
||||||
|
|
||||||
/* Initial thread, we close the socket that is for the
|
/* close unneeded file descriptors */
|
||||||
* subprocesses.
|
|
||||||
*/
|
|
||||||
close(ipc_sockets[1]);
|
close(ipc_sockets[1]);
|
||||||
free(cwd);
|
free(cwd);
|
||||||
|
lxc_proc_close_ns_fd(init_ctx);
|
||||||
|
if (options->attach_flags & LXC_ATTACH_ALLOCATE_PTY)
|
||||||
|
lxc_attach_pty_close_slave(&pty);
|
||||||
|
|
||||||
/* Attach to cgroup, if requested. */
|
/* Attach to cgroup, if requested. */
|
||||||
if (options->attach_flags & LXC_ATTACH_MOVE_TO_CGROUP) {
|
if (options->attach_flags & LXC_ATTACH_MOVE_TO_CGROUP) {
|
||||||
@ -1227,21 +1351,30 @@ int lxc_attach(const char *name, const char *lxcpath,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Setup resource limits */
|
/* Setup resource limits */
|
||||||
if (!lxc_list_empty(&init_ctx->container->lxc_conf->limits))
|
if (!lxc_list_empty(&init_ctx->container->lxc_conf->limits)) {
|
||||||
if (setup_resource_limits(&init_ctx->container->lxc_conf->limits, pid) < 0)
|
ret = setup_resource_limits(&init_ctx->container->lxc_conf->limits, pid);
|
||||||
|
if (ret < 0)
|
||||||
goto on_error;
|
goto on_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options->attach_flags & LXC_ATTACH_ALLOCATE_PTY) {
|
||||||
|
ret = lxc_attach_pty_mainloop_init(&pty, &descr);
|
||||||
|
if (ret < 0)
|
||||||
|
goto on_error;
|
||||||
|
TRACE("Initalized pty mainloop");
|
||||||
|
}
|
||||||
|
|
||||||
/* Let the child process know to go ahead. */
|
/* Let the child process know to go ahead. */
|
||||||
status = 0;
|
status = 0;
|
||||||
ret = lxc_write_nointr(ipc_sockets[0], &status, sizeof(status));
|
ret = lxc_write_nointr(ipc_sockets[0], &status, sizeof(status));
|
||||||
if (ret != sizeof(status))
|
if (ret != sizeof(status))
|
||||||
goto on_error;
|
goto close_mainloop;
|
||||||
TRACE("Told intermediate process to start initializing");
|
TRACE("Told intermediate process to start initializing");
|
||||||
|
|
||||||
/* Get pid of attached process from intermediate process. */
|
/* Get pid of attached process from intermediate process. */
|
||||||
ret = lxc_read_nointr(ipc_sockets[0], &attached_pid, sizeof(attached_pid));
|
ret = lxc_read_nointr(ipc_sockets[0], &attached_pid, sizeof(attached_pid));
|
||||||
if (ret != sizeof(attached_pid))
|
if (ret != sizeof(attached_pid))
|
||||||
goto on_error;
|
goto close_mainloop;
|
||||||
TRACE("Received pid %d of attached process in parent pid namespace", attached_pid);
|
TRACE("Received pid %d of attached process in parent pid namespace", attached_pid);
|
||||||
|
|
||||||
/* Ignore SIGKILL (CTRL-C) and SIGQUIT (CTRL-\) - issue #313. */
|
/* Ignore SIGKILL (CTRL-C) and SIGQUIT (CTRL-\) - issue #313. */
|
||||||
@ -1253,7 +1386,7 @@ int lxc_attach(const char *name, const char *lxcpath,
|
|||||||
/* Reap intermediate process. */
|
/* Reap intermediate process. */
|
||||||
ret = wait_for_pid(pid);
|
ret = wait_for_pid(pid);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto on_error;
|
goto close_mainloop;
|
||||||
TRACE("Intermediate process %d exited", pid);
|
TRACE("Intermediate process %d exited", pid);
|
||||||
|
|
||||||
/* We will always have to reap the attached process now. */
|
/* We will always have to reap the attached process now. */
|
||||||
@ -1269,7 +1402,7 @@ int lxc_attach(const char *name, const char *lxcpath,
|
|||||||
on_exec = options->attach_flags & LXC_ATTACH_LSM_EXEC ? 1 : 0;
|
on_exec = options->attach_flags & LXC_ATTACH_LSM_EXEC ? 1 : 0;
|
||||||
labelfd = lsm_open(attached_pid, on_exec);
|
labelfd = lsm_open(attached_pid, on_exec);
|
||||||
if (labelfd < 0)
|
if (labelfd < 0)
|
||||||
goto on_error;
|
goto close_mainloop;
|
||||||
TRACE("Opened LSM label file descriptor %d", labelfd);
|
TRACE("Opened LSM label file descriptor %d", labelfd);
|
||||||
|
|
||||||
/* Send child fd of the LSM security module to write to. */
|
/* Send child fd of the LSM security module to write to. */
|
||||||
@ -1277,45 +1410,66 @@ int lxc_attach(const char *name, const char *lxcpath,
|
|||||||
close(labelfd);
|
close(labelfd);
|
||||||
if (ret <= 0) {
|
if (ret <= 0) {
|
||||||
SYSERROR("%d", (int)ret);
|
SYSERROR("%d", (int)ret);
|
||||||
goto on_error;
|
goto close_mainloop;
|
||||||
}
|
}
|
||||||
TRACE("Sent LSM label file descriptor %d to child", labelfd);
|
TRACE("Sent LSM label file descriptor %d to child", labelfd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now shut down communication with child, we're done. */
|
|
||||||
shutdown(ipc_sockets[0], SHUT_RDWR);
|
|
||||||
close(ipc_sockets[0]);
|
|
||||||
lxc_proc_put_context_info(init_ctx);
|
|
||||||
|
|
||||||
/* We're done, the child process should now execute whatever it
|
/* We're done, the child process should now execute whatever it
|
||||||
* is that the user requested. The parent can now track it with
|
* is that the user requested. The parent can now track it with
|
||||||
* waitpid() or similar.
|
* waitpid() or similar.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
*attached_process = attached_pid;
|
*attached_process = attached_pid;
|
||||||
return 0;
|
|
||||||
|
|
||||||
on_error:
|
/* Now shut down communication with child, we're done. */
|
||||||
/* First shut down the socket, then wait for the pid, otherwise
|
|
||||||
* the pid we're waiting for may never exit.
|
|
||||||
*/
|
|
||||||
shutdown(ipc_sockets[0], SHUT_RDWR);
|
shutdown(ipc_sockets[0], SHUT_RDWR);
|
||||||
close(ipc_sockets[0]);
|
close(ipc_sockets[0]);
|
||||||
if (to_cleanup_pid)
|
ipc_sockets[0] = -1;
|
||||||
(void)wait_for_pid(to_cleanup_pid);
|
|
||||||
lxc_proc_put_context_info(init_ctx);
|
ret_parent = 0;
|
||||||
return -1;
|
to_cleanup_pid = -1;
|
||||||
|
if (options->attach_flags & LXC_ATTACH_ALLOCATE_PTY) {
|
||||||
|
ret = lxc_mainloop(&descr, -1);
|
||||||
|
if (ret < 0) {
|
||||||
|
ret_parent = -1;
|
||||||
|
to_cleanup_pid = attached_pid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* First subprocess begins here, we close the socket that is for the
|
close_mainloop:
|
||||||
* initial thread.
|
if (options->attach_flags & LXC_ATTACH_ALLOCATE_PTY)
|
||||||
*/
|
lxc_mainloop_close(&descr);
|
||||||
|
|
||||||
|
on_error:
|
||||||
|
if (ipc_sockets[0] >= 0) {
|
||||||
|
shutdown(ipc_sockets[0], SHUT_RDWR);
|
||||||
close(ipc_sockets[0]);
|
close(ipc_sockets[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (to_cleanup_pid > 0)
|
||||||
|
(void)wait_for_pid(to_cleanup_pid);
|
||||||
|
|
||||||
|
if (options->attach_flags & LXC_ATTACH_ALLOCATE_PTY) {
|
||||||
|
lxc_console_delete(&pty);
|
||||||
|
lxc_pty_conf_free(&pty);
|
||||||
|
}
|
||||||
|
lxc_proc_put_context_info(init_ctx);
|
||||||
|
return ret_parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* close unneeded file descriptors */
|
||||||
|
close(ipc_sockets[0]);
|
||||||
|
ipc_sockets[0] = -EBADF;
|
||||||
|
if (options->attach_flags & LXC_ATTACH_ALLOCATE_PTY) {
|
||||||
|
lxc_attach_pty_close_master(&pty);
|
||||||
|
lxc_attach_pty_close_peer(&pty);
|
||||||
|
lxc_attach_pty_close_log(&pty);
|
||||||
|
}
|
||||||
|
|
||||||
/* Wait for the parent to have setup cgroups. */
|
/* Wait for the parent to have setup cgroups. */
|
||||||
expected = 0;
|
|
||||||
ret = lxc_read_nointr(ipc_sockets[1], &status, sizeof(status));
|
ret = lxc_read_nointr(ipc_sockets[1], &status, sizeof(status));
|
||||||
if (ret != sizeof(status) || status != expected) {
|
if (ret != sizeof(status)) {
|
||||||
shutdown(ipc_sockets[1], SHUT_RDWR);
|
shutdown(ipc_sockets[1], SHUT_RDWR);
|
||||||
lxc_proc_put_context_info(init_ctx);
|
lxc_proc_put_context_info(init_ctx);
|
||||||
rexit(-1);
|
rexit(-1);
|
||||||
@ -1351,6 +1505,7 @@ int lxc_attach(const char *name, const char *lxcpath,
|
|||||||
payload.ipc_socket = ipc_sockets[1];
|
payload.ipc_socket = ipc_sockets[1];
|
||||||
payload.options = options;
|
payload.options = options;
|
||||||
payload.init_ctx = init_ctx;
|
payload.init_ctx = init_ctx;
|
||||||
|
payload.pty_fd = pty.slave;
|
||||||
payload.exec_function = exec_function;
|
payload.exec_function = exec_function;
|
||||||
payload.exec_payload = exec_payload;
|
payload.exec_payload = exec_payload;
|
||||||
|
|
||||||
@ -1368,6 +1523,8 @@ int lxc_attach(const char *name, const char *lxcpath,
|
|||||||
ERROR("Failed to exec");
|
ERROR("Failed to exec");
|
||||||
_exit(EXIT_FAILURE);
|
_exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
if (options->attach_flags & LXC_ATTACH_ALLOCATE_PTY)
|
||||||
|
lxc_attach_pty_close_slave(&pty);
|
||||||
|
|
||||||
/* Tell grandparent the pid of the pid of the newly created child. */
|
/* Tell grandparent the pid of the pid of the newly created child. */
|
||||||
ret = lxc_write_nointr(ipc_sockets[1], &pid, sizeof(pid));
|
ret = lxc_write_nointr(ipc_sockets[1], &pid, sizeof(pid));
|
||||||
|
@ -51,6 +51,7 @@ enum {
|
|||||||
LXC_ATTACH_LSM_NOW = 0x00020000, /*!< FIXME: unknown */
|
LXC_ATTACH_LSM_NOW = 0x00020000, /*!< FIXME: unknown */
|
||||||
/* Set PR_SET_NO_NEW_PRIVS to block execve() gainable privileges. */
|
/* Set PR_SET_NO_NEW_PRIVS to block execve() gainable privileges. */
|
||||||
LXC_ATTACH_NO_NEW_PRIVS = 0x00040000, /*!< PR_SET_NO_NEW_PRIVS */
|
LXC_ATTACH_NO_NEW_PRIVS = 0x00040000, /*!< PR_SET_NO_NEW_PRIVS */
|
||||||
|
LXC_ATTACH_ALLOCATE_PTY = 0x00080000, /*!< Allocate new pty for attached process. */
|
||||||
|
|
||||||
/* We have 16 bits for things that are on by default and 16 bits that
|
/* We have 16 bits for things that are on by default and 16 bits that
|
||||||
* are off by default, that should be sufficient to keep binary
|
* are off by default, that should be sufficient to keep binary
|
||||||
|
@ -27,11 +27,12 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
#include <lxc/lxccontainer.h>
|
#include <lxc/lxccontainer.h>
|
||||||
|
|
||||||
@ -46,12 +47,6 @@
|
|||||||
#include "mainloop.h"
|
#include "mainloop.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
#if HAVE_PTY_H
|
|
||||||
#include <pty.h>
|
|
||||||
#else
|
|
||||||
#include <../include/openpty.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static const struct option my_longopts[] = {
|
static const struct option my_longopts[] = {
|
||||||
{"elevated-privileges", optional_argument, 0, 'e'},
|
{"elevated-privileges", optional_argument, 0, 'e'},
|
||||||
{"arch", required_argument, 0, 'a'},
|
{"arch", required_argument, 0, 'a'},
|
||||||
@ -241,157 +236,31 @@ Options :\n\
|
|||||||
.checker = NULL,
|
.checker = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wrapargs {
|
static bool stdfd_is_pty(void)
|
||||||
lxc_attach_options_t *options;
|
|
||||||
lxc_attach_command_t *command;
|
|
||||||
struct lxc_console *console;
|
|
||||||
int ptyfd;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Minimalistic login_tty() implementation. */
|
|
||||||
static int login_pty(int fd)
|
|
||||||
{
|
|
||||||
setsid();
|
|
||||||
if (ioctl(fd, TIOCSCTTY, NULL) < 0)
|
|
||||||
return -1;
|
|
||||||
if (lxc_console_set_stdfds(fd) < 0)
|
|
||||||
return -1;
|
|
||||||
if (fd > STDERR_FILENO)
|
|
||||||
close(fd);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_pty_on_host_callback(void *p)
|
|
||||||
{
|
|
||||||
struct wrapargs *wrap = p;
|
|
||||||
|
|
||||||
close(wrap->console->master);
|
|
||||||
if (login_pty(wrap->console->slave) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (wrap->command->program)
|
|
||||||
lxc_attach_run_command(wrap->command);
|
|
||||||
else
|
|
||||||
lxc_attach_run_shell(NULL);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_pty_on_host(struct lxc_container *c, struct wrapargs *wrap, int *pid)
|
|
||||||
{
|
|
||||||
struct lxc_epoll_descr descr;
|
|
||||||
struct lxc_conf *conf;
|
|
||||||
struct lxc_tty_state *ts;
|
|
||||||
int ret = -1;
|
|
||||||
struct wrapargs *args = wrap;
|
|
||||||
|
|
||||||
if (!isatty(args->ptyfd)) {
|
|
||||||
fprintf(stderr, "Standard file descriptor does not refer to a pty\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c->lxc_conf) {
|
|
||||||
conf = c->lxc_conf;
|
|
||||||
} else {
|
|
||||||
/* If the container is not defined and the user didn't specify a
|
|
||||||
* config file to load we will simply init a dummy config here.
|
|
||||||
*/
|
|
||||||
conf = lxc_conf_init();
|
|
||||||
if (!conf) {
|
|
||||||
fprintf(stderr, "Failed to allocate dummy config file for the container\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We also need a dummy rootfs path otherwise
|
|
||||||
* lxc_console_create() will not let us create a console. Note,
|
|
||||||
* I don't want this change to make it into
|
|
||||||
* lxc_console_create()'s since this function will only be
|
|
||||||
* responsible for proper /dev/{console,tty<n>} devices.
|
|
||||||
* lxc-attach is just abusing it to also handle the pty case
|
|
||||||
* because it is very similar. However, with LXC 3.0 lxc-attach
|
|
||||||
* will need to move away from using lxc_console_create() since
|
|
||||||
* this is actually an internal symbol and we only want the
|
|
||||||
* tools to use the API with LXC 3.0.
|
|
||||||
*/
|
|
||||||
conf->rootfs.path = strdup("dummy");
|
|
||||||
if (!conf->rootfs.path)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
free(conf->console.log_path);
|
|
||||||
if (my_args.console_log)
|
|
||||||
conf->console.log_path = strdup(my_args.console_log);
|
|
||||||
else
|
|
||||||
conf->console.log_path = NULL;
|
|
||||||
|
|
||||||
/* In the case of lxc-attach our peer pty will always be the current
|
|
||||||
* controlling terminal. We clear whatever was set by the user for
|
|
||||||
* lxc.console.path here and set it NULL. lxc_console_peer_default()
|
|
||||||
* will then try to open /dev/tty. If the process doesn't have a
|
|
||||||
* controlling terminal we should still proceed.
|
|
||||||
*/
|
|
||||||
free(conf->console.path);
|
|
||||||
conf->console.path = NULL;
|
|
||||||
|
|
||||||
/* Create pty on the host. */
|
|
||||||
if (lxc_console_create(conf) < 0)
|
|
||||||
return -1;
|
|
||||||
ts = conf->console.tty_state;
|
|
||||||
conf->console.descr = &descr;
|
|
||||||
|
|
||||||
/* Shift ttys to container. */
|
|
||||||
ret = lxc_pty_map_ids(conf, &conf->console);
|
|
||||||
if (ret < 0) {
|
|
||||||
fprintf(stderr, "Failed to shift tty into container\n");
|
|
||||||
goto err1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Send wrapper function on its way. */
|
|
||||||
wrap->console = &conf->console;
|
|
||||||
if (c->attach(c, get_pty_on_host_callback, wrap, wrap->options, pid) < 0)
|
|
||||||
goto err1;
|
|
||||||
close(conf->console.slave); /* Close slave side. */
|
|
||||||
conf->console.slave = -1;
|
|
||||||
|
|
||||||
ret = lxc_mainloop_open(&descr);
|
|
||||||
if (ret) {
|
|
||||||
fprintf(stderr, "failed to create mainloop\n");
|
|
||||||
goto err2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lxc_console_mainloop_add(&descr, &conf->console) < 0) {
|
|
||||||
fprintf(stderr, "Failed to add handlers to lxc mainloop.\n");
|
|
||||||
goto err3;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = lxc_mainloop(&descr, -1);
|
|
||||||
if (ret) {
|
|
||||||
fprintf(stderr, "mainloop returned an error\n");
|
|
||||||
goto err3;
|
|
||||||
}
|
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
err3:
|
|
||||||
lxc_mainloop_close(&descr);
|
|
||||||
err2:
|
|
||||||
if (ts && ts->sigfd != -1)
|
|
||||||
lxc_console_signal_fini(ts);
|
|
||||||
err1:
|
|
||||||
lxc_console_delete(&conf->console);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int stdfd_is_pty(void)
|
|
||||||
{
|
{
|
||||||
if (isatty(STDIN_FILENO))
|
if (isatty(STDIN_FILENO))
|
||||||
return STDIN_FILENO;
|
return true;
|
||||||
if (isatty(STDOUT_FILENO))
|
if (isatty(STDOUT_FILENO))
|
||||||
return STDOUT_FILENO;
|
return true;
|
||||||
if (isatty(STDERR_FILENO))
|
if (isatty(STDERR_FILENO))
|
||||||
return STDERR_FILENO;
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lxc_attach_create_log_file(const char *log_file)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = open(log_file, O_CLOEXEC | O_RDWR | O_CREAT | O_APPEND, 0600);
|
||||||
|
if (fd < 0) {
|
||||||
|
fprintf(stderr, "Failed to open log file \"%s\"\n", log_file);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int ret = -1, r;
|
int ret = -1, r;
|
||||||
@ -463,6 +332,8 @@ int main(int argc, char *argv[])
|
|||||||
attach_options.attach_flags |= LXC_ATTACH_REMOUNT_PROC_SYS;
|
attach_options.attach_flags |= LXC_ATTACH_REMOUNT_PROC_SYS;
|
||||||
if (elevated_privileges)
|
if (elevated_privileges)
|
||||||
attach_options.attach_flags &= ~(elevated_privileges);
|
attach_options.attach_flags &= ~(elevated_privileges);
|
||||||
|
if (stdfd_is_pty())
|
||||||
|
attach_options.attach_flags |= LXC_ATTACH_ALLOCATE_PTY;
|
||||||
attach_options.namespaces = namespace_flags;
|
attach_options.namespaces = namespace_flags;
|
||||||
attach_options.personality = new_personality;
|
attach_options.personality = new_personality;
|
||||||
attach_options.env_policy = env_policy;
|
attach_options.env_policy = env_policy;
|
||||||
@ -474,28 +345,16 @@ int main(int argc, char *argv[])
|
|||||||
command.argv = (char**)my_args.argv;
|
command.argv = (char**)my_args.argv;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wrapargs wrap = (struct wrapargs){
|
|
||||||
.command = &command,
|
|
||||||
.options = &attach_options
|
|
||||||
};
|
|
||||||
|
|
||||||
wrap.ptyfd = stdfd_is_pty();
|
|
||||||
if (wrap.ptyfd >= 0) {
|
|
||||||
if ((!isatty(STDOUT_FILENO) || !isatty(STDERR_FILENO)) && my_args.console_log) {
|
|
||||||
fprintf(stderr, "-L/--pty-log can only be used when stdout and stderr refer to a pty.\n");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
ret = get_pty_on_host(c, &wrap, &pid);
|
|
||||||
} else {
|
|
||||||
if (my_args.console_log) {
|
if (my_args.console_log) {
|
||||||
fprintf(stderr, "-L/--pty-log can only be used when stdout and stderr refer to a pty.\n");
|
attach_options.log_fd = lxc_attach_create_log_file(my_args.console_log);
|
||||||
|
if (attach_options.log_fd < 0)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (command.program)
|
if (command.program)
|
||||||
ret = c->attach(c, lxc_attach_run_command, &command, &attach_options, &pid);
|
ret = c->attach(c, lxc_attach_run_command, &command, &attach_options, &pid);
|
||||||
else
|
else
|
||||||
ret = c->attach(c, lxc_attach_run_shell, NULL, &attach_options, &pid);
|
ret = c->attach(c, lxc_attach_run_shell, NULL, &attach_options, &pid);
|
||||||
}
|
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -19,16 +19,18 @@
|
|||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <lxc/lxccontainer.h>
|
#include <errno.h>
|
||||||
#include "lxc/utils.h"
|
|
||||||
#include "lxc/lsm/lsm.h"
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#include <errno.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include "lxctest.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "lsm/lsm.h"
|
||||||
|
|
||||||
|
#include <lxc/lxccontainer.h>
|
||||||
|
|
||||||
#define TSTNAME "lxc-attach-test"
|
#define TSTNAME "lxc-attach-test"
|
||||||
#define TSTOUT(fmt, ...) do { \
|
#define TSTOUT(fmt, ...) do { \
|
||||||
@ -392,19 +394,60 @@ err1:
|
|||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int ret;
|
int i, ret;
|
||||||
|
struct lxc_log log;
|
||||||
|
char template[sizeof(P_tmpdir"/attach_XXXXXX")];
|
||||||
|
int fret = EXIT_FAILURE;
|
||||||
|
|
||||||
|
strcpy(template, P_tmpdir"/attach_XXXXXX");
|
||||||
|
i = lxc_make_tmpfile(template, false);
|
||||||
|
if (i < 0) {
|
||||||
|
lxc_error("Failed to create temporary log file for container %s\n", TSTNAME);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
} else {
|
||||||
|
lxc_debug("Using \"%s\" as temporary log file for container %s\n", template, TSTNAME);
|
||||||
|
close(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.name = TSTNAME;
|
||||||
|
log.file = template;
|
||||||
|
log.level = "TRACE";
|
||||||
|
log.prefix = "attach";
|
||||||
|
log.quiet = false;
|
||||||
|
log.lxcpath = NULL;
|
||||||
|
if (lxc_log_init(&log))
|
||||||
|
goto on_error;
|
||||||
|
|
||||||
test_lsm_detect();
|
test_lsm_detect();
|
||||||
ret = test_attach(NULL, TSTNAME, "busybox");
|
ret = test_attach(NULL, TSTNAME, "busybox");
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return EXIT_FAILURE;
|
goto on_error;
|
||||||
|
|
||||||
TSTOUT("\n");
|
TSTOUT("\n");
|
||||||
ret = test_attach(LXCPATH "/alternate-path-test", TSTNAME, "busybox");
|
ret = test_attach(LXCPATH "/alternate-path-test", TSTNAME, "busybox");
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return EXIT_FAILURE;
|
goto on_error;
|
||||||
|
|
||||||
(void)rmdir(LXCPATH "/alternate-path-test");
|
|
||||||
TSTOUT("All tests passed\n");
|
TSTOUT("All tests passed\n");
|
||||||
return EXIT_SUCCESS;
|
fret = EXIT_SUCCESS;
|
||||||
|
|
||||||
|
on_error:
|
||||||
|
if (fret != EXIT_SUCCESS) {
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = open(template, O_RDONLY);
|
||||||
|
if (fd >= 0) {
|
||||||
|
char buf[4096];
|
||||||
|
ssize_t buflen;
|
||||||
|
while ((buflen = read(fd, buf, 1024)) > 0) {
|
||||||
|
buflen = write(STDERR_FILENO, buf, buflen);
|
||||||
|
if (buflen <= 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(void)rmdir(LXCPATH "/alternate-path-test");
|
||||||
|
(void)unlink(template);
|
||||||
|
exit(fret);
|
||||||
}
|
}
|
||||||
|
@ -190,17 +190,6 @@ fi
|
|||||||
|
|
||||||
rm -f $out $err
|
rm -f $out $err
|
||||||
|
|
||||||
if [ $allocate_pty = "pty" ]; then
|
|
||||||
# Test whether logging pty output to a file works.
|
|
||||||
trap "rm -f /tmp/ptylog" EXIT INT QUIT PIPE
|
|
||||||
lxc-attach -n busy -L /tmp/ptylog -- hostname || FAIL "to allocate or setup pty"
|
|
||||||
if [ ! -s /tmp/ptylog ]; then
|
|
||||||
FAIL "lxc-attach -n busy -L /tmp/ptylog -- hostname"
|
|
||||||
fi
|
|
||||||
|
|
||||||
rm -f /tmp/ptylog
|
|
||||||
fi
|
|
||||||
|
|
||||||
lxc-destroy -n busy -f
|
lxc-destroy -n busy -f
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
|
Loading…
Reference in New Issue
Block a user