[CRIU] Re: [PATCH 2/2] tty: Add checkpoint/restore for ttys

Andrew Vagin avagin at parallels.com
Thu Jun 21 06:46:56 EDT 2012


Looks like that it should be dead-locked if slave and master will be
opened in one process and a descriptor number of slave will be less than
a number of master.

On Fri, Jun 15, 2012 at 01:32:46PM +0400, Cyrill Gorcunov wrote:
> At moment it handles unix98 ttys only. At least
> that's what being tested with 'screen' session.
> 
> The base idea is to save/restore tty parameters with
> TCGETS/TCSETS ioctls.
> 
> Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
> ---
>  Makefile          |    1 +
>  cr-dump.c         |    7 +-
>  cr-restore.c      |    4 +
>  cr-show.c         |   33 ++++
>  crtools.c         |    1 +
>  include/crtools.h |    2 +
>  include/image.h   |   25 +++
>  include/tty.h     |   15 ++
>  tty.c             |  502 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  9 files changed, 588 insertions(+), 2 deletions(-)
>  create mode 100644 include/tty.h
>  create mode 100644 tty.c
> 
> diff --git a/Makefile b/Makefile
> index 44b6854..c4e5a58 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -55,6 +55,7 @@ OBJS		+= eventfd.o
>  OBJS		+= eventpoll.o
>  OBJS		+= mount.o
>  OBJS		+= inotify.o
> +OBJS		+= tty.o
>  
>  DEPS		:= $(patsubst %.o,%.d,$(OBJS))
>  
> diff --git a/cr-dump.c b/cr-dump.c
> index 47f2667..555c125 100644
> --- a/cr-dump.c
> +++ b/cr-dump.c
> @@ -41,6 +41,7 @@
>  #include "eventfd.h"
>  #include "eventpoll.h"
>  #include "inotify.h"
> +#include "tty.h"
>  
>  #ifndef CONFIG_X86_64
>  # error No x86-32 support yet
> @@ -443,12 +444,14 @@ static int dump_chrdev(struct fd_parms *p, int lfd, const struct cr_fdset *set)
>  	switch (maj) {
>  	case MEM_MAJOR:
>  		return dump_reg_file(p, lfd, set);
> -	case TTY_MAJOR:
> +	case TTYAUX_MAJOR:
> +	case UNIX98_PTY_MASTER_MAJOR ... (UNIX98_PTY_MASTER_MAJOR + UNIX98_PTY_MAJOR_COUNT - 1):
>  	case UNIX98_PTY_SLAVE_MAJOR:
>  		if (p->fd < 3) {
>  			pr_info("... Skipping tty ... %d\n", p->fd);
>  			return 0;
> -		}
> +		} else
> +			return dump_tty(p, lfd, set);
>  	}
>  
>  	return dump_unsupp_fd(p);
> diff --git a/cr-restore.c b/cr-restore.c
> index 9a17cd3..1c44716 100644
> --- a/cr-restore.c
> +++ b/cr-restore.c
> @@ -45,6 +45,7 @@
>  #include "shmem.h"
>  #include "mount.h"
>  #include "inotify.h"
> +#include "tty.h"
>  
>  static struct task_entries *task_entries;
>  
> @@ -290,6 +291,9 @@ static int prepare_shared(void)
>  	if (collect_pipes())
>  		return -1;
>  
> +	if (collect_tty())
> +		return -1;
> +
>  	if (collect_inet_sockets())
>  		return -1;
>  
> diff --git a/cr-show.c b/cr-show.c
> index 27de63a..296257a 100644
> --- a/cr-show.c
> +++ b/cr-show.c
> @@ -62,6 +62,7 @@ static char *fdtype2s(u8 type)
>  		[FDINFO_REG] = "reg",
>  		[FDINFO_INETSK] = "isk",
>  		[FDINFO_PIPE] = "pipe",
> +		[FDINFO_TTY] = "tty",
>  		[FDINFO_UNIXSK] = "usk",
>  		[FDINFO_EVENTFD] = "efd",
>  		[FDINFO_EVENTPOLL] = "epl",
> @@ -227,6 +228,38 @@ out:
>  	pr_img_tail(CR_FD_PIPES);
>  }
>  
> +void show_tty(int fd, struct cr_options *o)
> +{
> +	struct tty_file_entry e;
> +	int ret;
> +
> +	pr_img_head(CR_FD_TTY);
> +
> +	while (1) {
> +		ret = read_img_eof(fd, &e);
> +		if (ret <= 0)
> +			goto out;
> +		pr_msg("id: 0x%-8x flags: 0x%-8x rdev: 0x%-16lx index 0x%-8x ",
> +		       e.id, e.flags, e.rdev, e.index);
> +		show_fown_cont(&e.fown);
> +
> +		if (e.len) {
> +			int ret = read(fd, local_buf, e.len);
> +
> +			if (ret != e.len) {
> +				pr_perror("Can't read %d bytes", e.len);
> +				goto out;
> +			}
> +			local_buf[e.len] = 0;
> +			pr_msg(" --> %s", local_buf);
> +		}
> +		pr_msg("\n");
> +	}
> +
> +out:
> +	pr_img_tail(CR_FD_TTY);
> +}
> +
>  void show_fs(int fd_fs, struct cr_options *o)
>  {
>  	struct fs_entry fe;
> diff --git a/crtools.c b/crtools.c
> index fc0e010..536ec57 100644
> --- a/crtools.c
> +++ b/crtools.c
> @@ -60,6 +60,7 @@ struct cr_fd_desc_tmpl fdset_template[CR_FD_MAX] = {
>  	FD_ENTRY(VMAS,		"vmas-%d",	 show_vmas),
>  	FD_ENTRY(PIPES,		"pipes",	 show_pipes),
>  	FD_ENTRY(PIPES_DATA,	"pipes-data",	 show_pipes_data),
> +	FD_ENTRY(TTY,		"tty",		 show_tty),
>  	FD_ENTRY(PSTREE,	"pstree",	 show_pstree),
>  	FD_ENTRY(SIGACT,	"sigacts-%d",	 show_sigacts),
>  	FD_ENTRY(UNIXSK,	"unixsk",	 show_unixsk),
> diff --git a/include/crtools.h b/include/crtools.h
> index 798d196..557f0f1 100644
> --- a/include/crtools.h
> +++ b/include/crtools.h
> @@ -54,6 +54,7 @@ enum {
>  	CR_FD_UNIXSK,
>  	CR_FD_PIPES,
>  	CR_FD_PIPES_DATA,
> +	CR_FD_TTY,
>  	CR_FD_REMAP_FPATH,
>  	CR_FD_EVENTFD,
>  	CR_FD_EVENTPOLL,
> @@ -113,6 +114,7 @@ void show_remap_files(int fd, struct cr_options *o);
>  void show_ghost_file(int fd, struct cr_options *o);
>  void show_fown_cont(fown_t *fown);
>  void show_eventfds(int fd, struct cr_options *o);
> +void show_tty(int fd, struct cr_options *o);
>  
>  extern void print_data(unsigned long addr, unsigned char *data, size_t size);
>  extern struct cr_fd_desc_tmpl fdset_template[CR_FD_MAX];
> diff --git a/include/image.h b/include/image.h
> index eed7389..0c7b2fd 100644
> --- a/include/image.h
> +++ b/include/image.h
> @@ -40,11 +40,13 @@
>  #define INOTIFY_MAGIC		0x48424431 /* Volgograd */
>  #define INOTIFY_WD_MAGIC	0x54562009 /* Svetlogorsk (Rauschen) */
>  #define MOUNTPOINTS_MAGIC	0x55563928 /* Petushki */
> +#define TTY_MAGIC		0x59433025 /* Pushkin */
>  
>  enum fd_types {
>  	FDINFO_UND,
>  	FDINFO_REG,
>  	FDINFO_PIPE,
> +	FDINFO_TTY,
>  	FDINFO_INETSK,
>  	FDINFO_UNIXSK,
>  	FDINFO_EVENTFD,
> @@ -154,6 +156,29 @@ enum {
>  	PIPE_TYPE_MAX,
>  };
>  
> +typedef struct {
> +	u16	c_iflag;
> +	u16	c_oflag;
> +	u16	c_cflag;
> +	u16	c_lflag;
> +	u8	c_line;
> +	u8	c_cc[19];
> +	u16	c_ispeed;
> +	u16	c_ospeed;
> +} __packed term2_t;
> +
> +struct tty_file_entry {
> +	u32	id;
> +	u16	flags;
> +	u16	len;
> +	u64	pos;
> +	u64	rdev;
> +	u32	index;
> +	fown_t	fown;
> +	term2_t	term2;
> +	u8	name[0];
> +} __packed;
> +
>  struct pipe_entry {
>  	u32	id;
>  	u32	pipe_id;
> diff --git a/include/tty.h b/include/tty.h
> new file mode 100644
> index 0000000..9fa6055
> --- /dev/null
> +++ b/include/tty.h
> @@ -0,0 +1,15 @@
> +#ifndef CR_TTY_H__
> +#define CR_TTY_H__
> +
> +#include "files.h"
> +#include "crtools.h"
> +
> +#define PTMX_PATH "/dev/ptmx"
> +#ifndef PTMX_MINOR
> +# define PTMX_MINOR 2
> +#endif
> +
> +extern int dump_tty(struct fd_parms *p, int lfd, const struct cr_fdset *set);
> +extern int collect_tty(void);
> +
> +#endif /* CR_TTY_H__ */
> diff --git a/tty.c b/tty.c
> new file mode 100644
> index 0000000..5ed3fdc
> --- /dev/null
> +++ b/tty.c
> @@ -0,0 +1,502 @@
> +#include <unistd.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <errno.h>
> +#include <string.h>
> +#include <limits.h>
> +#include <fcntl.h>
> +#include <sys/stat.h>
> +#include <sys/types.h>
> +#include <sys/mman.h>
> +#include <sys/ioctl.h>
> +#include <termios.h>
> +#include <linux/major.h>
> +
> +#include "compiler.h"
> +#include "types.h"
> +
> +#include "syscall.h"
> +#include "files.h"
> +#include "crtools.h"
> +#include "image.h"
> +#include "util.h"
> +#include "log.h"
> +#include "list.h"
> +#include "util-net.h"
> +#include "proc_parse.h"
> +
> +#include "tty.h"
> +
> +struct tty_file_info;
> +
> +struct pty_unix98_priv {
> +	struct tty_file_info	*slave;		/* pointer to slave info if there */
> +	bool			fake_ptmx;	/* fake ptmx needed to create slave */
> +	bool			slave_here;	/* slave in the same ns as a master */
> +};
> +
> +struct tty_private {
> +  union {
> +	struct pty_unix98_priv	unix98;
> +  };
> +};
> +
> +struct tty_file_info {
> +	struct list_head	list;
> +	struct file_desc	d;
> +	struct tty_file_entry	tfe;
> +	struct tty_private	priv;
> +
> +	char			*path;
> +	int			major;
> +	int			minor;
> +	bool			create;
> +};
> +
> +static LIST_HEAD(all_ttys);
> +
> +static void from_termio(term2_t *d, struct termio *s)
> +{
> +	BUILD_BUG_ON(sizeof(d->c_cc) < sizeof(s->c_cc));
> +
> +	memzero(d, sizeof(*d));
> +	memcpy(d->c_cc, s->c_cc, sizeof(s->c_cc));
> +	ASSIGN_MEMBER(d, s, c_iflag);
> +	ASSIGN_MEMBER(d, s, c_oflag);
> +	ASSIGN_MEMBER(d, s, c_cflag);
> +	ASSIGN_MEMBER(d, s, c_lflag);
> +	ASSIGN_MEMBER(d, s, c_line);
> +}
> +
> +static void to_termio(struct termio *d, term2_t *s)
> +{
> +	memzero(d, sizeof(*d));
> +	memcpy(d->c_cc, s->c_cc, sizeof(d->c_cc));
> +	ASSIGN_MEMBER(d, s, c_iflag);
> +	ASSIGN_MEMBER(d, s, c_oflag);
> +	ASSIGN_MEMBER(d, s, c_cflag);
> +	ASSIGN_MEMBER(d, s, c_lflag);
> +	ASSIGN_MEMBER(d, s, c_line);
> +}
> +
> +#define PTMX_INDEX_ANY	-1
> +
> +static int tty_open_ptmx_index(int flags, int index)
> +{
> +	int fds[32], i, ret = -1, cur_idx;
> +
> +	memset(fds, 0xff, sizeof(fds));
> +
> +	for (i = 0; i < ARRAY_SIZE(fds); i++) {
> +		fds[i] = open(PTMX_PATH, flags);
> +		if (fds[i] < 0) {
> +			pr_perror("Can't open %s", PTMX_PATH);
> +			break;
> +		}
> +
> +		if (ioctl(fds[i], TIOCGPTN, &cur_idx)) {
> +			pr_perror("Can't obtain current index on %s", PTMX_PATH);
> +			break;
> +		}
> +
> +		/*
> +		 * Index match or any index requested.
> +		 */
> +		if (cur_idx == index || index == PTMX_INDEX_ANY) {
> +			ret = fds[i];
> +			fds[i] = -1;
> +			break;
> +		}
> +
> +
> +		/*
> +		 * Maybe indices are already borrowed by
> +		 * someone else, so no need to continue.
> +		 */
> +		if (cur_idx < index && (index - cur_idx) < ARRAY_SIZE(fds))
> +			continue;
> +		break;
> +	}
> +
> +	for (i = 0; i < ARRAY_SIZE(fds); i++) {
> +		if (fds[i] >= 0)
> +			close(fds[i]);
> +	}
> +
> +	if (ret < 0)
> +		pr_err("Unable to open %s with specified index %d\n",
> +		       PTMX_PATH, index);
> +
> +	return ret;
> +}
> +
> +static int unlock_pty_master(int master)
> +{
> +	const int lock = 0;
> +
> +	if (ioctl(master, TIOCSPTLCK, &lock)) {
> +		pr_err("Unable to unlock pty master device %d\n", master);
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> +
> +static int receive_tty_pts(struct tty_file_info *info)
> +{
> +	struct fdinfo_list_entry *fle;
> +	struct file_desc *info_desc;
> +	char path[64];
> +	int tmp, fd;
> +
> +	info_desc = find_file_desc_raw(FDINFO_TTY, info->tfe.id);
> +	fle = file_master(info_desc);
> +	pr_info("\tWaiting tty fd %d\n", fle->fe.fd);
> +
> +	tmp = recv_fd(fle->fe.fd);
> +	close(fle->fe.fd);
> +	if (tmp < 0) {
> +		pr_err("Can't get fd %d\n", tmp);
> +		return -1;
> +	}
> +
> +	snprintf(path, sizeof(path), "/proc/self/fd/%d", tmp);
> +	fd = open(path, info->tfe.flags);
> +	close(tmp);
> +
> +	return fd;
> +}
> +
> +static int tty_loopup_open_pts(struct tty_file_info *info)
> +{
> +	int slave_fd, master_fd = -1;
> +
> +	if (!info->create)
> +		return receive_tty_pts(info);
> +
> +	slave_fd = open(info->path, info->tfe.flags);
> +	if (slave_fd >= 0)
> +		goto out;
> +
> +	if (info->priv.unix98.fake_ptmx) {
> +
> +		/* If we faile here we won't connect slave anyway */
> +		master_fd = tty_open_ptmx_index(info->tfe.flags | O_RDWR, info->tfe.index);
> +		if (master_fd >= 0)
> +			unlock_pty_master(master_fd);
> +		else
> +			pr_err("Can't open fake ptmx for %s (%d)\n",
> +			       info->path, info->tfe.index);
> +	}
> +
> +	slave_fd = open(info->path, info->tfe.flags);
> +	if (slave_fd < 0) {
> +		pr_perror("Can't open %s\n", info->path);
> +		goto out;
> +	}
> +
> +out:
> +	close_safe(&master_fd);
> +	return slave_fd;
> +}
> +
> +static int tty_open_ptmx(struct tty_file_info *info)
> +{
> +	struct tty_file_info *slave = info->priv.unix98.slave;
> +	int master_fd = -1;
> +	int slave_fd = -1;
> +	int sock = -1;
> +	int ret = -1;
> +
> +	if (info->minor != PTMX_MINOR || strcmp(info->path, PTMX_PATH)) {
> +		pr_err("Unexpected tty path %s (%d %d)\n",
> +		       info->path, info->minor, PTMX_MINOR);
> +		return -1;
> +	}
> +
> +	if (slave) {
> +		struct fdinfo_list_entry *fle;
> +		struct file_desc *slave_desc;
> +		int index;
> +
> +		if (info->priv.unix98.fake_ptmx)
> +			index = -1;
> +		else
> +			index = slave->tfe.index;
> +
> +		master_fd = tty_open_ptmx_index(info->tfe.flags, index);
> +		if (master_fd < 0)
> +			goto err;
> +
> +		if (unlock_pty_master(master_fd))
> +			goto err;
> +
> +		sock = socket(PF_UNIX, SOCK_DGRAM, 0);
> +		if (sock < 0) {
> +			pr_perror("Can't create socket");
> +			goto err;
> +		}
> +
> +		slave_fd = open(slave->path, slave->tfe.flags);
> +		if (slave_fd < 0) {
> +			pr_perror("Can't open slave %s", slave->path);
> +			goto err;
> +		}
> +
> +		slave_desc = find_file_desc_raw(FDINFO_TTY, slave->tfe.id);
> +		fle = file_master(slave_desc);
> +
> +		list_for_each_entry(fle, &slave_desc->fd_info_head, desc_list) {
> +			if (fle->pid == getpid())
> +				continue;
> +			if (send_fd_to_peer(slave_fd, fle, sock)) {
> +				pr_perror("Can't send file descriptor");
> +				goto err;
> +			}
> +		}
> +
> +		ret = master_fd, master_fd = -1;
> +	} else
> +		ret = tty_open_ptmx_index(info->tfe.flags, info->tfe.index);
> +
> +err:
> +	close_safe(&master_fd);
> +	close_safe(&slave_fd);
> +	close_safe(&sock);
> +	return ret;
> +}
> +
> +static int tty_lookup_open(struct tty_file_info *info)
> +{
> +	switch (info->major) {
> +	case UNIX98_PTY_SLAVE_MAJOR:
> +		return tty_loopup_open_pts(info);
> +	case TTYAUX_MAJOR:
> +		return tty_open_ptmx(info);
> +	}
> +
> +	BUG_ON(1);
> +	return -1;
> +}
> +
> +static int tty_open(struct file_desc *d)
> +{
> +	struct tty_file_info *info = container_of(d, struct tty_file_info, d);
> +	int tmp, ret = -1;
> +	struct termio t;
> +
> +	tmp = tty_lookup_open(info);
> +	if (tmp < 0) {
> +		pr_perror("Can't open tty id %#08x [%s]",
> +			  info->tfe.id, info->path);
> +		return -1;
> +	}
> +
> +	if (rst_file_params(tmp, &info->tfe.fown, info->tfe.flags)) {
> +		pr_perror("Can't restore params on tfe %#08x",
> +			  info->tfe.id);
> +		goto err;
> +	}
> +
> +	to_termio(&t, &info->tfe.term2);
> +	if (ioctl(tmp, TCSETS, &t) < 0) {
> +		pr_perror("Can't set tty params on %d [%s]",
> +			  info->tfe.id, info->path);
> +		goto err;
> +	}
> +
> +	ret = tmp, tmp = -1;
> +err:
> +	close_safe(&tmp);
> +	return ret;
> +}
> +
> +static int want_transport(struct fdinfo_entry *fe, struct file_desc *d)
> +{
> +	struct tty_file_info *info = container_of(d, struct tty_file_info, d);
> +	return info->create == false;
> +}
> +
> +static struct file_desc_ops tty_desc_ops = {
> +	.type		= FDINFO_TTY,
> +	.open		= tty_open,
> +	.want_transport	= want_transport,
> +};
> +
> +static int tty_handle_priv(struct list_head *all_ttys_head)
> +{
> +	struct tty_file_info *info;
> +
> +	list_for_each_entry(info, all_ttys_head, list) {
> +		struct tty_file_info *entry;
> +		int master;
> +
> +		/*
> +		 * At moment we're only interested in UNIX98_PTY_SLAVE_MAJOR
> +		 * devices since they require to open ptmx with appropriate
> +		 * index.
> +		 */
> +		if (info->major == TTYAUX_MAJOR ||
> +		    info->major != UNIX98_PTY_SLAVE_MAJOR)
> +			continue;
> +
> +		/*
> +		 * Setup the ptmx index here, the kernel
> +		 * doesn't provide any other interface :/
> +		 */
> +		if (sscanf(info->path, "/dev/pts/%d", &master) != 1) {
> +			pr_err("Unexpected format on path %s\n", info->path);
> +			return -1;
> +		}
> +		info->tfe.index = master;
> +
> +		/*
> +		 * By default we assume the fake ptmx
> +		 * connection is needed, until contrary
> +		 * proved.
> +		 */
> +		info->priv.unix98.fake_ptmx = true;
> +
> +		/* Finally connect slave to a master device */
> +		list_for_each_entry(entry, all_ttys_head, list) {
> +			if (entry->major != TTYAUX_MAJOR ||
> +			    entry->tfe.index != master)
> +				continue;
> +
> +			entry->priv.unix98.fake_ptmx = false;
> +			entry->priv.unix98.slave = info;
> +			info->create = false;
> +			break;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +int collect_tty(void)
> +{
> +	struct tty_file_info *info = NULL;
> +	int fd, ret = -1;
> +
> +	fd = open_image_ro(CR_FD_TTY);
> +	if (fd < 0)
> +		return -1;
> +
> +	while (1) {
> +		int len;
> +
> +		info = xzalloc(sizeof(*info));
> +		if (!info) {
> +			ret = -1;
> +			break;
> +		}
> +
> +		ret = read_img_eof(fd, &info->tfe);
> +		if (ret <= 0)
> +			break;
> +
> +		len = info->tfe.len;
> +		info->path = xmalloc(len + 1);
> +		if (!info->path) {
> +			ret = -1;
> +			break;
> +		}
> +
> +		ret = read_img_buf(fd, info->path, len);
> +		if (ret < 0)
> +			break;
> +
> +		info->path[len] = '\0';
> +		info->create = true;
> +		info->major = major(info->tfe.rdev);
> +		info->minor = minor(info->tfe.rdev);
> +
> +		pr_info("Collected tty [%s] ID %#x\n", info->path, info->tfe.id);
> +
> +		/* Partial ordering is needed for search speedup */
> +		switch (info->major) {
> +		case TTYAUX_MAJOR:
> +			list_add(&info->list, &all_ttys);
> +			break;
> +		case UNIX98_PTY_SLAVE_MAJOR:
> +			list_add_tail(&info->list, &all_ttys);
> +			break;
> +		default:
> +			pr_err("Unsupported tty type %s (major %d)\n",
> +			       info->path, info->major);
> +			ret = -1;
> +			goto out;
> +		}
> +	}
> +
> +	ret = tty_handle_priv(&all_ttys);
> +
> +	if (!ret) {
> +		list_for_each_entry(info, &all_ttys, list)
> +			file_desc_add(&info->d, info->tfe.id, &tty_desc_ops);
> +		info = NULL;
> +	}
> +
> +out:
> +	if (info)
> +		xfree(info->path);
> +	xfree(info);
> +	close(fd);
> +	return ret;
> +}
> +
> +static int dump_one_tty(int lfd, u32 id, const struct fd_parms *p)
> +{
> +	struct tty_file_entry e = { };
> +	struct termio t;
> +	char *path;
> +	int fd, len;
> +
> +	pr_info("Dumping tty %d with id %#x\n", lfd, id);
> +
> +	path = read_proc_selffd_link(lfd, &len);
> +	if (!path)
> +		return -1;
> +
> +	if (ioctl(lfd, TCGETS, &t) < 0) {
> +		pr_perror("Can't get tty params on %d [%s]", p->fd, path);
> +		return -1;
> +	}
> +
> +	from_termio(&e.term2, &t);
> +
> +	e.id	= id;
> +	e.flags	= p->flags;
> +	e.len	= len;
> +	e.pos	= p->pos;
> +	e.fown	= p->fown;
> +	e.rdev	= p->stat.st_rdev;
> +
> +	/*
> +	 * This ioctl is implemented for unix98 ptys,
> +	 * so simply ignore error code if not implemented.
> +	 */
> +	if (ioctl(lfd, TIOCGPTN, &e.index))
> +		e.index = 0;
> +
> +	fd = fdset_fd(glob_fdset, CR_FD_TTY);
> +	if (write_img(fd, &e))
> +		return -1;
> +
> +	pr_info("Dumping path for tty %d fd via self %d [%s]\n", p->fd, lfd, path);
> +	if (write_img_buf(fd, path, e.len))
> +		return -1;
> +
> +	return 0;
> +}
> +
> +static const struct fdtype_ops tty_ops = {
> +	.type		= FDINFO_TTY,
> +	.make_gen_id	= make_gen_id,
> +	.dump		= dump_one_tty,
> +};
> +
> +int dump_tty(struct fd_parms *p, int lfd, const struct cr_fdset *set)
> +{
> +	return do_dump_gen_file(p, lfd, &tty_ops, set);
> +}
> -- 
> 1.7.7.6
> 


More information about the CRIU mailing list