2012-09-12 20:00:54 +04:00
|
|
|
#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"
|
2013-01-09 17:02:47 +04:00
|
|
|
#include "asm/types.h"
|
2012-09-12 20:00:54 +04:00
|
|
|
|
|
|
|
#include "syscall.h"
|
|
|
|
#include "files.h"
|
2013-11-06 17:21:11 +04:00
|
|
|
#include "cr_options.h"
|
2014-09-29 12:47:37 +04:00
|
|
|
#include "imgset.h"
|
2013-11-05 20:17:47 +04:00
|
|
|
#include "servicefd.h"
|
2012-09-12 20:00:54 +04:00
|
|
|
#include "image.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "log.h"
|
|
|
|
#include "list.h"
|
2013-07-29 12:43:30 +04:00
|
|
|
#include "util-pie.h"
|
2012-09-12 20:00:54 +04:00
|
|
|
#include "proc_parse.h"
|
|
|
|
#include "file-ids.h"
|
tty: Use regular files engine to save paths to the peers, v5
Currently we're using predefined format for master/slave pty peers:
masters are always /dev/ptmx, while slaves are /dev/pts/$index,
where $index is the peer number.
While fitting most of distros this is not always correct and slave peers
might be mounted to an arbitrary place, so that we need to somehow
carry paths with ourself in image.
Instead of bloating current tty image lets use regular file engine instead
and on checkpoint stage save a path to the link in regfiles set, then on
restore simply fetch it from the image.
Such approach will help in future when we need to support multiple
instances of devpts filesystem.
To support backward compatibility with images where no regfile
records are present we generate new one on the fly in
pty_alloc_reg() helper.
Because of the need to restore dead slave peers and restore of
the controlling terminal we need to generate that named "fake
inverted" pty_alloc_fake_reg() helper: in particular if
we need to open dead slave peer we generate fake master peer,
open it and the close out. Almost the same situation in
restoring contolling terminal -- we get master peer, generate
appropriate fake slave object, open it, manipulate, then
close it out and free.
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Acked-by: Tycho Andersen <tycho.andersen@canonical.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-10-17 16:52:00 +04:00
|
|
|
#include "files-reg.h"
|
2012-09-12 20:00:54 +04:00
|
|
|
|
|
|
|
#include "protobuf.h"
|
|
|
|
#include "protobuf/tty.pb-c.h"
|
2012-10-15 23:42:54 +04:00
|
|
|
|
|
|
|
#include "parasite-syscall.h"
|
|
|
|
#include "parasite.h"
|
2012-09-12 20:00:54 +04:00
|
|
|
|
|
|
|
#include "pstree.h"
|
|
|
|
#include "tty.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Here are some notes about overall TTY c/r design. At moment
|
2014-10-06 17:15:43 +04:00
|
|
|
* we support unix98 ptys only. Supporting legacy BSD terminals
|
|
|
|
* is impossible without help from the kernel side -- the indices
|
|
|
|
* of such terminals are not reported anywhere in the kernel so that
|
|
|
|
* we can't figure out active pairs.
|
2012-09-12 20:00:54 +04:00
|
|
|
*
|
|
|
|
* Usually the PTYs represent a pair of links -- master peer and slave
|
|
|
|
* peer. Master peer must be opened before slave. Internally, when kernel
|
|
|
|
* creates master peer it also generates a slave interface in a form of
|
|
|
|
* /dev/pts/N, where N is that named pty "index". Master/slave connection
|
|
|
|
* unambiguously identified by this index.
|
|
|
|
*
|
|
|
|
* Still, one master can carry multiple slaves -- for example a user opens
|
|
|
|
* one master via /dev/ptmx and appropriate /dev/pts/N in sequence.
|
|
|
|
* The result will be the following
|
|
|
|
*
|
|
|
|
* master
|
|
|
|
* `- slave 1
|
|
|
|
* `- slave 2
|
|
|
|
*
|
|
|
|
* both slave will have same master index but different file descriptors.
|
|
|
|
* Still inside the kernel pty parameters are same for both slaves. Thus
|
|
|
|
* only one slave parameters should be restored, there is no need to carry
|
|
|
|
* all parameters for every slave peer we've found.
|
|
|
|
*
|
2014-10-06 17:15:43 +04:00
|
|
|
* Note the /dev/pts/ is rather convenient agreement and internally the
|
|
|
|
* kernel doesn't care where exactly the inodes of ptys are laying --
|
|
|
|
* it depends on "devpts" mount point path.
|
2012-09-12 20:00:54 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
#undef LOG_PREFIX
|
|
|
|
#define LOG_PREFIX "tty: "
|
|
|
|
|
|
|
|
struct tty_info_entry {
|
|
|
|
struct list_head list;
|
|
|
|
TtyInfoEntry *tie;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct tty_info {
|
|
|
|
struct list_head list;
|
|
|
|
struct file_desc d;
|
|
|
|
|
tty: Use regular files engine to save paths to the peers, v5
Currently we're using predefined format for master/slave pty peers:
masters are always /dev/ptmx, while slaves are /dev/pts/$index,
where $index is the peer number.
While fitting most of distros this is not always correct and slave peers
might be mounted to an arbitrary place, so that we need to somehow
carry paths with ourself in image.
Instead of bloating current tty image lets use regular file engine instead
and on checkpoint stage save a path to the link in regfiles set, then on
restore simply fetch it from the image.
Such approach will help in future when we need to support multiple
instances of devpts filesystem.
To support backward compatibility with images where no regfile
records are present we generate new one on the fly in
pty_alloc_reg() helper.
Because of the need to restore dead slave peers and restore of
the controlling terminal we need to generate that named "fake
inverted" pty_alloc_fake_reg() helper: in particular if
we need to open dead slave peer we generate fake master peer,
open it and the close out. Almost the same situation in
restoring contolling terminal -- we get master peer, generate
appropriate fake slave object, open it, manipulate, then
close it out and free.
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Acked-by: Tycho Andersen <tycho.andersen@canonical.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-10-17 16:52:00 +04:00
|
|
|
struct file_desc *reg_d;
|
|
|
|
|
2012-09-12 20:00:54 +04:00
|
|
|
TtyFileEntry *tfe;
|
|
|
|
TtyInfoEntry *tie;
|
|
|
|
|
|
|
|
struct list_head sibling;
|
2014-10-16 14:27:20 +04:00
|
|
|
int type;
|
2012-09-14 17:50:46 +04:00
|
|
|
|
|
|
|
bool create;
|
2013-05-06 19:12:32 +04:00
|
|
|
bool inherit;
|
2012-09-12 20:00:54 +04:00
|
|
|
};
|
|
|
|
|
2012-10-29 13:37:34 +04:00
|
|
|
struct tty_dump_info {
|
|
|
|
struct list_head list;
|
|
|
|
|
|
|
|
u32 id;
|
|
|
|
pid_t sid;
|
|
|
|
pid_t pgrp;
|
|
|
|
int fd;
|
2014-10-16 14:27:20 +04:00
|
|
|
int type;
|
2012-10-29 13:37:34 +04:00
|
|
|
};
|
|
|
|
|
2012-09-12 20:00:54 +04:00
|
|
|
static LIST_HEAD(all_tty_info_entries);
|
|
|
|
static LIST_HEAD(all_ttys);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Usually an application has not that many ttys opened.
|
|
|
|
* If this won't be enough in future we simply need to
|
|
|
|
* change tracking mechanism to some more extendable.
|
|
|
|
*
|
|
|
|
* This particular bitmap requires 256 bytes of memory.
|
|
|
|
* Pretty acceptable trade off in a sake of simplicity.
|
|
|
|
*/
|
2014-10-16 14:20:34 +04:00
|
|
|
|
|
|
|
#define MAX_TTYS 1024
|
|
|
|
#define MAX_PTY_INDEX 1000
|
|
|
|
#define CONSOLE_INDEX 1002
|
2014-12-17 01:21:39 +02:00
|
|
|
#define VT_INDEX 1004
|
2014-10-16 14:20:34 +04:00
|
|
|
|
2012-09-12 20:00:54 +04:00
|
|
|
static DECLARE_BITMAP(tty_bitmap, (MAX_TTYS << 1));
|
2012-09-20 13:35:38 +04:00
|
|
|
static DECLARE_BITMAP(tty_active_pairs, (MAX_TTYS << 1));
|
2012-09-12 20:00:54 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* /dev/ptmx is a shared resource between all tasks
|
|
|
|
* so we need to serialize access to it.
|
|
|
|
*/
|
|
|
|
static mutex_t *tty_mutex;
|
|
|
|
|
tty: Use regular files engine to save paths to the peers, v5
Currently we're using predefined format for master/slave pty peers:
masters are always /dev/ptmx, while slaves are /dev/pts/$index,
where $index is the peer number.
While fitting most of distros this is not always correct and slave peers
might be mounted to an arbitrary place, so that we need to somehow
carry paths with ourself in image.
Instead of bloating current tty image lets use regular file engine instead
and on checkpoint stage save a path to the link in regfiles set, then on
restore simply fetch it from the image.
Such approach will help in future when we need to support multiple
instances of devpts filesystem.
To support backward compatibility with images where no regfile
records are present we generate new one on the fly in
pty_alloc_reg() helper.
Because of the need to restore dead slave peers and restore of
the controlling terminal we need to generate that named "fake
inverted" pty_alloc_fake_reg() helper: in particular if
we need to open dead slave peer we generate fake master peer,
open it and the close out. Almost the same situation in
restoring contolling terminal -- we get master peer, generate
appropriate fake slave object, open it, manipulate, then
close it out and free.
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Acked-by: Tycho Andersen <tycho.andersen@canonical.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-10-17 16:52:00 +04:00
|
|
|
static bool tty_is_master(struct tty_info *info);
|
|
|
|
|
2012-09-14 17:58:46 +04:00
|
|
|
int prepare_shared_tty(void)
|
2012-09-12 20:00:54 +04:00
|
|
|
{
|
|
|
|
tty_mutex = shmalloc(sizeof(*tty_mutex));
|
|
|
|
if (!tty_mutex) {
|
|
|
|
pr_err("Can't create ptmx index mutex\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_init(tty_mutex);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define winsize_copy(d, s) \
|
|
|
|
do { \
|
|
|
|
ASSIGN_MEMBER((d), (s), ws_row); \
|
|
|
|
ASSIGN_MEMBER((d), (s), ws_col); \
|
|
|
|
ASSIGN_MEMBER((d), (s), ws_xpixel); \
|
|
|
|
ASSIGN_MEMBER((d), (s), ws_ypixel); \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#define termios_copy(d, s) \
|
|
|
|
do { \
|
2012-10-01 21:10:55 +04:00
|
|
|
struct termios __t; \
|
|
|
|
\
|
2012-09-12 20:00:54 +04:00
|
|
|
memcpy((d)->c_cc, (s)->c_cc, \
|
2012-10-01 21:10:55 +04:00
|
|
|
sizeof(__t.c_cc)); \
|
2012-09-12 20:00:54 +04:00
|
|
|
\
|
|
|
|
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); \
|
|
|
|
} while (0)
|
|
|
|
|
2014-10-16 14:27:20 +04:00
|
|
|
static int tty_gen_id(int type, int index)
|
2012-09-12 20:00:54 +04:00
|
|
|
{
|
2014-10-16 14:27:20 +04:00
|
|
|
return (index << 1) + (type == TTY_TYPE_PTM);
|
2012-09-12 20:00:54 +04:00
|
|
|
}
|
|
|
|
|
2012-09-20 13:35:39 +04:00
|
|
|
static int tty_get_index(u32 id)
|
|
|
|
{
|
|
|
|
return id >> 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make sure the active pairs do exist */
|
|
|
|
int tty_verify_active_pairs(void)
|
|
|
|
{
|
2012-11-26 18:38:28 +04:00
|
|
|
unsigned long i, unpaired_slaves = 0;
|
|
|
|
|
|
|
|
for_each_bit(i, tty_active_pairs) {
|
2012-12-11 20:58:11 +04:00
|
|
|
if ((i % 2) == 0) {
|
2012-11-26 18:38:28 +04:00
|
|
|
if (test_bit(i + 1, tty_active_pairs)) {
|
|
|
|
i++;
|
|
|
|
continue;
|
|
|
|
}
|
2012-09-20 13:35:39 +04:00
|
|
|
|
2012-10-18 15:52:00 +04:00
|
|
|
if (!opts.shell_job) {
|
|
|
|
pr_err("Found slave peer index %d without "
|
|
|
|
"correspond master peer\n",
|
|
|
|
tty_get_index(i));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-10-22 15:48:42 +04:00
|
|
|
pr_debug("Unpaired slave %d\n", tty_get_index(i));
|
|
|
|
|
2012-10-18 15:52:00 +04:00
|
|
|
if (++unpaired_slaves > 1) {
|
|
|
|
pr_err("Only one slave external peer "
|
2012-10-22 15:48:42 +04:00
|
|
|
"is allowed (index %d)\n",
|
|
|
|
tty_get_index(i));
|
2012-10-18 15:52:00 +04:00
|
|
|
return -1;
|
|
|
|
}
|
2012-09-20 13:35:39 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-10-16 14:20:34 +04:00
|
|
|
static int parse_tty_index(u32 id, int lfd, const struct fd_parms *p, int type)
|
2012-09-12 20:00:54 +04:00
|
|
|
{
|
|
|
|
int index = -1;
|
|
|
|
|
2014-10-16 14:27:20 +04:00
|
|
|
switch (type) {
|
|
|
|
case TTY_TYPE_PTM:
|
2012-09-12 20:00:54 +04:00
|
|
|
if (ioctl(lfd, TIOCGPTN, &index)) {
|
2013-05-02 22:44:24 +04:00
|
|
|
pr_perror("Can't obtain ptmx index");
|
2012-09-12 20:00:54 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2014-10-16 14:27:20 +04:00
|
|
|
case TTY_TYPE_PTS: {
|
2014-10-16 14:27:22 +04:00
|
|
|
const struct fd_link *link = p->link;
|
|
|
|
char *pos = strrchr(link->name, '/');
|
2012-09-12 20:00:54 +04:00
|
|
|
|
2014-10-16 14:27:22 +04:00
|
|
|
if (!pos || pos == (link->name + link->len - 1)) {
|
|
|
|
pr_err("Unexpected format on path %s\n", link->name + 1);
|
2012-09-12 20:00:54 +04:00
|
|
|
return -1;
|
|
|
|
}
|
2014-10-16 14:27:22 +04:00
|
|
|
index = atoi(pos + 1);
|
2012-09-12 20:00:54 +04:00
|
|
|
break;
|
|
|
|
}
|
2014-10-16 14:20:34 +04:00
|
|
|
|
|
|
|
case TTY_TYPE_CONSOLE:
|
|
|
|
index = CONSOLE_INDEX;
|
|
|
|
break;
|
2014-12-17 01:21:39 +02:00
|
|
|
|
|
|
|
case TTY_TYPE_VT:
|
|
|
|
index = VT_INDEX;
|
|
|
|
break;
|
2014-10-16 14:20:34 +04:00
|
|
|
default:
|
|
|
|
BUG();
|
2012-09-12 20:00:54 +04:00
|
|
|
}
|
|
|
|
|
2014-10-16 14:20:34 +04:00
|
|
|
if (type != TTY_TYPE_CONSOLE &&
|
2014-12-17 01:21:39 +02:00
|
|
|
type != TTY_TYPE_VT &&
|
2014-10-16 14:20:34 +04:00
|
|
|
index > MAX_PTY_INDEX) {
|
2012-09-12 20:00:54 +04:00
|
|
|
pr_err("Index %d on tty %x is too big\n", index, id);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
2012-09-20 13:35:37 +04:00
|
|
|
static int tty_test_and_set(int bit, unsigned long *bitmap)
|
2012-09-12 20:00:54 +04:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2012-09-20 13:35:37 +04:00
|
|
|
ret = test_bit(bit, bitmap);
|
2012-09-12 20:00:54 +04:00
|
|
|
if (!ret)
|
2012-09-20 13:35:37 +04:00
|
|
|
set_bit(bit, bitmap);
|
2012-09-12 20:00:54 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
tty: Use regular files engine to save paths to the peers, v5
Currently we're using predefined format for master/slave pty peers:
masters are always /dev/ptmx, while slaves are /dev/pts/$index,
where $index is the peer number.
While fitting most of distros this is not always correct and slave peers
might be mounted to an arbitrary place, so that we need to somehow
carry paths with ourself in image.
Instead of bloating current tty image lets use regular file engine instead
and on checkpoint stage save a path to the link in regfiles set, then on
restore simply fetch it from the image.
Such approach will help in future when we need to support multiple
instances of devpts filesystem.
To support backward compatibility with images where no regfile
records are present we generate new one on the fly in
pty_alloc_reg() helper.
Because of the need to restore dead slave peers and restore of
the controlling terminal we need to generate that named "fake
inverted" pty_alloc_fake_reg() helper: in particular if
we need to open dead slave peer we generate fake master peer,
open it and the close out. Almost the same situation in
restoring contolling terminal -- we get master peer, generate
appropriate fake slave object, open it, manipulate, then
close it out and free.
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Acked-by: Tycho Andersen <tycho.andersen@canonical.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-10-17 16:52:00 +04:00
|
|
|
/*
|
|
|
|
* Generate a regular file object in case if such is missed
|
|
|
|
* in the image file, ie obsolete interface has been used on
|
|
|
|
* checkpoint.
|
|
|
|
*/
|
|
|
|
static struct file_desc *pty_alloc_reg(struct tty_info *info, bool add)
|
|
|
|
{
|
|
|
|
TtyFileEntry *tfe = info->tfe;
|
|
|
|
const size_t namelen = 64;
|
|
|
|
struct reg_file_info *r;
|
|
|
|
|
|
|
|
r = xzalloc(sizeof(*r) + sizeof(*r->rfe) + namelen);
|
|
|
|
if (!r)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
r->rfe = (void *)r + sizeof(*r);
|
|
|
|
reg_file_entry__init(r->rfe);
|
|
|
|
|
|
|
|
r->rfe->name = (void *)r + sizeof(*r) + sizeof(*r->rfe);
|
|
|
|
if (tty_is_master(info))
|
|
|
|
strcpy(r->rfe->name, "/dev/ptmx");
|
|
|
|
else
|
|
|
|
snprintf(r->rfe->name, namelen, "/dev/pts/%u",
|
|
|
|
info->tie->pty->index);
|
|
|
|
|
|
|
|
if (add)
|
|
|
|
file_desc_add(&r->d, tfe->id, NULL);
|
|
|
|
else
|
|
|
|
file_desc_init(&r->d, tfe->id, NULL);
|
|
|
|
|
|
|
|
r->rfe->id = tfe->id;
|
|
|
|
r->rfe->flags = tfe->flags;
|
|
|
|
r->rfe->fown = tfe->fown;
|
|
|
|
r->path = &r->rfe->name[1];
|
|
|
|
|
|
|
|
return &r->d;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* In case if we need to open a fake pty (for example
|
|
|
|
* a master peer which were deleted at checkpoint moment,
|
|
|
|
* or open a slave peer when restoring control terminal)
|
|
|
|
* we need to create a new reg-file object taking @info
|
|
|
|
* as a template. Here is a trick though: the @info might
|
|
|
|
* represent master peer while we need to allocate a slave
|
|
|
|
* one and the reverse. For such case taking path from the
|
|
|
|
* @info as a template we generate that named 'inverted-path'.
|
|
|
|
*
|
|
|
|
* For example if the master peer was /dev/pts/ptmx with index 1,
|
|
|
|
* the inverted path is /dev/pts/1, for inverted slaves it's simplier
|
|
|
|
* we just add 'ptmx' postfix.
|
|
|
|
*/
|
|
|
|
static struct reg_file_info *pty_alloc_fake_reg(struct tty_info *info, int type)
|
|
|
|
{
|
|
|
|
struct reg_file_info *new, *orig;
|
|
|
|
struct file_desc *fake_desc;
|
|
|
|
|
|
|
|
pr_debug("Allocating fake descriptor for %#x (reg_d %p)\n",
|
|
|
|
info->tfe->id, info->reg_d);
|
|
|
|
|
|
|
|
BUG_ON(!info->reg_d);
|
2014-10-16 14:20:34 +04:00
|
|
|
BUG_ON(!is_pty(info->type));
|
tty: Use regular files engine to save paths to the peers, v5
Currently we're using predefined format for master/slave pty peers:
masters are always /dev/ptmx, while slaves are /dev/pts/$index,
where $index is the peer number.
While fitting most of distros this is not always correct and slave peers
might be mounted to an arbitrary place, so that we need to somehow
carry paths with ourself in image.
Instead of bloating current tty image lets use regular file engine instead
and on checkpoint stage save a path to the link in regfiles set, then on
restore simply fetch it from the image.
Such approach will help in future when we need to support multiple
instances of devpts filesystem.
To support backward compatibility with images where no regfile
records are present we generate new one on the fly in
pty_alloc_reg() helper.
Because of the need to restore dead slave peers and restore of
the controlling terminal we need to generate that named "fake
inverted" pty_alloc_fake_reg() helper: in particular if
we need to open dead slave peer we generate fake master peer,
open it and the close out. Almost the same situation in
restoring contolling terminal -- we get master peer, generate
appropriate fake slave object, open it, manipulate, then
close it out and free.
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Acked-by: Tycho Andersen <tycho.andersen@canonical.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-10-17 16:52:00 +04:00
|
|
|
|
|
|
|
fake_desc = pty_alloc_reg(info, false);
|
|
|
|
if (!fake_desc)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
orig = container_of(info->reg_d, struct reg_file_info, d);
|
|
|
|
new = container_of(fake_desc, struct reg_file_info, d);
|
|
|
|
|
|
|
|
if ((type == TTY_TYPE_PTM && tty_is_master(info)) ||
|
|
|
|
(type == TTY_TYPE_PTS && !tty_is_master(info))) {
|
|
|
|
new->path = xstrdup(orig->path);
|
|
|
|
new->rfe->name = &new->path[1];
|
|
|
|
} else {
|
|
|
|
char *pos = strrchr(orig->rfe->name, '/');
|
|
|
|
size_t len = strlen(orig->rfe->name) + 1;
|
|
|
|
size_t slash_at = pos - orig->rfe->name;
|
|
|
|
char *inverted_path = xmalloc(len + 32);
|
|
|
|
|
|
|
|
BUG_ON(!pos || !inverted_path);
|
|
|
|
|
|
|
|
memcpy(inverted_path, orig->rfe->name, slash_at + 1);
|
|
|
|
if (type == TTY_TYPE_PTM)
|
|
|
|
strcat(inverted_path, "ptmx");
|
|
|
|
else {
|
2014-10-23 21:42:29 +04:00
|
|
|
if (slash_at >= 3 && strncmp(&inverted_path[slash_at - 3], "pts", 3))
|
tty: Use regular files engine to save paths to the peers, v5
Currently we're using predefined format for master/slave pty peers:
masters are always /dev/ptmx, while slaves are /dev/pts/$index,
where $index is the peer number.
While fitting most of distros this is not always correct and slave peers
might be mounted to an arbitrary place, so that we need to somehow
carry paths with ourself in image.
Instead of bloating current tty image lets use regular file engine instead
and on checkpoint stage save a path to the link in regfiles set, then on
restore simply fetch it from the image.
Such approach will help in future when we need to support multiple
instances of devpts filesystem.
To support backward compatibility with images where no regfile
records are present we generate new one on the fly in
pty_alloc_reg() helper.
Because of the need to restore dead slave peers and restore of
the controlling terminal we need to generate that named "fake
inverted" pty_alloc_fake_reg() helper: in particular if
we need to open dead slave peer we generate fake master peer,
open it and the close out. Almost the same situation in
restoring contolling terminal -- we get master peer, generate
appropriate fake slave object, open it, manipulate, then
close it out and free.
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Acked-by: Tycho Andersen <tycho.andersen@canonical.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-10-17 16:52:00 +04:00
|
|
|
snprintf(&inverted_path[slash_at + 1], 10, "pts/%u",
|
|
|
|
info->tie->pty->index);
|
|
|
|
else
|
|
|
|
snprintf(&inverted_path[slash_at + 1], 10, "%u",
|
|
|
|
info->tie->pty->index);
|
|
|
|
}
|
|
|
|
|
|
|
|
new->rfe->name = inverted_path;
|
|
|
|
new->path = &inverted_path[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
return new;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define pty_alloc_fake_master(info) pty_alloc_fake_reg(info, TTY_TYPE_PTM)
|
|
|
|
#define pty_alloc_fake_slave(info) pty_alloc_fake_reg(info, TTY_TYPE_PTS)
|
|
|
|
|
|
|
|
static void pty_free_fake_reg(struct reg_file_info **r)
|
|
|
|
{
|
|
|
|
if (*r) {
|
|
|
|
xfree((*r)->rfe->name);
|
|
|
|
xfree((*r));
|
|
|
|
*r = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int open_pty_reg(struct file_desc *reg_d, u32 flags)
|
|
|
|
{
|
|
|
|
return open_path(reg_d, do_open_reg_noseek_flags, &flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *path_from_reg(struct file_desc *d)
|
|
|
|
{
|
|
|
|
struct reg_file_info *rfi = container_of(d, struct reg_file_info, d);
|
|
|
|
return rfi->path;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int pty_open_ptmx_index(struct file_desc *d, int index, int flags)
|
2012-09-12 20:00:54 +04:00
|
|
|
{
|
|
|
|
int fds[32], i, ret = -1, cur_idx;
|
|
|
|
|
|
|
|
memset(fds, 0xff, sizeof(fds));
|
|
|
|
|
|
|
|
mutex_lock(tty_mutex);
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(fds); i++) {
|
tty: Use regular files engine to save paths to the peers, v5
Currently we're using predefined format for master/slave pty peers:
masters are always /dev/ptmx, while slaves are /dev/pts/$index,
where $index is the peer number.
While fitting most of distros this is not always correct and slave peers
might be mounted to an arbitrary place, so that we need to somehow
carry paths with ourself in image.
Instead of bloating current tty image lets use regular file engine instead
and on checkpoint stage save a path to the link in regfiles set, then on
restore simply fetch it from the image.
Such approach will help in future when we need to support multiple
instances of devpts filesystem.
To support backward compatibility with images where no regfile
records are present we generate new one on the fly in
pty_alloc_reg() helper.
Because of the need to restore dead slave peers and restore of
the controlling terminal we need to generate that named "fake
inverted" pty_alloc_fake_reg() helper: in particular if
we need to open dead slave peer we generate fake master peer,
open it and the close out. Almost the same situation in
restoring contolling terminal -- we get master peer, generate
appropriate fake slave object, open it, manipulate, then
close it out and free.
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Acked-by: Tycho Andersen <tycho.andersen@canonical.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-10-17 16:52:00 +04:00
|
|
|
fds[i] = open_pty_reg(d, flags);
|
2012-09-12 20:00:54 +04:00
|
|
|
if (fds[i] < 0) {
|
tty: Use regular files engine to save paths to the peers, v5
Currently we're using predefined format for master/slave pty peers:
masters are always /dev/ptmx, while slaves are /dev/pts/$index,
where $index is the peer number.
While fitting most of distros this is not always correct and slave peers
might be mounted to an arbitrary place, so that we need to somehow
carry paths with ourself in image.
Instead of bloating current tty image lets use regular file engine instead
and on checkpoint stage save a path to the link in regfiles set, then on
restore simply fetch it from the image.
Such approach will help in future when we need to support multiple
instances of devpts filesystem.
To support backward compatibility with images where no regfile
records are present we generate new one on the fly in
pty_alloc_reg() helper.
Because of the need to restore dead slave peers and restore of
the controlling terminal we need to generate that named "fake
inverted" pty_alloc_fake_reg() helper: in particular if
we need to open dead slave peer we generate fake master peer,
open it and the close out. Almost the same situation in
restoring contolling terminal -- we get master peer, generate
appropriate fake slave object, open it, manipulate, then
close it out and free.
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Acked-by: Tycho Andersen <tycho.andersen@canonical.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-10-17 16:52:00 +04:00
|
|
|
pr_perror("Can't open %s", path_from_reg(d));
|
2012-09-12 20:00:54 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ioctl(fds[i], TIOCGPTN, &cur_idx)) {
|
tty: Use regular files engine to save paths to the peers, v5
Currently we're using predefined format for master/slave pty peers:
masters are always /dev/ptmx, while slaves are /dev/pts/$index,
where $index is the peer number.
While fitting most of distros this is not always correct and slave peers
might be mounted to an arbitrary place, so that we need to somehow
carry paths with ourself in image.
Instead of bloating current tty image lets use regular file engine instead
and on checkpoint stage save a path to the link in regfiles set, then on
restore simply fetch it from the image.
Such approach will help in future when we need to support multiple
instances of devpts filesystem.
To support backward compatibility with images where no regfile
records are present we generate new one on the fly in
pty_alloc_reg() helper.
Because of the need to restore dead slave peers and restore of
the controlling terminal we need to generate that named "fake
inverted" pty_alloc_fake_reg() helper: in particular if
we need to open dead slave peer we generate fake master peer,
open it and the close out. Almost the same situation in
restoring contolling terminal -- we get master peer, generate
appropriate fake slave object, open it, manipulate, then
close it out and free.
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Acked-by: Tycho Andersen <tycho.andersen@canonical.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-10-17 16:52:00 +04:00
|
|
|
pr_perror("Can't obtain current index on %s",
|
|
|
|
path_from_reg(d));
|
2012-09-12 20:00:54 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_debug("\t\tptmx opened with index %d\n", cur_idx);
|
|
|
|
|
|
|
|
if (cur_idx == index) {
|
|
|
|
pr_info("ptmx opened with index %d\n", cur_idx);
|
|
|
|
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;
|
|
|
|
|
tty: Use regular files engine to save paths to the peers, v5
Currently we're using predefined format for master/slave pty peers:
masters are always /dev/ptmx, while slaves are /dev/pts/$index,
where $index is the peer number.
While fitting most of distros this is not always correct and slave peers
might be mounted to an arbitrary place, so that we need to somehow
carry paths with ourself in image.
Instead of bloating current tty image lets use regular file engine instead
and on checkpoint stage save a path to the link in regfiles set, then on
restore simply fetch it from the image.
Such approach will help in future when we need to support multiple
instances of devpts filesystem.
To support backward compatibility with images where no regfile
records are present we generate new one on the fly in
pty_alloc_reg() helper.
Because of the need to restore dead slave peers and restore of
the controlling terminal we need to generate that named "fake
inverted" pty_alloc_fake_reg() helper: in particular if
we need to open dead slave peer we generate fake master peer,
open it and the close out. Almost the same situation in
restoring contolling terminal -- we get master peer, generate
appropriate fake slave object, open it, manipulate, then
close it out and free.
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Acked-by: Tycho Andersen <tycho.andersen@canonical.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-10-17 16:52:00 +04:00
|
|
|
pr_err("Unable to open %s with specified index %d\n",
|
|
|
|
path_from_reg(d), index);
|
2012-09-12 20:00:54 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(fds); i++) {
|
|
|
|
if (fds[i] >= 0)
|
|
|
|
close(fds[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_unlock(tty_mutex);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int unlock_pty(int fd)
|
|
|
|
{
|
|
|
|
const int lock = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Usually when ptmx opened it gets locked
|
|
|
|
* by kernel and we need to unlock it to be
|
|
|
|
* able to connect slave peer.
|
|
|
|
*/
|
|
|
|
if (ioctl(fd, TIOCSPTLCK, &lock)) {
|
|
|
|
pr_err("Unable to unlock pty device via y%d\n", fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int lock_pty(int fd)
|
|
|
|
{
|
|
|
|
const int lock = 1;
|
|
|
|
|
|
|
|
if (ioctl(fd, TIOCSPTLCK, &lock)) {
|
|
|
|
pr_err("Unable to lock pty device via %d\n", fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-09-12 20:00:58 +04:00
|
|
|
static int tty_set_sid(int fd)
|
|
|
|
{
|
|
|
|
if (ioctl(fd, TIOCSCTTY, 1)) {
|
2013-05-02 22:44:24 +04:00
|
|
|
pr_perror("Can't set sid on terminal fd %d", fd);
|
2012-09-12 20:00:58 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int tty_set_prgp(int fd, int group)
|
|
|
|
{
|
|
|
|
if (ioctl(fd, TIOCSPGRP, &group)) {
|
2013-05-02 22:44:24 +04:00
|
|
|
pr_perror("Failed to set group %d on %d", group, fd);
|
2012-09-12 20:00:58 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int tty_restore_ctl_terminal(struct file_desc *d, int fd)
|
|
|
|
{
|
|
|
|
struct tty_info *info = container_of(d, struct tty_info, d);
|
2014-10-16 14:20:34 +04:00
|
|
|
struct reg_file_info *fake = NULL;
|
2014-10-30 17:05:00 +04:00
|
|
|
int slave = -1, ret = -1, index = -1;
|
2012-09-12 20:00:58 +04:00
|
|
|
|
2012-09-13 14:45:14 +04:00
|
|
|
if (!is_service_fd(fd, CTL_TTY_OFF))
|
2012-09-12 20:00:58 +04:00
|
|
|
return 0;
|
|
|
|
|
2014-10-16 14:20:34 +04:00
|
|
|
if (is_pty(info->type)) {
|
|
|
|
fake = pty_alloc_fake_slave(info);
|
|
|
|
if (!fake)
|
|
|
|
goto err;
|
|
|
|
slave = open_pty_reg(&fake->d, O_RDONLY);
|
2014-10-30 00:44:00 +04:00
|
|
|
index = info->tie->pty->index;
|
2014-10-16 14:20:34 +04:00
|
|
|
if (slave < 0) {
|
|
|
|
pr_perror("Can't open %s", path_from_reg(&fake->d));
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
} else if (info->type == TTY_TYPE_CONSOLE) {
|
|
|
|
slave = open_pty_reg(info->reg_d, O_RDONLY);
|
2014-10-30 17:05:00 +04:00
|
|
|
index = CONSOLE_INDEX;
|
2014-10-16 14:20:34 +04:00
|
|
|
if (slave < 0) {
|
|
|
|
pr_perror("Can't open %s", path_from_reg(info->reg_d));
|
|
|
|
goto err;
|
|
|
|
}
|
2014-12-17 01:21:39 +02:00
|
|
|
} else if (info->type == TTY_TYPE_VT) {
|
|
|
|
slave = open_pty_reg(info->reg_d, O_RDONLY);
|
|
|
|
index = VT_INDEX;
|
|
|
|
if (slave < 0) {
|
|
|
|
pr_perror("Can't open %s", path_from_reg(info->reg_d));
|
|
|
|
goto err;
|
|
|
|
}
|
2014-10-16 14:20:34 +04:00
|
|
|
} else
|
|
|
|
BUG();
|
2012-09-12 20:00:58 +04:00
|
|
|
|
|
|
|
pr_info("Restore session %d by %d tty (index %d)\n",
|
2014-10-30 00:44:00 +04:00
|
|
|
info->tie->sid, (int)getpid(), index);
|
2012-09-12 20:00:58 +04:00
|
|
|
|
|
|
|
ret = tty_set_sid(slave);
|
|
|
|
if (!ret)
|
|
|
|
ret = tty_set_prgp(slave, info->tie->pgrp);
|
|
|
|
|
|
|
|
close(slave);
|
tty: Use regular files engine to save paths to the peers, v5
Currently we're using predefined format for master/slave pty peers:
masters are always /dev/ptmx, while slaves are /dev/pts/$index,
where $index is the peer number.
While fitting most of distros this is not always correct and slave peers
might be mounted to an arbitrary place, so that we need to somehow
carry paths with ourself in image.
Instead of bloating current tty image lets use regular file engine instead
and on checkpoint stage save a path to the link in regfiles set, then on
restore simply fetch it from the image.
Such approach will help in future when we need to support multiple
instances of devpts filesystem.
To support backward compatibility with images where no regfile
records are present we generate new one on the fly in
pty_alloc_reg() helper.
Because of the need to restore dead slave peers and restore of
the controlling terminal we need to generate that named "fake
inverted" pty_alloc_fake_reg() helper: in particular if
we need to open dead slave peer we generate fake master peer,
open it and the close out. Almost the same situation in
restoring contolling terminal -- we get master peer, generate
appropriate fake slave object, open it, manipulate, then
close it out and free.
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Acked-by: Tycho Andersen <tycho.andersen@canonical.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-10-17 16:52:00 +04:00
|
|
|
err:
|
|
|
|
pty_free_fake_reg(&fake);
|
2012-09-12 20:00:58 +04:00
|
|
|
close(fd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-10-16 14:27:20 +04:00
|
|
|
static char *tty_name(int type)
|
2012-09-12 20:00:54 +04:00
|
|
|
{
|
2014-10-16 14:27:20 +04:00
|
|
|
switch (type) {
|
|
|
|
case TTY_TYPE_PTM:
|
|
|
|
return "ptmx";
|
|
|
|
case TTY_TYPE_PTS:
|
|
|
|
return "pts";
|
2014-10-16 14:20:34 +04:00
|
|
|
case TTY_TYPE_CONSOLE:
|
|
|
|
return "console";
|
2014-12-17 01:21:39 +02:00
|
|
|
case TTY_TYPE_VT:
|
|
|
|
return "tty";
|
2012-09-12 20:00:54 +04:00
|
|
|
}
|
2014-10-16 14:27:20 +04:00
|
|
|
return "unknown";
|
2012-09-12 20:00:54 +04:00
|
|
|
}
|
|
|
|
|
2014-10-06 17:15:44 +04:00
|
|
|
static bool tty_is_master(struct tty_info *info)
|
2012-09-12 20:00:54 +04:00
|
|
|
{
|
2014-12-17 01:21:39 +02:00
|
|
|
if (info->type == TTY_TYPE_PTM || info->type == TTY_TYPE_CONSOLE)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (info->type == TTY_TYPE_VT && !opts.shell_job)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
2012-09-12 20:00:54 +04:00
|
|
|
}
|
|
|
|
|
2014-10-06 17:15:44 +04:00
|
|
|
static bool tty_is_hung(struct tty_info *info)
|
2012-10-29 13:36:18 +04:00
|
|
|
{
|
2012-10-30 18:24:15 +04:00
|
|
|
return info->tie->termios == NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool tty_has_active_pair(struct tty_info *info)
|
|
|
|
{
|
2014-10-06 17:15:44 +04:00
|
|
|
int d = tty_is_master(info) ? -1 : + 1;
|
2012-10-30 18:24:15 +04:00
|
|
|
|
|
|
|
return test_bit(info->tfe->tty_info_id + d,
|
|
|
|
tty_active_pairs);
|
2012-10-29 13:36:18 +04:00
|
|
|
}
|
|
|
|
|
2012-09-12 20:00:54 +04:00
|
|
|
static void tty_show_pty_info(char *prefix, struct tty_info *info)
|
|
|
|
{
|
2014-12-17 01:21:39 +02:00
|
|
|
int index = -1;
|
|
|
|
|
|
|
|
switch (info->type) {
|
|
|
|
case TTY_TYPE_CONSOLE:
|
|
|
|
index = CONSOLE_INDEX;
|
|
|
|
break;
|
|
|
|
case TTY_TYPE_VT:
|
|
|
|
index = VT_INDEX;
|
|
|
|
break;
|
|
|
|
case TTY_TYPE_PTM:
|
|
|
|
case TTY_TYPE_PTS:
|
|
|
|
index = info->tie->pty->index;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-05-06 19:12:32 +04:00
|
|
|
pr_info("%s type %s id %#x index %d (master %d sid %d pgrp %d inherit %d)\n",
|
2014-12-17 01:21:39 +02:00
|
|
|
prefix, tty_name(info->type), info->tfe->id, index,
|
2014-10-06 17:15:44 +04:00
|
|
|
tty_is_master(info), info->tie->sid, info->tie->pgrp, info->inherit);
|
2012-09-12 20:00:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int restore_tty_params(int fd, struct tty_info *info)
|
|
|
|
{
|
|
|
|
struct winsize w;
|
|
|
|
struct termios t;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* It's important to zeroify termios
|
|
|
|
* because it contain @c_cc array which
|
|
|
|
* is bigger than TERMIOS_NCC. Same applies
|
|
|
|
* to winsize usage, we can't guarantee the
|
2013-04-12 13:00:06 -07:00
|
|
|
* structure taken from the system headers will
|
2012-09-12 20:00:54 +04:00
|
|
|
* never be extended.
|
|
|
|
*/
|
|
|
|
|
2012-09-14 17:50:41 +04:00
|
|
|
if (info->tie->termios_locked) {
|
|
|
|
memzero(&t, sizeof(t));
|
|
|
|
termios_copy(&t, info->tie->termios_locked);
|
|
|
|
if (ioctl(fd, TIOCSLCKTRMIOS, &t) < 0)
|
|
|
|
goto err;
|
|
|
|
}
|
2012-09-12 20:00:54 +04:00
|
|
|
|
2012-09-14 17:50:41 +04:00
|
|
|
if (info->tie->termios) {
|
|
|
|
memzero(&t, sizeof(t));
|
|
|
|
termios_copy(&t, info->tie->termios);
|
|
|
|
if (ioctl(fd, TCSETS, &t) < 0)
|
|
|
|
goto err;
|
|
|
|
}
|
2012-09-12 20:00:54 +04:00
|
|
|
|
2012-09-14 17:50:41 +04:00
|
|
|
if (info->tie->winsize) {
|
|
|
|
memzero(&w, sizeof(w));
|
|
|
|
winsize_copy(&w, info->tie->winsize);
|
|
|
|
if (ioctl(fd, TIOCSWINSZ, &w) < 0)
|
|
|
|
goto err;
|
|
|
|
}
|
2012-09-12 20:00:54 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
err:
|
|
|
|
pr_perror("Can't set tty params on %d", info->tfe->id);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int pty_open_slaves(struct tty_info *info)
|
|
|
|
{
|
|
|
|
int sock = -1, fd = -1, ret = -1;
|
|
|
|
struct fdinfo_list_entry *fle;
|
|
|
|
struct tty_info *slave;
|
|
|
|
|
|
|
|
sock = socket(PF_UNIX, SOCK_DGRAM, 0);
|
|
|
|
if (sock < 0) {
|
|
|
|
pr_perror("Can't create socket");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
list_for_each_entry(slave, &info->sibling, sibling) {
|
2014-10-06 17:15:44 +04:00
|
|
|
BUG_ON(tty_is_master(slave));
|
2012-09-12 20:00:54 +04:00
|
|
|
|
tty: Use regular files engine to save paths to the peers, v5
Currently we're using predefined format for master/slave pty peers:
masters are always /dev/ptmx, while slaves are /dev/pts/$index,
where $index is the peer number.
While fitting most of distros this is not always correct and slave peers
might be mounted to an arbitrary place, so that we need to somehow
carry paths with ourself in image.
Instead of bloating current tty image lets use regular file engine instead
and on checkpoint stage save a path to the link in regfiles set, then on
restore simply fetch it from the image.
Such approach will help in future when we need to support multiple
instances of devpts filesystem.
To support backward compatibility with images where no regfile
records are present we generate new one on the fly in
pty_alloc_reg() helper.
Because of the need to restore dead slave peers and restore of
the controlling terminal we need to generate that named "fake
inverted" pty_alloc_fake_reg() helper: in particular if
we need to open dead slave peer we generate fake master peer,
open it and the close out. Almost the same situation in
restoring contolling terminal -- we get master peer, generate
appropriate fake slave object, open it, manipulate, then
close it out and free.
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Acked-by: Tycho Andersen <tycho.andersen@canonical.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-10-17 16:52:00 +04:00
|
|
|
fd = open_pty_reg(slave->reg_d, slave->tfe->flags | O_NOCTTY);
|
2012-09-12 20:00:54 +04:00
|
|
|
if (fd < 0) {
|
tty: Use regular files engine to save paths to the peers, v5
Currently we're using predefined format for master/slave pty peers:
masters are always /dev/ptmx, while slaves are /dev/pts/$index,
where $index is the peer number.
While fitting most of distros this is not always correct and slave peers
might be mounted to an arbitrary place, so that we need to somehow
carry paths with ourself in image.
Instead of bloating current tty image lets use regular file engine instead
and on checkpoint stage save a path to the link in regfiles set, then on
restore simply fetch it from the image.
Such approach will help in future when we need to support multiple
instances of devpts filesystem.
To support backward compatibility with images where no regfile
records are present we generate new one on the fly in
pty_alloc_reg() helper.
Because of the need to restore dead slave peers and restore of
the controlling terminal we need to generate that named "fake
inverted" pty_alloc_fake_reg() helper: in particular if
we need to open dead slave peer we generate fake master peer,
open it and the close out. Almost the same situation in
restoring contolling terminal -- we get master peer, generate
appropriate fake slave object, open it, manipulate, then
close it out and free.
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Acked-by: Tycho Andersen <tycho.andersen@canonical.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-10-17 16:52:00 +04:00
|
|
|
pr_perror("Can't open slave %s", path_from_reg(slave->reg_d));
|
2012-09-12 20:00:54 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (restore_tty_params(fd, slave))
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
fle = file_master(&slave->d);
|
|
|
|
|
|
|
|
pr_debug("send slave %#x fd %d connected on %s (pid %d)\n",
|
tty: Use regular files engine to save paths to the peers, v5
Currently we're using predefined format for master/slave pty peers:
masters are always /dev/ptmx, while slaves are /dev/pts/$index,
where $index is the peer number.
While fitting most of distros this is not always correct and slave peers
might be mounted to an arbitrary place, so that we need to somehow
carry paths with ourself in image.
Instead of bloating current tty image lets use regular file engine instead
and on checkpoint stage save a path to the link in regfiles set, then on
restore simply fetch it from the image.
Such approach will help in future when we need to support multiple
instances of devpts filesystem.
To support backward compatibility with images where no regfile
records are present we generate new one on the fly in
pty_alloc_reg() helper.
Because of the need to restore dead slave peers and restore of
the controlling terminal we need to generate that named "fake
inverted" pty_alloc_fake_reg() helper: in particular if
we need to open dead slave peer we generate fake master peer,
open it and the close out. Almost the same situation in
restoring contolling terminal -- we get master peer, generate
appropriate fake slave object, open it, manipulate, then
close it out and free.
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Acked-by: Tycho Andersen <tycho.andersen@canonical.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-10-17 16:52:00 +04:00
|
|
|
slave->tfe->id, fd, path_from_reg(slave->reg_d), fle->pid);
|
2012-09-12 20:00:54 +04:00
|
|
|
|
|
|
|
if (send_fd_to_peer(fd, fle, sock)) {
|
|
|
|
pr_perror("Can't send file descriptor");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
fd = -1;
|
|
|
|
}
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
err:
|
|
|
|
close_safe(&fd);
|
|
|
|
close_safe(&sock);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int receive_tty(struct tty_info *info)
|
|
|
|
{
|
|
|
|
struct fdinfo_list_entry *fle;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
fle = file_master(&info->d);
|
|
|
|
pr_info("\tWaiting tty fd %d (pid %d)\n", fle->fe->fd, fle->pid);
|
|
|
|
|
|
|
|
fd = recv_fd(fle->fe->fd);
|
|
|
|
close(fle->fe->fd);
|
|
|
|
if (fd < 0) {
|
|
|
|
pr_err("Can't get fd %d\n", fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rst_file_params(fd, info->tfe->fown, info->tfe->flags))
|
|
|
|
close_safe(&fd);
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2012-10-18 15:52:01 +04:00
|
|
|
static int pty_open_unpaired_slave(struct file_desc *d, struct tty_info *slave)
|
2012-09-14 17:50:46 +04:00
|
|
|
{
|
tty: Use regular files engine to save paths to the peers, v5
Currently we're using predefined format for master/slave pty peers:
masters are always /dev/ptmx, while slaves are /dev/pts/$index,
where $index is the peer number.
While fitting most of distros this is not always correct and slave peers
might be mounted to an arbitrary place, so that we need to somehow
carry paths with ourself in image.
Instead of bloating current tty image lets use regular file engine instead
and on checkpoint stage save a path to the link in regfiles set, then on
restore simply fetch it from the image.
Such approach will help in future when we need to support multiple
instances of devpts filesystem.
To support backward compatibility with images where no regfile
records are present we generate new one on the fly in
pty_alloc_reg() helper.
Because of the need to restore dead slave peers and restore of
the controlling terminal we need to generate that named "fake
inverted" pty_alloc_fake_reg() helper: in particular if
we need to open dead slave peer we generate fake master peer,
open it and the close out. Almost the same situation in
restoring contolling terminal -- we get master peer, generate
appropriate fake slave object, open it, manipulate, then
close it out and free.
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Acked-by: Tycho Andersen <tycho.andersen@canonical.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-10-17 16:52:00 +04:00
|
|
|
struct reg_file_info *fake = NULL;
|
2012-09-14 17:50:46 +04:00
|
|
|
int master = -1, ret = -1, fd = -1;
|
|
|
|
|
2012-10-18 15:52:01 +04:00
|
|
|
/*
|
|
|
|
* We may have 2 cases here: the slave either need to
|
|
|
|
* be inherited, either it requires a fake master.
|
|
|
|
*/
|
2012-09-14 17:50:46 +04:00
|
|
|
|
2013-05-06 19:12:32 +04:00
|
|
|
if (likely(slave->inherit)) {
|
2012-10-18 15:52:01 +04:00
|
|
|
fd = dup(get_service_fd(SELF_STDIN_OFF));
|
|
|
|
if (fd < 0) {
|
|
|
|
pr_perror("Can't dup SELF_STDIN_OFF");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
pr_info("Migrated slave peer %x -> to fd %d\n",
|
|
|
|
slave->tfe->id, fd);
|
|
|
|
} else {
|
tty: Use regular files engine to save paths to the peers, v5
Currently we're using predefined format for master/slave pty peers:
masters are always /dev/ptmx, while slaves are /dev/pts/$index,
where $index is the peer number.
While fitting most of distros this is not always correct and slave peers
might be mounted to an arbitrary place, so that we need to somehow
carry paths with ourself in image.
Instead of bloating current tty image lets use regular file engine instead
and on checkpoint stage save a path to the link in regfiles set, then on
restore simply fetch it from the image.
Such approach will help in future when we need to support multiple
instances of devpts filesystem.
To support backward compatibility with images where no regfile
records are present we generate new one on the fly in
pty_alloc_reg() helper.
Because of the need to restore dead slave peers and restore of
the controlling terminal we need to generate that named "fake
inverted" pty_alloc_fake_reg() helper: in particular if
we need to open dead slave peer we generate fake master peer,
open it and the close out. Almost the same situation in
restoring contolling terminal -- we get master peer, generate
appropriate fake slave object, open it, manipulate, then
close it out and free.
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Acked-by: Tycho Andersen <tycho.andersen@canonical.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-10-17 16:52:00 +04:00
|
|
|
fake = pty_alloc_fake_master(slave);
|
|
|
|
if (!fake)
|
|
|
|
goto err;
|
|
|
|
master = pty_open_ptmx_index(&fake->d, slave->tie->pty->index, O_RDONLY);
|
2012-10-18 15:52:01 +04:00
|
|
|
if (master < 0) {
|
|
|
|
pr_perror("Can't open fale %x (index %d)",
|
|
|
|
slave->tfe->id, slave->tie->pty->index);
|
tty: Use regular files engine to save paths to the peers, v5
Currently we're using predefined format for master/slave pty peers:
masters are always /dev/ptmx, while slaves are /dev/pts/$index,
where $index is the peer number.
While fitting most of distros this is not always correct and slave peers
might be mounted to an arbitrary place, so that we need to somehow
carry paths with ourself in image.
Instead of bloating current tty image lets use regular file engine instead
and on checkpoint stage save a path to the link in regfiles set, then on
restore simply fetch it from the image.
Such approach will help in future when we need to support multiple
instances of devpts filesystem.
To support backward compatibility with images where no regfile
records are present we generate new one on the fly in
pty_alloc_reg() helper.
Because of the need to restore dead slave peers and restore of
the controlling terminal we need to generate that named "fake
inverted" pty_alloc_fake_reg() helper: in particular if
we need to open dead slave peer we generate fake master peer,
open it and the close out. Almost the same situation in
restoring contolling terminal -- we get master peer, generate
appropriate fake slave object, open it, manipulate, then
close it out and free.
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Acked-by: Tycho Andersen <tycho.andersen@canonical.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-10-17 16:52:00 +04:00
|
|
|
goto err;
|
2012-10-18 15:52:01 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
unlock_pty(master);
|
|
|
|
|
tty: Use regular files engine to save paths to the peers, v5
Currently we're using predefined format for master/slave pty peers:
masters are always /dev/ptmx, while slaves are /dev/pts/$index,
where $index is the peer number.
While fitting most of distros this is not always correct and slave peers
might be mounted to an arbitrary place, so that we need to somehow
carry paths with ourself in image.
Instead of bloating current tty image lets use regular file engine instead
and on checkpoint stage save a path to the link in regfiles set, then on
restore simply fetch it from the image.
Such approach will help in future when we need to support multiple
instances of devpts filesystem.
To support backward compatibility with images where no regfile
records are present we generate new one on the fly in
pty_alloc_reg() helper.
Because of the need to restore dead slave peers and restore of
the controlling terminal we need to generate that named "fake
inverted" pty_alloc_fake_reg() helper: in particular if
we need to open dead slave peer we generate fake master peer,
open it and the close out. Almost the same situation in
restoring contolling terminal -- we get master peer, generate
appropriate fake slave object, open it, manipulate, then
close it out and free.
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Acked-by: Tycho Andersen <tycho.andersen@canonical.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-10-17 16:52:00 +04:00
|
|
|
fd = open_pty_reg(slave->reg_d, slave->tfe->flags | O_NOCTTY);
|
2012-10-18 15:52:01 +04:00
|
|
|
if (fd < 0) {
|
tty: Use regular files engine to save paths to the peers, v5
Currently we're using predefined format for master/slave pty peers:
masters are always /dev/ptmx, while slaves are /dev/pts/$index,
where $index is the peer number.
While fitting most of distros this is not always correct and slave peers
might be mounted to an arbitrary place, so that we need to somehow
carry paths with ourself in image.
Instead of bloating current tty image lets use regular file engine instead
and on checkpoint stage save a path to the link in regfiles set, then on
restore simply fetch it from the image.
Such approach will help in future when we need to support multiple
instances of devpts filesystem.
To support backward compatibility with images where no regfile
records are present we generate new one on the fly in
pty_alloc_reg() helper.
Because of the need to restore dead slave peers and restore of
the controlling terminal we need to generate that named "fake
inverted" pty_alloc_fake_reg() helper: in particular if
we need to open dead slave peer we generate fake master peer,
open it and the close out. Almost the same situation in
restoring contolling terminal -- we get master peer, generate
appropriate fake slave object, open it, manipulate, then
close it out and free.
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Acked-by: Tycho Andersen <tycho.andersen@canonical.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-10-17 16:52:00 +04:00
|
|
|
pr_perror("Can't open slave %s", path_from_reg(slave->reg_d));
|
2012-10-18 15:52:01 +04:00
|
|
|
goto err;
|
|
|
|
}
|
2012-09-14 17:50:46 +04:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (restore_tty_params(fd, slave))
|
|
|
|
goto err;
|
|
|
|
|
2012-10-18 15:52:01 +04:00
|
|
|
/*
|
|
|
|
* If tty is migrated we need to set its group
|
|
|
|
* to the parent group, because signals on key
|
|
|
|
* presses are delivered to a group of terminal.
|
|
|
|
*
|
|
|
|
* Note, at this point the group/session should
|
|
|
|
* be already restored properly thus we can simply
|
2013-04-12 13:00:06 -07:00
|
|
|
* use syscalls instead of lookup via process tree.
|
2012-10-18 15:52:01 +04:00
|
|
|
*/
|
2013-05-06 19:12:32 +04:00
|
|
|
if (likely(slave->inherit)) {
|
2013-05-06 19:12:34 +04:00
|
|
|
/*
|
|
|
|
* The restoration procedure only works if we're
|
|
|
|
* migrating not a session leader, otherwise it's
|
|
|
|
* not allowed to restore a group and one better to
|
|
|
|
* checkpoint complete process tree together with
|
|
|
|
* the process which keeps the master peer.
|
|
|
|
*/
|
|
|
|
if (root_item->sid != root_item->pid.virt) {
|
|
|
|
pr_debug("Restore inherited group %d\n",
|
|
|
|
getpgid(getppid()));
|
|
|
|
if (tty_set_prgp(fd, getpgid(getppid())))
|
|
|
|
goto err;
|
|
|
|
}
|
2012-10-18 15:52:01 +04:00
|
|
|
}
|
|
|
|
|
2012-09-14 17:50:46 +04:00
|
|
|
if (pty_open_slaves(slave))
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
ret = fd;
|
|
|
|
fd = -1;
|
|
|
|
err:
|
|
|
|
close_safe(&master);
|
|
|
|
close_safe(&fd);
|
tty: Use regular files engine to save paths to the peers, v5
Currently we're using predefined format for master/slave pty peers:
masters are always /dev/ptmx, while slaves are /dev/pts/$index,
where $index is the peer number.
While fitting most of distros this is not always correct and slave peers
might be mounted to an arbitrary place, so that we need to somehow
carry paths with ourself in image.
Instead of bloating current tty image lets use regular file engine instead
and on checkpoint stage save a path to the link in regfiles set, then on
restore simply fetch it from the image.
Such approach will help in future when we need to support multiple
instances of devpts filesystem.
To support backward compatibility with images where no regfile
records are present we generate new one on the fly in
pty_alloc_reg() helper.
Because of the need to restore dead slave peers and restore of
the controlling terminal we need to generate that named "fake
inverted" pty_alloc_fake_reg() helper: in particular if
we need to open dead slave peer we generate fake master peer,
open it and the close out. Almost the same situation in
restoring contolling terminal -- we get master peer, generate
appropriate fake slave object, open it, manipulate, then
close it out and free.
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Acked-by: Tycho Andersen <tycho.andersen@canonical.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-10-17 16:52:00 +04:00
|
|
|
pty_free_fake_reg(&fake);
|
2012-09-14 17:50:46 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-09-12 20:00:54 +04:00
|
|
|
static int pty_open_ptmx(struct tty_info *info)
|
|
|
|
{
|
|
|
|
int master = -1;
|
|
|
|
|
tty: Use regular files engine to save paths to the peers, v5
Currently we're using predefined format for master/slave pty peers:
masters are always /dev/ptmx, while slaves are /dev/pts/$index,
where $index is the peer number.
While fitting most of distros this is not always correct and slave peers
might be mounted to an arbitrary place, so that we need to somehow
carry paths with ourself in image.
Instead of bloating current tty image lets use regular file engine instead
and on checkpoint stage save a path to the link in regfiles set, then on
restore simply fetch it from the image.
Such approach will help in future when we need to support multiple
instances of devpts filesystem.
To support backward compatibility with images where no regfile
records are present we generate new one on the fly in
pty_alloc_reg() helper.
Because of the need to restore dead slave peers and restore of
the controlling terminal we need to generate that named "fake
inverted" pty_alloc_fake_reg() helper: in particular if
we need to open dead slave peer we generate fake master peer,
open it and the close out. Almost the same situation in
restoring contolling terminal -- we get master peer, generate
appropriate fake slave object, open it, manipulate, then
close it out and free.
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Acked-by: Tycho Andersen <tycho.andersen@canonical.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-10-17 16:52:00 +04:00
|
|
|
master = pty_open_ptmx_index(info->reg_d, info->tie->pty->index, info->tfe->flags);
|
2012-09-12 20:00:54 +04:00
|
|
|
if (master < 0) {
|
|
|
|
pr_perror("Can't open %x (index %d)",
|
|
|
|
info->tfe->id, info->tie->pty->index);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
unlock_pty(master);
|
|
|
|
|
|
|
|
if (restore_tty_params(master, info))
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
if (info->tie->packet_mode) {
|
|
|
|
int packet_mode = 1;
|
|
|
|
|
|
|
|
if (ioctl(master, TIOCPKT, &packet_mode) < 0) {
|
|
|
|
pr_perror("Can't set packed mode on %x",
|
|
|
|
info->tfe->id);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pty_open_slaves(info))
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
if (info->tie->locked)
|
|
|
|
lock_pty(master);
|
|
|
|
|
|
|
|
return master;
|
|
|
|
err:
|
|
|
|
close_safe(&master);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-12-17 01:21:39 +02:00
|
|
|
static int open_simple_tty(struct tty_info *info)
|
2014-10-16 14:20:34 +04:00
|
|
|
{
|
|
|
|
int fd = -1;
|
|
|
|
|
|
|
|
fd = open_pty_reg(info->reg_d, info->tfe->flags);
|
|
|
|
if (fd < 0) {
|
2014-12-17 01:21:39 +02:00
|
|
|
pr_perror("Can't open %s %x",
|
|
|
|
info->type == TTY_TYPE_CONSOLE ? "console" : "virtual terminal",
|
|
|
|
info->tfe->id);
|
2014-10-16 14:20:34 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (restore_tty_params(fd, info))
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
err:
|
|
|
|
close_safe(&fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-09-12 20:00:54 +04:00
|
|
|
static int tty_open(struct file_desc *d)
|
|
|
|
{
|
|
|
|
struct tty_info *info = container_of(d, struct tty_info, d);
|
|
|
|
|
|
|
|
tty_show_pty_info("open", info);
|
|
|
|
|
2012-09-14 17:50:46 +04:00
|
|
|
if (!info->create)
|
2012-09-12 20:00:54 +04:00
|
|
|
return receive_tty(info);
|
|
|
|
|
2014-10-06 17:15:44 +04:00
|
|
|
if (!tty_is_master(info))
|
2012-10-18 15:52:01 +04:00
|
|
|
return pty_open_unpaired_slave(d, info);
|
2012-09-14 17:50:46 +04:00
|
|
|
|
2014-12-17 01:21:39 +02:00
|
|
|
if (info->type == TTY_TYPE_CONSOLE || info->type == TTY_TYPE_VT)
|
|
|
|
return open_simple_tty(info);
|
2012-09-12 20:00:54 +04:00
|
|
|
|
2014-10-16 14:20:34 +04:00
|
|
|
return pty_open_ptmx(info);
|
2012-09-12 20:00:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int tty_transport(FdinfoEntry *fe, struct file_desc *d)
|
|
|
|
{
|
|
|
|
struct tty_info *info = container_of(d, struct tty_info, d);
|
2012-09-14 17:50:46 +04:00
|
|
|
return !info->create;
|
2012-09-12 20:00:54 +04:00
|
|
|
}
|
|
|
|
|
2014-02-05 15:55:29 +04:00
|
|
|
static void tty_collect_fd(struct file_desc *d, struct fdinfo_list_entry *fle,
|
|
|
|
struct rst_info *ri)
|
2012-09-14 21:53:51 +04:00
|
|
|
{
|
2014-02-05 15:55:29 +04:00
|
|
|
struct list_head *tgt;
|
|
|
|
|
2012-09-14 21:53:51 +04:00
|
|
|
/*
|
|
|
|
* Unix98 pty slave peers requires the master peers being
|
|
|
|
* opened before them
|
|
|
|
*/
|
|
|
|
|
2014-10-06 17:15:44 +04:00
|
|
|
if (tty_is_master(container_of(d, struct tty_info, d)))
|
2014-02-05 15:55:29 +04:00
|
|
|
tgt = &ri->fds;
|
2012-09-14 21:53:51 +04:00
|
|
|
else
|
2014-02-05 15:55:29 +04:00
|
|
|
tgt = &ri->tty_slaves;
|
|
|
|
|
|
|
|
list_add_tail(&fle->ps_list, tgt);
|
2012-09-14 21:53:51 +04:00
|
|
|
}
|
|
|
|
|
2012-09-12 20:00:54 +04:00
|
|
|
static struct file_desc_ops tty_desc_ops = {
|
|
|
|
.type = FD_TYPES__TTY,
|
|
|
|
.open = tty_open,
|
2012-09-12 20:00:58 +04:00
|
|
|
.post_open = tty_restore_ctl_terminal,
|
2012-09-12 20:00:54 +04:00
|
|
|
.want_transport = tty_transport,
|
2014-02-05 15:55:29 +04:00
|
|
|
.collect_fd = tty_collect_fd,
|
2012-09-12 20:00:54 +04:00
|
|
|
};
|
|
|
|
|
2012-10-18 15:52:01 +04:00
|
|
|
static struct pstree_item *find_first_sid(int sid)
|
|
|
|
{
|
|
|
|
struct pstree_item *item;
|
|
|
|
|
|
|
|
for_each_pstree_item(item) {
|
|
|
|
if (item->sid == sid)
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-09-12 20:00:58 +04:00
|
|
|
static int tty_find_restoring_task(struct tty_info *info)
|
|
|
|
{
|
|
|
|
struct pstree_item *item;
|
|
|
|
|
2012-10-30 18:24:15 +04:00
|
|
|
/*
|
|
|
|
* The overall scenario is the following (note
|
|
|
|
* we might have corrupted image so don't believe
|
|
|
|
* anything).
|
|
|
|
*
|
|
|
|
* SID is present on a peer
|
|
|
|
* ------------------------
|
|
|
|
*
|
|
|
|
* - if it's master peer and we have as well a slave
|
|
|
|
* peer then prefer restore controlling terminal
|
|
|
|
* via slave peer
|
|
|
|
*
|
|
|
|
* - if it's master peer without slave, there must be
|
|
|
|
* a SID leader who will be restoring the peer
|
|
|
|
*
|
|
|
|
* - if it's a slave peer and no session leader found
|
|
|
|
* than we need an option to inherit terminal
|
|
|
|
*
|
|
|
|
* No SID present on a peer
|
|
|
|
* ------------------------
|
|
|
|
*
|
|
|
|
* - if it's a master peer than we are in good shape
|
|
|
|
* and continue in a normal way, we're the peer keepers
|
|
|
|
*
|
|
|
|
* - if it's a slave peer and no appropriate master peer
|
|
|
|
* found we need an option to inherit terminal
|
|
|
|
*
|
|
|
|
* In any case if it's hungup peer, then we jump out
|
|
|
|
* early since it will require fake master peer and
|
|
|
|
* rather non-usable anyway.
|
|
|
|
*/
|
|
|
|
|
2014-10-06 17:15:44 +04:00
|
|
|
if (tty_is_hung(info)) {
|
2012-10-30 18:24:15 +04:00
|
|
|
pr_debug("Hungup terminal found id %x\n", info->tfe->id);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-10-29 13:35:47 +04:00
|
|
|
if (info->tie->sid) {
|
2014-10-06 17:15:44 +04:00
|
|
|
if (!tty_is_master(info)) {
|
2012-10-30 18:24:15 +04:00
|
|
|
if (tty_has_active_pair(info))
|
2012-10-29 13:37:42 +04:00
|
|
|
return 0;
|
2013-03-19 23:01:51 +04:00
|
|
|
else
|
|
|
|
goto shell_job;
|
2012-10-29 13:37:42 +04:00
|
|
|
}
|
|
|
|
|
2012-11-20 21:05:17 +04:00
|
|
|
/*
|
|
|
|
* Find out the task which is session leader
|
|
|
|
* and it can restore the controlling terminal
|
|
|
|
* for us.
|
|
|
|
*/
|
2012-10-30 19:05:00 +04:00
|
|
|
item = find_first_sid(info->tie->sid);
|
2012-11-20 21:05:17 +04:00
|
|
|
if (item && item->pid.virt == item->sid) {
|
2012-10-30 18:24:15 +04:00
|
|
|
pr_info("Set a control terminal %x to %d\n",
|
|
|
|
info->tfe->id, info->tie->sid);
|
|
|
|
return prepare_ctl_tty(item->pid.virt,
|
2014-09-29 22:04:39 +04:00
|
|
|
rsti(item),
|
2012-10-30 18:24:15 +04:00
|
|
|
info->tfe->id);
|
2012-10-29 13:35:47 +04:00
|
|
|
}
|
2012-10-29 13:36:18 +04:00
|
|
|
|
2013-03-19 23:01:51 +04:00
|
|
|
goto notask;
|
2012-10-30 18:24:15 +04:00
|
|
|
} else {
|
2014-10-06 17:15:44 +04:00
|
|
|
if (tty_is_master(info))
|
2012-10-30 18:24:15 +04:00
|
|
|
return 0;
|
|
|
|
if (tty_has_active_pair(info))
|
|
|
|
return 0;
|
2012-10-29 13:36:18 +04:00
|
|
|
}
|
2012-09-12 20:00:58 +04:00
|
|
|
|
2013-03-19 23:01:51 +04:00
|
|
|
shell_job:
|
2012-10-30 18:24:15 +04:00
|
|
|
if (opts.shell_job) {
|
2012-10-29 13:36:35 +04:00
|
|
|
pr_info("Inherit terminal for id %x\n", info->tfe->id);
|
2013-05-06 19:12:32 +04:00
|
|
|
info->inherit = true;
|
2012-10-18 15:52:01 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-10-30 18:24:15 +04:00
|
|
|
notask:
|
2012-09-12 20:00:58 +04:00
|
|
|
pr_err("No task found with sid %d\n", info->tie->sid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-10-15 20:02:29 +04:00
|
|
|
static int tty_setup_orphan_slavery(void)
|
2012-09-14 17:50:46 +04:00
|
|
|
{
|
|
|
|
struct tty_info *info, *peer, *m;
|
|
|
|
|
|
|
|
list_for_each_entry(info, &all_ttys, list) {
|
|
|
|
struct fdinfo_list_entry *a, *b;
|
|
|
|
bool has_leader = false;
|
|
|
|
|
2014-10-06 17:15:44 +04:00
|
|
|
if (tty_is_master(info))
|
2012-09-14 17:50:46 +04:00
|
|
|
continue;
|
|
|
|
|
|
|
|
a = file_master(&info->d);
|
|
|
|
m = info;
|
|
|
|
|
|
|
|
list_for_each_entry(peer, &info->sibling, sibling) {
|
2014-10-06 17:15:44 +04:00
|
|
|
if (tty_is_master(peer)) {
|
2012-09-14 17:50:46 +04:00
|
|
|
has_leader = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Same check as in pipes and files -- need to
|
|
|
|
* order slave ends so that they do not dead lock
|
|
|
|
* waiting for each other.
|
|
|
|
*/
|
|
|
|
b = file_master(&peer->d);
|
2012-09-14 22:09:22 +04:00
|
|
|
if (fdinfo_rst_prio(b, a)) {
|
2012-09-14 17:50:46 +04:00
|
|
|
a = b;
|
|
|
|
m = peer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!has_leader) {
|
|
|
|
m->create = true;
|
|
|
|
pr_debug("Found orphan slave fake leader (%#x)\n",
|
|
|
|
m->tfe->id);
|
|
|
|
}
|
|
|
|
}
|
2012-10-15 20:02:29 +04:00
|
|
|
|
|
|
|
return 0;
|
2012-09-14 17:50:46 +04:00
|
|
|
}
|
|
|
|
|
2012-10-15 20:02:29 +04:00
|
|
|
int tty_setup_slavery(void)
|
2012-09-12 20:00:54 +04:00
|
|
|
{
|
|
|
|
struct tty_info *info, *peer, *m;
|
|
|
|
|
|
|
|
list_for_each_entry(info, &all_ttys, list) {
|
2012-10-15 20:02:29 +04:00
|
|
|
if (tty_find_restoring_task(info))
|
|
|
|
return -1;
|
2014-12-17 01:21:39 +02:00
|
|
|
if (info->type == TTY_TYPE_CONSOLE || info->type == TTY_TYPE_VT)
|
2014-10-16 14:20:34 +04:00
|
|
|
continue;
|
2012-09-12 20:00:54 +04:00
|
|
|
|
|
|
|
peer = info;
|
|
|
|
list_for_each_entry_safe_continue(peer, m, &all_ttys, list) {
|
2014-12-17 01:21:39 +02:00
|
|
|
if (peer->type == TTY_TYPE_CONSOLE || info->type == TTY_TYPE_VT)
|
2014-10-16 14:20:34 +04:00
|
|
|
continue;
|
2012-09-12 20:00:54 +04:00
|
|
|
if (peer->tie->pty->index != info->tie->pty->index)
|
|
|
|
continue;
|
|
|
|
|
2012-10-15 20:02:29 +04:00
|
|
|
if (tty_find_restoring_task(peer))
|
|
|
|
return -1;
|
2012-09-12 20:00:58 +04:00
|
|
|
|
2012-09-12 20:00:54 +04:00
|
|
|
list_add(&peer->sibling, &info->sibling);
|
|
|
|
list_del(&peer->list);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Print out information about peers.
|
|
|
|
*/
|
|
|
|
list_for_each_entry(info, &all_ttys, list) {
|
|
|
|
tty_show_pty_info("head", info);
|
|
|
|
list_for_each_entry(peer, &info->sibling, sibling)
|
|
|
|
tty_show_pty_info(" `- sibling", peer);
|
|
|
|
}
|
|
|
|
|
2012-10-15 20:02:29 +04:00
|
|
|
return tty_setup_orphan_slavery();
|
2012-09-12 20:00:54 +04:00
|
|
|
}
|
|
|
|
|
2012-09-14 17:50:45 +04:00
|
|
|
static int verify_termios(u32 id, TermiosEntry *e)
|
2012-09-12 20:00:54 +04:00
|
|
|
{
|
2012-09-14 17:50:41 +04:00
|
|
|
if (e && e->n_c_cc < TERMIOS_NCC) {
|
2012-09-12 20:00:54 +04:00
|
|
|
pr_err("pty ID %#x n_c_cc (%d) has wrong value\n",
|
|
|
|
id, (int)e->n_c_cc);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-09-14 17:50:45 +04:00
|
|
|
#define term_opts_missing_cmp(p, op) \
|
|
|
|
(!(p)->tie->termios op \
|
|
|
|
!(p)->tie->termios_locked op \
|
|
|
|
!(p)->tie->winsize)
|
|
|
|
|
|
|
|
#define term_opts_missing_any(p) \
|
|
|
|
term_opts_missing_cmp(p, ||)
|
|
|
|
|
|
|
|
#define term_opts_missing_all(p) \
|
|
|
|
term_opts_missing_cmp(p, &&)
|
|
|
|
|
|
|
|
static int verify_info(struct tty_info *info)
|
|
|
|
{
|
2014-10-16 14:27:20 +04:00
|
|
|
if (info->type != TTY_TYPE_PTM &&
|
2014-10-16 14:20:34 +04:00
|
|
|
info->type != TTY_TYPE_PTS &&
|
2014-12-17 01:21:39 +02:00
|
|
|
info->type != TTY_TYPE_CONSOLE &&
|
|
|
|
info->type != TTY_TYPE_VT) {
|
2014-10-16 14:27:20 +04:00
|
|
|
pr_err("Unknown type %d master peer %x\n",
|
|
|
|
info->type, info->tfe->id);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-09-14 17:50:45 +04:00
|
|
|
/*
|
|
|
|
* Master peer must have all parameters present,
|
|
|
|
* while slave peer must have either all parameters present
|
|
|
|
* or don't have them at all.
|
|
|
|
*/
|
|
|
|
if (term_opts_missing_any(info)) {
|
2014-10-06 17:15:44 +04:00
|
|
|
if (tty_is_master(info)) {
|
2012-09-14 17:50:45 +04:00
|
|
|
pr_err("Corrupted master peer %x\n", info->tfe->id);
|
|
|
|
return -1;
|
|
|
|
} else if (!term_opts_missing_all(info)) {
|
|
|
|
pr_err("Corrupted slave peer %x\n", info->tfe->id);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (verify_termios(info->tfe->id, info->tie->termios_locked) ||
|
|
|
|
verify_termios(info->tfe->id, info->tie->termios))
|
|
|
|
return -1;
|
2014-10-06 17:15:41 +04:00
|
|
|
|
|
|
|
if (info->tie->termios && info->tfe->tty_info_id > (MAX_TTYS << 1))
|
|
|
|
return -1;
|
2012-09-14 17:50:45 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-09-12 20:00:54 +04:00
|
|
|
static TtyInfoEntry *lookup_tty_info_entry(u32 id)
|
|
|
|
{
|
|
|
|
struct tty_info_entry *e;
|
|
|
|
|
|
|
|
list_for_each_entry(e, &all_tty_info_entries, list) {
|
|
|
|
if (e->tie->id == id)
|
|
|
|
return e->tie;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int collect_one_tty_info_entry(void *obj, ProtobufCMessage *msg)
|
|
|
|
{
|
|
|
|
struct tty_info_entry *info = obj;
|
|
|
|
|
|
|
|
info->tie = pb_msg(msg, TtyInfoEntry);
|
|
|
|
|
2014-10-16 14:20:34 +04:00
|
|
|
switch (info->tie->type) {
|
|
|
|
case TTY_TYPE__PTY:
|
|
|
|
if (!info->tie->pty) {
|
|
|
|
pr_err("No PTY data found (id %x), corrupted image?\n",
|
|
|
|
info->tie->id);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TTY_TYPE__CONSOLE:
|
2014-12-17 01:21:39 +02:00
|
|
|
case TTY_TYPE__VT:
|
2014-10-16 14:20:34 +04:00
|
|
|
if (info->tie->pty) {
|
|
|
|
pr_err("PTY data found (id %x), corrupted image?\n",
|
|
|
|
info->tie->id);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2012-09-12 20:00:54 +04:00
|
|
|
pr_err("Unexpected TTY type %d (id %x)\n",
|
|
|
|
info->tie->type, info->tie->id);
|
|
|
|
return -1;
|
|
|
|
}
|
2014-10-16 14:20:34 +04:00
|
|
|
|
2012-09-12 20:00:54 +04:00
|
|
|
INIT_LIST_HEAD(&info->list);
|
|
|
|
list_add(&info->list, &all_tty_info_entries);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-08-21 03:27:06 +04:00
|
|
|
struct collect_image_info tty_info_cinfo = {
|
2014-10-06 17:15:40 +04:00
|
|
|
.fd_type = CR_FD_TTY_INFO,
|
|
|
|
.pb_type = PB_TTY_INFO,
|
|
|
|
.priv_size = sizeof(struct tty_info_entry),
|
|
|
|
.collect = collect_one_tty_info_entry,
|
|
|
|
.flags = COLLECT_OPTIONAL,
|
2013-08-21 03:27:06 +04:00
|
|
|
};
|
|
|
|
|
2012-09-12 20:00:54 +04:00
|
|
|
static int collect_one_tty(void *obj, ProtobufCMessage *msg)
|
|
|
|
{
|
|
|
|
struct tty_info *info = obj;
|
|
|
|
|
|
|
|
info->tfe = pb_msg(msg, TtyFileEntry);
|
|
|
|
|
|
|
|
info->tie = lookup_tty_info_entry(info->tfe->tty_info_id);
|
|
|
|
if (!info->tie) {
|
|
|
|
pr_err("No tty-info-id %x found on id %x\n",
|
|
|
|
info->tfe->tty_info_id, info->tfe->id);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
INIT_LIST_HEAD(&info->sibling);
|
2014-10-16 14:27:20 +04:00
|
|
|
info->type = tty_type(major(info->tie->rdev), minor(info->tie->rdev));
|
2014-10-06 17:15:47 +04:00
|
|
|
info->create = tty_is_master(info);
|
2013-05-06 19:12:32 +04:00
|
|
|
info->inherit = false;
|
2012-09-12 20:00:54 +04:00
|
|
|
|
2012-09-14 17:50:45 +04:00
|
|
|
if (verify_info(info))
|
2012-09-12 20:00:54 +04:00
|
|
|
return -1;
|
|
|
|
|
tty: Use regular files engine to save paths to the peers, v5
Currently we're using predefined format for master/slave pty peers:
masters are always /dev/ptmx, while slaves are /dev/pts/$index,
where $index is the peer number.
While fitting most of distros this is not always correct and slave peers
might be mounted to an arbitrary place, so that we need to somehow
carry paths with ourself in image.
Instead of bloating current tty image lets use regular file engine instead
and on checkpoint stage save a path to the link in regfiles set, then on
restore simply fetch it from the image.
Such approach will help in future when we need to support multiple
instances of devpts filesystem.
To support backward compatibility with images where no regfile
records are present we generate new one on the fly in
pty_alloc_reg() helper.
Because of the need to restore dead slave peers and restore of
the controlling terminal we need to generate that named "fake
inverted" pty_alloc_fake_reg() helper: in particular if
we need to open dead slave peer we generate fake master peer,
open it and the close out. Almost the same situation in
restoring contolling terminal -- we get master peer, generate
appropriate fake slave object, open it, manipulate, then
close it out and free.
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Acked-by: Tycho Andersen <tycho.andersen@canonical.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-10-17 16:52:00 +04:00
|
|
|
/*
|
|
|
|
* The image might have no reg file record in old CRIU, so
|
|
|
|
* lets don't fail for a while. After a couple of releases
|
|
|
|
* simply require the record to present.
|
|
|
|
*/
|
|
|
|
info->reg_d = try_collect_special_file(info->tfe->id, 1);
|
|
|
|
if (!info->reg_d) {
|
2014-10-16 14:20:34 +04:00
|
|
|
if (is_pty(info->type)) {
|
|
|
|
info->reg_d = pty_alloc_reg(info, true);
|
|
|
|
if (!info->reg_d) {
|
|
|
|
pr_err("Can't generate new reg descriptor for id %#x\n",
|
|
|
|
info->tfe->id);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
pr_err("No reg_d descriptor for id %#x\n", info->tfe->id);
|
tty: Use regular files engine to save paths to the peers, v5
Currently we're using predefined format for master/slave pty peers:
masters are always /dev/ptmx, while slaves are /dev/pts/$index,
where $index is the peer number.
While fitting most of distros this is not always correct and slave peers
might be mounted to an arbitrary place, so that we need to somehow
carry paths with ourself in image.
Instead of bloating current tty image lets use regular file engine instead
and on checkpoint stage save a path to the link in regfiles set, then on
restore simply fetch it from the image.
Such approach will help in future when we need to support multiple
instances of devpts filesystem.
To support backward compatibility with images where no regfile
records are present we generate new one on the fly in
pty_alloc_reg() helper.
Because of the need to restore dead slave peers and restore of
the controlling terminal we need to generate that named "fake
inverted" pty_alloc_fake_reg() helper: in particular if
we need to open dead slave peer we generate fake master peer,
open it and the close out. Almost the same situation in
restoring contolling terminal -- we get master peer, generate
appropriate fake slave object, open it, manipulate, then
close it out and free.
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Acked-by: Tycho Andersen <tycho.andersen@canonical.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-10-17 16:52:00 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-18 15:51:59 +04:00
|
|
|
/*
|
2013-04-12 13:00:06 -07:00
|
|
|
* The tty peers which have no @termios are hung up,
|
2012-10-18 15:51:59 +04:00
|
|
|
* so don't mark them as active, we create them with
|
|
|
|
* faked master and they are rather a rudiment which
|
|
|
|
* can't be used. Most likely they appear if a user has
|
|
|
|
* dumped program when it was closing a peer.
|
|
|
|
*/
|
2014-10-16 14:20:34 +04:00
|
|
|
if (is_pty(info->type) && info->tie->termios)
|
2012-10-18 15:51:59 +04:00
|
|
|
tty_test_and_set(info->tfe->tty_info_id, tty_active_pairs);
|
|
|
|
|
2012-09-12 20:00:54 +04:00
|
|
|
pr_info("Collected tty ID %#x\n", info->tfe->id);
|
|
|
|
|
|
|
|
list_add(&info->list, &all_ttys);
|
2013-08-21 01:06:58 +04:00
|
|
|
return file_desc_add(&info->d, info->tfe->id, &tty_desc_ops);
|
2012-09-12 20:00:54 +04:00
|
|
|
}
|
|
|
|
|
2013-08-21 03:27:06 +04:00
|
|
|
struct collect_image_info tty_cinfo = {
|
2014-10-06 17:15:40 +04:00
|
|
|
.fd_type = CR_FD_TTY_FILES,
|
|
|
|
.pb_type = PB_TTY_FILE,
|
|
|
|
.priv_size = sizeof(struct tty_info),
|
|
|
|
.collect = collect_one_tty,
|
|
|
|
.flags = COLLECT_OPTIONAL,
|
2013-08-21 03:27:06 +04:00
|
|
|
};
|
|
|
|
|
2012-10-29 13:37:34 +04:00
|
|
|
/* Make sure the ttys we're dumping do belong our process tree */
|
|
|
|
int dump_verify_tty_sids(void)
|
|
|
|
{
|
|
|
|
struct tty_dump_info *dinfo, *n;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* There might be a cases where we get sid/pgid on
|
|
|
|
* slave peer. For example the application is running
|
|
|
|
* with redirection and we're migrating shell job.
|
|
|
|
*
|
|
|
|
* # ./app < /dev/zero > /dev/zero &2>1
|
|
|
|
*
|
|
|
|
* Which produce a tree like
|
|
|
|
* PID PPID PGID SID
|
|
|
|
* root 23786 23784 23786 23786 pts/0 \_ -bash
|
|
|
|
* root 24246 23786 24246 23786 pts/0 \_ ./app
|
|
|
|
*
|
|
|
|
* And the application goes background, then we dump
|
|
|
|
* it from the same shell.
|
|
|
|
*
|
|
|
|
* In this case we simply zap sid/pgid and inherit
|
|
|
|
* the peer from the current terminal on restore.
|
|
|
|
*/
|
|
|
|
list_for_each_entry_safe(dinfo, n, &all_ttys, list) {
|
|
|
|
if (!ret && dinfo->sid) {
|
|
|
|
struct pstree_item *item = find_first_sid(dinfo->sid);
|
|
|
|
|
|
|
|
if (!item || item->pid.virt != dinfo->sid) {
|
|
|
|
if (!opts.shell_job) {
|
2013-12-03 09:59:17 +04:00
|
|
|
pr_err("Found dangling tty with sid %d pgid %d (%s) on peer fd %d.\n",
|
2012-10-29 13:37:34 +04:00
|
|
|
dinfo->sid, dinfo->pgrp,
|
2014-10-16 14:27:20 +04:00
|
|
|
tty_name(dinfo->type),
|
2012-10-29 13:37:34 +04:00
|
|
|
dinfo->fd);
|
2013-12-03 09:59:17 +04:00
|
|
|
/*
|
|
|
|
* First thing people do with criu is dump smth
|
|
|
|
* run from shell. This is typical pitfall, warn
|
|
|
|
* user about it explicitly.
|
|
|
|
*/
|
|
|
|
pr_msg("Task attached to shell terminal. "
|
|
|
|
"Consider using --" OPT_SHELL_JOB " option. "
|
|
|
|
"More details on http://criu.org/Simple_loop\n");
|
2012-10-29 13:37:34 +04:00
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
xfree(dinfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-10-16 14:20:34 +04:00
|
|
|
static int dump_tty_info(int lfd, u32 id, const struct fd_parms *p, int type, int index)
|
2012-09-12 20:00:54 +04:00
|
|
|
{
|
|
|
|
TtyInfoEntry info = TTY_INFO_ENTRY__INIT;
|
|
|
|
TermiosEntry termios = TERMIOS_ENTRY__INIT;
|
|
|
|
TermiosEntry termios_locked = TERMIOS_ENTRY__INIT;
|
|
|
|
WinsizeEntry winsize = WINSIZE_ENTRY__INIT;
|
|
|
|
TtyPtyEntry pty = TTY_PTY_ENTRY__INIT;
|
2012-10-15 23:55:34 +04:00
|
|
|
struct parasite_tty_args *pti;
|
2012-10-29 13:37:34 +04:00
|
|
|
struct tty_dump_info *dinfo;
|
2012-09-12 20:00:54 +04:00
|
|
|
|
|
|
|
struct termios t;
|
|
|
|
struct winsize w;
|
|
|
|
|
2012-10-15 23:55:34 +04:00
|
|
|
int ret = -1;
|
2012-09-12 20:00:54 +04:00
|
|
|
|
2012-10-01 21:10:55 +04:00
|
|
|
/*
|
|
|
|
* 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));
|
|
|
|
|
2014-10-16 14:27:21 +04:00
|
|
|
pti = parasite_dump_tty(p->ctl, p->fd, type);
|
2012-10-15 23:55:34 +04:00
|
|
|
if (!pti)
|
2012-09-12 20:00:54 +04:00
|
|
|
return -1;
|
|
|
|
|
2012-10-29 13:37:34 +04:00
|
|
|
dinfo = xmalloc(sizeof(*dinfo));
|
|
|
|
if (!dinfo)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
dinfo->id = id;
|
|
|
|
dinfo->sid = pti->sid;
|
|
|
|
dinfo->pgrp = pti->pgrp;
|
|
|
|
dinfo->fd = p->fd;
|
2014-10-16 14:27:20 +04:00
|
|
|
dinfo->type = type;
|
2012-10-29 13:37:34 +04:00
|
|
|
|
|
|
|
list_add_tail(&dinfo->list, &all_ttys);
|
2012-10-18 15:52:01 +04:00
|
|
|
|
2012-09-12 20:00:54 +04:00
|
|
|
info.id = id;
|
2012-10-15 23:55:34 +04:00
|
|
|
info.sid = pti->sid;
|
|
|
|
info.pgrp = pti->pgrp;
|
2012-09-12 20:00:54 +04:00
|
|
|
info.rdev = p->stat.st_rdev;
|
2014-10-16 14:20:34 +04:00
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case TTY_TYPE_PTM:
|
|
|
|
case TTY_TYPE_PTS:
|
|
|
|
info.type = TTY_TYPE__PTY;
|
|
|
|
info.pty = &pty;
|
|
|
|
pty.index = index;
|
|
|
|
break;
|
|
|
|
case TTY_TYPE_CONSOLE:
|
|
|
|
info.type = TTY_TYPE__CONSOLE;
|
|
|
|
break;
|
2014-12-17 01:21:39 +02:00
|
|
|
case TTY_TYPE_VT:
|
|
|
|
info.type = TTY_TYPE__VT;
|
|
|
|
break;
|
2014-10-16 14:20:34 +04:00
|
|
|
default:
|
|
|
|
BUG();
|
|
|
|
}
|
2012-09-12 20:00:54 +04:00
|
|
|
|
2012-10-29 13:37:00 +04:00
|
|
|
info.locked = pti->st_lock;
|
|
|
|
info.exclusive = pti->st_excl;
|
|
|
|
info.packet_mode = pti->st_pckt;
|
|
|
|
|
2012-09-14 17:50:44 +04:00
|
|
|
/*
|
2013-04-12 13:00:06 -07:00
|
|
|
* Nothing we can do on hanging up terminal,
|
2012-09-14 17:50:44 +04:00
|
|
|
* just write out minimum information we can
|
|
|
|
* gather.
|
|
|
|
*/
|
2012-10-15 23:55:34 +04:00
|
|
|
if (pti->hangup)
|
2014-09-29 12:47:37 +04:00
|
|
|
return pb_write_one(img_from_set(glob_imgset, CR_FD_TTY_INFO), &info, PB_TTY_INFO);
|
2012-09-14 17:50:44 +04:00
|
|
|
|
2012-09-20 13:35:38 +04:00
|
|
|
/*
|
|
|
|
* Now trace the paired/unpaired ttys. For example
|
|
|
|
* the task might have slave peer assigned but no
|
|
|
|
* master peer. Such "detached" master peers are
|
|
|
|
* not yet supported by our tool and better to
|
2013-04-12 13:00:06 -07:00
|
|
|
* inform a user about such situation.
|
2012-09-20 13:35:38 +04:00
|
|
|
*/
|
2014-10-16 14:20:34 +04:00
|
|
|
if (is_pty(type))
|
|
|
|
tty_test_and_set(id, tty_active_pairs);
|
2012-09-20 13:35:38 +04:00
|
|
|
|
2012-09-14 17:50:44 +04:00
|
|
|
info.termios = &termios;
|
|
|
|
info.termios_locked = &termios_locked;
|
|
|
|
info.winsize = &winsize;
|
|
|
|
|
2012-09-12 20:00:54 +04:00
|
|
|
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);
|
|
|
|
|
2014-09-29 12:47:37 +04:00
|
|
|
ret = pb_write_one(img_from_set(glob_imgset, CR_FD_TTY_INFO), &info, PB_TTY_INFO);
|
2012-09-12 20:00:54 +04:00
|
|
|
out:
|
|
|
|
xfree(termios.c_cc);
|
|
|
|
xfree(termios_locked.c_cc);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-10-16 14:20:34 +04:00
|
|
|
static int dump_one_tty(int lfd, u32 id, const struct fd_parms *p)
|
2012-09-12 20:00:54 +04:00
|
|
|
{
|
|
|
|
TtyFileEntry e = TTY_FILE_ENTRY__INIT;
|
2014-10-16 14:20:34 +04:00
|
|
|
int ret = 0, type, index = -1;
|
2012-09-12 20:00:54 +04:00
|
|
|
|
|
|
|
pr_info("Dumping tty %d with id %#x\n", lfd, id);
|
|
|
|
|
tty: Use regular files engine to save paths to the peers, v5
Currently we're using predefined format for master/slave pty peers:
masters are always /dev/ptmx, while slaves are /dev/pts/$index,
where $index is the peer number.
While fitting most of distros this is not always correct and slave peers
might be mounted to an arbitrary place, so that we need to somehow
carry paths with ourself in image.
Instead of bloating current tty image lets use regular file engine instead
and on checkpoint stage save a path to the link in regfiles set, then on
restore simply fetch it from the image.
Such approach will help in future when we need to support multiple
instances of devpts filesystem.
To support backward compatibility with images where no regfile
records are present we generate new one on the fly in
pty_alloc_reg() helper.
Because of the need to restore dead slave peers and restore of
the controlling terminal we need to generate that named "fake
inverted" pty_alloc_fake_reg() helper: in particular if
we need to open dead slave peer we generate fake master peer,
open it and the close out. Almost the same situation in
restoring contolling terminal -- we get master peer, generate
appropriate fake slave object, open it, manipulate, then
close it out and free.
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Acked-by: Tycho Andersen <tycho.andersen@canonical.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-10-17 16:52:00 +04:00
|
|
|
if (dump_one_reg_file(lfd, id, p))
|
|
|
|
return -1;
|
|
|
|
|
2014-10-16 14:27:20 +04:00
|
|
|
type = tty_type(major(p->stat.st_rdev), minor(p->stat.st_rdev));
|
2014-10-16 14:20:34 +04:00
|
|
|
index = parse_tty_index(id, lfd, p, type);
|
|
|
|
if (index < 0) {
|
|
|
|
pr_info("Can't obtain index on tty %d id %#x\n", lfd, id);
|
2012-09-12 20:00:54 +04:00
|
|
|
return -1;
|
2014-10-16 14:20:34 +04:00
|
|
|
}
|
2012-09-12 20:00:54 +04:00
|
|
|
|
|
|
|
e.id = id;
|
2014-10-16 14:27:20 +04:00
|
|
|
e.tty_info_id = tty_gen_id(type, index);
|
2012-09-12 20:00:54 +04:00
|
|
|
e.flags = p->flags;
|
|
|
|
e.fown = (FownEntry *)&p->fown;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FIXME
|
|
|
|
*
|
|
|
|
* Figure out how to fetch data buffered in terminal.
|
|
|
|
* For a while simply flush before dumping. Note
|
|
|
|
* we don't check for errors here since it makes
|
|
|
|
* no sense anyway, the buffered data is not handled
|
|
|
|
* properly yet.
|
tty: Don't flush tty data on checkpoint stage
In case if we're dumping the peer which another
end belongs not to us but some other application
the attempts to flush data may lead to endless
SIGTTOU storm:
| 1158 ioctl(53, TCFLSH, 0x2) = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
| 1158 --- SIGTTOU {si_signo=SIGTTOU, si_code=SI_KERNEL, si_value={int=5, ptr=0x5}} ---
| 1158 --- stopped by SIGTTOU ---
| 1158 ioctl(53, TCFLSH, 0x2) = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
| 1158 --- SIGTTOU {si_signo=SIGTTOU, si_code=SI_KERNEL, si_value={int=5, ptr=0x5}} ---
| 1158 --- stopped by SIGTTOU ---
so simply don't flush data, the initial attempt to use
TCIOFLUSH was rather "hey, we don't have a way to
say the kernel to freeze tty link for a while, lets
try to workaround this limitation" but without proper
kernel help this won't work anyway as Andrey has discovered.
Reported-by: Andrey Vagin <avagin@openvz.org>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Acked-by: Andrew Vagin <avagin@parallels.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2012-11-22 19:04:12 +04:00
|
|
|
*
|
|
|
|
* Note as well that if we have only one peer here
|
|
|
|
* the external end might be sending the data to us
|
|
|
|
* again and again while kernel buffer is not full,
|
|
|
|
* this might lead to endless SIGTTOU signal delivery
|
|
|
|
* to the dumpee, ruining checkpoint procedure.
|
|
|
|
*
|
|
|
|
* So simply do not flush the line while we dump
|
|
|
|
* parameters tty never was being a guaranteed delivery
|
|
|
|
* transport anyway.
|
2012-09-12 20:00:54 +04:00
|
|
|
*/
|
|
|
|
|
2012-09-20 13:35:37 +04:00
|
|
|
if (!tty_test_and_set(e.tty_info_id, tty_bitmap))
|
2014-10-16 14:20:34 +04:00
|
|
|
ret = dump_tty_info(lfd, e.tty_info_id, p, type, index);
|
2012-09-12 20:00:54 +04:00
|
|
|
|
|
|
|
if (!ret)
|
2014-09-29 12:47:37 +04:00
|
|
|
ret = pb_write_one(img_from_set(glob_imgset, CR_FD_TTY_FILES), &e, PB_TTY_FILE);
|
2012-09-12 20:00:54 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-06-14 00:11:08 +04:00
|
|
|
const struct fdtype_ops tty_dump_ops = {
|
2012-09-12 20:00:54 +04:00
|
|
|
.type = FD_TYPES__TTY,
|
2014-10-16 14:20:34 +04:00
|
|
|
.dump = dump_one_tty,
|
2012-09-12 20:00:54 +04:00
|
|
|
};
|
|
|
|
|
2013-05-28 21:11:13 +04:00
|
|
|
int tty_prep_fds(void)
|
2012-10-18 15:51:56 +04:00
|
|
|
{
|
2013-05-28 21:11:13 +04:00
|
|
|
if (!opts.shell_job)
|
2013-01-22 22:45:31 +04:00
|
|
|
return 0;
|
|
|
|
|
2012-10-18 15:51:56 +04:00
|
|
|
if (!isatty(STDIN_FILENO)) {
|
2013-04-12 13:00:05 -07:00
|
|
|
pr_err("Standard stream is not a terminal, aborting\n");
|
2012-10-18 15:51:56 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-01-11 18:16:20 +04:00
|
|
|
if (install_service_fd(SELF_STDIN_OFF, STDIN_FILENO) < 0) {
|
2012-10-18 15:51:56 +04:00
|
|
|
pr_perror("Can't dup stdin to SELF_STDIN_OFF");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void tty_fini_fds(void)
|
|
|
|
{
|
2013-01-11 18:16:20 +04:00
|
|
|
close_service_fd(SELF_STDIN_OFF);
|
2012-10-18 15:51:56 +04:00
|
|
|
}
|