2012-04-05 20:02:00 +04:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
2012-04-05 20:02:00 +04:00
|
|
|
#include "crtools.h"
|
|
|
|
#include "image.h"
|
|
|
|
#include "files.h"
|
2012-04-05 20:02:00 +04:00
|
|
|
#include "util-net.h"
|
|
|
|
|
|
|
|
/* The sequence of objects which should be restored:
|
|
|
|
* pipe -> files struct-s -> fd-s.
|
|
|
|
* pipe_entry describes pipe's file structs-s.
|
|
|
|
* A pipe has not own properties, so it has not own object.
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct pipe_info {
|
|
|
|
struct pipe_entry pe;
|
|
|
|
struct list_head pipe_list; /* all pipe_info with the same pipe_id
|
|
|
|
* This is pure circular list whiout head */
|
|
|
|
struct list_head list; /* list head for fdinfo_list_entry-s */
|
|
|
|
struct list_head fd_head;
|
|
|
|
int create;
|
|
|
|
};
|
|
|
|
|
|
|
|
static LIST_HEAD(pipes);
|
|
|
|
|
|
|
|
static struct pipe_info *find_pipe(int id)
|
|
|
|
{
|
|
|
|
struct pipe_info *pi;
|
|
|
|
|
|
|
|
list_for_each_entry(pi, &pipes, list)
|
|
|
|
if (pi->pe.id == id)
|
|
|
|
return pi;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct list_head *find_pipe_fd(int id)
|
|
|
|
{
|
|
|
|
struct pipe_info *pi;
|
|
|
|
|
|
|
|
pi = find_pipe(id);
|
|
|
|
return &pi->fd_head;
|
|
|
|
}
|
|
|
|
|
|
|
|
int collect_pipes(void)
|
|
|
|
{
|
|
|
|
struct pipe_info *pi = NULL, *tmp;
|
|
|
|
int fd, ret = -1;
|
|
|
|
|
|
|
|
fd = open_image_ro(CR_FD_PIPES);
|
|
|
|
if (fd < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
int len;
|
|
|
|
|
|
|
|
pi = xmalloc(sizeof(*pi));
|
|
|
|
ret = -1;
|
|
|
|
if (pi == NULL)
|
|
|
|
break;
|
|
|
|
|
|
|
|
ret = read_img_eof(fd, &pi->pe);
|
|
|
|
if (ret <= 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
lseek(fd, pi->pe.bytes, SEEK_CUR);
|
|
|
|
|
|
|
|
pr_info("Collected pipe entry ID %x PIPE ID %x\n",
|
|
|
|
pi->pe.id, pi->pe.pipe_id);
|
|
|
|
INIT_LIST_HEAD(&pi->fd_head);
|
|
|
|
|
|
|
|
list_for_each_entry(tmp, &pipes, list)
|
|
|
|
if (pi->pe.pipe_id == tmp->pe.pipe_id)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (&tmp->list == &pipes)
|
|
|
|
INIT_LIST_HEAD(&pi->pipe_list);
|
|
|
|
else
|
|
|
|
list_add(&pi->pipe_list, &tmp->pipe_list);
|
|
|
|
|
|
|
|
list_add_tail(&pi->list, &pipes);
|
|
|
|
}
|
|
|
|
|
|
|
|
xfree(pi);
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void show_saved_pipe_fds(struct pipe_info *pi)
|
|
|
|
{
|
|
|
|
struct fdinfo_list_entry *fle;
|
|
|
|
|
|
|
|
pr_info(" `- ID %p %xpn", pi, pi->pe.id);
|
|
|
|
list_for_each_entry(fle, &pi->fd_head, list)
|
|
|
|
pr_info(" `- FD %d pid %d\n", fle->fd, fle->pid);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Choose who will restore a pipe. */
|
|
|
|
void mark_pipe_master()
|
|
|
|
{
|
|
|
|
LIST_HEAD(head);
|
|
|
|
|
|
|
|
pr_info("Pipes:\n");
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
struct fdinfo_list_entry *fle;
|
|
|
|
struct pipe_info *pi, *pic, *p;
|
|
|
|
int fd, pid;
|
|
|
|
|
|
|
|
if (list_empty(&pipes))
|
|
|
|
break;
|
|
|
|
|
|
|
|
pi = list_first_entry(&pipes, struct pipe_info, list);
|
|
|
|
list_move(&pi->list, &head);
|
|
|
|
|
|
|
|
pr_info(" `- PIPE ID %x\n", pi->pe.pipe_id);
|
|
|
|
show_saved_pipe_fds(pi);
|
|
|
|
|
|
|
|
fle = list_first_entry(&pi->fd_head,
|
|
|
|
struct fdinfo_list_entry, list);
|
|
|
|
p = pi;
|
|
|
|
fd = fle->fd;
|
|
|
|
pid = fle->pid;
|
|
|
|
|
|
|
|
list_for_each_entry(pic, &pi->pipe_list, pipe_list) {
|
|
|
|
list_move(&pic->list, &head);
|
|
|
|
|
|
|
|
fle = list_first_entry(&p->fd_head,
|
|
|
|
struct fdinfo_list_entry, list);
|
|
|
|
if (fle->pid < pid ||
|
|
|
|
(pid == fle->pid && fle->fd < fd)) {
|
|
|
|
p = pic;
|
|
|
|
fd = fle->fd;
|
|
|
|
pid = fle->pid;
|
|
|
|
}
|
|
|
|
|
|
|
|
show_saved_pipe_fds(pic);
|
|
|
|
}
|
|
|
|
p->create = 1;
|
|
|
|
pr_info(" by %x\n", p->pe.id);
|
|
|
|
}
|
2012-04-05 20:02:00 +04:00
|
|
|
|
2012-04-05 20:02:00 +04:00
|
|
|
list_splice(&head, &pipes);
|
|
|
|
}
|
2012-04-05 20:02:00 +04:00
|
|
|
|
|
|
|
int pipe_should_open_transport(struct fdinfo_entry *fe,
|
|
|
|
struct list_head *fd_list)
|
|
|
|
{
|
|
|
|
struct pipe_info *pi = container_of(fd_list, struct pipe_info, fd_head);
|
|
|
|
|
|
|
|
return !pi->create;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int recv_pipe_fd(struct pipe_info *pi)
|
|
|
|
{
|
|
|
|
struct fdinfo_list_entry *fle;
|
|
|
|
char path[PATH_MAX];
|
|
|
|
int tmp, fd;
|
|
|
|
|
|
|
|
fle = list_first_entry(&pi->fd_head, struct fdinfo_list_entry, list);
|
|
|
|
fd = fle->fd;
|
|
|
|
|
|
|
|
pr_info("\tWaiting fd for %d\n", fd);
|
|
|
|
|
|
|
|
tmp = recv_fd(fd);
|
|
|
|
if (tmp < 0) {
|
|
|
|
pr_err("Can't get fd %d\n", tmp);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
snprintf(path, PATH_MAX, "/proc/self/fd/%d", tmp);
|
|
|
|
fd = open(path, pi->pe.flags);
|
|
|
|
close(tmp);
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT | O_NOATIME)
|
|
|
|
static int set_fd_flags(int fd, int flags)
|
|
|
|
{
|
|
|
|
int old;
|
|
|
|
|
|
|
|
old = fcntl(fd, F_GETFL, 0);
|
|
|
|
if (old < 0)
|
|
|
|
return old;
|
|
|
|
|
|
|
|
flags = (SETFL_MASK & flags) | (old & ~SETFL_MASK);
|
|
|
|
|
|
|
|
return fcntl(fd, F_SETFL, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
int open_pipe(struct list_head *l)
|
|
|
|
{
|
|
|
|
unsigned long time = 1000;
|
|
|
|
struct pipe_info *pi, *pc, *p;
|
|
|
|
int ret, tmp;
|
|
|
|
int pfd[2];
|
|
|
|
int sock;
|
|
|
|
int create;
|
|
|
|
|
|
|
|
pi = container_of(l, struct pipe_info, fd_head);
|
|
|
|
|
|
|
|
pr_info("\tCreating pipe pipe_id=%x id=%x\n", pi->pe.pipe_id, pi->pe.id);
|
|
|
|
|
|
|
|
if (!pi->create)
|
|
|
|
return recv_pipe_fd(pi);
|
|
|
|
|
|
|
|
if (pipe(pfd) < 0) {
|
|
|
|
pr_perror("Can't create pipe");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
sock = socket(PF_UNIX, SOCK_DGRAM, 0);
|
|
|
|
if (sock < 0) {
|
|
|
|
pr_perror("Can't create socket");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
list_for_each_entry(p, &pi->pipe_list, pipe_list) {
|
|
|
|
int len, fd;
|
|
|
|
struct sockaddr_un saddr;
|
|
|
|
struct fdinfo_list_entry *fle;
|
|
|
|
|
|
|
|
BUG_ON(list_empty(&p->fd_head));
|
|
|
|
fle = list_first_entry(&p->fd_head,
|
|
|
|
struct fdinfo_list_entry, list);
|
|
|
|
|
|
|
|
pr_info("\t\tWait fdinfo pid=%d fd=%d\n", fle->pid, fle->fd);
|
|
|
|
futex_wait_while(&fle->real_pid, 0);
|
|
|
|
|
|
|
|
transport_name_gen(&saddr, &len,
|
|
|
|
futex_get(&fle->real_pid), fle->fd);
|
|
|
|
|
|
|
|
fd = pfd[p->pe.flags & O_WRONLY];
|
|
|
|
|
|
|
|
pr_info("\t\tSend fd %d to %s\n", fd, saddr.sun_path + 1);
|
|
|
|
|
|
|
|
if (send_fd(sock, &saddr, len, fd) < 0) {
|
|
|
|
pr_perror("Can't send file descriptor");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
close(sock);
|
|
|
|
|
|
|
|
out:
|
|
|
|
close(pfd[!(pi->pe.flags & O_WRONLY)]);
|
|
|
|
tmp = pfd[pi->pe.flags & O_WRONLY];
|
|
|
|
ret = set_fd_flags(tmp, pi->pe.flags);
|
|
|
|
if (ret < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return tmp;
|
|
|
|
}
|