attach: move pty allocation into api

parent 79bd7662
......@@ -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">--keep-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">--keep-var <replaceable>variable</replaceable></arg>
<arg choice="opt">-- <replaceable>command</replaceable></arg>
......@@ -258,22 +257,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
<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>
<term>
<option>-v, --set-var <replaceable>variable</replaceable></option>
</term>
<listitem>
......
......@@ -51,6 +51,7 @@ enum {
LXC_ATTACH_LSM_NOW = 0x00020000, /*!< FIXME: unknown */
/* Set PR_SET_NO_NEW_PRIVS to block execve() gainable privileges. */
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
* are off by default, that should be sufficient to keep binary
......
......@@ -27,11 +27,12 @@
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <termios.h>
#include <unistd.h>
#include <lxc/lxccontainer.h>
......@@ -46,12 +47,6 @@
#include "mainloop.h"
#include "utils.h"
#if HAVE_PTY_H
#include <pty.h>
#else
#include <../include/openpty.h>
#endif
static const struct option my_longopts[] = {
{"elevated-privileges", optional_argument, 0, 'e'},
{"arch", required_argument, 0, 'a'},
......@@ -241,155 +236,29 @@ Options :\n\
.checker = NULL,
};
struct wrapargs {
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)
static bool stdfd_is_pty(void)
{
struct wrapargs *wrap = p;
close(wrap->console->master);
if (login_pty(wrap->console->slave) < 0)
return -1;
if (isatty(STDIN_FILENO))
return true;
if (isatty(STDOUT_FILENO))
return true;
if (isatty(STDERR_FILENO))
return true;
if (wrap->command->program)
lxc_attach_run_command(wrap->command);
else
lxc_attach_run_shell(NULL);
return -1;
return false;
}
static int get_pty_on_host(struct lxc_container *c, struct wrapargs *wrap, int *pid)
int lxc_attach_create_log_file(const char *log_file)
{
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;
}
int fd;
/* 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)
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;
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))
return STDIN_FILENO;
if (isatty(STDOUT_FILENO))
return STDOUT_FILENO;
if (isatty(STDERR_FILENO))
return STDERR_FILENO;
return -1;
return fd;
}
int main(int argc, char *argv[])
......@@ -463,6 +332,8 @@ int main(int argc, char *argv[])
attach_options.attach_flags |= LXC_ATTACH_REMOUNT_PROC_SYS;
if (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.personality = new_personality;
attach_options.env_policy = env_policy;
......@@ -474,29 +345,17 @@ int main(int argc, char *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) {
fprintf(stderr, "-L/--pty-log can only be used when stdout and stderr refer to a pty.\n");
if (my_args.console_log) {
attach_options.log_fd = lxc_attach_create_log_file(my_args.console_log);
if (attach_options.log_fd < 0)
goto out;
}
if (command.program)
ret = c->attach(c, lxc_attach_run_command, &command, &attach_options, &pid);
else
ret = c->attach(c, lxc_attach_run_shell, NULL, &attach_options, &pid);
}
if (command.program)
ret = c->attach(c, lxc_attach_run_command, &command, &attach_options, &pid);
else
ret = c->attach(c, lxc_attach_run_shell, NULL, &attach_options, &pid);
if (ret < 0)
goto out;
......
......@@ -19,16 +19,18 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <lxc/lxccontainer.h>
#include "lxc/utils.h"
#include "lxc/lsm/lsm.h"
#include <sys/types.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.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 TSTOUT(fmt, ...) do { \
......@@ -392,19 +394,60 @@ err1:
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();
ret = test_attach(NULL, TSTNAME, "busybox");
if (ret < 0)
return EXIT_FAILURE;
goto on_error;
TSTOUT("\n");
ret = test_attach(LXCPATH "/alternate-path-test", TSTNAME, "busybox");
if (ret < 0)
return EXIT_FAILURE;
goto on_error;
(void)rmdir(LXCPATH "/alternate-path-test");
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
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
exit 0
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment