2012-04-05 20:02:00 +04:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
2012-05-29 20:11:00 +04:00
|
|
|
#include <stdlib.h>
|
2012-04-05 20:02:00 +04:00
|
|
|
|
2012-04-05 20:02:00 +04:00
|
|
|
#include "crtools.h"
|
|
|
|
#include "image.h"
|
|
|
|
#include "files.h"
|
2012-05-03 17:36:00 +04:00
|
|
|
#include "pipes.h"
|
2012-04-05 20:02:00 +04:00
|
|
|
#include "util-net.h"
|
|
|
|
|
2012-06-19 12:30:00 +04:00
|
|
|
/*
|
|
|
|
* The sequence of objects which should be restored:
|
2012-04-05 20:02:00 +04:00
|
|
|
* pipe -> files struct-s -> fd-s.
|
|
|
|
* pipe_entry describes pipe's file structs-s.
|
2012-04-06 14:04:00 +04:00
|
|
|
* A pipe doesn't have own properties, so it has no object.
|
2012-04-05 20:02:00 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
struct pipe_info {
|
2012-06-19 12:30:00 +04:00
|
|
|
struct pipe_entry pe;
|
|
|
|
struct list_head pipe_list; /* All pipe_info with the same pipe_id
|
|
|
|
* This is pure circular list without head */
|
|
|
|
struct list_head list; /* list head for fdinfo_list_entry-s */
|
|
|
|
struct file_desc d;
|
|
|
|
int create;
|
|
|
|
int bytes;
|
|
|
|
off_t off;
|
2012-04-05 20:02:00 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
static LIST_HEAD(pipes);
|
|
|
|
|
|
|
|
static void show_saved_pipe_fds(struct pipe_info *pi)
|
|
|
|
{
|
|
|
|
struct fdinfo_list_entry *fle;
|
|
|
|
|
2012-04-24 15:20:24 +04:00
|
|
|
pr_info(" `- ID %p %#xpn", pi, pi->pe.id);
|
2012-04-18 15:46:04 +04:00
|
|
|
list_for_each_entry(fle, &pi->d.fd_info_head, desc_list)
|
2012-07-07 01:03:00 +04:00
|
|
|
pr_info(" `- FD %d pid %d\n", fle->fe->fd, fle->pid);
|
2012-04-05 20:02:00 +04:00
|
|
|
}
|
|
|
|
|
2012-06-19 12:30:00 +04:00
|
|
|
static int handle_pipes_data(void)
|
2012-04-05 20:02:00 +04:00
|
|
|
{
|
|
|
|
int fd, ret;
|
|
|
|
|
|
|
|
fd = open_image_ro(CR_FD_PIPES_DATA);
|
|
|
|
if (fd < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
struct pipe_info *pi;
|
|
|
|
struct pipe_data_entry pde;
|
|
|
|
|
|
|
|
ret = read_img_eof(fd, &pde);
|
2012-06-28 13:32:59 +04:00
|
|
|
if (ret <= 0)
|
2012-04-05 20:02:00 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
list_for_each_entry(pi, &pipes, list) {
|
|
|
|
if (pi->pe.pipe_id != pde.pipe_id)
|
|
|
|
continue;
|
|
|
|
if (!pi->create)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
pi->off = lseek(fd, 0, SEEK_CUR) + pde.off;
|
|
|
|
pi->bytes = pde.bytes;
|
|
|
|
|
|
|
|
lseek(fd, pde.bytes + pde.off, SEEK_CUR);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-06-28 13:32:59 +04:00
|
|
|
|
2012-04-05 20:02:00 +04:00
|
|
|
close(fd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-04-05 20:02:00 +04:00
|
|
|
/* Choose who will restore a pipe. */
|
2012-06-19 12:30:00 +04:00
|
|
|
void mark_pipe_master(void)
|
2012-04-05 20:02:00 +04:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
2012-04-24 15:20:24 +04:00
|
|
|
pr_info(" `- PIPE ID %#x\n", pi->pe.pipe_id);
|
2012-04-05 20:02:00 +04:00
|
|
|
show_saved_pipe_fds(pi);
|
|
|
|
|
2012-04-06 20:03:31 +04:00
|
|
|
fle = file_master(&pi->d);
|
2012-04-05 20:02:00 +04:00
|
|
|
p = pi;
|
2012-07-07 01:03:00 +04:00
|
|
|
fd = fle->fe->fd;
|
2012-04-05 20:02:00 +04:00
|
|
|
pid = fle->pid;
|
|
|
|
|
|
|
|
list_for_each_entry(pic, &pi->pipe_list, pipe_list) {
|
|
|
|
list_move(&pic->list, &head);
|
|
|
|
|
2012-04-06 20:03:31 +04:00
|
|
|
fle = file_master(&p->d);
|
2012-04-05 20:02:00 +04:00
|
|
|
if (fle->pid < pid ||
|
2012-07-07 01:03:00 +04:00
|
|
|
(pid == fle->pid && fle->fe->fd < fd)) {
|
2012-04-05 20:02:00 +04:00
|
|
|
p = pic;
|
2012-07-07 01:03:00 +04:00
|
|
|
fd = fle->fe->fd;
|
2012-04-05 20:02:00 +04:00
|
|
|
pid = fle->pid;
|
|
|
|
}
|
|
|
|
|
|
|
|
show_saved_pipe_fds(pic);
|
|
|
|
}
|
|
|
|
p->create = 1;
|
2012-04-24 15:20:24 +04:00
|
|
|
pr_info(" by %#x\n", p->pe.id);
|
2012-04-05 20:02:00 +04:00
|
|
|
}
|
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
|
|
|
|
|
|
|
handle_pipes_data();
|
2012-04-05 20:02:00 +04:00
|
|
|
}
|
2012-04-05 20:02:00 +04:00
|
|
|
|
2012-06-28 19:59:00 +04:00
|
|
|
int restore_pipe_data(int img_type, int pfd, u32 id, int bytes, off_t off)
|
2012-04-05 20:02:00 +04:00
|
|
|
{
|
2012-06-28 19:59:00 +04:00
|
|
|
int img, size = 0, ret;
|
2012-04-05 20:02:00 +04:00
|
|
|
|
2012-06-28 19:59:00 +04:00
|
|
|
img = open_image_ro(img_type);
|
|
|
|
if (img < 0)
|
2012-04-05 20:02:00 +04:00
|
|
|
return -1;
|
|
|
|
|
2012-06-28 19:59:00 +04:00
|
|
|
lseek(img, off, SEEK_SET);
|
2012-04-05 20:02:00 +04:00
|
|
|
|
2012-06-28 19:59:00 +04:00
|
|
|
pr_info("\t\tSplicing data size=%d off=%ld\n", bytes, off);
|
2012-04-05 20:02:00 +04:00
|
|
|
|
2012-06-28 19:59:00 +04:00
|
|
|
while (size != bytes) {
|
|
|
|
ret = splice(img, NULL, pfd, NULL, bytes - size, 0);
|
2012-04-05 20:02:00 +04:00
|
|
|
if (ret < 0) {
|
2012-06-28 19:59:00 +04:00
|
|
|
pr_perror("%#x: Error splicing data", id);
|
2012-04-05 20:02:00 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret == 0) {
|
2012-04-24 15:20:24 +04:00
|
|
|
pr_err("%#x: Wanted to restore %d bytes, but got %d\n",
|
2012-06-28 19:59:00 +04:00
|
|
|
id, bytes, size);
|
2012-04-05 20:02:00 +04:00
|
|
|
ret = -1;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
size += ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
err:
|
2012-06-28 19:59:00 +04:00
|
|
|
close(img);
|
2012-04-05 20:02:00 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-06-19 12:30:00 +04:00
|
|
|
static int recv_pipe_fd(struct pipe_info *pi)
|
|
|
|
{
|
|
|
|
struct fdinfo_list_entry *fle;
|
|
|
|
char path[PATH_MAX];
|
|
|
|
int tmp, fd;
|
|
|
|
|
|
|
|
fle = file_master(&pi->d);
|
2012-07-07 01:03:00 +04:00
|
|
|
fd = fle->fe->fd;
|
2012-06-19 12:30:00 +04:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2012-06-19 12:30:00 +04:00
|
|
|
if (fd >= 0) {
|
|
|
|
if (restore_fown(fd, &pi->pe.fown)) {
|
|
|
|
close(fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
2012-06-19 12:30:00 +04:00
|
|
|
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2012-04-06 20:39:48 +04:00
|
|
|
static int open_pipe(struct file_desc *d)
|
2012-04-05 20:02:00 +04:00
|
|
|
{
|
2012-04-06 21:22:28 +04:00
|
|
|
struct pipe_info *pi, *p;
|
2012-04-05 20:02:00 +04:00
|
|
|
int ret, tmp;
|
|
|
|
int pfd[2];
|
|
|
|
int sock;
|
|
|
|
|
2012-04-06 20:03:31 +04:00
|
|
|
pi = container_of(d, struct pipe_info, d);
|
2012-04-05 20:02:00 +04:00
|
|
|
|
2012-05-02 14:42:00 +04:00
|
|
|
pr_info("\t\tCreating pipe pipe_id=%#x id=%#x\n", pi->pe.pipe_id, pi->pe.id);
|
2012-04-05 20:02:00 +04:00
|
|
|
|
|
|
|
if (!pi->create)
|
|
|
|
return recv_pipe_fd(pi);
|
|
|
|
|
|
|
|
if (pipe(pfd) < 0) {
|
|
|
|
pr_perror("Can't create pipe");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-06-28 19:59:00 +04:00
|
|
|
ret = restore_pipe_data(CR_FD_PIPES_DATA, pfd[1], pi->pe.id, pi->bytes, pi->off);
|
2012-05-23 17:03:00 +04:00
|
|
|
if (ret)
|
|
|
|
return -1;
|
2012-04-05 20:02:00 +04:00
|
|
|
|
2012-04-05 20:02:00 +04:00
|
|
|
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) {
|
|
|
|
struct fdinfo_list_entry *fle;
|
2012-04-06 21:20:28 +04:00
|
|
|
int fd;
|
2012-04-05 20:02:00 +04:00
|
|
|
|
2012-04-06 20:03:31 +04:00
|
|
|
fle = file_master(&p->d);
|
2012-04-05 20:02:00 +04:00
|
|
|
fd = pfd[p->pe.flags & O_WRONLY];
|
|
|
|
|
2012-04-06 21:20:28 +04:00
|
|
|
if (send_fd_to_peer(fd, fle, sock)) {
|
2012-04-05 20:02:00 +04:00
|
|
|
pr_perror("Can't send file descriptor");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
close(sock);
|
|
|
|
|
|
|
|
close(pfd[!(pi->pe.flags & O_WRONLY)]);
|
|
|
|
tmp = pfd[pi->pe.flags & O_WRONLY];
|
|
|
|
|
2012-04-26 14:03:49 +04:00
|
|
|
if (rst_file_params(tmp, &pi->pe.fown, pi->pe.flags))
|
2012-04-10 22:54:00 +04:00
|
|
|
return -1;
|
|
|
|
|
2012-04-05 20:02:00 +04:00
|
|
|
return tmp;
|
|
|
|
}
|
2012-05-03 17:36:00 +04:00
|
|
|
|
2012-06-19 12:30:00 +04:00
|
|
|
static int want_transport(struct fdinfo_entry *fe, struct file_desc *d)
|
2012-06-19 12:30:00 +04:00
|
|
|
{
|
|
|
|
struct pipe_info *pi;
|
|
|
|
|
|
|
|
pi = container_of(d, struct pipe_info, d);
|
|
|
|
return !pi->create;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct file_desc_ops pipe_desc_ops = {
|
|
|
|
.type = FDINFO_PIPE,
|
|
|
|
.open = open_pipe,
|
2012-06-19 12:30:00 +04:00
|
|
|
.want_transport = want_transport,
|
2012-06-19 12:30:00 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
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) {
|
|
|
|
pi = xmalloc(sizeof(*pi));
|
|
|
|
ret = -1;
|
|
|
|
if (pi == NULL)
|
|
|
|
break;
|
|
|
|
|
2012-06-19 12:30:00 +04:00
|
|
|
pi->create = 0;
|
2012-06-19 12:30:00 +04:00
|
|
|
ret = read_img_eof(fd, &pi->pe);
|
|
|
|
if (ret <= 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
pr_info("Collected pipe entry ID %#x PIPE ID %#x\n",
|
|
|
|
pi->pe.id, pi->pe.pipe_id);
|
|
|
|
|
|
|
|
file_desc_add(&pi->d, pi->pe.id, &pipe_desc_ops);
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-07-01 08:21:54 +04:00
|
|
|
int dump_one_pipe_data(struct pipe_data_dump *pd, int lfd, const struct fd_parms *p)
|
2012-06-19 12:30:00 +04:00
|
|
|
{
|
2012-07-01 08:21:54 +04:00
|
|
|
int img;
|
2012-06-19 12:30:00 +04:00
|
|
|
int pipe_size, i, bytes;
|
|
|
|
int steal_pipe[2];
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (p->flags & O_WRONLY)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Maybe we've dumped it already */
|
2012-07-01 08:21:54 +04:00
|
|
|
for (i = 0; i < pd->nr; i++) {
|
|
|
|
if (pd->ids[i] == p->stat.st_ino)
|
2012-06-19 12:30:00 +04:00
|
|
|
return 0;
|
|
|
|
}
|
2012-07-01 08:21:54 +04:00
|
|
|
|
2012-07-01 07:50:39 +04:00
|
|
|
pr_info("Dumping data from pipe %#x fd %d\n", (u32)p->stat.st_ino, lfd);
|
2012-06-19 12:30:00 +04:00
|
|
|
|
2012-07-01 08:21:54 +04:00
|
|
|
if (pd->nr >= NR_PIPES_WITH_DATA) {
|
2012-06-19 12:30:00 +04:00
|
|
|
pr_err("OOM storing pipe\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-07-01 08:21:54 +04:00
|
|
|
img = fdset_fd(glob_fdset, pd->img_type);
|
|
|
|
pd->ids[pd->nr++] = p->stat.st_ino;
|
2012-06-19 12:30:00 +04:00
|
|
|
|
|
|
|
pipe_size = fcntl(lfd, F_GETPIPE_SZ);
|
|
|
|
if (pipe_size < 0) {
|
|
|
|
pr_err("Can't obtain piped data size\n");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pipe(steal_pipe) < 0) {
|
|
|
|
pr_perror("Can't create pipe for stealing data");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
bytes = tee(lfd, steal_pipe[1], pipe_size, SPLICE_F_NONBLOCK);
|
|
|
|
if (bytes > 0) {
|
|
|
|
struct pipe_data_entry pde;
|
|
|
|
int wrote;
|
|
|
|
|
2012-06-03 19:54:13 +04:00
|
|
|
pde.pipe_id = p->stat.st_ino;
|
2012-06-19 12:30:00 +04:00
|
|
|
pde.bytes = bytes;
|
|
|
|
pde.off = 0;
|
|
|
|
|
|
|
|
if (bytes > PIPE_MAX_NONALIG_SIZE) {
|
|
|
|
off_t off;
|
|
|
|
|
2012-06-28 19:59:00 +04:00
|
|
|
off = lseek(img, 0, SEEK_CUR);
|
2012-06-19 12:30:00 +04:00
|
|
|
off += sizeof(pde);
|
|
|
|
off &= ~PAGE_MASK;
|
|
|
|
|
|
|
|
if (off)
|
|
|
|
pde.off = PAGE_SIZE - off;
|
|
|
|
|
|
|
|
pr_info("\toff %#lx %#x bytes %#x\n", off, pde.off, bytes);
|
|
|
|
}
|
|
|
|
|
2012-06-28 19:59:00 +04:00
|
|
|
if (write_img(img, &pde))
|
2012-06-19 12:30:00 +04:00
|
|
|
goto err_close;
|
|
|
|
|
|
|
|
/* Don't forget to advance position if a hole needed */
|
|
|
|
if (pde.off)
|
2012-06-28 19:59:00 +04:00
|
|
|
lseek(img, pde.off, SEEK_CUR);
|
2012-06-19 12:30:00 +04:00
|
|
|
|
2012-06-28 19:59:00 +04:00
|
|
|
wrote = splice(steal_pipe[0], NULL, img, NULL, bytes, 0);
|
2012-06-19 12:30:00 +04:00
|
|
|
if (wrote < 0) {
|
|
|
|
pr_perror("Can't push pipe data");
|
|
|
|
goto err_close;
|
|
|
|
} else if (wrote != bytes) {
|
2012-07-01 07:50:39 +04:00
|
|
|
pr_err("%#x: Wanted to write %d bytes, but wrote %d\n",
|
|
|
|
(u32)p->stat.st_ino, bytes, wrote);
|
2012-06-19 12:30:00 +04:00
|
|
|
goto err_close;
|
|
|
|
}
|
|
|
|
} else if (bytes < 0) {
|
|
|
|
if (errno != EAGAIN) {
|
|
|
|
pr_perror("Can't pick pipe data");
|
|
|
|
goto err_close;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
err_close:
|
|
|
|
close(steal_pipe[0]);
|
|
|
|
close(steal_pipe[1]);
|
|
|
|
err:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-07-01 08:21:54 +04:00
|
|
|
static struct pipe_data_dump pd_pipes = { .img_type = CR_FD_PIPES_DATA, };
|
|
|
|
|
2012-05-04 15:34:55 +04:00
|
|
|
static int dump_one_pipe(int lfd, u32 id, const struct fd_parms *p)
|
2012-05-03 17:36:00 +04:00
|
|
|
{
|
|
|
|
struct pipe_entry pe;
|
|
|
|
|
2012-06-03 19:54:13 +04:00
|
|
|
pr_info("Dumping pipe %d with id %#x pipe_id %#x\n",
|
|
|
|
lfd, id, (u32)p->stat.st_ino);
|
2012-05-03 17:36:00 +04:00
|
|
|
|
2012-06-19 12:30:00 +04:00
|
|
|
pe.id = id;
|
2012-06-03 19:54:13 +04:00
|
|
|
pe.pipe_id = p->stat.st_ino;
|
2012-06-19 12:30:00 +04:00
|
|
|
pe.flags = p->flags;
|
|
|
|
pe.fown = p->fown;
|
2012-05-03 17:36:00 +04:00
|
|
|
|
2012-06-19 12:30:00 +04:00
|
|
|
if (write_img(fdset_fd(glob_fdset, CR_FD_PIPES), &pe))
|
2012-05-03 17:36:00 +04:00
|
|
|
return -1;
|
|
|
|
|
2012-07-01 08:21:54 +04:00
|
|
|
return dump_one_pipe_data(&pd_pipes, lfd, p);
|
2012-05-03 17:36:00 +04:00
|
|
|
}
|
|
|
|
|
2012-05-04 15:34:55 +04:00
|
|
|
static const struct fdtype_ops pipe_ops = {
|
|
|
|
.type = FDINFO_PIPE,
|
|
|
|
.make_gen_id = make_gen_id,
|
|
|
|
.dump = dump_one_pipe,
|
|
|
|
};
|
|
|
|
|
2012-06-19 12:30:00 +04:00
|
|
|
int dump_pipe(struct fd_parms *p, int lfd, const struct cr_fdset *cr_fdset)
|
2012-05-04 15:34:55 +04:00
|
|
|
{
|
|
|
|
return do_dump_gen_file(p, lfd, &pipe_ops, cr_fdset);
|
|
|
|
}
|