[CRIU] [PATCH 11/11] tty: Add dump and restore of /dev/console opened

Cyrill Gorcunov gorcunov at openvz.org
Mon Sep 29 09:25:37 PDT 2014


/dev/console is a system console which provided
by the system with major 5 and minor 1. It's usually
configured on system startup with console= option
and underlied driver is resposible to deliver messages
to the console user.

The underlied driver may have own .ioctls which we
don't account for a while but stick with simple
solution first to see how it goes:

 - simply fetch general tty parameters such as termios
   and winsize and save them in image

 - the image entry will have own tty type TTY_TYPE__CONSOLE

 - on restore simply open the console by predefinde path
   as /dev/console and restore the parameters

 - because tty_info::tie::pty = NULL for consoles put
   BUG_ON where appropriate

Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
---
 tty.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 161 insertions(+), 12 deletions(-)

diff --git a/tty.c b/tty.c
index 07889a6ec605..12a3ef086194 100644
--- a/tty.c
+++ b/tty.c
@@ -362,6 +362,8 @@ static int tty_restore_ctl_terminal(struct file_desc *d, int fd)
 	if (!is_service_fd(fd, CTL_TTY_OFF))
 		return 0;
 
+	BUG_ON(!info->tie->pty);
+
 	snprintf(pts_name, sizeof(pts_name), PTS_FMT, info->tie->pty->index);
 	slave = open(pts_name, O_RDONLY);
 	if (slave < 0) {
@@ -420,7 +422,8 @@ static bool tty_has_active_pair(struct tty_info *info)
 static void tty_show_pty_info(char *prefix, struct tty_info *info)
 {
 	pr_info("%s type %s id %#x index %d (master %d sid %d pgrp %d inherit %d)\n",
-		prefix, tty_type(info->major, info->minor), info->tfe->id, info->tie->pty->index,
+		prefix, tty_type(info->major, info->minor), info->tfe->id,
+		info->tie->pty ? info->tie->pty->index : -1,
 		tty_is_master(info), info->tie->sid, info->tie->pgrp, info->inherit);
 }
 
@@ -472,6 +475,7 @@ static int pty_open_slaves(struct tty_info *info)
 	struct tty_info *slave;
 	char pts_name[64];
 
+	BUG_ON(!info->tie->pty);
 	snprintf(pts_name, sizeof(pts_name), PTS_FMT, info->tie->pty->index);
 
 	sock = socket(PF_UNIX, SOCK_DGRAM, 0);
@@ -554,6 +558,7 @@ static int pty_open_unpaired_slave(struct file_desc *d, struct tty_info *slave)
 	} else {
 		char pts_name[64];
 
+		BUG_ON(!slave->tie->pty);
 		snprintf(pts_name, sizeof(pts_name), PTS_FMT, slave->tie->pty->index);
 
 		master = pty_open_ptmx_index(O_RDONLY, slave->tie->pty->index);
@@ -616,6 +621,7 @@ static int pty_open_ptmx(struct tty_info *info)
 {
 	int master = -1;
 
+	BUG_ON(!info->tie->pty);
 	master = pty_open_ptmx_index(info->tfe->flags, info->tie->pty->index);
 	if (master < 0) {
 		pr_perror("Can't open %x (index %d)",
@@ -653,6 +659,30 @@ err:
 	return -1;
 }
 
+static int console_open(struct tty_info *info)
+{
+	const char console_path[] = "/dev/console";
+	int console = -1;
+
+	console = open(console_path, info->tfe->flags);
+	if (console < 0) {
+		pr_perror("Can't open %s %x",
+			  console_path, info->tfe->id);
+		return -1;
+	}
+
+	if (rst_file_params(console, info->tfe->fown, info->tfe->flags))
+		goto err;
+
+	if (restore_tty_params(console, info))
+		goto err;
+
+	return console;
+err:
+	close_safe(&console);
+	return -1;
+}
+
 static int tty_open(struct file_desc *d)
 {
 	struct tty_info *info = container_of(d, struct tty_info, d);
@@ -662,11 +692,15 @@ static int tty_open(struct file_desc *d)
 	if (!info->create)
 		return receive_tty(info);
 
-	if (!tty_is_master(info))
-		return pty_open_unpaired_slave(d, info);
-
-	return pty_open_ptmx(info);
+	if (info->tie->type == TTY_TYPE__PTY) {
+		if (!tty_is_master(info))
+			return pty_open_unpaired_slave(d, info);
+		return pty_open_ptmx(info);
+	} else if (info->tie->type == TTY_TYPE__CONSOLE)
+		return console_open(info);
 
+	pr_err("Unexpected type of TTY %d\n", info->tie->type);
+	return -1;
 }
 
 static int tty_transport(FdinfoEntry *fe, struct file_desc *d)
@@ -843,11 +877,16 @@ int tty_setup_slavery(void)
 	struct tty_info *info, *peer, *m;
 
 	list_for_each_entry(info, &all_ttys, list) {
+		if (info->tie->type != TTY_TYPE__PTY)
+			continue;
 		if (tty_find_restoring_task(info))
 			return -1;
 
 		peer = info;
 		list_for_each_entry_safe_continue(peer, m, &all_ttys, list) {
+			if (peer->tie->type != TTY_TYPE__PTY)
+				continue;
+
 			if (peer->tie->pty->index != info->tie->pty->index)
 				continue;
 
@@ -937,18 +976,21 @@ static int collect_one_tty_info_entry(void *obj, ProtobufCMessage *msg)
 
 	info->tie = pb_msg(msg, TtyInfoEntry);
 
-	if (info->tie->type != TTY_TYPE__PTY) {
+	if (info->tie->type == TTY_TYPE__PTY) {
+		if (!info->tie->pty) {
+			pr_err("No PTY data found (id %x), corrupted image?\n",
+			       info->tie->id);
+			return -1;
+		}
+	} else if (info->tie->type == TTY_TYPE__CONSOLE) {
+		/* Nothing */;
+	} else {
 		pr_err("Unexpected TTY type %d (id %x)\n",
 		       info->tie->type, info->tie->id);
 		return -1;
 	}
 
-	if (!info->tie->pty) {
-		pr_err("No PTY data found (id %x), corrupted image?\n",
-		       info->tie->id);
-		return -1;
-	}
-
+	pr_info("Collected tty-info ID %#x\n", info->tie->id);
 	INIT_LIST_HEAD(&info->list);
 	list_add(&info->list, &all_tty_info_entries);
 
@@ -1214,6 +1256,111 @@ static int dump_one_pty(int lfd, u32 id, const struct fd_parms *p, int major, in
 	return ret;
 }
 
+static int dump_console_info(int lfd, u32 id, const struct fd_parms *p, int major, int minor, int index)
+{
+	TtyInfoEntry info		= TTY_INFO_ENTRY__INIT;
+	TermiosEntry termios		= TERMIOS_ENTRY__INIT;
+	TermiosEntry termios_locked	= TERMIOS_ENTRY__INIT;
+	WinsizeEntry winsize		= WINSIZE_ENTRY__INIT;
+	struct tty_dump_info *dinfo;
+
+	struct termios t;
+	struct winsize w;
+
+	int ret = -1;
+
+	/*
+	 * Make sure the structures the system provides us
+	 * correlates well with protobuf templates.
+	 */
+	BUILD_BUG_ON(ARRAY_SIZE(t.c_cc) < TERMIOS_NCC);
+	BUILD_BUG_ON(sizeof(termios.c_cc) != sizeof(void *));
+	BUILD_BUG_ON((sizeof(termios.c_cc) * TERMIOS_NCC) < sizeof(t.c_cc));
+
+	dinfo = xmalloc(sizeof(*dinfo));
+	if (!dinfo)
+		return -1;
+
+	/*
+	 * Make sure no @sid and @pgrp here since
+	 * that's how we check if we need to validate
+	 * this particular peer as a contol terminal
+	 * (which system console can't be).
+	 */
+	dinfo->id		= id;
+	dinfo->sid		= 0;
+	dinfo->pgrp		= 0;
+	dinfo->fd		= p->fd;
+	dinfo->major		= major;
+	dinfo->minor		= minor;
+
+	list_add_tail(&dinfo->list, &all_ttys);
+
+	info.id			= id;
+	info.type		= TTY_TYPE__CONSOLE;
+	info.sid		= 0;
+	info.pgrp		= 0;
+	info.rdev		= p->stat.st_rdev;
+
+	info.termios		= &termios;
+	info.termios_locked	= &termios_locked;
+	info.winsize		= &winsize;
+
+	termios.n_c_cc		= TERMIOS_NCC;
+	termios.c_cc		= xmalloc(pb_repeated_size(&termios, c_cc));
+
+	termios_locked.n_c_cc	= TERMIOS_NCC;
+	termios_locked.c_cc	= xmalloc(pb_repeated_size(&termios_locked, c_cc));
+
+	if (!termios.c_cc || !termios_locked.c_cc)
+		goto out;
+
+	memzero(&t, sizeof(t));
+	if (ioctl(lfd, TCGETS, &t) < 0) {
+		pr_perror("Can't get tty params on %x", id);
+		goto out;
+	}
+	termios_copy(&termios, &t);
+
+	memzero(&t, sizeof(t));
+	if (ioctl(lfd, TIOCGLCKTRMIOS, &t) < 0) {
+		pr_perror("Can't get tty locked params on %x", id);
+		goto out;
+	}
+	termios_copy(&termios_locked, &t);
+
+	memzero(&w, sizeof(w));
+	if (ioctl(lfd, TIOCGWINSZ, &w) < 0) {
+		pr_perror("Can't get tty window params on %x", id);
+		goto out;
+	}
+	winsize_copy(&winsize, &w);
+
+	ret = pb_write_one(fdset_fd(glob_fdset, CR_FD_TTY_INFO), &info, PB_TTY_INFO);
+out:
+	xfree(termios.c_cc);
+	xfree(termios_locked.c_cc);
+	return ret;
+}
+
+static int dump_one_console(int lfd, u32 id, const struct fd_parms *p, int major, int minor)
+{
+	TtyFileEntry e = TTY_FILE_ENTRY__INIT;
+	int ret = 0;
+
+	e.id		= id;
+	e.tty_info_id	= tty_gen_id(major, CONSOLE_START);
+	e.flags		= p->flags;
+	e.fown		= (FownEntry *)&p->fown;
+
+	if (!tty_test_and_set(e.tty_info_id, tty_bitmap))
+		ret = dump_console_info(lfd, e.tty_info_id, p, major, minor, CONSOLE_START);
+
+	if (!ret)
+		ret = pb_write_one(fdset_fd(glob_fdset, CR_FD_TTY_FILES), &e, PB_TTY_FILE);
+	return ret;
+}
+
 static int dump_one_tty(int lfd, u32 id, const struct fd_parms *p)
 {
 	int major = major(p->stat.st_rdev);
@@ -1226,6 +1373,8 @@ static int dump_one_tty(int lfd, u32 id, const struct fd_parms *p)
 	case TTYAUX_MAJOR:
 		if (minor == 0 || minor == 2)
 			return dump_one_pty(lfd, id, p, major, minor);
+		else if (minor == 1)
+			return dump_one_console(lfd, id, p, major, minor);
 		break;
 	case UNIX98_PTY_MASTER_MAJOR ... (UNIX98_PTY_MASTER_MAJOR + UNIX98_PTY_MAJOR_COUNT - 1):
 	case UNIX98_PTY_SLAVE_MAJOR:
-- 
1.9.3



More information about the CRIU mailing list