diff --git a/cr-dump.c b/cr-dump.c index 7d7f67a5b..be078b189 100644 --- a/cr-dump.c +++ b/cr-dump.c @@ -158,6 +158,89 @@ static int dump_one_reg_file(int lfd, u32 id, const struct fd_parms *p) return 0; } +#define PIPES_SIZE 1024 +static u32 *pipes; /* pipes for which data already dumped */ +static int nr_pipes = 0; + +static int dump_one_pipe(int lfd, u32 id, const struct fd_parms *p) +{ + struct pipe_entry pe; + int fd_pipes; + int steal_pipe[2]; + int pipe_size; + int has_bytes = 0; + int ret = -1; + int i = 0; + + pr_info("Dumping pipe %d with id %x pipe_id %x\n", lfd, id, p->id); + + fd_pipes = fdset_fd(glob_fdset, CR_FD_PIPES); + + if (p->flags & O_WRONLY) + goto dump; + + pr_info("Dumping data from pipe %x fd %d\n", id, lfd); + + for (i = 0; i < nr_pipes; i++) + if (pipes[i] == p->id) + goto dump; /* data was dumped already */ + + nr_pipes++; + if (nr_pipes > PIPES_SIZE) { + pr_err("OOM storing pipe\n"); + return -1; + } + + pipes[nr_pipes - 1] = p->id; + + 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; + } + + has_bytes = tee(lfd, steal_pipe[1], pipe_size, SPLICE_F_NONBLOCK); + if (has_bytes < 0) { + if (errno != EAGAIN) { + pr_perror("Can't pick pipe data"); + goto err_close; + } else + has_bytes = 0; + } +dump: + pe.id = id; + pe.pipe_id = p->id; + pe.bytes = has_bytes; + pe.flags = p->flags; + + if (write_img(fd_pipes, &pe)) + goto err_close; + + if (has_bytes) { + ret = splice(steal_pipe[0], NULL, fd_pipes, + NULL, has_bytes, 0); + if (ret < 0) { + pr_perror("Can't push pipe data"); + goto err_close; + } + } + + ret = 0; + +err_close: + if (has_bytes) { + close(steal_pipe[0]); + close(steal_pipe[1]); + } +err: + return ret; +} + static int do_dump_one_fdinfo(const struct fd_parms *p, int lfd, const struct cr_fdset *cr_fdset) { @@ -170,7 +253,14 @@ static int do_dump_one_fdinfo(const struct fd_parms *p, int lfd, ret = fd_id_generate(p->pid, &e); if (ret == 1) /* new ID generated */ - ret = dump_one_reg_file(lfd, e.id, p); + switch (p->type) { + case FDINFO_PIPE: + ret = dump_one_pipe(lfd, e.id, p); + break; + default: + ret = dump_one_reg_file(lfd, e.id, p); + break; + } if (ret < 0) goto err; @@ -190,7 +280,10 @@ static int dump_one_fdinfo(struct fd_parms *p, int lfd, const struct cr_fdset *cr_fdset) { p->id = MAKE_FD_GENID(p->stat.st_dev, p->stat.st_ino, p->pos); - p->type = FDINFO_REG; + if (S_ISFIFO(p->stat.st_mode)) + p->type = FDINFO_PIPE; + else + p->type = FDINFO_REG; return do_dump_one_fdinfo(p, lfd, cr_fdset); } @@ -231,101 +324,6 @@ static int dump_task_special_files(pid_t pid, const struct cr_fdset *cr_fdset) return ret; } -static int dump_pipe_and_data(int lfd, struct pipe_entry *e, - const struct cr_fdset *cr_fdset) -{ - int fd_pipes; - int steal_pipe[2]; - int pipe_size; - int has_bytes; - int ret = -1; - - fd_pipes = fdset_fd(cr_fdset, CR_FD_PIPES); - - pr_info("Dumping data from pipe %x\n", e->pipeid); - if (pipe(steal_pipe) < 0) { - pr_perror("Can't create pipe for stealing data"); - goto err; - } - - pipe_size = fcntl(lfd, F_GETPIPE_SZ); - if (pipe_size < 0) { - pr_err("Can't obtain piped data size\n"); - goto err; - } - - has_bytes = tee(lfd, steal_pipe[1], pipe_size, SPLICE_F_NONBLOCK); - if (has_bytes < 0) { - if (errno != EAGAIN) { - pr_perror("Can't pick pipe data"); - goto err_close; - } else - has_bytes = 0; - } - - e->bytes = has_bytes; - if (write_img(fd_pipes, e)) - goto err_close; - - if (has_bytes) { - ret = splice(steal_pipe[0], NULL, fd_pipes, - NULL, has_bytes, 0); - if (ret < 0) { - pr_perror("Can't push pipe data"); - goto err_close; - } - } - - ret = 0; - -err_close: - close(steal_pipe[0]); - close(steal_pipe[1]); - -err: - return ret; -} - -static int dump_one_pipe(const struct fd_parms *p, int lfd, - const struct cr_fdset *cr_fdset) -{ - struct pipe_entry e; - int ret = -1; - struct statfs stfs_buf; - int id = p->stat.st_ino; - - if (fstatfs(lfd, &stfs_buf) < 0) { - pr_perror("Can't fstatfs on %ld", p->fd_name); - return -1; - } - - if (stfs_buf.f_type != PIPEFS_MAGIC) { - pr_err("Dumping of FIFO's is not supported: %ld\n", p->fd_name); - return -1; - } - - pr_info("Dumping pipe %ld/%x flags %x\n", p->fd_name, id, p->flags); - - e.fd = p->fd_name; - e.pipeid = id; - e.flags = p->flags; - - if (p->flags & O_WRONLY) { - e.bytes = 0; - ret = write_img(fdset_fd(cr_fdset, CR_FD_PIPES), &e); - } else - ret = dump_pipe_and_data(lfd, &e, cr_fdset); - -err: - if (!ret) - pr_info("Dumped pipe: fd: %8x pipeid: %8x flags: %8x bytes: %8x\n", - e.fd, e.pipeid, e.flags, e.bytes); - else - pr_err("Dumping pipe %ld/%x flags %x\n", p->fd_name, id, p->flags); - - return ret; -} - static int fill_fd_params(pid_t pid, int fd, int lfd, struct fd_parms *p) { if (fstat(lfd, &p->stat) < 0) { @@ -385,12 +383,11 @@ static int dump_one_fd(pid_t pid, int fd, int lfd, if (S_ISCHR(p.stat.st_mode)) return dump_one_chrdev(&p, lfd, cr_fdset); - if (S_ISREG(p.stat.st_mode) || S_ISDIR(p.stat.st_mode)) + if (S_ISREG(p.stat.st_mode) || + S_ISDIR(p.stat.st_mode) || + S_ISFIFO(p.stat.st_mode)) return dump_one_fdinfo(&p, lfd, cr_fdset); - if (S_ISFIFO(p.stat.st_mode)) - return dump_one_pipe(&p, lfd, cr_fdset); - return dump_unsupp_fd(&p); } @@ -1517,6 +1514,9 @@ int cr_dump_tasks(pid_t pid, const struct cr_options *opts) shmems = xmalloc(SHMEMS_SIZE); if (!shmems) goto err; + pipes = xmalloc(PIPES_SIZE * sizeof(*pipes)); + if (!pipes) + goto err; list_for_each_entry(item, &pstree_list, list) { if (dump_one_task(item)) @@ -1527,10 +1527,11 @@ int cr_dump_tasks(pid_t pid, const struct cr_options *opts) } ret = cr_dump_shmem(); - xfree(shmems); fd_id_show_tree(); err: + xfree(shmems); + xfree(pipes); close_cr_fdset(&glob_fdset); pstree_switch_state(&pstree_list, opts); free_pstree(&pstree_list); diff --git a/cr-show.c b/cr-show.c index bafd2a8c5..1ed3e5c6f 100644 --- a/cr-show.c +++ b/cr-show.c @@ -139,8 +139,8 @@ void show_pipes(int fd_pipes, struct cr_options *o) ret = read_img_eof(fd_pipes, &e); if (ret <= 0) goto out; - pr_msg("fd: %8x pipeid: %8x flags: %8x bytes: %8x\n", - e.fd, e.pipeid, e.flags, e.bytes); + pr_msg("id: %8x pipeid: %8x flags: %8x bytes: %8x\n", + e.id, e.pipe_id, e.flags, e.bytes); if (e.bytes) lseek(fd_pipes, e.bytes, SEEK_CUR); } diff --git a/include/crtools.h b/include/crtools.h index 90b30f3f4..ef967d4da 100644 --- a/include/crtools.h +++ b/include/crtools.h @@ -23,7 +23,6 @@ enum { CR_FD_PAGES, CR_FD_CORE, CR_FD_VMAS, - CR_FD_PIPES, CR_FD_SIGACT, CR_FD_UNIXSK, CR_FD_ITIMERS, @@ -49,6 +48,7 @@ enum { CR_FD_SK_QUEUES, CR_FD_REG_FILES, CR_FD_INETSK, + CR_FD_PIPES, _CR_FD_GLOB_TO, CR_FD_MAX @@ -97,7 +97,7 @@ extern struct cr_fd_desc_tmpl fdset_template[CR_FD_MAX]; #define FMT_FNAME_REG_FILES "reg-files.img" #define FMT_FNAME_CORE "core-%d.img" #define FMT_FNAME_VMAS "vmas-%d.img" -#define FMT_FNAME_PIPES "pipes-%d.img" +#define FMT_FNAME_PIPES "pipes.img" #define FMT_FNAME_PSTREE "pstree.img" #define FMT_FNAME_SIGACTS "sigacts-%d.img" #define FMT_FNAME_UNIXSK "unixsk-%d.img" diff --git a/include/image.h b/include/image.h index 097dc2c78..1a0135cb5 100644 --- a/include/image.h +++ b/include/image.h @@ -33,6 +33,7 @@ enum fd_types { FDINFO_UND, FDINFO_REG, + FDINFO_PIPE, FDINFO_MAP, FDINFO_INETSK, FDINFO_CWD, @@ -71,8 +72,8 @@ struct pstree_entry { } __packed; struct pipe_entry { - u32 fd; - u32 pipeid; + u32 id; + u32 pipe_id; u32 flags; u32 bytes; u8 data[0];