Esempio n. 1
0
/* Run a diff on two files. */
static void
diff (struct file *file1, guestfs_h *g1, struct file *file2, guestfs_h *g2)
{
    CLEANUP_FREE char *tmpdir = guestfs_get_tmpdir (g1);
    CLEANUP_FREE char *tmpd, *tmpda = NULL, *tmpdb = NULL, *cmd = NULL;
    int r;

    assert (is_reg (file1->stat->st_mode));
    assert (is_reg (file2->stat->st_mode));

    if (asprintf (&tmpd, "%s/virtdiffXXXXXX", tmpdir) < 0) {
        perror ("asprintf");
        exit (EXIT_FAILURE);
    }
    if (mkdtemp (tmpd) == NULL) {
        perror ("mkdtemp");
        exit (EXIT_FAILURE);
    }

    if (asprintf (&tmpda, "%s/a", tmpd) < 0 ||
            asprintf (&tmpdb, "%s/b", tmpd) < 0) {
        perror ("asprintf");
        exit (EXIT_FAILURE);
    }

    if (guestfs_download (g1, file1->path, tmpda) == -1)
        goto out;
    if (guestfs_download (g2, file2->path, tmpdb) == -1)
        goto out;

    /* Note that the tmpdir is safe, and the rest of the path
     * should not need quoting.
     */
    if (asprintf (&cmd, "diff -u '%s' '%s' | tail -n +3", tmpda, tmpdb) < 0) {
        perror ("asprintf");
        exit (EXIT_FAILURE);
    }

    if (verbose)
        fprintf (stderr, "%s\n", cmd);
    r = system (cmd);
    if (!WIFEXITED (r) || WEXITSTATUS (r) != 0) {
        fprintf (stderr, _("%s: external diff command failed\n"), guestfs_int_program_name);
        goto out;
    }

    printf ("@@ %s @@\n", _("End of diff"));

out:
    unlink (tmpda);
    unlink (tmpdb);
    rmdir (tmpd);
}
Esempio n. 2
0
char *
guestfs_impl_read_file (guestfs_h *g, const char *path, size_t *size_r)
{
  int fd = -1;
  size_t size;
  CLEANUP_UNLINK_FREE char *tmpfile = NULL;
  char *ret = NULL;
  struct stat statbuf;

  tmpfile = guestfs_int_make_temp_path (g, "cat", NULL);
  if (tmpfile == NULL)
    goto err;

  if (guestfs_download (g, path, tmpfile) == -1)
    goto err;

  fd = open (tmpfile, O_RDONLY|O_CLOEXEC);
  if (fd == -1) {
    perrorf (g, "open: %s", tmpfile);
    goto err;
  }

  /* Read the whole file into memory. */
  if (fstat (fd, &statbuf) == -1) {
    perrorf (g, "stat: %s", tmpfile);
    goto err;
  }

  /* Don't use safe_malloc, because we want to return an errno to the caller. */
  size = statbuf.st_size;
  ret = malloc (size + 1);
  if (!ret) {
    perrorf (g, "malloc: %zu bytes", size + 1);
    goto err;
  }

  if (full_read (fd, ret, size) != size) {
    perrorf (g, "full-read: %s: %zu bytes", tmpfile, size + 1);
    goto err;
  }

  ret[size] = '\0';

  if (close (fd) == -1) {
    perrorf (g, "close: %s", tmpfile);
    goto err;
  }

  /* Mustn't touch *size_r until we are sure that we won't return any
   * error (RHBZ#589039).
   */
  *size_r = size;
  return ret;

 err:
  free (ret);
  if (fd >= 0)
    close (fd);
  return NULL;
}
Esempio n. 3
0
/* Download a guest file to a local temporary file.  The file is
 * cached in the temporary directory, and is not downloaded again.
 *
 * The name of the temporary (downloaded) file is returned.  The
 * caller must free the pointer, but does *not* need to delete the
 * temporary file.  It will be deleted when the handle is closed.
 *
 * Refuse to download the guest file if it is larger than max_size.
 * On this and other errors, NULL is returned.
 *
 * There is actually one cache per 'struct inspect_fs *' in order
 * to handle the case of multiple roots.
 */
