return 0;
}
-static int setup_console(const char *rootfs, const char *tty)
+static int setup_console(const char *rootfs, const struct lxc_console *console)
{
- char console[MAXPATHLEN];
-
- snprintf(console, sizeof(console), "%s/dev/console",
- rootfs ? rootfs : "");
+ char path[MAXPATHLEN];
+ struct stat s;
- /* we have the rootfs with /dev/console but no tty
- * to be used as console, let's remap /dev/console
- * to /dev/null to avoid to log to the system console
- */
- if (rootfs && !tty[0]) {
+ /* We don't have a rootfs, /dev/console will be shared */
+ if (!rootfs)
+ return 0;
- if (!access(console, F_OK)) {
+ snprintf(path, sizeof(path), "%s/dev/console", rootfs);
- if (mount("/dev/null", console, "none", MS_BIND, 0)) {
- SYSERROR("failed to mount '/dev/null'->'%s'",
- console);
- return -1;
- }
- }
+ if (access(path, F_OK)) {
+ WARN("rootfs specified but no console found");
+ return 0;
}
- if (!tty[0])
- return 0;
+ if (console->peer == -1)
+ INFO("no console output required");
- if (access(console, R_OK|W_OK))
- return 0;
+ if (stat(path, &s)) {
+ SYSERROR("failed to stat '%s'", path);
+ return -1;
+ }
+
+ if (chmod(console->name, s.st_mode)) {
+ SYSERROR("failed to set mode '0%o' to '%s'",
+ s.st_mode, console->name);
+ return -1;
+ }
- if (mount(tty, console, "none", MS_BIND, 0)) {
- ERROR("failed to mount the console");
+ if (mount(console->name, path, "none", MS_BIND, 0)) {
+ ERROR("failed to mount '%s' on '%s'", console->name, path);
return -1;
}
- INFO("console '%s' mounted to '%s'", tty, console);
+ INFO("console has been setup");
return 0;
}
new->utsname = NULL;
new->tty = 0;
new->pts = 0;
- new->console[0] = '\0';
+ new->console.peer = -1;
+ new->console.master = -1;
+ new->console.slave = -1;
+ new->console.name[0] = '\0';
lxc_list_init(&new->cgroup);
lxc_list_init(&new->network);
lxc_list_init(&new->mount_list);
return -1;
}
- if (setup_console(lxc_conf->rootfs, lxc_conf->console)) {
+ if (setup_console(lxc_conf->rootfs, &lxc_conf->console)) {
ERROR("failed to setup the console for '%s'", name);
return -1;
}
struct lxc_pty_info *pty_info;
};
+/*
+ * Defines the structure to store the console information
+ * @peer : the file descriptor put/get console traffic
+ * @name : the file name of the slave pty
+ */
+struct lxc_console {
+ int slave;
+ int master;
+ int peer;
+ char name[MAXPATHLEN];
+};
+
/*
* Defines the global container configuration
- * @rootfs : the root directory to run the container
- * @mount : the list of mount points
- * @network : the network configuration
- * @utsname : the container utsname
+ * @rootfs : root directory to run the container
+ * @pivotdir : pivotdir path, if not set default will be used
+ * @mount : list of mount points
+ * @tty : numbers of tty
+ * @pts : new pts instance
+ * @mount_list : list of mount point (alternative to fstab file)
+ * @network : network configuration
+ * @utsname : container utsname
+ * @fstab : path to a fstab file format
+ * @caps : list of the capabilities
+ * @tty_info : tty data
+ * @console : console data
*/
struct lxc_conf {
char *rootfs;
struct lxc_list mount_list;
struct lxc_list caps;
struct lxc_tty_info tty_info;
- char console[MAXPATHLEN];
+ struct lxc_console console;
};
/*
#include <string.h>
#include <unistd.h>
#include <errno.h>
+#include <fcntl.h>
+#include <pty.h>
+#include <sys/stat.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/utsname.h>
static int config_network_ipv4(const char *, char *, struct lxc_conf *);
static int config_network_ipv6(const char *, char *, struct lxc_conf *);
static int config_cap_drop(const char *, char *, struct lxc_conf *);
+static int config_console(const char *, char *, struct lxc_conf *);
typedef int (*config_cb)(const char *, char *, struct lxc_conf *);
{ "lxc.network.ipv4", config_network_ipv4 },
{ "lxc.network.ipv6", config_network_ipv6 },
{ "lxc.cap.drop", config_cap_drop },
+ { "lxc.console", config_console },
};
static const size_t config_size = sizeof(config)/sizeof(struct config);
return ret;
}
+static int config_console(const char *key, char *value, struct lxc_conf *lxc_conf)
+{
+ int fd;
+
+ fd = open(value, O_CLOEXEC | O_RDWR | O_CREAT | O_APPEND, 0600);
+ if (fd < 0) {
+ SYSERROR("failed to open '%s'", value);
+ return -1;
+ }
+
+ lxc_conf->console.peer = fd;
+
+ return 0;
+}
+
static int config_rootfs(const char *key, char *value, struct lxc_conf *lxc_conf)
{
if (strlen(value) >= MAXPATHLEN) {
#include <stdio.h>
#include <unistd.h>
+#include <fcntl.h>
#include <errno.h>
+#include <pty.h>
#include <sys/types.h>
#include <sys/un.h>
#include <lxc/start.h> /* for struct lxc_handler */
#include "commands.h"
+#include "mainloop.h"
#include "af_unix.h"
lxc_log_define(lxc_console, lxc);
}
extern int lxc_console_callback(int fd, struct lxc_request *request,
- struct lxc_handler *handler)
+ struct lxc_handler *handler)
{
int ttynum = request->data;
struct lxc_tty_info *tty_info = &handler->conf->tty_info;
return 1;
}
+int lxc_create_console(struct lxc_console *console)
+{
+ if (openpty(&console->master, &console->slave,
+ console->name, NULL, NULL)) {
+ SYSERROR("failed to allocate a pty");
+ return -1;
+ }
+
+ if (fcntl(console->master, F_SETFD, FD_CLOEXEC)) {
+ SYSERROR("failed to set console master to close-on-exec");
+ goto err;
+ }
+
+ if (fcntl(console->slave, F_SETFD, FD_CLOEXEC)) {
+ SYSERROR("failed to set console slave to close-on-exec");
+ goto err;
+ }
+
+ return 0;
+err:
+ close(console->master);
+ close(console->slave);
+ return -1;
+}
+
+void lxc_delete_console(const struct lxc_console *console)
+{
+ close(console->master);
+ close(console->slave);
+}
+
+static int console_handler(int fd, void *data, struct lxc_epoll_descr *descr)
+{
+ struct lxc_console *console = (struct lxc_console *)data;
+ char buf[1024];
+ int r;
+
+ r = read(fd, buf, sizeof(buf));
+ if (r < 0) {
+ SYSERROR("failed to read");
+ return 1;
+ }
+
+ /* no output for the console, do nothing */
+ if (console->peer == -1)
+ return 0;
+
+ if (console->peer == fd)
+ write(console->master, buf, r);
+ else
+ write(console->peer, buf, r);
+
+ return 0;
+}
+
+int lxc_console_mainloop_add(struct lxc_epoll_descr *descr,
+ struct lxc_handler *handler)
+{
+ struct lxc_conf *conf = handler->conf;
+ struct lxc_console *console = &conf->console;
+
+ if (lxc_mainloop_add_handler(descr, console->master,
+ console_handler, console)) {
+ ERROR("failed to add to mainloop console handler for '%d'",
+ console->master);
+ return -1;
+ }
+
+ if (console->peer != -1 &&
+ lxc_mainloop_add_handler(descr, console->peer,
+ console_handler, console))
+ WARN("console input disabled");
+
+ return 0;
+}
--- /dev/null
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2010
+ *
+ * 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_create_console(struct lxc_console *);
+extern void lxc_delete_console(struct lxc_console *);
+extern int lxc_console_mainloop_add(struct lxc_epoll_descr *, struct lxc_handler *);
#include "log.h"
#include "lxc.h"
#include "conf.h"
+#include "cgroup.h"
#include "utils.h"
#include "config.h"
#include "confile.h"
.daemonize = 0,
};
-static int save_tty(struct termios *tios)
-{
- if (!isatty(0))
- return 0;
-
- if (tcgetattr(0, tios))
- WARN("failed to get current terminal settings : %s",
- strerror(errno));
-
- return 0;
-}
-
-static int restore_tty(struct termios *tios)
-{
- struct termios current_tios;
- void (*oldhandler)(int);
- int ret;
-
- if (!isatty(0))
- return 0;
-
- if (tcgetattr(0, ¤t_tios)) {
- ERROR("failed to get current terminal settings : %s",
- strerror(errno));
- return -1;
- }
-
- if (!memcmp(tios, ¤t_tios, sizeof(*tios)))
- return 0;
-
- oldhandler = signal(SIGTTOU, SIG_IGN);
- ret = tcsetattr(0, TCSADRAIN, tios);
- if (ret)
- ERROR("failed to restore terminal attributes");
- signal(SIGTTOU, oldhandler);
-
- return ret;
-}
-
int main(int argc, char *argv[])
{
char *const *args;
int err = -1;
- struct termios tios;
char *const default_args[] = {
"/sbin/init",
}
}
- save_tty(&tios);
-
err = lxc_start(my_args.name, args, conf);
- restore_tty(&tios);
-
return err;
}
#define PR_CAPBSET_DROP 24
#endif
-#include <lxc/log.h>
-#include <lxc/conf.h>
-#include <lxc/confile.h>
-#include <lxc/start.h>
-#include <lxc/utils.h>
-#include <lxc/cgroup.h>
-#include <lxc/monitor.h>
-
+#include "start.h"
+#include "conf.h"
+#include "log.h"
#include "error.h"
#include "af_unix.h"
#include "mainloop.h"
+#include "utils.h"
+#include "monitor.h"
#include "commands.h"
-
+#include "console.h"
lxc_log_define(lxc_start, lxc);
goto out_mainloop_open;
}
+ if (lxc_console_mainloop_add(&descr, handler)) {
+ ERROR("failed to add console handler to mainloop");
+ goto out_mainloop_open;
+ }
+
if (lxc_command_mainloop_add(name, &descr, handler))
goto out_mainloop_open;
return -1;
}
-static int fdname(int fd, char *name, size_t size)
-{
- char path[MAXPATHLEN];
- ssize_t len;
-
- snprintf(path, MAXPATHLEN, "/proc/self/fd/%d", fd);
-
- len = readlink(path, name, size);
- if (len > 0)
- path[len] = '\0';
-
- return (len <= 0) ? -1 : 0;
-}
-
-static int console_init(char *console, size_t size)
-{
- struct stat stat;
- int i;
-
- for (i = 0; i < 3; i++) {
- if (!isatty(i))
- continue;
-
- if (ttyname_r(i, console, size)) {
- SYSERROR("failed to retrieve tty name");
- return -1;
- }
-
- return 0;
- }
-
- if (!fstat(0, &stat)) {
- if (S_ISREG(stat.st_mode) || S_ISCHR(stat.st_mode) ||
- S_ISFIFO(stat.st_mode) || S_ISLNK(stat.st_mode))
- return fdname(0, console, size);
- }
-
- console[0] = '\0';
-
- DEBUG("console initialized");
-
- return 0;
-}
-
struct lxc_handler *lxc_init(const char *name, struct lxc_conf *conf)
{
struct lxc_handler *handler;
goto out_free;
}
- if (console_init(conf->console, sizeof(conf->console))) {
- ERROR("failed to initialize the console");
- goto out_aborting;
- }
-
if (lxc_create_tty(name, conf)) {
ERROR("failed to create the ttys");
goto out_aborting;
}
+ if (lxc_create_console(&conf->console)) {
+ ERROR("failed to create console");
+ goto out_delete_tty;
+ }
+
/* 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 */
handler->sigfd = setup_sigchld_fd(&handler->oldmask);
if (handler->sigfd < 0) {
ERROR("failed to set sigchild fd handler");
- goto out_delete_tty;
+ goto out_delete_console;
}
/* Avoid signals from terminal */
INFO("'%s' is initialized", name);
return handler;
+out_delete_console:
+ lxc_delete_console(&conf->console);
out_delete_tty:
lxc_delete_tty(&conf->tty_info);
out_aborting:
lxc_set_state(name, handler, STOPPED);
lxc_unlink_nsgroup(name);
+ lxc_delete_console(&handler->conf->console);
lxc_delete_tty(&handler->conf->tty_info);
free(handler);