diff --git a/doc/lxc-attach.sgml.in b/doc/lxc-attach.sgml.in
index 7535bb114..713a30e7f 100644
--- a/doc/lxc-attach.sgml.in
+++ b/doc/lxc-attach.sgml.in
@@ -58,7 +58,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-R, --remount-sys-proc
--keep-env
--clear-env
- -L, --pty-log file
-v, --set-var variable
--keep-var variable
-- command
@@ -256,22 +255,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-
-
-
-
-
- Specify a file where the output of lxc-attach will be
- logged.
-
-
- Important: When a standard file descriptor
- does not refer to a pty output produced on it will not be logged.
-
-
-
-
diff --git a/src/lxc/attach.c b/src/lxc/attach.c
index b6f290ad3..34bdf9145 100644
--- a/src/lxc/attach.c
+++ b/src/lxc/attach.c
@@ -66,6 +66,7 @@
#include "lsm/lsm.h"
#include "lxclock.h"
#include "lxcseccomp.h"
+#include "mainloop.h"
#include "namespace.h"
#include "utils.h"
@@ -819,12 +820,30 @@ static signed long get_personality(const char *name, const char *lxcpath)
struct attach_clone_payload {
int ipc_socket;
+ int pty_fd;
lxc_attach_options_t *options;
struct lxc_proc_context_info *init_ctx;
lxc_attach_exec_t exec_function;
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)
{
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);
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.
* 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. */
rexit(payload->exec_function(payload->exec_payload));
on_error:
- if (payload->ipc_socket >= 0) {
- shutdown(payload->ipc_socket, SHUT_RDWR);
- close(payload->ipc_socket);
- payload->ipc_socket = -1;
- }
- lxc_proc_put_context_info(init_ctx);
+ lxc_put_attach_clone_payload(payload);
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,
lxc_attach_exec_t exec_function, void *exec_payload,
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];
char *cwd, *new_cwd;
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_console pty;
struct attach_clone_payload payload = {0};
ret = access("/proc/self/ns", X_OK);
@@ -1150,6 +1259,18 @@ int lxc_attach(const char *name, const char *lxcpath,
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
* to make sure we don't irritate other threads that want to fork+exec
* away
@@ -1210,13 +1331,16 @@ int lxc_attach(const char *name, const char *lxcpath,
}
if (pid) {
+ int ret_parent = -1;
pid_t to_cleanup_pid = pid;
+ struct lxc_epoll_descr descr = {0};
- /* Initial thread, we close the socket that is for the
- * subprocesses.
- */
+ /* close unneeded file descriptors */
close(ipc_sockets[1]);
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. */
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 */
- if (!lxc_list_empty(&init_ctx->container->lxc_conf->limits))
- if (setup_resource_limits(&init_ctx->container->lxc_conf->limits, pid) < 0)
+ if (!lxc_list_empty(&init_ctx->container->lxc_conf->limits)) {
+ ret = setup_resource_limits(&init_ctx->container->lxc_conf->limits, pid);
+ if (ret < 0)
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. */
status = 0;
ret = lxc_write_nointr(ipc_sockets[0], &status, sizeof(status));
if (ret != sizeof(status))
- goto on_error;
+ goto close_mainloop;
TRACE("Told intermediate process to start initializing");
/* Get pid of attached process from intermediate process. */
ret = lxc_read_nointr(ipc_sockets[0], &attached_pid, 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);
/* 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. */
ret = wait_for_pid(pid);
if (ret < 0)
- goto on_error;
+ goto close_mainloop;
TRACE("Intermediate process %d exited", pid);
/* 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;
labelfd = lsm_open(attached_pid, on_exec);
if (labelfd < 0)
- goto on_error;
+ goto close_mainloop;
TRACE("Opened LSM label file descriptor %d", labelfd);
/* 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);
if (ret <= 0) {
SYSERROR("%d", (int)ret);
- goto on_error;
+ goto close_mainloop;
}
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
* is that the user requested. The parent can now track it with
* waitpid() or similar.
*/
*attached_process = attached_pid;
- return 0;
- on_error:
- /* First shut down the socket, then wait for the pid, otherwise
- * the pid we're waiting for may never exit.
- */
+ /* Now shut down communication with child, we're done. */
shutdown(ipc_sockets[0], SHUT_RDWR);
close(ipc_sockets[0]);
- if (to_cleanup_pid)
+ ipc_sockets[0] = -1;
+
+ ret_parent = 0;
+ 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;
+ }
+ }
+
+ close_mainloop:
+ 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]);
+ }
+
+ 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 -1;
+ return ret_parent;
}
- /* First subprocess begins here, we close the socket that is for the
- * initial thread.
- */
+ /* 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. */
- expected = 0;
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);
lxc_proc_put_context_info(init_ctx);
rexit(-1);
@@ -1351,6 +1505,7 @@ int lxc_attach(const char *name, const char *lxcpath,
payload.ipc_socket = ipc_sockets[1];
payload.options = options;
payload.init_ctx = init_ctx;
+ payload.pty_fd = pty.slave;
payload.exec_function = exec_function;
payload.exec_payload = exec_payload;
@@ -1368,6 +1523,8 @@ int lxc_attach(const char *name, const char *lxcpath,
ERROR("Failed to exec");
_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. */
ret = lxc_write_nointr(ipc_sockets[1], &pid, sizeof(pid));
diff --git a/src/lxc/attach_options.h b/src/lxc/attach_options.h
index fad6456cc..1e64e4abf 100644
--- a/src/lxc/attach_options.h
+++ b/src/lxc/attach_options.h
@@ -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
diff --git a/src/lxc/tools/lxc_attach.c b/src/lxc/tools/lxc_attach.c
index 0615cc719..926bf079e 100644
--- a/src/lxc/tools/lxc_attach.c
+++ b/src/lxc/tools/lxc_attach.c
@@ -27,11 +27,12 @@
#include
#include
#include
-#include
-#include
-#include
#include
#include
+#include
+#include
+#include
+#include
#include
@@ -46,12 +47,6 @@
#include "mainloop.h"
#include "utils.h"
-#if HAVE_PTY_H
-#include
-#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)
-{
- 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} 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)
+static bool stdfd_is_pty(void)
{
if (isatty(STDIN_FILENO))
- return STDIN_FILENO;
+ return true;
if (isatty(STDOUT_FILENO))
- return STDOUT_FILENO;
+ return true;
if (isatty(STDERR_FILENO))
- return STDERR_FILENO;
+ return true;
- return -1;
+ 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 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");
+ 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;
- }
- 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");
- 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;
diff --git a/src/tests/attach.c b/src/tests/attach.c
index 7bf5ef179..2c771278c 100644
--- a/src/tests/attach.c
+++ b/src/tests/attach.c
@@ -19,16 +19,18 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#include
-#include "lxc/utils.h"
-#include "lxc/lsm/lsm.h"
-
-#include
+#include
#include
#include
#include
#include
-#include
+#include
+
+#include "lxctest.h"
+#include "utils.h"
+#include "lsm/lsm.h"
+
+#include
#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);
}
diff --git a/src/tests/lxc-test-lxc-attach b/src/tests/lxc-test-lxc-attach
index 380a6db30..2aa0b830b 100755
--- a/src/tests/lxc-test-lxc-attach
+++ b/src/tests/lxc-test-lxc-attach
@@ -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