static void * start_srcthread (void *arg) { struct threaddata *threaddata = arg; guestfs_h *srcg; char fdname[128]; /* Open the source domain. */ srcg = guestfs_create (); if (!srcg) { perror ("failed to create libguestfs handle"); pthread_cancel (threaddata->mainthread); exit (EXIT_FAILURE); } if (open_guest (srcg, threaddata->src, 1) == -1) { pthread_cancel (threaddata->mainthread); exit (EXIT_FAILURE); } /* Begin the download. */ snprintf (fdname, sizeof fdname, "/dev/fd/%d", threaddata->fd); if (guestfs_tar_out (srcg, threaddata->srcdir, fdname) == -1) { pthread_cancel (threaddata->mainthread); exit (EXIT_FAILURE); } /* Close the pipe; this will cause the receiver to finish the upload. */ if (close (threaddata->fd) == -1) { pthread_cancel (threaddata->mainthread); exit (EXIT_FAILURE); } /* Clean up. */ guestfs_close (srcg); return NULL; }
int run_copy_out (const char *cmd, size_t argc, char *argv[]) { if (argc < 2) { fprintf (stderr, _("use 'copy-out <remote> [<remote>...] <localdir>' to copy files out of the image\n")); return -1; } /* Local directory is always the last arg. */ const char *local = argv[argc-1]; int nr_remotes = argc-1; struct stat statbuf; if (stat (local, &statbuf) == -1 || ! (S_ISDIR (statbuf.st_mode))) { fprintf (stderr, _("copy-out: target '%s' is not a directory\n"), local); return -1; } /* Download each remote one at a time using tar-out. */ int i, r; for (i = 0; i < nr_remotes; ++i) { char *remote = argv[i]; /* Allow win:... prefix on remotes. */ remote = win_prefix (remote); if (remote == NULL) return -1; /* If the remote is a file, download it. If it's a directory, * create the directory in local first before using tar-out. */ r = guestfs_is_file (g, remote); if (r == -1) { free (remote); return -1; } if (r == 1) { /* is file */ char buf[PATH_MAX]; const char *basename; if (split_path (buf, sizeof buf, remote, NULL, &basename) == -1) { free (remote); return -1; } char filename[PATH_MAX]; snprintf (filename, sizeof filename, "%s/%s", local, basename); if (guestfs_download (g, remote, filename) == -1) { free (remote); return -1; } } else { /* not a regular file */ r = guestfs_is_dir (g, remote); if (r == -1) { free (remote); return -1; } if (r == 0) { fprintf (stderr, _("copy-out: '%s' is not a file or directory\n"), remote); free (remote); return -1; } char buf[PATH_MAX]; const char *basename; if (split_path (buf, sizeof buf, remote, NULL, &basename) == -1) { free (remote); return -1; } struct fd_pid fdpid = make_tar_output (local, basename); if (fdpid.fd == -1) { free (remote); return -1; } char fdbuf[64]; snprintf (fdbuf, sizeof fdbuf, "/dev/fd/%d", fdpid.fd); int r = guestfs_tar_out (g, remote, fdbuf); if (close (fdpid.fd) == -1) { perror ("close (tar-output subprocess)"); free (remote); r = -1; } int status; if (waitpid (fdpid.pid, &status, 0) == -1) { perror ("wait (tar-output subprocess)"); free (remote); return -1; } if (!(WIFEXITED (status) && WEXITSTATUS (status) == 0)) { free (remote); return -1; } if (r == -1) { free (remote); return -1; } } free (remote); } return 0; }
int guestfs_impl_copy_out (guestfs_h *g, const char *remotepath, const char *localdir) { struct stat statbuf; int r; if (stat (localdir, &statbuf) == -1 || ! (S_ISDIR (statbuf.st_mode))) { error (g, _("target '%s' is not a directory"), localdir); return -1; } /* If the remote is a file, download it. If it's a directory, * create the directory in localdir first before using tar-out. */ r = guestfs_is_file (g, remotepath); if (r == -1) return -1; if (r == 1) { /* is file */ CLEANUP_FREE char *filename = NULL; size_t buf_len = strlen (remotepath) + 1; CLEANUP_FREE char *buf = safe_malloc (g, buf_len); const char *basename; if (split_path (g, buf, buf_len, remotepath, NULL, &basename) == -1) return -1; if (asprintf (&filename, "%s/%s", localdir, basename) == -1) { perrorf (g, "asprintf"); return -1; } if (guestfs_download (g, remotepath, filename) == -1) return -1; } else { /* not a regular file */ CLEANUP_CMD_CLOSE struct command *cmd = guestfs_int_new_command (g); struct copy_out_child_data data; char fdbuf[64]; int fd; r = guestfs_is_dir (g, remotepath); if (r == -1) return -1; if (r == 0) { error (g, _("'%s' is not a file or directory"), remotepath); return -1; } size_t buf_len = strlen (remotepath) + 1; CLEANUP_FREE char *buf = safe_malloc (g, buf_len); const char *basename; if (split_path (g, buf, buf_len, remotepath, NULL, &basename) == -1) return -1; /* RHBZ#845522: If remotepath == "/" then basename would be an empty * string. Replace it with "." so that make_tar_output writes * to "localdir/." */ if (STREQ (basename, "")) basename = "."; data.localdir = localdir; data.basename = basename; guestfs_int_cmd_set_child_callback (cmd, &child_setup, &data); guestfs_int_cmd_add_arg (cmd, "tar"); guestfs_int_cmd_add_arg (cmd, "-xf"); guestfs_int_cmd_add_arg (cmd, "-"); guestfs_int_cmd_clear_capture_errors (cmd); fd = guestfs_int_cmd_pipe_run (cmd, "w"); if (fd == -1) return -1; snprintf (fdbuf, sizeof fdbuf, "/dev/fd/%d", fd); r = guestfs_tar_out (g, remotepath, fdbuf); if (close (fd) == -1) { perrorf (g, "close (tar-output subprocess)"); return -1; } r = guestfs_int_cmd_pipe_wait (cmd); if (r == -1) return -1; if (!WIFEXITED (r) || WEXITSTATUS (r) != 0) { CLEANUP_FREE char *errors = guestfs_int_cmd_get_pipe_errors (cmd); if (errors == NULL) return -1; error (g, "tar subprocess failed: %s", errors); return -1; } } return 0; }