Exemple #1
0
int
do_copy_file_to_file (const char *src, const char *dest,
                      int64_t srcoffset, int64_t destoffset, int64_t size,
                      int sparse, int append)
{
  CLEANUP_FREE char *src_buf = NULL, *dest_buf = NULL;
  int wrflags = O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC;

  src_buf = sysroot_path (src);
  if (!src_buf) {
    reply_with_perror ("malloc");
    return -1;
  }

  dest_buf = sysroot_path (dest);
  if (!dest_buf) {
    reply_with_perror ("malloc");
    return -1;
  }

  if ((optargs_bitmask & GUESTFS_COPY_FILE_TO_FILE_APPEND_BITMASK) &&
      append)
    wrflags |= O_APPEND;
  else
    wrflags |= O_TRUNC;

  return copy (src_buf, src, dest_buf, dest, wrflags, 0666,
               COPY_UNLINK_DEST_ON_FAILURE,
               srcoffset, destoffset, size, sparse);
}
Exemple #2
0
/* If the network is enabled, we want <sysroot>/etc/resolv.conf to
 * reflect the contents of /etc/resolv.conf so that name resolution
 * works.  It would be nice to bind-mount the file (single file bind
 * mounts are possible).  However annoyingly that doesn't work for
 * Ubuntu guests where the guest resolv.conf is a dangling symlink,
 * and for reasons unknown mount tries to follow the symlink and
 * fails (likely a bug).  So this is a hack.  Note we only invoke
 * this if the network is enabled.
 */
static int
set_up_etc_resolv_conf (struct resolver_state *rs)
{
  struct stat statbuf;
  CLEANUP_FREE char *buf = NULL;

  rs->sysroot_etc_resolv_conf_old = NULL;

  rs->sysroot_etc_resolv_conf = sysroot_path ("/etc/resolv.conf");

  if (!rs->sysroot_etc_resolv_conf) {
    reply_with_perror ("malloc");
    goto error;
  }

  /* If /etc/resolv.conf exists, rename it to the backup file.  Note
   * that on Ubuntu it's a dangling symlink.
   */
  if (lstat (rs->sysroot_etc_resolv_conf, &statbuf) == 0) {
    /* Make a random name for the backup file. */
    if (asprintf (&buf, "%s/etc/XXXXXXXX", sysroot) == -1) {
      reply_with_perror ("asprintf");
      goto error;
    }
    if (random_name (buf) == -1) {
      reply_with_perror ("random_name");
      goto error;
    }
    rs->sysroot_etc_resolv_conf_old = strdup (buf);
    if (!rs->sysroot_etc_resolv_conf_old) {
      reply_with_perror ("strdup");
      goto error;
    }

    if (verbose)
      fprintf (stderr, "renaming %s to %s\n", rs->sysroot_etc_resolv_conf,
               rs->sysroot_etc_resolv_conf_old);

    if (rename (rs->sysroot_etc_resolv_conf,
                rs->sysroot_etc_resolv_conf_old) == -1) {
      reply_with_perror ("rename: %s to %s", rs->sysroot_etc_resolv_conf,
                         rs->sysroot_etc_resolv_conf_old);
      goto error;
    }
  }

  /* Now that the guest's <sysroot>/etc/resolv.conf is out the way, we
   * can create our own copy of the appliance /etc/resolv.conf.
   */
  ignore_value (command (NULL, NULL, str_cp, "/etc/resolv.conf",
                         rs->sysroot_etc_resolv_conf, NULL));

  rs->mounted = true;
  return 0;

 error:
  free (rs->sysroot_etc_resolv_conf);
  free (rs->sysroot_etc_resolv_conf_old);
  return -1;
}
Exemple #3
0
int64_t
do_inotify_add_watch (const char *path, int mask)
{
#ifdef HAVE_SYS_INOTIFY_H
  int64_t r;
  char *buf;

  NEED_INOTIFY (-1);

  buf = sysroot_path (path);
  if (!buf) {
    reply_with_perror ("malloc");
    return -1;
  }

  r = inotify_add_watch (inotify_fd, buf, mask);
  free (buf);
  if (r == -1) {
    reply_with_perror ("%s", path);
    return -1;
  }

  return r;
#else
  NOT_AVAILABLE (-1);
#endif
}
Exemple #4
0
int
do_hivex_commit (const char *filename)
{
  CLEANUP_FREE char *buf = NULL;

  NEED_HANDLE (-1);

  /* The 'filename' parameter is an optional string, and in most
   * cases will be NULL.
   */
  if (filename) {
    buf = sysroot_path (filename);
    if (!buf) {
      reply_with_perror ("malloc");
      return -1;
    }

    if (hivex_commit (h, buf, 0) == -1) {
      reply_with_perror ("%s: commit failed", filename);
      return -1;
    }
  }
  else {
    if (hivex_commit (h, NULL, 0) == -1) {
      reply_with_perror ("commit failed");
      return -1;
    }
  }

  return 0;
}
Exemple #5
0
guestfs_int_xfsinfo *
do_xfs_info (const char *pathordevice)
{
  int r;
  CLEANUP_FREE char *buf = NULL;
  CLEANUP_FREE char *out = NULL, *err = NULL;
  CLEANUP_FREE_STRING_LIST char **lines = NULL;
  int is_dev;

  is_dev = STREQLEN (pathordevice, "/dev/", 5);
  buf = is_dev ? strdup (pathordevice)
               : sysroot_path (pathordevice);
  if (buf == NULL) {
    reply_with_perror ("malloc");
    return NULL;
  }

  r = command (&out, &err, str_xfs_info, buf, NULL);
  if (r == -1) {
    reply_with_error ("%s", err);
    return NULL;
  }

  lines = split_lines (out);
  if (lines == NULL)
    return NULL;

  return parse_xfs_info (lines);
}
Exemple #6
0
/* We need to rewrite the root path so it is based at /sysroot. */
int
do_aug_init (const char *root, int flags)
{
#ifdef HAVE_AUGEAS
  char *buf;

  if (aug) {
    aug_close (aug);
    aug = NULL;
  }

  buf = sysroot_path (root);
  if (!buf) {
    reply_with_perror ("malloc");
    return -1;
  }

  aug = aug_init (buf, NULL, flags);
  free (buf);

  if (!aug) {
    reply_with_error ("Augeas initialization failed");
    return -1;
  }

  return 0;
#else
  NOT_AVAILABLE (-1);
#endif
}
Exemple #7
0
int64_t
do_get_e2generation (const char *filename)
{
    int r;
    CLEANUP_FREE char *buf = NULL, *out = NULL, *err = NULL;
    int64_t ret;

    buf = sysroot_path (filename);
    if (!buf) {
        reply_with_perror ("malloc");
        return -1;
    }

    r = command (&out, &err, str_lsattr, "-dv", "--", buf, NULL);
    if (r == -1) {
        reply_with_error ("%s: %s: %s", "lsattr", filename, err);
        return -1;
    }

    if (sscanf (out, "%" SCNi64, &ret) != 1) {
        reply_with_error ("cannot parse output from '%s' command: %s",
                          "lsattr", out);
        return -1;
    }
    if (ret < 0) {
        reply_with_error ("unexpected negative number from '%s' command: %s",
                          "lsattr", out);
        return -1;
    }

    return ret;
}
Exemple #8
0
/* This implementation is quick and dirty, and allows people to try
 * to remove parts of the initramfs (eg. "rm -r /..") but if people
 * do stupid stuff, who are we to try to stop them?
 */
int
do_rm_rf (const char *path)
{
  int r;
  char *buf, *err;

  if (STREQ (path, "/")) {
    reply_with_error ("cannot remove root directory");
    return -1;
  }

  buf = sysroot_path (path);
  if (buf == NULL) {
    reply_with_perror ("malloc");
    return -1;
  }

  r = command (NULL, &err, str_rm, "-rf", buf, NULL);
  free (buf);

  /* rm -rf is never supposed to fail.  I/O errors perhaps? */
  if (r == -1) {
    reply_with_error ("%s: %s", path, err);
    free (err);
    return -1;
  }

  free (err);

  return 0;
}
Exemple #9
0
int64_t
do_du (const char *path)
{
  int r;
  int64_t rv;
  CLEANUP_FREE char *out = NULL, *err = NULL, *buf = NULL;

  /* Make the path relative to /sysroot. */
  buf = sysroot_path (path);
  if (!buf) {
    reply_with_perror ("malloc");
    return -1;
  }

  pulse_mode_start ();

  r = command (&out, &err, str_du, "-s", buf, NULL);
  if (r == -1) {
    pulse_mode_cancel ();
    reply_with_error ("%s: %s", path, err);
    return -1;
  }

  if (sscanf (out, "%"SCNi64, &rv) != 1) {
    pulse_mode_cancel ();
    reply_with_error ("%s: could not read output: %s", path, out);
    return -1;
  }

  pulse_mode_end ();

  return rv;
}
Exemple #10
0
/* Takes optional arguments, consult optargs_bitmask. */
int
do_rsync (const char *src_orig, const char *dest_orig,
          int archive, int deletedest)
{
  CLEANUP_FREE char *src = NULL, *dest = NULL;

  src = sysroot_path (src_orig);
  dest = sysroot_path (dest_orig);
  if (!src || !dest) {
    reply_with_perror ("malloc");
    return -1;
  }

  if (!(optargs_bitmask & GUESTFS_RSYNC_ARCHIVE_BITMASK))
    archive = 0;
  if (!(optargs_bitmask & GUESTFS_RSYNC_DELETEDEST_BITMASK))
    deletedest = 0;

  return rsync (src, src_orig, dest, dest_orig, archive, deletedest);
}
Exemple #11
0
int
do_copy_file_to_file (const char *src, const char *dest,
                      int64_t srcoffset, int64_t destoffset, int64_t size,
                      int sparse)
{
  CLEANUP_FREE char *src_buf = NULL, *dest_buf = NULL;

  src_buf = sysroot_path (src);
  if (!src_buf) {
    reply_with_perror ("malloc");
    return -1;
  }

  dest_buf = sysroot_path (dest);
  if (!dest_buf) {
    reply_with_perror ("malloc");
    return -1;
  }

  return copy (src_buf, src, dest_buf, dest, DEST_FILE_FLAGS,
               srcoffset, destoffset, size, sparse);
}
Exemple #12
0
/* Resolve path within sysroot, calling sysroot_path on the resolved path.
 *
 * Caller must check for NULL and call reply_with_perror ("malloc/realpath")
 * if it is.  Caller must also free the string.
 *
 * See also the custom %R printf formatter which does shell quoting too.
 */
