guestfs-examples(3)

NAME

   guestfs-examples - Examples of using libguestfs from C

SYNOPSIS

    #include <guestfs.h>

    guestfs_h *g = guestfs_create ();
    guestfs_add_drive_ro (g, "disk.img");
    guestfs_launch (g);

    cc prog.c -o prog -lguestfs
   or:
    cc prog.c -o prog `pkg-config libguestfs --cflags --libs`

DESCRIPTION

   This manual page contains examples of calling libguestfs from the C
   programming language.  If you are not familiar with using libguestfs,
   you also need to read guestfs(3).

EXAMPLE: CREATE A DISK IMAGE

    /* Example showing how to create a disk image. */

    #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);
      }

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

      /* Create a raw-format sparse disk image, 512 MB in size. */
      if (guestfs_disk_create (g, "disk.img", "raw", UINT64_C(512)*1024*1024,
                               -1) == -1)
        exit (EXIT_FAILURE);

      /* 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 (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 we wrote to the disk and we want to detect write
       * errors, call guestfs_shutdown.  You don't need to do this:
       * guestfs_close will do it implicitly.
       */
      if (guestfs_shutdown (g) == -1)
        exit (EXIT_FAILURE);

      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);
    }

EXAMPLE: INSPECT A VIRTUAL MACHINE DISK IMAGE

    /* Inspect a disk image and display operating systems it may contain. */

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

    static int
    compare_keys_len (const void *p1, const void *p2)
    {
      const char *key1 = * (char * const *) p1;
      const char *key2 = * (char * const *) p2;
      return strlen (key1) - strlen (key2);
    }

    static size_t
    count_strings (char *const *argv)
    {
      size_t c;

      for (c = 0; argv[c]; ++c)
        ;
      return c;
    }

    int
    main (int argc, char *argv[])
    {
      guestfs_h *g;
      const char *disk;
      char **roots, *root, *str, **mountpoints, **lines;
      size_t i, j;

      if (argc != 2) {
        fprintf (stderr, "usage: inspect_vm disk.img\n");
        exit (EXIT_FAILURE);
      }
      disk = argv[1];

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

      /* Attach the disk image read-only to libguestfs. */
      if (guestfs_add_drive_opts (g, disk,
                                 /* GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", */
                                 GUESTFS_ADD_DRIVE_OPTS_READONLY, 1,
                                 -1) /* this marks end of optional arguments */
          == -1)
        exit (EXIT_FAILURE);

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

      /* Ask libguestfs to inspect for operating systems. */
      roots = guestfs_inspect_os (g);
      if (roots == NULL)
        exit (EXIT_FAILURE);
      if (roots[0] == NULL) {
        fprintf (stderr, "inspect_vm: no operating systems found\n");
        exit (EXIT_FAILURE);
      }

      for (j = 0; roots[j] != NULL; ++j) {
        root = roots[j];

        printf ("Root device: %s\n", root);

        /* Print basic information about the operating system. */
        str = guestfs_inspect_get_product_name (g, root);
        if (str)
          printf ("  Product name: %s\n", str);
        free (str);

        printf ("  Version:      %d.%d\n",
                guestfs_inspect_get_major_version (g, root),
                guestfs_inspect_get_minor_version (g, root));

        str = guestfs_inspect_get_type (g, root);
        if (str)
          printf ("  Type:         %s\n", str);
        free (str);
        str = guestfs_inspect_get_distro (g, root);
        if (str)
          printf ("  Distro:       %s\n", str);
        free (str);

        /* Mount up the disks, like guestfish -i.
         *
         * Sort keys by length, shortest first, so that we end up
         * mounting the filesystems in the correct order.
         */
        mountpoints = guestfs_inspect_get_mountpoints (g, root);
        if (mountpoints == NULL)
          exit (EXIT_FAILURE);

        qsort (mountpoints, count_strings (mountpoints) / 2, 2 * sizeof (char *),
               compare_keys_len);
        for (i = 0; mountpoints[i] != NULL; i += 2) {
          /* Ignore failures from this call, since bogus entries can
           * appear in the guest's /etc/fstab.
           */
          guestfs_mount_ro (g, mountpoints[i+1], mountpoints[i]);
          free (mountpoints[i]);
          free (mountpoints[i+1]);
        }
        free (mountpoints);

        /* If /etc/issue.net file exists, print up to 3 lines. */
        if (guestfs_is_file (g, "/etc/issue.net") > 0) {
          printf ("--- /etc/issue.net ---\n");
          lines = guestfs_head_n (g, 3, "/etc/issue.net");
          if (lines == NULL)
            exit (EXIT_FAILURE);
          for (i = 0; lines[i] != NULL; ++i) {
            printf ("%s\n", lines[i]);
            free (lines[i]);
          }
          free (lines);
        }

        /* Unmount everything. */
        if (guestfs_umount_all (g) == -1)
          exit (EXIT_FAILURE);

        free (root);
      }
      free (roots);

      guestfs_close (g);

      exit (EXIT_SUCCESS);
    }

EXAMPLE: ENABLE DEBUGGING AND LOGGING

    /* Example showing how to enable debugging, and capture it into any
     * custom logging system (syslog in this example, but any could be
     * used).  Note this uses the event API which is also available in
     * non-C language bindings.
     */

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

    static void message_callback (guestfs_h *g, void *opaque, uint64_t event, int event_handle, int flags, const char *buf, size_t buf_len, const uint64_t *array, size_t array_len);

    /* Events we are interested in.  This bitmask covers all trace and
     * debug messages.
     */
    static const uint64_t event_bitmask =
      GUESTFS_EVENT_LIBRARY |
      GUESTFS_EVENT_WARNING |
      GUESTFS_EVENT_APPLIANCE |
      GUESTFS_EVENT_TRACE;

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

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

      /* By default, debugging information is printed on stderr.  To
       * capture it somewhere else you have to set up an event handler
       * which will be called back as debug messages are generated.  To do
       * this use the event API.
       *
       * For more information see EVENTS in guestfs(3).
       */
      if (guestfs_set_event_callback (g, message_callback,
                                      event_bitmask, 0, NULL) == -1)
        exit (EXIT_FAILURE);

      /* This is how debugging is enabled:
       *
       * Setting the 'trace' flag in the handle means that each libguestfs
       * call is logged (name, parameters, return).  This flag is useful
       * to see how libguestfs is being used by a program.
       *
       * Setting the 'verbose' flag enables a great deal of extra
       * debugging throughout the system.  This is useful if there is a
       * libguestfs error which you don't understand.
       *
       * Note that you should set the flags early on after creating the
       * handle.  In particular if you set the verbose flag after launch
       * then you won't see all messages.
       *
       * For more information see:
       * http://libguestfs.org/guestfs-faq.1.html#debugging-libguestfs
       *
       * Error messages raised by APIs are *not* debugging information,
       * and they are not affected by any of this.  You may have to log
       * them separately.
       */
      guestfs_set_trace (g, 1);
      guestfs_set_verbose (g, 1);

      /* Do some operations which will generate plenty of trace and debug
       * messages.
       */
      if (guestfs_add_drive (g, "/dev/null") == -1)
        exit (EXIT_FAILURE);

      printf ("There is no output from this program.  "
              "Take a look in your system log file,\n"
              "eg. /var/log/messages.\n");

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

      guestfs_close (g);

      exit (EXIT_SUCCESS);
    }

    /* This function is called back by libguestfs whenever a trace or
     * debug message is generated.
     *
     * For the classes of events we have registered above, 'array' and
     * 'array_len' will not be meaningful.  Only 'buf' and 'buf_len' will
     * be interesting and these will contain the trace or debug message.
     *
     * This example simply redirects these messages to syslog, but
     * obviously you could do something more advanced here.
     */
    static void
    message_callback (guestfs_h *g, void *opaque,
                      uint64_t event, int event_handle,
                      int flags,
                      const char *buf, size_t buf_len,
                      const uint64_t *array, size_t array_len)
    {
      const int priority = LOG_USER|LOG_INFO;
      char *event_name, *msg;

      if (buf_len > 0) {
        event_name = guestfs_event_to_string (event);
        msg = strndup (buf, buf_len);
        syslog (priority, "[%s] %s", event_name, msg);
        free (msg);
        free (event_name);
      }
    }

EXAMPLE: DISPLAY THE OPERATING SYSTEM ICON OF A GUEST

    /* This example inspects a guest using libguestfs inspection (see
     * "INSPECTION" in guestfs(3)), and if possible displays a
     * representative icon or logo for the guest's operating system.
     */

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

    static int
    compare_keys_len (const void *p1, const void *p2)
    {
      const char *key1 = * (char * const *) p1;
      const char *key2 = * (char * const *) p2;
      return strlen (key1) - strlen (key2);
    }

    static size_t
    count_strings (char *const *argv)
    {
      size_t c;

      for (c = 0; argv[c]; ++c)
        ;
      return c;
    }

    int
    main (int argc, char *argv[])
    {
      guestfs_h *g;
      const char *disk;
      char **roots, *root, **mountpoints, *icon;
      size_t i, j, icon_size;
      FILE *fp;

      if (argc != 2) {
        fprintf (stderr, "usage: display-icon disk.img\n");
        exit (EXIT_FAILURE);
      }
      disk = argv[1];

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

      /* Attach the disk image read-only to libguestfs. */
      if (guestfs_add_drive_opts (g, disk,
                                 /* GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", */
                                 GUESTFS_ADD_DRIVE_OPTS_READONLY, 1,
                                 -1) /* this marks end of optional arguments */
          == -1)
        exit (EXIT_FAILURE);

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

      /* Ask libguestfs to inspect for operating systems. */
      roots = guestfs_inspect_os (g);
      if (roots == NULL)
        exit (EXIT_FAILURE);
      if (roots[0] == NULL) {
        fprintf (stderr, "display-icon: no operating systems found\n");
        exit (EXIT_FAILURE);
      }

      for (j = 0; roots[j] != NULL; ++j) {
        root = roots[j];

        /* Mount up the disks, like guestfish -i.
         *
         * Sort keys by length, shortest first, so that we end up
         * mounting the filesystems in the correct order.
         */
        mountpoints = guestfs_inspect_get_mountpoints (g, root);
        if (mountpoints == NULL)
          exit (EXIT_FAILURE);

        qsort (mountpoints, count_strings (mountpoints) / 2, 2 * sizeof (char *),
               compare_keys_len);
        for (i = 0; mountpoints[i] != NULL; i += 2) {
          /* Ignore failures from this call, since bogus entries can
           * appear in the guest's /etc/fstab.
           */
          guestfs_mount_ro (g, mountpoints[i+1], mountpoints[i]);
          free (mountpoints[i]);
          free (mountpoints[i+1]);
        }
        free (mountpoints);

        /* Get the icon.
         * This function returns a buffer ('icon').  Normally it is a png
         * file, returned as a string, but it can also be a zero length
         * buffer which has a special meaning, or NULL which means there
         * was an error.
         */
        icon = guestfs_inspect_get_icon (g, root, &icon_size, -1);
        if (!icon)                  /* actual libguestfs error */
          exit (EXIT_FAILURE);
        if (icon_size == 0)         /* no icon available */
          fprintf (stderr, "%s: %s: no icon available for this operating system\n",
                   disk, root);
        else {
          /* Display the icon. */
          fp = popen ("display -", "w");
          if (fp == NULL) {
            perror ("display");
            exit (EXIT_FAILURE);
          }
          if (fwrite (icon, 1, icon_size, fp) != icon_size) {
            perror ("write");
            exit (EXIT_FAILURE);
          }
          if (pclose (fp) == -1) {
            perror ("pclose");
            exit (EXIT_FAILURE);
          }
        }
        free (icon);

        /* Unmount everything. */
        if (guestfs_umount_all (g) == -1)
          exit (EXIT_FAILURE);

        free (root);
      }
      free (roots);

      guestfs_close (g);

      exit (EXIT_SUCCESS);
    }

EXAMPLE: THE LIBVIRT AUTHENTICATION API

    /* Example of using the libvirt authentication event-driven API.
     *
     * See "LIBVIRT AUTHENTICATION" in guestfs(3).
     */

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

    #include <guestfs.h>

    static void
    usage (void)
    {
      fprintf (stderr,
              "Usage:\n"
              "\n"
              "  libvirt-auth URI domain\n"
              "\n"
              "where:\n"
              "\n"
              "  URI     is the libvirt URI, eg. qemu+libssh2://USER@localhost/system\n"
              "  domain  is the name of the guest\n"
              "\n"
              "Example:\n"
              "\n"
              "  libvirt-auth 'qemu+libssh2://USER@localhost/system' 'foo'\n"
              "\n"
              "would connect (read-only) to libvirt URI given and open the guest\n"
              "called 'foo' and list some information about its filesystems.\n"
              "\n"
              "The important point of this example is that any libvirt authentication\n"
              "required to connect to the server should be done.\n"
              "\n");
    }

    static void auth_callback (guestfs_h *g, void *opaque, uint64_t event, int event_handle, int flags, const char *buf, size_t buf_len, const uint64_t *array, size_t array_len);

    int
    main (int argc, char *argv[])
    {
      const char *uri, *dom;
      guestfs_h *g;
      const char *creds[] = { "authname", "passphrase",
                              "echoprompt", "noechoprompt", NULL };
      int r, eh;
      char **filesystems;
      size_t i;

      if (argc != 3) {
        usage ();
        exit (EXIT_FAILURE);
      }
      uri = argv[1];
      dom = argv[2];

      g = guestfs_create ();
      if (!g)
        exit (EXIT_FAILURE);

      r = guestfs_set_libvirt_supported_credentials (g, (char **) creds);
      if (r == -1)
        exit (EXIT_FAILURE);

      /* Set up the event handler. */
      eh = guestfs_set_event_callback (g, auth_callback,
                                       GUESTFS_EVENT_LIBVIRT_AUTH, 0, NULL);
      if (eh == -1)
        exit (EXIT_FAILURE);

      /* Add the named domain. */
      r = guestfs_add_domain (g, dom,
                              GUESTFS_ADD_DOMAIN_LIBVIRTURI, uri,
                              -1);
      if (r == -1)
        exit (EXIT_FAILURE);

      /* Launch and do some simple inspection. */
      r = guestfs_launch (g);
      if (r == -1)
        exit (EXIT_FAILURE);

      filesystems = guestfs_list_filesystems (g);
      if (filesystems == NULL)
        exit (EXIT_FAILURE);

      for (i = 0; filesystems[i] != NULL; i += 2) {
        printf ("%s:%s is a %s filesystem\n",
                dom, filesystems[i], filesystems[i+1]);
        free (filesystems[i]);
        free (filesystems[i+1]);
      }
      free (filesystems);

      exit (EXIT_SUCCESS);
    }

    static void
    auth_callback (guestfs_h *g,
                   void *opaque,
                   uint64_t event,
                   int event_handle,
                   int flags,
                   const char *buf, size_t buf_len,
                   const uint64_t *array, size_t array_len)
    {
      char **creds;
      size_t i;
      char *prompt;
      char *reply = NULL;
      size_t allocsize = 0;
      char *pass;
      ssize_t len;
      int r;

      printf ("libvirt-auth.c: authentication required for libvirt URI '%s'\n\n",
              buf);

      /* Ask libguestfs what credentials libvirt is demanding. */
      creds = guestfs_get_libvirt_requested_credentials (g);
      if (creds == NULL)
        exit (EXIT_FAILURE);

      /* Now ask the user for answers. */
      for (i = 0; creds[i] != NULL; ++i)
      {
        printf ("libvirt-auth.c: credential '%s'\n", creds[i]);

        if (strcmp (creds[i], "authname") == 0 ||
            strcmp (creds[i], "echoprompt") == 0) {
          prompt = guestfs_get_libvirt_requested_credential_prompt (g, i);
          if (prompt && strcmp (prompt, "") != 0)
            printf ("%s: ", prompt);
          free (prompt);

          len = getline (&reply, &allocsize, stdin);
          if (len == -1) {
            perror ("getline");
            exit (EXIT_FAILURE);
          }
          if (len > 0 && reply[len-1] == '\n')
            reply[--len] = '\0';

          r = guestfs_set_libvirt_requested_credential (g, i, reply, len);
          if (r == -1)
            exit (EXIT_FAILURE);
        } else if (strcmp (creds[i], "passphrase") == 0 ||
                   strcmp (creds[i], "noechoprompt") == 0) {
          prompt = guestfs_get_libvirt_requested_credential_prompt (g, i);
          if (prompt && strcmp (prompt, "") != 0)
            printf ("%s: ", prompt);
          free (prompt);

          pass = getpass ("");
          if (pass == NULL) {
            perror ("getpass");
            exit (EXIT_FAILURE);
          }
          len = strlen (pass);

          r = guestfs_set_libvirt_requested_credential (g, i, pass, len);
          if (r == -1)
            exit (EXIT_FAILURE);
        }

        free (creds[i]);
      }

      free (reply);
      free (creds);
    }

EXAMPLE: THE MOUNT LOCAL API

    /* Demonstrate the use of the 'mount-local' API.
     *
     * Run this program as (eg) mount-local /tmp/test.img.  Note that
     * '/tmp/test.img' is created or overwritten.  Follow the instructions
     * on screen.
     *
     * See "MOUNT LOCAL" in guestfs(3).
     */

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/wait.h>

    #include <guestfs.h>

    #ifndef O_CLOEXEC
    #define O_CLOEXEC 0
    #endif

    /* Define a list of filesystem mount options (used on the libguestfs
     * side, nothing to do with FUSE).  An empty string may be used here
     * instead.
     */
    #define MOUNT_OPTIONS "acl,user_xattr"

    /* Size of the disk (megabytes). */
    #define SIZE_MB 512

    static void
    usage (void)
    {
      fprintf (stderr,
               "Usage: mount-local disk.img\n"
               "\n"
               "NOTE: disk.img will be created or overwritten.\n"
               "\n");
    }

    int
    main (int argc, char *argv[])
    {
      guestfs_h *g;
      int r;
      char tempdir[] = "/tmp/mlXXXXXX";
      pid_t pid;
      char *shell, *p;

      if (argc != 2) {
        usage ();
        exit (EXIT_FAILURE);
      }

      if (argv[1][0] == '-') {
        usage ();
        exit (EXIT_FAILURE);
      }

      printf ("\n"
              "This is the 'mount-local' demonstration program.  Follow the\n"
              "instructions on screen.\n"
              "\n"
              "Creating and formatting the disk image, please wait a moment ...\n");
      fflush (stdout);

      /* Guestfs handle. */
      g = guestfs_create ();
      if (g == NULL) {
        perror ("could not create libguestfs handle");
        exit (EXIT_FAILURE);
      }

      /* Create the output disk image: raw sparse. */
      if (guestfs_disk_create (g, argv[1], "raw", SIZE_MB * 1024 * 1024, -1) == -1)
        exit (EXIT_FAILURE);

      /* Create the disk image and format it with a partition and a filesystem. */
      if (guestfs_add_drive_opts (g, argv[1],
                                  GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw",
                                  -1) == -1)
        exit (EXIT_FAILURE);

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

      if (guestfs_part_disk (g, "/dev/sda", "mbr") == -1)
        exit (EXIT_FAILURE);

      if (guestfs_mkfs (g, "ext2", "/dev/sda1") == -1)
        exit (EXIT_FAILURE);

      /* Mount the empty filesystem. */
      if (guestfs_mount_options (g, MOUNT_OPTIONS, "/dev/sda1", "/") == -1)
        exit (EXIT_FAILURE);

      /* Create a file in the new filesystem. */
      if (guestfs_touch (g, "/PUT_FILES_AND_DIRECTORIES_HERE") == -1)
        exit (EXIT_FAILURE);

      /* Create a temporary mount directory. */
      if (mkdtemp (tempdir) == NULL) {
        perror ("mkdtemp");
        exit (EXIT_FAILURE);
      }

      /* Mount the filesystem. */
      if (guestfs_mount_local (g, tempdir, -1) == -1)
        exit (EXIT_FAILURE);

      /* Fork the shell for the user. */
      pid = fork ();
      if (pid == -1) {
        perror ("fork");
        exit (EXIT_FAILURE);
      }

      if (pid == 0) {               /* Child. */
        if (chdir (tempdir) == -1) {
          perror (tempdir);
          _exit (EXIT_FAILURE);
        }

        printf ("\n"
                "The *current directory* is a FUSE filesystem backed by the disk\n"
                "image which is managed by libguestfs.  Any files or directories\n"
                "you copy into here (up to %d MB) will be saved into the disk\n"
                "image.  You can also delete files, create certain special files\n"
                "and so on.\n"
                "\n"
                "When you have finished adding files, hit ^D or type 'exit' to\n"
                "exit the shell and return to the mount-local program.\n"
                "\n",
                SIZE_MB);

        shell = getenv ("SHELL");
        if (!shell)
          r = system ("/bin/sh");
        else {
          /* Set a magic prompt.  We only know how to do this for bash. */
          p = strrchr (shell, '/');
          if (p && strcmp (p+1, "bash") == 0) {
            const size_t len = 64 + strlen (shell);
            char buf[len];

            snprintf (buf, len, "PS1='mount-local-shell> ' %s --norc -i", shell);
            r = system (buf);
          } else
            r = system (shell);
        }
        if (r == -1) {
          fprintf (stderr, "error: failed to run sub-shell (%s) "
                   "(is $SHELL set correctly?)\n",
                   shell);
          //FALLTHROUGH
        }

        if (chdir ("/") == -1)
          perror ("chdir: /");
        guestfs_umount_local (g, GUESTFS_UMOUNT_LOCAL_RETRY, 1, -1);
        _exit (EXIT_SUCCESS);
      }

      /* Note that we are *not* waiting for the child yet.  We want to
       * run the FUSE code in parallel with the subshell.
       */

      /* We're going to hide libguestfs errors here, but in a real program
       * you would probably want to log them somewhere.
       */
      guestfs_push_error_handler (g, NULL, NULL);

      /* Now run the FUSE thread. */
      if (guestfs_mount_local_run (g) == -1)
        exit (EXIT_FAILURE);

      guestfs_pop_error_handler (g);

      waitpid (pid, NULL, 0);

      /* Shutdown the handle explicitly so write errors can be detected. */
      if (guestfs_shutdown (g) == -1)
        exit (EXIT_FAILURE);

      guestfs_close (g);

      printf ("\n"
              "Any files or directories that you copied in have been saved into\n"
              "the disk image called '%s'.\n"
              "\n"
              "Try opening the disk image with guestfish to see those files:\n"
              "\n"
              "  guestfish -a %s -m /dev/sda1\n"
              "\n",
              argv[1], argv[1]);

      exit (EXIT_SUCCESS);
    }

EXAMPLE: MULTIPLE HANDLES AND THREADS

    /* Copy a directory from one libvirt guest to another.
     *
     * This is a more substantial example of using the libguestfs API,
     * demonstrating amongst other things:
     *
     * - using multiple handles with threads
     * - upload and downloading (using a pipe between handles)
     * - inspection
     */

    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <inttypes.h>
    #include <string.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <errno.h>
    #include <sys/time.h>

    #include <pthread.h>

    #include <guestfs.h>

    struct threaddata {
      const char *src;
      const char *srcdir;
      int fd;
      pthread_t mainthread;
    };

    static void *start_srcthread (void *);
    static int open_guest (guestfs_h *g, const char *dom, int readonly);
    static int64_t timeval_diff (const struct timeval *x, const struct timeval *y);
    static int compare_keys_len (const void *p1, const void *p2);
    static size_t count_strings (char *const *argv);

    static void
    usage (void)
    {
      fprintf (stderr,
              "Usage: copy-over source srcdir dest destdir\n"
              "\n"
              "  source  : the source domain (a libvirt guest name)\n"
              "  srcdir  : the directory to copy from the source guest\n"
              "  dest    : the destination domain (a libvirt guest name)\n"
              "  destdir : the destination directory (must exist at destination)\n"
              "\n"
              "eg: copy-over Src /home/rjones Dest /tmp/dir\n"
              "would copy /home/rjones from Src to /tmp/dir on Dest\n"
              "\n"
              "The destination guest cannot be running.\n");
    }

    int
    main (int argc, char *argv[])
    {
      const char *src, *srcdir, *dest, *destdir;
      guestfs_h *destg;
      int fd[2];
      pthread_t srcthread;
      struct threaddata threaddata;
      int err;
      char fdname[128];
      struct timeval start_t, end_t;
      int64_t ms;

      if (argc != 5) {
        usage ();
        exit (EXIT_FAILURE);
      }

      src = argv[1];
      srcdir = argv[2];
      dest = argv[3];
      destdir = argv[4];

      /* Instead of downloading to local disk and uploading, we are going
       * to connect the source download and destination upload using a
       * pipe.  Create that pipe.
       */
      if (pipe (fd) == -1) {
        perror ("pipe");
        exit (EXIT_FAILURE);
      }

      /* We don't want the pipe to be passed to subprocesses. */
      if (fcntl (fd[0], F_SETFD, FD_CLOEXEC) == -1 ||
          fcntl (fd[1], F_SETFD, FD_CLOEXEC) == -1) {
        perror ("fcntl");
        exit (EXIT_FAILURE);
      }

      /* The libguestfs API is synchronous, so if we want to use two
       * handles concurrently, then we have to have two threads.  In this
       * case the main thread (this one) is handling the destination
       * domain (uploading), and we create one more thread to handle the
       * source domain (downloading).
       */
      threaddata.src = src;
      threaddata.srcdir = srcdir;
      threaddata.fd = fd[1];
      threaddata.mainthread = pthread_self ();
      err = pthread_create (&srcthread, NULL, start_srcthread, &threaddata);
      if (err != 0) {
        fprintf (stderr, "pthread_create: %s\n", strerror (err));
        exit (EXIT_FAILURE);
      }

      /* Open the destination domain. */
      destg = guestfs_create ();
      if (!destg) {
        perror ("failed to create libguestfs handle");
        pthread_cancel (srcthread);
        exit (EXIT_FAILURE);
      }
      if (open_guest (destg, dest, 0) == -1) {
        pthread_cancel (srcthread);
        exit (EXIT_FAILURE);
      }

      gettimeofday (&start_t, NULL);

      /* Begin the upload. */
      snprintf (fdname, sizeof fdname, "/dev/fd/%d", fd[0]);
      if (guestfs_tar_in (destg, fdname, destdir) == -1) {
        pthread_cancel (srcthread);
        exit (EXIT_FAILURE);
      }

      /* Close our end of the pipe.  The other thread will close the
       * other side of the pipe.
       */
      close (fd[0]);

      /* Wait for the other thread to finish. */
      err = pthread_join (srcthread, NULL);
      if (err != 0) {
        fprintf (stderr, "pthread_join: %s\n", strerror (err));
        exit (EXIT_FAILURE);
      }

      /* Clean up. */
      if (guestfs_shutdown (destg) == -1)
        exit (EXIT_FAILURE);
      guestfs_close (destg);

      gettimeofday (&end_t, NULL);

      /* Print the elapsed time. */
      ms = timeval_diff (&start_t, &end_t);
      printf ("copy finished, elapsed time (excluding launch) was "
              "%" PRIi64 ".%03" PRIi64 " s\n",
              ms / 1000, ms % 1000);

      exit (EXIT_SUCCESS);
    }

    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;
    }

    /* This function deals with the complexity of adding the domain,
     * launching the handle, and mounting up filesystems.  See
     * 'examples/inspect-vm.c' to understand how this works.
     */
    static int
    open_guest (guestfs_h *g, const char *dom, int readonly)
    {
      char **roots, *root, **mountpoints;
      size_t i;

      /* Use libvirt to find the guest disks and add them to the handle. */
      if (guestfs_add_domain (g, dom,
                              GUESTFS_ADD_DOMAIN_READONLY, readonly,
                              -1) == -1)
        return -1;

      if (guestfs_launch (g) == -1)
        return -1;

      /* Inspect the guest, looking for operating systems. */
      roots = guestfs_inspect_os (g);
      if (roots == NULL)
        return -1;

      if (roots[0] == NULL || roots[1] != NULL) {
        fprintf (stderr, "copy-over: %s: no operating systems or multiple operating systems found\n", dom);
        return -1;
      }

      root = roots[0];

      /* Mount up the filesystems (like 'guestfish -i'). */
      mountpoints = guestfs_inspect_get_mountpoints (g, root);
      if (mountpoints == NULL)
        return -1;

      qsort (mountpoints, count_strings (mountpoints) / 2, 2 * sizeof (char *),
             compare_keys_len);
      for (i = 0; mountpoints[i] != NULL; i += 2) {
        /* Ignore failures from this call, since bogus entries can
         * appear in the guest's /etc/fstab.
         */
        (readonly ? guestfs_mount_ro : guestfs_mount)
          (g, mountpoints[i+1], mountpoints[i]);
        free (mountpoints[i]);
        free (mountpoints[i+1]);
      }

      free (mountpoints);

      free (root);
      free (roots);

      /* Everything ready, no error. */
      return 0;
    }

    /* Compute Y - X and return the result in milliseconds.
     * Approximately the same as this code:
     * http://www.mpp.mpg.de/~huber/util/timevaldiff.c
     */
    static int64_t
    timeval_diff (const struct timeval *x, const struct timeval *y)
    {
      int64_t msec;

      msec = (y->tv_sec - x->tv_sec) * 1000;
      msec += (y->tv_usec - x->tv_usec) / 1000;
      return msec;
    }

    static int
    compare_keys_len (const void *p1, const void *p2)
    {
      const char *key1 = * (char * const *) p1;
      const char *key2 = * (char * const *) p2;
      return strlen (key1) - strlen (key2);
    }

    static size_t
    count_strings (char *const *argv)
    {
      size_t c;

      for (c = 0; argv[c]; ++c)
        ;
      return c;
    }