char *
guestfs___download_to_tmp (guestfs_h *g, struct inspect_fs *fs,
                           const char *filename,
                           const char *basename, uint64_t max_size)
{
    char *r;
    int fd;
    char devfd[32];
    int64_t size;

    /* Make the basename unique by prefixing it with the fs number.
     * This also ensures there is one cache per filesystem.
     */
    if (asprintf (&r, "%s/%td-%s", g->tmpdir, fs - g->fses, basename) == -1) {
        perrorf (g, "asprintf");
        return NULL;
    }

    /* If the file has already been downloaded, return. */
    if (access (r, R_OK) == 0)
        return r;

    /* Check size of remote file. */
    size = guestfs_filesize (g, filename);
    if (size == -1)
        /* guestfs_filesize failed and has already set error in handle */
        goto error;
    if ((uint64_t) size > max_size) {
        error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"),
               filename, size);
        goto error;
    }

    fd = open (r, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY|O_CLOEXEC, 0600);
    if (fd == -1) {
        perrorf (g, "open: %s", r);
        goto error;
    }

    snprintf (devfd, sizeof devfd, "/dev/fd/%d", fd);

    if (guestfs_download (g, filename, devfd) == -1) {
        unlink (r);
        close (fd);
        goto error;
    }

    if (close (fd) == -1) {
        perrorf (g, "close: %s", r);
        unlink (r);
        goto error;
    }

    return r;

error:
    free (r);
    return NULL;
}
Esempio n. 4
0
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;
}
Esempio n. 5
0
/* For Windows >= Vista, if evtxdump.py is installed then we can
 * use it to dump the System.evtx log.
 */
