Closes #1857.
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
#include "namespace.h"
#include "network.h"
#include "parse.h"
+#include "ringbuf.h"
#include "storage.h"
#include "storage/aufs.h"
#include "storage/overlay.h"
new->autodev = 1;
new->console.log_path = NULL;
new->console.log_fd = -1;
+ new->console.log_size = 0;
new->console.path = NULL;
new->console.peer = -1;
new->console.peerpty.busy = -1;
new->console.master = -1;
new->console.slave = -1;
new->console.name[0] = '\0';
+ memset(&new->console.ringbuf, 0, sizeof(struct lxc_ringbuf));
new->maincmd_fd = -1;
new->nbd_idx = -1;
new->rootfs.mount = strdup(default_rootfs_mount);
return true;
}
+/**
+ * Note that this function needs to run before the mainloop starts. Since we
+ * register a handler for the console's masterfd when we create the mainloop
+ * the console handler needs to see an allocated ringbuffer.
+ */
+static int lxc_setup_console_ringbuf(struct lxc_console *console)
+{
+ int ret;
+ struct lxc_ringbuf *buf = &console->ringbuf;
+ uint64_t size = console->log_size;
+
+ /* no ringbuffer previously allocated and no ringbuffer requested */
+ if (!buf->addr && size <= 0)
+ return 0;
+
+ /* ringbuffer allocated but no new ringbuffer requested */
+ if (buf->addr && size <= 0) {
+ lxc_ringbuf_release(buf);
+ buf->addr = NULL;
+ buf->r_off = 0;
+ buf->w_off = 0;
+ buf->size = 0;
+ TRACE("Deallocated console ringbuffer");
+ return 0;
+ }
+
+ if (size <= 0)
+ return 0;
+
+ /* check wether the requested size for the ringbuffer has changed */
+ if (buf->addr && buf->size != size) {
+ TRACE("Console ringbuffer size changed from %" PRIu64
+ " to %" PRIu64 " bytes. Deallocating console ringbuffer",
+ buf->size, size);
+ lxc_ringbuf_release(buf);
+ }
+
+ ret = lxc_ringbuf_create(buf, size);
+ if (ret < 0) {
+ ERROR("Failed to setup %" PRIu64 " byte console ringbuffer", size);
+ return -1;
+ }
+
+ TRACE("Allocated %" PRIu64 " byte console ringbuffer", size);
+ return 0;
+}
+
+int lxc_setup_parent(struct lxc_handler *handler)
+{
+ int ret;
+
+ ret = lxc_setup_console_ringbuf(&handler->conf->console);
+ if (ret < 0)
+ return -1;
+
+ return 0;
+}
+
int lxc_setup_child(struct lxc_handler *handler)
{
int ret;
current_config = NULL;
free(conf->console.log_path);
free(conf->console.path);
+ if (conf->console.log_size > 0 && conf->console.ringbuf.addr)
+ lxc_ringbuf_release(&conf->console.ringbuf);
free(conf->rootfs.mount);
free(conf->rootfs.bdev_type);
free(conf->rootfs.options);
#include <stdbool.h>
#include "list.h"
+#include "ringbuf.h"
#include "start.h" /* for lxc_handler */
#if HAVE_SCMP_FILTER_CTX
struct termios *tios;
struct lxc_tty_state *tty_state;
uint64_t log_size;
+ struct lxc_ringbuf ringbuf;
};
/*
extern int do_rootfs_setup(struct lxc_conf *conf, const char *name,
const char *lxcpath);
extern int lxc_setup_child(struct lxc_handler *handler);
+extern int lxc_setup_parent(struct lxc_handler *handler);
extern int setup_resource_limits(struct lxc_list *limits, pid_t pid);
extern int find_unmapped_nsid(struct lxc_conf *conf, enum idtype idtype);
extern int mapped_hostid(unsigned id, struct lxc_conf *conf,
#include <../include/openpty.h>
#endif
+#define LXC_CONSOLE_BUFFER_SIZE 1024
+
lxc_log_define(console, lxc);
static struct lxc_list lxc_ttys;
struct lxc_epoll_descr *descr)
{
struct lxc_console *console = (struct lxc_console *)data;
- char buf[1024];
- int r, w;
+ char buf[LXC_CONSOLE_BUFFER_SIZE];
+ int r, w, w_log, w_rbuf;
w = r = lxc_read_nointr(fd, buf, sizeof(buf));
if (r <= 0) {
- INFO("console client on fd %d has exited", fd);
+ INFO("Console client on fd %d has exited", fd);
lxc_mainloop_del_handler(descr, fd);
if (fd == console->peer) {
if (console->tty_state) {
if (fd == console->peer)
w = lxc_write_nointr(console->master, buf, r);
+ w_rbuf = w_log = 0;
if (fd == console->master) {
- if (console->log_fd >= 0)
- w = lxc_write_nointr(console->log_fd, buf, r);
-
+ /* write to peer first */
if (console->peer >= 0)
w = lxc_write_nointr(console->peer, buf, r);
+
+ /* write to console ringbuffer */
+ if (console->log_size > 0)
+ w_rbuf = lxc_ringbuf_write(&console->ringbuf, buf, r);
+
+ /* write to console log */
+ if (console->log_fd >= 0)
+ w_log = lxc_write_nointr(console->log_fd, buf, r);
}
if (w != r)
- WARN("console short write r:%d w:%d", r, w);
+ WARN("Console short write r:%d != w:%d", r, w);
+
+ if (w_rbuf < 0)
+ TRACE("%s - Failed to write %d bytes to console ringbuffer",
+ strerror(-w_rbuf), r);
+
+ if (w_log < 0)
+ TRACE("Failed to write %d bytes to console log", r);
return 0;
}
struct lxc_epoll_descr *descr)
{
struct lxc_tty_state *ts = cbdata;
- char buf[1024];
+ char buf[LXC_CONSOLE_BUFFER_SIZE];
int r, w;
if (fd != ts->masterfd)
*/
flags &= ~CLONE_NEWNET;
}
+
+ ret = lxc_setup_parent(handler);
+ if (ret < 0)
+ goto out_delete_net;
+
handler->pid = lxc_clone(do_start, handler, flags);
if (handler->pid < 0) {
SYSERROR("Failed to clone a new set of namespaces.");