Commit 20d6762d authored by Cyrill Gorcunov's avatar Cyrill Gorcunov Committed by Pavel Emelyanov

tty: Add restoration of controlling terminal v4

The idea behind is pretty simple -- once we find
that there is a controlling terminal present we
do call ioctl on appropriate /dev/pts/N.

This is done in a bit unusuall manner. When we
find that there is a controling terminal present
we do create an additional FdinfoEntry for it
with object id taken from existing master peer.

The file engine stack this new FdinfoEntry on
fd_info_head head list. Thus we will have at
least two entries on this list. One for real
Fdinfo associated with master peer and one for
our new generated Fdfinfo entry, it depends on
pid which one become a file master.

Finally we do use post_open_fd hook in our
tty code which allows us to open controlling
terminal and yield proper ioctl on it.

v2:
 - restore control terminals via service fd,
   still need to speedup service fd retrieval.

v3:
 - use prepare_ctl_tty() helper to generate
   control terminal fdinfo entry

v4:
 - use post_open_fd
Signed-off-by: 's avatarCyrill Gorcunov <gorcunov@openvz.org>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent d5dfab77
...@@ -134,6 +134,12 @@ static int prepare_shared(void) ...@@ -134,6 +134,12 @@ static int prepare_shared(void)
ret = prepare_fd_pid(pi->pid.virt, pi->rst); ret = prepare_fd_pid(pi->pid.virt, pi->rst);
if (ret < 0) if (ret < 0)
break; break;
if (pi->ctl_tty_id) {
ret = prepare_ctl_tty(pi->pid.virt, pi->rst, pi->ctl_tty_id);
if (ret < 0)
break;
}
} }
mark_pipe_master(); mark_pipe_master();
......
...@@ -196,6 +196,25 @@ static int collect_fd(int pid, FdinfoEntry *e, struct rst_info *rst_info) ...@@ -196,6 +196,25 @@ static int collect_fd(int pid, FdinfoEntry *e, struct rst_info *rst_info)
return 0; return 0;
} }
int prepare_ctl_tty(int pid, struct rst_info *rst_info, u32 ctl_tty_id)
{
FdinfoEntry *e = xmalloc(sizeof(*e));
if (!e)
return -1;
fdinfo_entry__init(e);
e->id = ctl_tty_id;
e->fd = get_service_fd(CTL_TTY_OFF);
e->type = FD_TYPES__TTY;
if (collect_fd(pid, e, rst_info)) {
xfree(e);
return -1;
}
return 0;
}
int prepare_fd_pid(int pid, struct rst_info *rst_info) int prepare_fd_pid(int pid, struct rst_info *rst_info)
{ {
int fdinfo_fd, ret = 0; int fdinfo_fd, ret = 0;
...@@ -358,6 +377,9 @@ static int post_open_fd(int pid, FdinfoEntry *fe, struct file_desc *d) ...@@ -358,6 +377,9 @@ static int post_open_fd(int pid, FdinfoEntry *fe, struct file_desc *d)
if (!d->ops->post_open) if (!d->ops->post_open)
return 0; return 0;
if (fe->fd == get_service_fd(CTL_TTY_OFF))
return d->ops->post_open(d, fe->fd);
fle = file_master(d); fle = file_master(d);
if ((fle->pid != pid) || (fe->fd != fle->fe->fd)) if ((fle->pid != pid) || (fe->fd != fle->fe->fd))
return 0; return 0;
......
...@@ -106,6 +106,7 @@ enum { ...@@ -106,6 +106,7 @@ enum {
IMG_FD_OFF, IMG_FD_OFF,
SELF_EXE_FD_OFF, SELF_EXE_FD_OFF,
PROC_FD_OFF, PROC_FD_OFF,
CTL_TTY_OFF,
}; };
int get_service_fd(int type); int get_service_fd(int type);
......
...@@ -87,6 +87,7 @@ extern void show_saved_files(void); ...@@ -87,6 +87,7 @@ extern void show_saved_files(void);
extern int prepare_fds(struct pstree_item *me); extern int prepare_fds(struct pstree_item *me);
extern int prepare_fd_pid(int pid, struct rst_info *rst_info); extern int prepare_fd_pid(int pid, struct rst_info *rst_info);
extern int prepare_ctl_tty(int pid, struct rst_info *rst_info, u32 ctl_tty_id);
extern int prepare_shared_fdinfo(void); extern int prepare_shared_fdinfo(void);
extern int get_filemap_fd(int pid, VmaEntry *vma_entry); extern int get_filemap_fd(int pid, VmaEntry *vma_entry);
extern int prepare_fs(int pid); extern int prepare_fs(int pid);
......
...@@ -11,6 +11,7 @@ struct pstree_item { ...@@ -11,6 +11,7 @@ struct pstree_item {
pid_t pgid; pid_t pgid;
pid_t sid; pid_t sid;
pid_t born_sid; pid_t born_sid;
u32 ctl_tty_id;
int state; /* TASK_XXX constants */ int state; /* TASK_XXX constants */
int nr_threads; /* number of threads */ int nr_threads; /* number of threads */
struct pid *threads; /* array of threads */ struct pid *threads; /* array of threads */
......
...@@ -320,6 +320,55 @@ static int tty_get_pgrp(int fd) ...@@ -320,6 +320,55 @@ static int tty_get_pgrp(int fd)
return prgp; return prgp;
} }
static int tty_set_sid(int fd)
{
if (ioctl(fd, TIOCSCTTY, 1)) {
pr_perror("Can't set sid on terminal fd %d\n", fd);
return -1;
}
return 0;
}
static int tty_set_prgp(int fd, int group)
{
if (ioctl(fd, TIOCSPGRP, &group)) {
pr_perror("Failed to set group %d on %d\n", group, fd);
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);
int slave, ret = -1;
char pts_name[64];
if (fd != get_service_fd(CTL_TTY_OFF))
return 0;
snprintf(pts_name, sizeof(pts_name), PTS_FMT, info->tie->pty->index);
slave = open(pts_name, O_RDONLY);
if (slave < 0) {
pr_perror("Can't open %s", pts_name);
return -1;
}
pr_info("Restore session %d by %d tty (index %d)\n",
info->tie->sid, (int)getpid(),
info->tie->pty->index);
ret = tty_set_sid(slave);
if (!ret)
ret = tty_set_prgp(slave, info->tie->pgrp);
close(slave);
close(fd);
return ret;
}
static char *tty_type(struct tty_info *info) static char *tty_type(struct tty_info *info)
{ {
static char *tty_types[] = { static char *tty_types[] = {
...@@ -526,20 +575,44 @@ static int tty_transport(FdinfoEntry *fe, struct file_desc *d) ...@@ -526,20 +575,44 @@ static int tty_transport(FdinfoEntry *fe, struct file_desc *d)
static struct file_desc_ops tty_desc_ops = { static struct file_desc_ops tty_desc_ops = {
.type = FD_TYPES__TTY, .type = FD_TYPES__TTY,
.open = tty_open, .open = tty_open,
.post_open = tty_restore_ctl_terminal,
.want_transport = tty_transport, .want_transport = tty_transport,
}; };
static int tty_find_restoring_task(struct tty_info *info)
{
struct pstree_item *item;
if (info->tie->sid == 0)
return 0;
pr_info("Set a control terminal to %d\n", info->tie->sid);
for_each_pstree_item(item) {
if (item->sid == info->tie->sid) {
item->ctl_tty_id = info->tfe->id;
return 0;
}
}
pr_err("No task found with sid %d\n", info->tie->sid);
return -1;
}
static int tty_setup_slavery(void) static int tty_setup_slavery(void)
{ {
struct tty_info *info, *peer, *m; struct tty_info *info, *peer, *m;
list_for_each_entry(info, &all_ttys, list) { list_for_each_entry(info, &all_ttys, list) {
tty_find_restoring_task(info);
peer = info; peer = info;
list_for_each_entry_safe_continue(peer, m, &all_ttys, list) { list_for_each_entry_safe_continue(peer, m, &all_ttys, list) {
if (peer->tie->pty->index != info->tie->pty->index) if (peer->tie->pty->index != info->tie->pty->index)
continue; continue;
tty_find_restoring_task(peer);
list_add(&peer->sibling, &info->sibling); list_add(&peer->sibling, &info->sibling);
list_del(&peer->list); list_del(&peer->list);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment