Tag Archives: api

Tip: libguestfs API: Get the mounted device from a path

This useful libguestfs API tip shows you how to get the device name that contains a mounted path. You can use this if you want to find out the filesystem type of a path (eg. is this directory mounted on ext4?).

What you do is call guestfs_mountpoints which returns a hash of device name to mount point, eg:

/dev/sda1 -> /boot
/dev/sda2 -> /
/dev/sda3 -> /usr

Then compare the pathname (“/boot/grub”) to each entry in the hash. If the mountpoint is a string prefix of the path, give this entry a score which is the length of the mountpoint string. If it is not a prefix, give the entry a score 0. So:

/dev/sda1 -> /boot (score: 5)
/dev/sda2 -> / (score: 1)
/dev/sda3 -> /usr (score: 0)

Then sort the entries to pick the highest score. If the hash is empty or the highest score is 0, then return an error, otherwise return the device with the highest score.

Here is the code to implement this in OCaml:

open Printf
open ExtString
open ExtList

let get_mounted_device g path =
  let mps = g#mountpoints () in
  let mps = List.map (
    fun (dev, mp) ->
      if String.starts_with path mp then
        dev, String.length mp
      else
        dev, 0
  ) mps in
  let cmp (_,n1) (_,n2) = compare n2 n1 in
  let mps = List.sort ~cmp mps in
  match mps with
  | [] ->
      invalid_arg (sprintf "%s: not mounted" path)
  | (_,0) :: _ ->
      invalid_arg (sprintf "%s: not found on any filesystem" path)
  | (dev,_) :: _ -> dev

To answer the question “is this directory mounted on ext4?” you would then call guestfs_vfs_type on the result of this, eg:

if g#vfs_type (get_mounted_device g "/boot/grub") = "ext4" then
  (* do something based on ext4 *)

Leave a comment

Filed under Uncategorized

Example: using the libguestfs API from C

I spent about the last 18 hours contributing a section on libguestfs to the RHEL 6 Virtualization Guide. There is precisely zero in the guide at the moment on this subject, but hopefully there will be lots when RHEL 6.1 is released.

You might have forgotten that libguestfs is really a C library that just happens to have a lot of high level wrappers around it. But you can use the C API directly and (for a C API) it’s not too hard.

Below is the example that will appear in the Virtualization Guide next year. You can compile and run the program by saving it to a file test.c and typing:

gcc -Wall test.c -o test -lguestfs
./test

After you run it, there will be a disk image in the current directory called disk.img which you can view using guestfish:

guestfish -a disk.img -m /dev/sda1

For more information about the libguestfs C API, read the API overview section of the documentation.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <guestfs.h>

int                                                                            
main (int argc, char *argv[])
{
  guestfs_h *g;
  size_t i;

  g = guestfs_create ();
  if (g == NULL) {
    perror ("failed to create libguestfs handle");
    exit (EXIT_FAILURE);
 }

  /* Create a raw-format sparse disk image, 512 MB in size. */
  int fd = open ("disk.img", O_CREAT|O_WRONLY|O_TRUNC|O_NOCTTY, 0666);
  if (fd == -1) {
    perror ("disk.img");
    exit (EXIT_FAILURE);
  }
  if (ftruncate (fd, 512 * 1024 * 1024) == -1) {
    perror ("disk.img: truncate");
    exit (EXIT_FAILURE);
  }
  if (close (fd) == -1) {
    perror ("disk.img: close");
    exit (EXIT_FAILURE);
  }

  /* Set the trace flag so that we can see each libguestfs call. */
  guestfs_set_trace (g, 1);

  /* Set the autosync flag so that the disk will be synchronized
   * automatically when the libguestfs handle is closed.
   */
  guestfs_set_autosync (g, 1);

  /* Add the disk image to libguestfs. */
  if (guestfs_add_drive_opts (g, "disk.img",
        GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", /* raw format */
        GUESTFS_ADD_DRIVE_OPTS_READONLY, 0, /* for write */
        -1) /* this marks end of optional arguments */
      == -1)
    exit (EXIT_FAILURE);

  /* Run the libguestfs back-end. */
  if (guestfs_launch (g) == -1)
    exit (EXIT_FAILURE);

  /* Get the list of devices.  Because we only added one drive
   * above, we expect that this list should contain a single
   * element.
   */
  char **devices = guestfs_list_devices (g);
  if (devices == NULL)
    exit (EXIT_FAILURE);
  if (devices[0] == NULL || devices[1] != NULL) {
    fprintf (stderr, "error: expected a single device from list-devices\n");
    exit (EXIT_FAILURE);
  }

  /* Partition the disk as one single MBR partition. */
  if (guestfs_part_disk (g, devices[0], "mbr") == -1)
    exit (EXIT_FAILURE);

  /* Get the list of partitions.  We expect a single element, which
   * is the partition we have just created.
   */
  char **partitions = guestfs_list_partitions (g);
  if (partitions == NULL)
    exit (EXIT_FAILURE);
  if (partitions[0] == NULL || partitions[1] != NULL) {
    fprintf (stderr, "error: expected a single partition from list-partitions\n");
    exit (EXIT_FAILURE);
  }

  /* Create a filesystem on the partition. */
  if (guestfs_mkfs (g, "ext4", partitions[0]) == -1)
    exit (EXIT_FAILURE);

  /* Now mount the filesystem so that we can add files. */
  if (guestfs_mount_options (g, "", partitions[0], "/") == -1)
    exit (EXIT_FAILURE);

  /* Create some files and directories. */
  if (guestfs_touch (g, "/empty") == -1)
    exit (EXIT_FAILURE);
  const char *message = "Hello, world\n";
  if (guestfs_write (g, "/hello", message, strlen (message)) == -1)
    exit (EXIT_FAILURE);
  if (guestfs_mkdir (g, "/foo") == -1)
    exit (EXIT_FAILURE);

  /* This one uploads the local file /etc/resolv.conf into the disk image. */
  if (guestfs_upload (g, "/etc/resolv.conf", "/foo/resolv.conf") == -1)
    exit (EXIT_FAILURE);

  /* Because 'autosync' was set (above) we can just close the handle
   * and the disk contents will be synchronized.  You can also do
   * this manually by calling guestfs_umount_all and guestfs_sync.
   */
  guestfs_close (g);

  /* Free up the lists. */
  for (i = 0; devices[i] != NULL; ++i)
    free (devices[i]);
  free (devices);
  for (i = 0; partitions[i] != NULL; ++i)
    free (partitions[i]);
  free (partitions);

  exit (EXIT_SUCCESS);
}

Leave a comment

Filed under Uncategorized

Easy introduction to the libguestfs API

Baffled by the 269 calls that libguestfs provides? Read the libguestfs API overview.

Also: Internet News interviews Paul Frields about Fedora 12.

Update: Another favourable F12 article at arstechnica.

Leave a comment

Filed under Uncategorized