EXAMPLE: FETCH DHCP ADDRESS FROM A GUEST

    /* This is a more significant example of a tool which can grab the
     * DHCP address from some types of virtual machine.  Since there are
     * so many possible ways to do this, without clarity on which is the
     * best way, I don't want to make this into an official virt tool.
     *
     * For more information, see:
     *
     * https://rwmj.wordpress.com/2010/10/26/tip-find-the-ip-address-of-a-virtual-machine/
     * https://rwmj.wordpress.com/2011/03/30/tip-another-way-to-get-the-ip-address-of-a-virtual-machine/
     */

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    #include <unistd.h>
    #include <assert.h>

    #include <guestfs.h>

    static int compare_keys_len (const void *p1, const void *p2);
    static size_t count_strings (char *const *argv);
    static void free_strings (char **argv);
    static void mount_disks (guestfs_h *g, char *root);
    static void print_dhcp_address (guestfs_h *g, char *root);
    static void print_dhcp_address_linux (guestfs_h *g, char *root, const char *logfile);
    static void print_dhcp_address_windows (guestfs_h *g, char *root);

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

      if (argc < 2) {
        fprintf (stderr,
                 "Usage: virt-dhcp-address disk.img [disk.img [...]]\n"
                 "Note that all disks must come from a single virtual machine.\n");
        exit (EXIT_FAILURE);
      }

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

      for (i = 1; i < (size_t) argc; ++i) {
        /* Attach the disk image(s) read-only to libguestfs. */
        if (guestfs_add_drive_opts (g, argv[i],
                                    /* GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", */
                                    GUESTFS_ADD_DRIVE_OPTS_READONLY, 1,
                                    -1) /* this marks end of optional arguments */
            == -1)
          exit (EXIT_FAILURE);
      }

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

      /* Ask libguestfs to inspect for operating systems. */
      roots = guestfs_inspect_os (g);
      if (roots == NULL)
        exit (EXIT_FAILURE);
      if (roots[0] == NULL) {
        fprintf (stderr, "virt-dhcp-address: no operating systems found\n");
        exit (EXIT_FAILURE);
      }
      if (count_strings (roots) > 1) {
        fprintf (stderr, "virt-dhcp-address: multi-boot operating system\n");
        exit (EXIT_FAILURE);
      }

      root = roots[0];

      /* Mount up the guest's disks. */
      mount_disks (g, root);

      /* Print DHCP address. */
      print_dhcp_address (g, root);

      /* Close handle and exit. */
      guestfs_close (g);
      free_strings (roots);

      exit (EXIT_SUCCESS);
    }

    static void
    mount_disks (guestfs_h *g, char *root)
    {
      char **mountpoints;
      size_t i;

      /* Mount up the disks, like guestfish -i.
       *
       * Sort keys by length, shortest first, so that we end up
       * mounting the filesystems in the correct order.
       */
      mountpoints = guestfs_inspect_get_mountpoints (g, root);
      if (mountpoints == NULL)
        exit (EXIT_FAILURE);

      qsort (mountpoints, count_strings (mountpoints) / 2, 2 * sizeof (char *),
             compare_keys_len);

      for (i = 0; mountpoints[i] != NULL; i += 2) {
        /* Ignore failures from this call, since bogus entries can
         * appear in the guest's /etc/fstab.
         */
        guestfs_mount_ro (g, mountpoints[i+1], mountpoints[i]);
      }

      free_strings (mountpoints);
    }

    static void
    print_dhcp_address (guestfs_h *g, char *root)
    {
      char *guest_type, *guest_distro;

      /* Depending on the guest type, try to get the DHCP address. */
      guest_type = guestfs_inspect_get_type (g, root);
      if (guest_type == NULL)
        exit (EXIT_FAILURE);

      if (strcmp (guest_type, "linux") == 0) {
        guest_distro = guestfs_inspect_get_distro (g, root);
        if (guest_distro == NULL)
          exit (EXIT_FAILURE);

        if (strcmp (guest_distro, "fedora") == 0 ||
            strcmp (guest_distro, "rhel") == 0 ||
            strcmp (guest_distro, "redhat-based") == 0) {
          print_dhcp_address_linux (g, root, "/var/log/messages");
        }
        else if (strcmp (guest_distro, "debian") == 0 ||
                 strcmp (guest_distro, "ubuntu") == 0) {
          print_dhcp_address_linux (g, root, "/var/log/syslog");
        }
        else {
          fprintf (stderr, "virt-dhcp-address: don't know how to get DHCP address from '%s'\n",
                   guest_distro);
          exit (EXIT_FAILURE);
        }

        free (guest_distro);
      }
      else if (strcmp (guest_type, "windows") == 0) {
        print_dhcp_address_windows (g, root);
      }
      else {
        fprintf (stderr, "virt-dhcp-address: don't know how to get DHCP address from '%s'\n",
                 guest_type);
        exit (EXIT_FAILURE);
      }

      free (guest_type);
    }

    /* Look for dhclient messages in logfile.
     */
    static void
    print_dhcp_address_linux (guestfs_h *g, char *root, const char *logfile)
    {
      char **lines, *p;
      size_t len;

      lines = guestfs_grep_opts (g, "dhclient.*: bound to ", logfile,
                                 GUESTFS_GREP_OPTS_EXTENDED, 1,
                                 -1);
      if (lines == NULL)
        exit (EXIT_FAILURE);

      len = count_strings (lines);
      if (len == 0) {
        fprintf (stderr, "virt-dhcp-address: cannot find DHCP address for this guest.\n");
        exit (EXIT_FAILURE);
      }

      /* Only want the last message. */
      p = strstr (lines[len-1], "bound to ");
      assert (p);
      p += 9;
      len = strcspn (p, " ");
      p[len] = '\0';

      printf ("%s\n", p);

      free_strings (lines);
    }

    /* Download the Windows SYSTEM hive and find DHCP configuration in there. */
    static void
    print_dhcp_address_windows (guestfs_h *g, char *root_fs)
    {
      char *system_path;
      int64_t root, node, value;
      struct guestfs_hivex_node_list *nodes;
      char *controlset;
      size_t i;
      char *p;

      /* Locate the SYSTEM hive case-sensitive path. */
      system_path =
        guestfs_case_sensitive_path (g, "/windows/system32/config/system");
      if (!system_path)
        exit (EXIT_FAILURE);

      /* Open the hive to parse it.  Note that before libguestfs 1.19.35
       * you had to download the file and parse it using hivex(3).  Since
       * libguestfs 1.19.35, parts of the hivex(3) API are now exposed
       * through libguestfs, and that is what we'll use here because it is
       * more convenient and avoids having to download the hive.
       */
      if (guestfs_hivex_open (g, system_path, -1) == -1)
        exit (EXIT_FAILURE);

      free (system_path);

      root = guestfs_hivex_root (g);
      if (root == -1)
        exit (EXIT_FAILURE);

      /* Get ControlSetXXX\Services\Tcpip\Parameters\Interfaces. */
      controlset = guestfs_inspect_get_windows_current_control_set (g, root_fs);
      if (controlset == NULL)
        exit (EXIT_FAILURE);
      const char *path[] = { controlset, "Services", "Tcpip", "Parameters",
                             "Interfaces" };
      node = root;
      for (i = 0; node > 0 && i < sizeof path / sizeof path[0]; ++i)
        node = guestfs_hivex_node_get_child (g, node, path[i]);

      if (node == -1)
        exit (EXIT_FAILURE);

      if (node == 0) {
        fprintf (stderr, "virt-dhcp-address: HKLM\\System\\%s\\Services\\Tcpip\\Parameters\\Interfaces not found.", controlset);
        exit (EXIT_FAILURE);
      }

      free (controlset);

      /* Look for a node under here which has a "DhcpIPAddress" entry in it. */
      nodes = guestfs_hivex_node_children (g, node);
      if (nodes == NULL)
        exit (EXIT_FAILURE);

      value = 0;
      for (i = 0; value == 0 && i < nodes->len; ++i) {
        value = guestfs_hivex_node_get_value (g, nodes->val[i].hivex_node_h,
                                              "DhcpIPAddress");
        if (value == -1)
          exit (EXIT_FAILURE);
      }

      if (value == 0) {
        fprintf (stderr, "virt-dhcp-address: cannot find DHCP address for this guest.\n");
        exit (EXIT_FAILURE);
      }

      guestfs_free_hivex_node_list (nodes);

      /* Get the string and use libguestfs's auto-conversion to convert it
       * to UTF-8 for output.
       */
      p = guestfs_hivex_value_utf8 (g, value);
      if (!p)
        exit (EXIT_FAILURE);

      printf ("%s\n", p);

      free (p);

      /* Close the hive handle. */
      guestfs_hivex_close (g);
    }

    static int
    compare_keys_len (const void *p1, const void *p2)
    {
      const char *key1 = * (char * const *) p1;
      const char *key2 = * (char * const *) p2;
      return strlen (key1) - strlen (key2);
    }

    static size_t
    count_strings (char *const *argv)
    {
      size_t c;

      for (c = 0; argv[c]; ++c)
        ;
      return c;
    }

    static void
    free_strings (char **argv)
    {
      size_t i;

      for (i = 0; argv[i]; ++i)
        free (argv[i]);
      free (argv);
    }