char *
sysroot_realpath (const char *path)
{
  CLEANUP_FREE char *rp = NULL;

  CHROOT_IN;
  rp = realpath (path, NULL);
  CHROOT_OUT;
  if (rp == NULL)
    return NULL;

  return sysroot_path (rp);
}
Exemple #13
0
int
do_swapoff_file (const char *path)
{
  CLEANUP_FREE char *buf = NULL;

  buf = sysroot_path (path);
  if (!buf) {
    reply_with_perror ("malloc");
    return -1;
  }

  return swaponoff ("swapoff", NULL, buf);
}
Exemple #14
0
guestfs_int_isoinfo *
do_isoinfo (const char *path)
{
  guestfs_int_isoinfo *ret;
  CLEANUP_FREE char *buf = sysroot_path (path);
  if (!buf) {
    reply_with_perror ("malloc");
    return NULL;
  }

  ret = isoinfo (buf);

  return ret;
}
Exemple #15
0
int
do_copy_file_to_device (const char *src, const char *dest,
                        int64_t srcoffset, int64_t destoffset, int64_t size,
                        int sparse)
{
  CLEANUP_FREE char *src_buf = sysroot_path (src);

  if (!src_buf) {
    reply_with_perror ("malloc");
    return -1;
  }

  return copy (src_buf, src, dest, dest, DEST_DEVICE_FLAGS, 0,
               srcoffset, destoffset, size, sparse);
}
Exemple #16
0
static int
cpmv_cmd (const char *cmd, const char *flags, const char *src, const char *dest)
{
  CLEANUP_FREE char *srcbuf = NULL, *destbuf = NULL;
  CLEANUP_FREE char *err = NULL;
  int r;

  srcbuf = sysroot_path (src);
  if (srcbuf == NULL) {
    reply_with_perror ("malloc");
    return -1;
  }

  destbuf = sysroot_path (dest);
  if (destbuf == NULL) {
    reply_with_perror ("malloc");
    return -1;
  }

  pulse_mode_start ();

  if (flags)
    r = command (NULL, &err, cmd, flags, srcbuf, destbuf, NULL);
  else
    r = command (NULL, &err, cmd, srcbuf, destbuf, NULL);

  if (r == -1) {
    pulse_mode_cancel ();
    reply_with_error ("%s", err);
    return -1;
  }

  pulse_mode_end ();

  return 0;
}
Exemple #17
0
/* While running the command, bind-mount /dev, /proc, /sys
 * into the chroot.  However we must be careful to unmount them
 * afterwards because otherwise they would interfere with
 * future mount and unmount operations.
 *
 * We deliberately allow these commands to fail silently, BUT
 * if a mount fails, don't unmount the corresponding mount.
 */