static int
do_log_windows_evtx (void)
{
  CLEANUP_FREE char *filename = NULL;
  CLEANUP_FREE char *tmpdir = guestfs_get_tmpdir (g);
  CLEANUP_UNLINK_FREE char *localfile = NULL;
  CLEANUP_FREE char *cmd = NULL;
  char dev_fd[64];
  int fd, status;

  if (system ("evtxdump.py -h >/dev/null 2>&1") != 0) {
    fprintf (stderr, _("%s: you need to install 'evtxdump.py' (from the python-evtx package)\n"
                       "in order to parse Windows Event Logs.  If you cannot install this, then\n"
                       "use virt-copy-out(1) to copy the contents of /Windows/System32/winevt/Logs\n"
                       "from this guest, and examine in a binary file viewer.\n"),
             guestfs_int_program_name);
    return -1;
  }

  /* Check if System.evtx exists.  XXX Allow the filename to be
   * configurable, since there are many logs.
   */
  filename = guestfs_case_sensitive_path (g, "/Windows/System32/winevt/Logs/System.evtx");
  if (filename == NULL)
    return -1;

  /* Note that guestfs_case_sensitive_path does NOT check for existence. */
  if (guestfs_is_file_opts (g, filename,
                            GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1,
                            -1) <= 0) {
    fprintf (stderr, _("%s: Windows Event Log file (%s) not found\n"),
             guestfs_int_program_name, filename);
    return -1;
  }

  /* Download the file to a temporary.  Python-evtx wants to mmap
   * the file so we cannot use a pipe.
   */
  if (asprintf (&localfile, "%s/virtlogXXXXXX", tmpdir) == -1) {
    perror ("asprintf");
    return -1;
  }
  if ((fd = mkstemp (localfile)) == -1) {
    perror ("mkstemp");
    return -1;
  }

  snprintf (dev_fd, sizeof dev_fd, "/dev/fd/%d", fd);

  if (guestfs_download (g, filename, dev_fd) == -1)
    return -1;
  close (fd);

  /* This should be safe as long as $TMPDIR is not set to something wild. */
  if (asprintf (&cmd, "evtxdump.py '%s'", localfile) == -1) {
    perror ("asprintf");
    return -1;
  }

  status = system (cmd);
  if (status) {
    char buf[256];
    fprintf (stderr, "%s: %s\n",
             guestfs_int_program_name,
             guestfs_int_exit_status_to_string (status, "evtxdump.py",
                                                buf, sizeof buf));
    return -1;
  }

  return 0;
}
Esempio n. 6
0
static int
do_log_text_file (const char *filename)
{
  return guestfs_download (g, filename, "/dev/stdout");
}
Esempio n. 7
0
static void
edit (const char *filename, const char *root)
{
  char *filename_to_free = NULL;
  const char *tmpdir = guestfs_tmpdir ();
  char tmpfile[strlen (tmpdir) + 32];
  sprintf (tmpfile, "%s/virteditXXXXXX", tmpdir);
  int fd;
  char fdbuf[32];
  char *upload_from = NULL;
  char *newname = NULL;
  char *backupname = NULL;

  /* Windows?  Special handling is required. */
  if (is_windows (g, root))
    filename = filename_to_free = windows_path (g, root, filename);

  /* Download the file to a temporary. */
  fd = mkstemp (tmpfile);
  if (fd == -1) {
    perror ("mkstemp");
    exit (EXIT_FAILURE);
  }

  snprintf (fdbuf, sizeof fdbuf, "/dev/fd/%d", fd);

  if (guestfs_download (g, filename, fdbuf) == -1)
    goto error;

  if (close (fd) == -1) {
    perror (tmpfile);
    goto error;
  }

  if (!perl_expr)
    upload_from = edit_interactively (tmpfile);
  else
    upload_from = edit_non_interactively (tmpfile);

  /* We don't always need to upload: upload_from could be NULL because
   * the user closed the editor without changing the file.
   */
  if (upload_from) {
    /* Upload to a new file in the same directory, so if it fails we
     * don't end up with a partially written file.  Give the new file
     * a completely random name so we have only a tiny chance of
     * overwriting some existing file.
     */
    newname = generate_random_name (filename);

    if (guestfs_upload (g, upload_from, newname) == -1)
      goto error;

    /* Backup or overwrite the file. */
    if (backup_extension) {
      backupname = generate_backup_name (filename);
      if (guestfs_mv (g, filename, backupname) == -1)
        goto error;
    }
    if (guestfs_mv (g, newname, filename) == -1)
      goto error;
  }

  unlink (tmpfile);
  free (filename_to_free);
  free (upload_from);
  free (newname);
  free (backupname);
  return;

 error:
  unlink (tmpfile);
  exit (EXIT_FAILURE);
}
Esempio n. 8
0
int
run_edit (const char *cmd, size_t argc, char *argv[])
{
  CLEANUP_FREE char *tmpdir = guestfs_get_tmpdir (g);
  CLEANUP_UNLINK_FREE char *filename = NULL;
  char buf[256];
  const char *editor;
  CLEANUP_FREE char *remotefilename = NULL, *newname = NULL;
  struct stat oldstat, newstat;
  int r, fd;

  if (argc != 1) {
    fprintf (stderr, _("use '%s filename' to edit a file\n"), cmd);
    return -1;
  }

  /* Choose an editor. */
  if (STRCASEEQ (cmd, "vi"))
    editor = "vi";
  else if (STRCASEEQ (cmd, "emacs"))
    editor = "emacs -nw";
  else {
    editor = getenv ("EDITOR");
    if (editor == NULL)
      editor = "vi"; /* could be cruel here and choose ed(1) */
  }

  /* Handle 'win:...' prefix. */
  remotefilename = win_prefix (argv[0]);
  if (remotefilename == NULL)
    return -1;

  /* Download the file and write it to a temporary. */
  if (asprintf (&filename, "%s/guestfishXXXXXX", tmpdir) == -1) {
    perror ("asprintf");
    return -1;
  }

  fd = mkstemp (filename);
  if (fd == -1) {
    perror ("mkstemp");
    return -1;
  }

  snprintf (buf, sizeof buf, "/dev/fd/%d", fd);

  if (guestfs_download (g, remotefilename, buf) == -1) {
    close (fd);
    return -1;
  }

  if (close (fd) == -1) {
    perror (filename);
    return -1;
  }

  /* Get the old stat. */
  if (stat (filename, &oldstat) == -1) {
    perror (filename);
    return -1;
  }

  /* Edit it. */
  /* XXX Safe? */
  snprintf (buf, sizeof buf, "%s %s", editor, filename);

  r = system (buf);
  if (r != 0) {
    perror (buf);
    return -1;
  }

  /* Get the new stat. */
  if (stat (filename, &newstat) == -1) {
    perror (filename);
    return -1;
  }

  /* Changed? */
  if (oldstat.st_ctime == newstat.st_ctime &&
      oldstat.st_size == newstat.st_size)
    return 0;

  /* Upload to a new file in the same directory, so if it fails we
   * don't end up with a partially written file.  Give the new file
   * a completely random name so we have only a tiny chance of
   * overwriting some existing file.
   */
  newname = generate_random_name (remotefilename);
  if (!newname)
    return -1;

  /* Write new content. */
  if (guestfs_upload (g, filename, newname) == -1)
    return -1;

  /* Set the permissions, UID, GID and SELinux context of the new
   * file to match the old file (RHBZ#788641).
   */
  if (guestfs_copy_attributes (g, remotefilename, newname,
      GUESTFS_COPY_ATTRIBUTES_ALL, 1, -1) == -1)
    return -1;

  if (guestfs_mv (g, newname, remotefilename) == -1)
    return -1;

  return 0;
}
Esempio n. 9
0
static void
test_virtio_serial (void)
{
  int fd, r, eh;
  char tmpfile[] = "/tmp/speedtestXXXXXX";
  struct sigaction sa, old_sa;

  if (!virtio_serial_upload && !virtio_serial_download)
    return;

  /* Create a sparse file.  We could upload from /dev/zero, but we
   * won't get progress messages because libguestfs tests if the
   * source file is a regular file.
   */
  fd = mkstemp (tmpfile);
  if (fd == -1)
    error (EXIT_FAILURE, errno, "mkstemp: %s", tmpfile);
  if (ftruncate (fd, TEST_SERIAL_MAX_SIZE) == -1)
    error (EXIT_FAILURE, errno, "ftruncate");
  if (close (fd) == -1)
    error (EXIT_FAILURE, errno, "close");

  g = guestfs_create ();
  if (!g)
    error (EXIT_FAILURE, errno, "guestfs_create");

  if (guestfs_add_drive_scratch (g, INT64_C (100*1024*1024), -1) == -1)
    exit (EXIT_FAILURE);

  if (guestfs_launch (g) == -1)
    exit (EXIT_FAILURE);

  /* Make and mount a filesystem which will be used by the download test. */
  if (guestfs_mkfs (g, "ext4", "/dev/sda") == -1)
    exit (EXIT_FAILURE);
  if (guestfs_mount (g, "/dev/sda", "/") == -1)
    exit (EXIT_FAILURE);

  /* Time out the upload after TEST_SERIAL_MAX_TIME seconds have passed. */
  memset (&sa, 0, sizeof sa);
  sa.sa_handler = stop_transfer;
  sa.sa_flags = SA_RESTART;
  sigaction (SIGALRM, &sa, &old_sa);

  /* Get progress messages, which will tell us how much data has been
   * transferred.
   */
  eh = guestfs_set_event_callback (g, progress_cb, GUESTFS_EVENT_PROGRESS,
                                   0, NULL);
  if (eh == -1)
    exit (EXIT_FAILURE);

  if (virtio_serial_upload) {
    gettimeofday (&start, NULL);
    rate = -1;
    operation = "upload";
    alarm (max_time_override > 0 ? max_time_override : TEST_SERIAL_MAX_TIME);

    /* For the upload test, upload the sparse file to /dev/null in the
     * appliance.  Hopefully this is mostly testing just virtio-serial.
     */
    guestfs_push_error_handler (g, NULL, NULL);
    r = guestfs_upload (g, tmpfile, "/dev/null");
    alarm (0);
    unlink (tmpfile);
    guestfs_pop_error_handler (g);

    /* It's possible that the upload will finish before the alarm fires,
     * or that the upload will be stopped by the alarm.
     */
    if (r == -1 && guestfs_last_errno (g) != EINTR) {
      fprintf (stderr,
               "%s: expecting upload command to return EINTR\n%s\n",
               guestfs_int_program_name, guestfs_last_error (g));
      exit (EXIT_FAILURE);
    }

    if (rate == -1) {
    rate_error:
      fprintf (stderr, "%s: internal error: progress callback was not called! (r=%d, errno=%d)\n",
               guestfs_int_program_name,
               r, guestfs_last_errno (g));
      exit (EXIT_FAILURE);
    }

    print_rate ("virtio-serial upload rate:", rate);
  }

  if (virtio_serial_download) {
    /* For the download test, download a sparse file within the
     * appliance to /dev/null on the host.
     */
    if (guestfs_touch (g, "/sparse") == -1)
      exit (EXIT_FAILURE);
    if (guestfs_truncate_size (g, "/sparse", TEST_SERIAL_MAX_SIZE) == -1)
      exit (EXIT_FAILURE);

    gettimeofday (&start, NULL);
    rate = -1;
    operation = "download";
    alarm (max_time_override > 0 ? max_time_override : TEST_SERIAL_MAX_TIME);
    guestfs_push_error_handler (g, NULL, NULL);
    r = guestfs_download (g, "/sparse", "/dev/null");
    alarm (0);
    guestfs_pop_error_handler (g);

    if (r == -1 && guestfs_last_errno (g) != EINTR) {
      fprintf (stderr,
               "%s: expecting download command to return EINTR\n%s\n",
               guestfs_int_program_name, guestfs_last_error (g));
      exit (EXIT_FAILURE);
    }

    if (rate == -1)
      goto rate_error;

    print_rate ("virtio-serial download rate:", rate);
  }

  if (guestfs_shutdown (g) == -1)
    exit (EXIT_FAILURE);

  guestfs_close (g);

  /* Restore SIGALRM signal handler. */
  sigaction (SIGALRM, &old_sa, NULL);
}
Esempio n. 10
0
int
run_more (const char *cmd, size_t argc, char *argv[])
{
  CLEANUP_FREE char *tmpdir = guestfs_get_tmpdir (g);
  CLEANUP_UNLINK_FREE char *filename = NULL;
  char buf[256];
  CLEANUP_FREE char *remote = NULL;
  const char *pager;
  int r, fd;

  if (argc != 1) {
    fprintf (stderr, _("use '%s filename' to page a file\n"), cmd);
    return -1;
  }

  /* Choose a pager. */
  if (STRCASEEQ (cmd, "less"))
    pager = "less";
  else {
    pager = getenv ("PAGER");
    if (pager == NULL)
      pager = "more";
  }

  /* Allow win:... prefix on remote. */
  remote = win_prefix (argv[0]);
  if (remote == NULL)
    return -1;

  /* Download the file and write it to a temporary. */
  if (asprintf (&filename, "%s/guestfishXXXXXX", tmpdir) == -1) {
    perror ("asprintf");
    return -1;
  }

  fd = mkstemp (filename);
  if (fd == -1) {
    perror ("mkstemp");
    return -1;
  }

  snprintf (buf, sizeof buf, "/dev/fd/%d", fd);

  if (guestfs_download (g, remote, buf) == -1) {
    close (fd);
    return -1;
  }

  if (close (fd) == -1) {
    perror (filename);
    return -1;
  }

  /* View it. */
  /* XXX Safe? */
  snprintf (buf, sizeof buf, "%s %s", pager, filename);

  r = system (buf);
  if (r != 0) {
    perror (buf);
    return -1;
  }

  return 0;
}
Esempio n. 11
0
int
run_more (const char *cmd, size_t argc, char *argv[])
{
  TMP_TEMPLATE_ON_STACK (filename);
  char buf[256];
  char *remote;
  const char *pager;
  int r, fd;

  if (argc != 1) {
    fprintf (stderr, _("use '%s filename' to page a file\n"), cmd);
    return -1;
  }

  /* Choose a pager. */
  if (STRCASEEQ (cmd, "less"))
    pager = "less";
  else {
    pager = getenv ("PAGER");
    if (pager == NULL)
      pager = "more";
  }

  remote = argv[0];

  /* Allow win:... prefix on remote. */
  remote = win_prefix (remote);
  if (remote == NULL)
    return -1;

  /* Download the file and write it to a temporary. */
  fd = mkstemp (filename);
  if (fd == -1) {
    perror ("mkstemp");
    free (remote);
    return -1;
  }

  snprintf (buf, sizeof buf, "/dev/fd/%d", fd);

  if (guestfs_download (g, remote, buf) == -1) {
    close (fd);
    unlink (filename);
    free (remote);
    return -1;
  }

  if (close (fd) == -1) {
    perror (filename);
    unlink (filename);
    free (remote);
    return -1;
  }

  /* View it. */
  /* XXX Safe? */
  snprintf (buf, sizeof buf, "%s %s", pager, filename);

  r = system (buf);
  unlink (filename);
  if (r != 0) {
    perror (buf);
    free (remote);
    return -1;
  }

  free (remote);
  return 0;
}
Esempio n. 12
0
int
run_display (const char *cmd, size_t argc, char *argv[])
{
  TMP_TEMPLATE_ON_STACK (filename);
  char *remote;
  const char *display;
  char buf[256];
  int r, fd;

  if (argc != 1) {
    fprintf (stderr, _("display filename\n"));
    return -1;
  }

  /* Choose a display command. */
  display = getenv ("GUESTFISH_DISPLAY_IMAGE");
  if (display == NULL)
    display = "display";

  remote = argv[0];

  /* Allow win:... prefix on remote. */
  remote = win_prefix (remote);
  if (remote == NULL)
    return -1;

  /* Download the file and write it to a temporary. */
  fd = mkstemp (filename);
  if (fd == -1) {
    perror ("mkstemp");
    free (remote);
    return -1;
  }

  snprintf (buf, sizeof buf, "/dev/fd/%d", fd);

  if (guestfs_download (g, remote, buf) == -1) {
    close (fd);
    unlink (filename);
    free (remote);
    return -1;
  }

  if (close (fd) == -1) {
    perror (filename);
    unlink (filename);
    free (remote);
    return -1;
  }

  /* View it. */
  snprintf (buf, sizeof buf, "%s %s", display, filename);

  r = system (buf);
  unlink (filename);
  if (r != 0) {
    perror (buf);
    free (remote);
    return -1;
  }

  free (remote);
  return 0;
}
Esempio n. 13
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;
}
Esempio n. 14
0
int
run_display (const char *cmd, size_t argc, char *argv[])
{
  CLEANUP_FREE char *tmpdir = guestfs_get_tmpdir (g), *filename = NULL;
  CLEANUP_FREE char *remote = NULL;
  const char *display;
  char buf[256];
  int r, fd;

  if (argc != 1) {
    fprintf (stderr, _("display filename\n"));
    return -1;
  }

  /* Choose a display command. */
  display = getenv ("GUESTFISH_DISPLAY_IMAGE");
  if (display == NULL)
    display = "display";

  /* Allow win:... prefix on remote. */
  remote = win_prefix (argv[0]);
  if (remote == NULL)
    return -1;

  /* Download the file and write it to a temporary. */
  if (asprintf (&filename, "%s/guestfishXXXXXX", tmpdir) == -1) {
    perror ("asprintf");
    return -1;
  }

  fd = mkstemp (filename);
  if (fd == -1) {
    perror ("mkstemp");
    return -1;
  }

  snprintf (buf, sizeof buf, "/dev/fd/%d", fd);

  if (guestfs_download (g, remote, buf) == -1) {
    close (fd);
    unlink (filename);
    return -1;
  }

  if (close (fd) == -1) {
    perror (filename);
    unlink (filename);
    return -1;
  }

  /* View it. */
  snprintf (buf, sizeof buf, "%s %s", display, filename);

  r = system (buf);
  unlink (filename);
  if (r != 0) {
    perror (buf);
    return -1;
  }

  return 0;
}
Esempio n. 15
0
int
main (int argc, char *argv[])
{
  /* Set global program name that is not polluted with libtool artifacts.  */
  set_program_name (argv[0]);

  setlocale (LC_ALL, "");
  bindtextdomain (PACKAGE, LOCALEBASEDIR);
  textdomain (PACKAGE);

  enum { HELP_OPTION = CHAR_MAX + 1 };

  static const char *options = "a:c:d:vVx";
  static const struct option long_options[] = {
    { "add", 1, 0, 'a' },
    { "connect", 1, 0, 'c' },
    { "domain", 1, 0, 'd' },
    { "echo-keys", 0, 0, 0 },
    { "format", 2, 0, 0 },
    { "help", 0, 0, HELP_OPTION },
    { "keys-from-stdin", 0, 0, 0 },
    { "verbose", 0, 0, 'v' },
    { "version", 0, 0, 'V' },
    { 0, 0, 0, 0 }
  };
  struct drv *drvs = NULL;
  struct drv *drv;
  const char *format = NULL;
  int c;
  int option_index;

  g = guestfs_create ();
  if (g == NULL) {
    fprintf (stderr, _("guestfs_create: failed to create handle\n"));
    exit (EXIT_FAILURE);
  }

  argv[0] = bad_cast (program_name);

  for (;;) {
    c = getopt_long (argc, argv, options, long_options, &option_index);
    if (c == -1) break;

    switch (c) {
    case 0:			/* options which are long only */
      if (STREQ (long_options[option_index].name, "keys-from-stdin")) {
        keys_from_stdin = 1;
      } else if (STREQ (long_options[option_index].name, "echo-keys")) {
        echo_keys = 1;
      } else if (STREQ (long_options[option_index].name, "format")) {
        if (!optarg || STREQ (optarg, ""))
          format = NULL;
        else
          format = optarg;
      } else {
        fprintf (stderr, _("%s: unknown long option: %s (%d)\n"),
                 program_name, long_options[option_index].name, option_index);
        exit (EXIT_FAILURE);
      }
      break;

    case 'a':
      OPTION_a;
      break;

    case 'c':
      OPTION_c;
      break;

    case 'd':
      OPTION_d;
      break;

    case 'v':
      OPTION_v;
      break;

    case 'V':
      OPTION_V;
      break;

    case 'x':
      OPTION_x;
      break;

    case HELP_OPTION:
      usage (EXIT_SUCCESS);

    default:
      usage (EXIT_FAILURE);
    }
  }

  /* Old-style syntax?  There were no -a or -d options in the old
   * virt-cat which is how we detect this.
   */
  if (drvs == NULL) {
    /* argc - 1 because last parameter is the single filename. */
    while (optind < argc - 1) {
      if (strchr (argv[optind], '/') ||
          access (argv[optind], F_OK) == 0) { /* simulate -a option */
        drv = calloc (1, sizeof (struct drv));
        if (!drv) {
          perror ("malloc");
          exit (EXIT_FAILURE);
        }
        drv->type = drv_a;
        drv->a.filename = argv[optind];
        drv->next = drvs;
        drvs = drv;
      } else {                  /* simulate -d option */
        drv = calloc (1, sizeof (struct drv));
        if (!drv) {
          perror ("malloc");
          exit (EXIT_FAILURE);
        }
        drv->type = drv_d;
        drv->d.guest = argv[optind];
        drv->next = drvs;
        drvs = drv;
      }

      optind++;
    }
  }

  /* These are really constants, but they have to be variables for the
   * options parsing code.  Assert here that they have known-good
   * values.
   */
  assert (read_only == 1);
  assert (inspector == 1);
  assert (live == 0);

  /* User must specify at least one filename on the command line. */
  if (optind >= argc || argc - optind < 1)
    usage (EXIT_FAILURE);

  /* User must have specified some drives. */
  if (drvs == NULL)
    usage (EXIT_FAILURE);

  /* Add drives, inspect and mount.  Note that inspector is always true,
   * and there is no -m option.
   */
  add_drives (drvs, 'a');

  if (guestfs_launch (g) == -1)
    exit (EXIT_FAILURE);

  inspect_mount ();

  /* Free up data structures, no longer needed after this point. */
  free_drives (drvs);

  unsigned errors = 0;
  int windows;
  char *root, **roots;

  /* Get root mountpoint.  See: fish/inspect.c:inspect_mount */
  roots = guestfs_inspect_get_roots (g);
  assert (roots);
  assert (roots[0] != NULL);
  assert (roots[1] == NULL);
  root = roots[0];
  free (roots);

  /* Windows?  Special handling is required. */
  windows = is_windows (g, root);

  for (; optind < argc; optind++) {
    char *filename_to_free = NULL;
    const char *filename = argv[optind];

    if (windows) {
      filename = filename_to_free = windows_path (g, root, filename);
      if (filename == NULL) {
        errors++;
        continue;
      }
    }

    if (guestfs_download (g, filename, "/dev/stdout") == -1)
      errors++;

    free (filename_to_free);
  }

  free (root);

  guestfs_close (g);

  exit (errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
Esempio n. 16
0
static char *
cpio_arch (guestfs_h *g, const char *file, const char *path)
{
  CLEANUP_FREE char *tmpdir = guestfs_get_tmpdir (g), *dir = NULL;
  CLEANUP_FREE char *initrd = NULL;
  CLEANUP_CMD_CLOSE struct command *cmd = guestfs___new_command (g);
  char *ret = NULL;
  const char *method;
  int64_t size;
  int r;
  size_t i;

  if (asprintf (&dir, "%s/libguestfsXXXXXX", tmpdir) == -1) {
    perror ("asprintf");
    return NULL;
  }

  if (strstr (file, "gzip"))
    method = "zcat";
  else if (strstr (file, "bzip2"))
    method = "bzcat";
  else
    method = "cat";

  /* Security: Refuse to download initrd if it is huge. */
  size = guestfs_filesize (g, path);
  if (size == -1 || size > 100000000) {
    error (g, _("size of %s unreasonable (%" PRIi64 " bytes)"),
           path, size);
    goto out;
  }

  if (mkdtemp (dir) == NULL) {
    perrorf (g, "mkdtemp");
    goto out;
  }

  initrd = safe_asprintf (g, "%s/initrd", dir);
  if (guestfs_download (g, path, initrd) == -1)
    goto out;

  /* Construct a command to extract named binaries from the initrd file. */
  guestfs___cmd_add_string_unquoted (cmd, "cd ");
  guestfs___cmd_add_string_quoted   (cmd, dir);
  guestfs___cmd_add_string_unquoted (cmd, " && ");
  guestfs___cmd_add_string_unquoted (cmd, method);
  guestfs___cmd_add_string_unquoted (cmd, " initrd | cpio --quiet -id");
  for (i = 0; initrd_binaries[i] != NULL; ++i) {
    guestfs___cmd_add_string_unquoted (cmd, " ");
    guestfs___cmd_add_string_quoted (cmd, initrd_binaries[i]);
  }

  r = guestfs___cmd_run (cmd);
  if (r == -1)
    goto out;
  if (!WIFEXITED (r) || WEXITSTATUS (r) != 0) {
    guestfs___external_command_failed (g, r, "cpio", path);
    goto out;
  }

  for (i = 0; initrd_binaries[i] != NULL; ++i) {
    CLEANUP_FREE char *bin =
      safe_asprintf (g, "%s/%s", dir, initrd_binaries[i]);

    if (is_regular_file (bin)) {
      int flags = g->verbose ? MAGIC_DEBUG : 0;
      flags |= MAGIC_ERROR | MAGIC_RAW;

      magic_t m = magic_open (flags);
      if (m == NULL) {
        perrorf (g, "magic_open");
        goto out;
      }

      if (magic_load (m, NULL) == -1) {
        perrorf (g, "magic_load: default magic database file");
        magic_close (m);
        goto out;
      }

      const char *line = magic_file (m, bin);
      if (line == NULL) {
        perrorf (g, "magic_file: %s", bin);
        magic_close (m);
        goto out;
      }

      CLEANUP_FREE char *elf_arch = match1 (g, line, re_file_elf);
      if (elf_arch != NULL) {
        ret = canonical_elf_arch (g, elf_arch);
        magic_close (m);
        goto out;
      }
      magic_close (m);
    }
  }
  error (g, "file_architecture: could not determine architecture of cpio archive");

 out:
  guestfs___recursive_remove_dir (g, dir);

  return ret;
}