SEE ALSO

   guestfs(3), guestfs-erlang(3), guestfs-golang(3), guestfs-java(3),
   guestfs-lua(3), guestfs-ocaml(3), guestfs-perl(3), guestfs-python(3),
   guestfs-recipes(1), guestfs-ruby(3), http://libguestfs.org/.

AUTHORS

   Richard W.M. Jones ("rjones at redhat dot com")

COPYRIGHT

   Copyright (C) 2010-2016 Red Hat Inc.

LICENSE

   This manual page contains examples which we hope you will use in your
   programs.  The examples may be freely copied, modified and distributed
   for any purpose without any restrictions.

BUGS

   To get a list of bugs against libguestfs, use this link:
   https://bugzilla.redhat.com/buglist.cgi?component=libguestfs&product=Virtualization+Tools

   To report a new bug against libguestfs, use this link:
   https://bugzilla.redhat.com/enter_bug.cgi?component=libguestfs&product=Virtualization+Tools

   When reporting a bug, please supply:

   *   The version of libguestfs.

   *   Where you got libguestfs (eg. which Linux distro, compiled from
       source, etc)

   *   Describe the bug accurately and give a way to reproduce it.

   *   Run libguestfs-test-tool(1) and paste the complete, unedited output
       into the bug report.



Opportunity