static int
bind_mount (struct bind_state *bs)
{
  int r;

  memset (bs, 0, sizeof *bs);

  bs->sysroot_dev = sysroot_path ("/dev");
  bs->sysroot_dev_pts = sysroot_path ("/dev/pts");
  bs->sysroot_proc = sysroot_path ("/proc");
  bs->sysroot_selinux = sysroot_path ("/selinux");
  bs->sysroot_sys = sysroot_path ("/sys");
  bs->sysroot_sys_fs_selinux = sysroot_path ("/sys/fs/selinux");

  if (bs->sysroot_dev == NULL || bs->sysroot_dev_pts == NULL ||
      bs->sysroot_proc == NULL || bs->sysroot_selinux == NULL ||
      bs->sysroot_sys == NULL || bs->sysroot_sys_fs_selinux == NULL) {
    reply_with_perror ("malloc");
    free (bs->sysroot_dev);
    free (bs->sysroot_dev_pts);
    free (bs->sysroot_proc);
    free (bs->sysroot_selinux);
    free (bs->sysroot_sys);
    free (bs->sysroot_sys_fs_selinux);
    return -1;
  }

  /* Note it is tempting to use --rbind here (to bind submounts).
   * However I have not found a reliable way to unmount the same set
   * of directories (umount -R does NOT work).
   */
  r = command (NULL, NULL, str_mount, "--bind", "/dev", bs->sysroot_dev, NULL);
  bs->dev_ok = r != -1;
  r = command (NULL, NULL, str_mount, "--bind", "/dev/pts", bs->sysroot_dev_pts, NULL);
  bs->dev_pts_ok = r != -1;
  r = command (NULL, NULL, str_mount, "--bind", "/proc", bs->sysroot_proc, NULL);
  bs->proc_ok = r != -1;
  /* Note on the next line we have to bind-mount /sys/fs/selinux (appliance
   * kernel) on top of /selinux (where guest is expecting selinux).
   */
  r = command (NULL, NULL, str_mount, "--bind", "/sys/fs/selinux", bs->sysroot_selinux, NULL);
  bs->selinux_ok = r != -1;
  r = command (NULL, NULL, str_mount, "--bind", "/sys", bs->sysroot_sys, NULL);
  bs->sys_ok = r != -1;
  r = command (NULL, NULL, str_mount, "--bind", "/sys/fs/selinux", bs->sysroot_sys_fs_selinux, NULL);
  bs->sys_fs_selinux_ok = r != -1;

  bs->mounted = true;

  return 0;
}
Exemple #18
0
/* Takes optional arguments, consult optargs_bitmask. */
int
do_rsync_in (const char *remote, const char *dest_orig,
             int archive, int deletedest)
{
  CLEANUP_FREE char *dest = NULL;

  dest = sysroot_path (dest_orig);
  if (!dest) {
    reply_with_perror ("malloc");
    return -1;
  }

  if (!(optargs_bitmask & GUESTFS_RSYNC_IN_ARCHIVE_BITMASK))
    archive = 0;
  if (!(optargs_bitmask & GUESTFS_RSYNC_IN_DELETEDEST_BITMASK))
    deletedest = 0;

  return rsync (remote, remote, dest, dest_orig, archive, deletedest);
}
Exemple #19
0
int
do_copy_file_to_device (const char *src, const char *dest,
                        int64_t srcoffset, int64_t destoffset, int64_t size,
                        int sparse, int append)
{
  CLEANUP_FREE char *src_buf = sysroot_path (src);

  if (!src_buf) {
    reply_with_perror ("malloc");
    return -1;
  }

  if ((optargs_bitmask & GUESTFS_COPY_FILE_TO_DEVICE_APPEND_BITMASK) &&
      append) {
    reply_with_error ("the append flag cannot be set for this call");
    return -1;
  }

  return copy (src_buf, src, dest, dest, DEST_DEVICE_FLAGS, 0,
               srcoffset, destoffset, size, sparse);
}
Exemple #20
0
int
do_mkswap_file (const char *path)
{
  CLEANUP_FREE char *buf = NULL, *err = NULL;
  int r;

  buf = sysroot_path (path);
  if (!buf) {
    reply_with_perror ("malloc");
    return -1;
  }

  r = command (NULL, &err, "mkswap", "-f", buf, NULL);

  if (r == -1) {
    reply_with_error ("%s: %s", path, err);
    return -1;
  }

  return r;
}
Exemple #21
0
int
do_scrub_freespace (const char *dir)
{
  CLEANUP_FREE char *buf = NULL;
  CLEANUP_FREE char *err = NULL;
  int r;

  /* Make the path relative to /sysroot. */
  buf = sysroot_path (dir);
  if (!buf) {
    reply_with_perror ("malloc");
    return -1;
  }

  r = command (NULL, &err, str_scrub, "-X", buf, NULL);
  if (r == -1) {
    reply_with_error ("%s: %s", dir, err);
    return -1;
  }

  return 0;
}
Exemple #22
0
int64_t
do_inotify_add_watch (const char *path, int mask)
{
  int64_t r;
  CLEANUP_FREE char *buf = NULL;

  NEED_INOTIFY (-1);

  buf = sysroot_path (path);
  if (!buf) {
    reply_with_perror ("malloc");
    return -1;
  }

  r = inotify_add_watch (inotify_fd, buf, mask);
  if (r == -1) {
    reply_with_perror ("%s", path);
    return -1;
  }

  return r;
}
Exemple #23
0
char *
do_get_e2attrs (const char *filename)
{
    int r;
    CLEANUP_FREE char *buf = NULL;
    char *out;
    CLEANUP_FREE char *err = NULL;
    size_t i, j;

    buf = sysroot_path (filename);
    if (!buf) {
        reply_with_perror ("malloc");
        return NULL;
    }

    r = command (&out, &err, str_lsattr, "-d", "--", buf, NULL);
    if (r == -1) {
        reply_with_error ("%s: %s: %s", "lsattr", filename, err);
        free (out);
        return NULL;
    }

    /* Output looks like:
     * -------------e- filename
     * Remove the dashes and return everything up to the space.
     */
    for (i = j = 0; out[j] != ' '; j++) {
        if (out[j] != '-')
            out[i++] = out[j];
    }

    out[i] = '\0';

    /* Sort the output, mainly to make testing simpler. */
    qsort (out, i, sizeof (char), compare_chars);

    return out;
}
Exemple #24
0
/* Takes optional arguments, consult optargs_bitmask. */
int
do_hivex_open (const char *filename, int verbose, int debug, int write)
{
  CLEANUP_FREE char *buf = NULL;
  int flags = 0;

  if (h) {
    hivex_close (h);
    h = NULL;
  }

  buf = sysroot_path (filename);
  if (!buf) {
    reply_with_perror ("malloc");
    return -1;
  }

  if (optargs_bitmask & GUESTFS_HIVEX_OPEN_VERBOSE_BITMASK) {
    if (verbose)
      flags |= HIVEX_OPEN_VERBOSE;
  }
  if (optargs_bitmask & GUESTFS_HIVEX_OPEN_DEBUG_BITMASK) {
    if (debug)
      flags |= HIVEX_OPEN_DEBUG;
  }
  if (optargs_bitmask & GUESTFS_HIVEX_OPEN_WRITE_BITMASK) {
    if (write)
      flags |= HIVEX_OPEN_WRITE;
  }

  h = hivex_open (buf, flags);
  if (!h) {
    reply_with_perror ("hivex failed to open %s", filename);
    return -1;
  }

  return 0;
}
Exemple #25
0
guestfs_int_xfsinfo *
do_xfs_info (const char *pathordevice)
{
  int r;
  char *buf;
  char *out = NULL, *err = NULL;
  char **lines = NULL;
  guestfs_int_xfsinfo *ret = NULL;
  int is_dev;

  is_dev = STREQLEN (pathordevice, "/dev/", 5);
  buf = is_dev ? strdup (pathordevice)
               : sysroot_path (pathordevice);
  if (buf == NULL) {
    reply_with_perror ("malloc");
    return NULL;
  }

  r = command (&out, &err, "xfs_info", buf, NULL);
  free (buf);
  if (r == -1) {
    reply_with_error ("%s", err);
    goto error;
  }

  lines = split_lines (out);
  if (lines == NULL)
    goto error;

  ret = parse_xfs_info (lines);

error:
  free (err);
  free (out);
  if (lines)
    free_strings (lines);
  return ret;
}
Exemple #26
0
char *
do_llz (const char *path)
{
  int r;
  char *out;
  CLEANUP_FREE char *err = NULL;
  CLEANUP_FREE char *spath = NULL;

  spath = sysroot_path (path);
  if (!spath) {
    reply_with_perror ("malloc");
    return NULL;
  }

  r = command (&out, &err, str_ls, "-laZ", spath, NULL);
  if (r == -1) {
    reply_with_error ("%s", err);
    free (out);
    return NULL;
  }

  return out;			/* caller frees */
}
Exemple #27
0
int
do_set_e2generation (const char *filename, int64_t generation)
{
    int r;
    CLEANUP_FREE char *buf = NULL, *err = NULL;
    char generation_str[64];

    buf = sysroot_path (filename);
    if (!buf) {
        reply_with_perror ("malloc");
        return -1;
    }

    snprintf (generation_str, sizeof generation_str,
              "%" PRIu64, (uint64_t) generation);

    r = command (NULL, &err, str_chattr, "-v", generation_str, "--", buf, NULL);
    if (r == -1) {
        reply_with_error ("%s: %s: %s", "chattr", filename, err);
        return -1;
    }

    return 0;
}
Exemple #28
0
/* Has one FileOut parameter. */
int
do_find0 (const char *dir)
{
  struct stat statbuf;
  int r;
  FILE *fp;
  char *cmd;
  char *sysrootdir;
  size_t sysrootdirlen, len;
  char str[GUESTFS_MAX_CHUNK_SIZE];

  sysrootdir = sysroot_path (dir);
  if (!sysrootdir) {
    reply_with_perror ("malloc");
    return -1;
  }

  r = stat (sysrootdir, &statbuf);
  if (r == -1) {
    reply_with_perror ("%s", dir);
    free (sysrootdir);
    return -1;
  }
  if (!S_ISDIR (statbuf.st_mode)) {
    reply_with_error ("%s: not a directory", dir);
    free (sysrootdir);
    return -1;
  }

  sysrootdirlen = strlen (sysrootdir);

  if (asprintf_nowarn (&cmd, "%s %Q -print0", str_find, sysrootdir) == -1) {
    reply_with_perror ("asprintf");
    free (sysrootdir);
    return -1;
  }
  free (sysrootdir);

  if (verbose)
    fprintf (stderr, "%s\n", cmd);

  fp = popen (cmd, "r");
  if (fp == NULL) {
    reply_with_perror ("%s", cmd);
    free (cmd);
    return -1;
  }
  free (cmd);

  /* Now we must send the reply message, before the file contents.  After
   * this there is no opportunity in the protocol to send any error
   * message back.  Instead we can only cancel the transfer.
   */
  reply (NULL, NULL);

  while ((r = input_to_nul (fp, str, GUESTFS_MAX_CHUNK_SIZE)) > 0) {
    len = strlen (str);
    if (len <= sysrootdirlen)
      continue;

    /* Remove the directory part of the path before sending it. */
    if (send_file_write (str + sysrootdirlen, r - sysrootdirlen) < 0) {
      pclose (fp);
      return -1;
    }
  }

  if (ferror (fp)) {
    perror (dir);
    send_file_end (1);                /* Cancel. */
    pclose (fp);
    return -1;
  }

  if (pclose (fp) != 0) {
    perror (dir);
    send_file_end (1);                /* Cancel. */
    return -1;
  }

  if (send_file_end (0))        /* Normal end of file. */
    return -1;

  return 0;
}
Exemple #29
0
/* Takes optional arguments, consult optargs_bitmask. */
int
do_tar_out (const char *dir, const char *compress, int numericowner,
            char *const *excludes)
{
  CLEANUP_FREE char *buf = NULL;
  struct stat statbuf;
  const char *filter;
  int r;
  FILE *fp;
  CLEANUP_FREE char *excludes_args = NULL;
  CLEANUP_FREE char *cmd = NULL;
  char buffer[GUESTFS_MAX_CHUNK_SIZE];

  if ((optargs_bitmask & GUESTFS_TAR_OUT_COMPRESS_BITMASK)) {
    if (STREQ (compress, "compress"))
      filter = " --compress";
    else if (STREQ (compress, "gzip"))
      filter = " --gzip";
    else if (STREQ (compress, "bzip2"))
      filter = " --bzip2";
    else if (STREQ (compress, "xz"))
      filter = " --xz";
    else if (STREQ (compress, "lzop"))
      filter = " --lzop";
    else {
      reply_with_error ("unknown compression type: %s", compress);
      return -1;
    }
  } else
    filter = "";

  if (!(optargs_bitmask & GUESTFS_TAR_OUT_NUMERICOWNER_BITMASK))
    numericowner = 0;

  if ((optargs_bitmask & GUESTFS_TAR_OUT_EXCLUDES_BITMASK)) {
    excludes_args = make_excludes_args (excludes);
    if (!excludes_args)
      return -1;
  } else {
    excludes_args = strdup ("");
    if (excludes_args == NULL) {
      reply_with_perror ("strdup");
      return -1;
    }
  }

  /* Check the filename exists and is a directory (RHBZ#908322). */
  buf = sysroot_path (dir);
  if (buf == NULL) {
    reply_with_perror ("malloc");
    return -1;
  }

  if (stat (buf, &statbuf) == -1) {
    reply_with_perror ("stat: %s", dir);
    return -1;
  }

  if (! S_ISDIR (statbuf.st_mode)) {
    reply_with_error ("%s: not a directory", dir);
    return -1;
  }

  /* "tar -C /sysroot%s -cf - ." but we have to quote the dir. */
  if (asprintf_nowarn (&cmd, "%s -C %s%s%s%s -cf - .",
                       str_tar,
                       buf, filter,
                       numericowner ? " --numeric-owner" : "",
                       excludes_args) == -1) {
    reply_with_perror ("asprintf");
    return -1;
  }

  if (verbose)
    fprintf (stderr, "%s\n", cmd);

  fp = popen (cmd, "r");
  if (fp == NULL) {
    reply_with_perror ("%s", cmd);
    return -1;
  }

  /* Now we must send the reply message, before the file contents.  After
   * this there is no opportunity in the protocol to send any error
   * message back.  Instead we can only cancel the transfer.
   */
  reply (NULL, NULL);

  while ((r = fread (buffer, 1, sizeof buffer, fp)) > 0) {
    if (send_file_write (buffer, r) < 0) {
      pclose (fp);
      return -1;
    }
  }

  if (ferror (fp)) {
    fprintf (stderr, "fread: %s: %m\n", dir);
    send_file_end (1);		/* Cancel. */
    pclose (fp);
    return -1;
  }

  if (pclose (fp) != 0) {
    fprintf (stderr, "pclose: %s: %m\n", dir);
    send_file_end (1);		/* Cancel. */
    return -1;
  }

  if (send_file_end (0))	/* Normal end of file. */
    return -1;

  return 0;
}
Exemple #30
0
/* Has one FileOut parameter. */
int
do_checksums_out (const char *csumtype, const char *dir)
{
  struct stat statbuf;
  int r;

  const char *program = program_of_csum (csumtype);
  if (program == NULL)
    return -1;

  CLEANUP_FREE char *sysrootdir = sysroot_path (dir);
  if (!sysrootdir) {
    reply_with_perror ("malloc");
    return -1;
  }

  r = stat (sysrootdir, &statbuf);
  if (r == -1) {
    reply_with_perror ("%s", dir);
    return -1;
  }
  if (!S_ISDIR (statbuf.st_mode)) {
    reply_with_error ("%s: not a directory", dir);
    return -1;
  }

  CLEANUP_FREE char *cmd = NULL;
  if (asprintf_nowarn (&cmd, "cd %Q && %s -type f -print0 | %s -0 %s",
                       sysrootdir, str_find, str_xargs, program) == -1) {
    reply_with_perror ("asprintf");
    return -1;
  }

  if (verbose)
    fprintf (stderr, "%s\n", cmd);

  FILE *fp = popen (cmd, "r");
  if (fp == NULL) {
    reply_with_perror ("%s", cmd);
    return -1;
  }

  /* Now we must send the reply message, before the file contents.  After
   * this there is no opportunity in the protocol to send any error
   * message back.  Instead we can only cancel the transfer.
   */
  reply (NULL, NULL);

  char str[GUESTFS_MAX_CHUNK_SIZE];

  while ((r = fread (str, 1, GUESTFS_MAX_CHUNK_SIZE, fp)) > 0) {
    if (send_file_write (str, r) < 0) {
      pclose (fp);
      return -1;
    }
  }

  if (ferror (fp)) {
    fprintf (stderr, "fread: %s: %m\n", dir);
    send_file_end (1);                /* Cancel. */
    pclose (fp);
    return -1;
  }

  if (pclose (fp) != 0) {
    fprintf (stderr, "pclose: %s: %m\n", dir);
    send_file_end (1);                /* Cancel. */
    return -1;
  }

  if (send_file_end (0))        /* Normal end of file. */
    return -1;

  return 0;
}