Personal Opportunity - Free software gives you access to billions of dollars of software at no cost. Use this software for your business, personal use or to develop a profitable skill. Access to source code provides access to a level of capabilities/information that companies protect though copyrights. Open source is a core component of the Internet and it is available to you. Leverage the billions of dollars in resources and capabilities to build a career, establish a business or change the world. The potential is endless for those who understand the opportunity.

Business Opportunity - Goldman Sachs, IBM and countless large corporations are leveraging open source to reduce costs, develop products and increase their bottom lines. Learn what these companies know about open source and how open source can give you the advantage.


Free Software


Free Software provides computer programs and capabilities at no cost but more importantly, it provides the freedom to run, edit, contribute to, and share the software. The importance of free software is a matter of access, not price. Software at no cost is a benefit but ownership rights to the software and source code is far more significant.

Free Office Software - The Libre Office suite provides top desktop productivity tools for free. This includes, a word processor, spreadsheet, presentation engine, drawing and flowcharting, database and math applications. Libre Office is available for Linux or Windows.


Free Books


The Free Books Library is a collection of thousands of the most popular public domain books in an online readable format. The collection includes great classical literature and more recent works where the U.S. copyright has expired. These books are yours to read and use without restrictions.

Source Code - Want to change a program or know how it works? Open Source provides the source code for its programs so that anyone can use, modify or learn how to write those programs themselves. Visit the GNU source code repositories to download the source.


Education


Study at Harvard, Stanford or MIT - Open edX provides free online courses from Harvard, MIT, Columbia, UC Berkeley and other top Universities. Hundreds of courses for almost all major subjects and course levels. Open edx also offers some paid courses and selected certifications.

Linux Manual Pages - A man or manual page is a form of software documentation found on Linux/Unix operating systems. Topics covered include computer programs (including library and system calls), formal standards and conventions, and even abstract concepts.