depcomp
.deps
emptydisk
-examples/hello
-examples/to-xml
+examples/create_disk
+examples/guestfs-examples.3
+examples/inspect_vm
+examples/stamp-guestfs-examples.pod
fish/cmds.c
fish/cmds_gperf.c
fish/cmds_gperf.gperf
*.hi
html/guestfish.1.html
html/guestfs.3.html
+html/guestfs-examples.3.html
html/guestmount.1.html
html/recipes.html
html/virt-cat.1.html
HTMLFILES = \
html/guestfs.3.html \
+ html/guestfs-examples.3.html \
html/guestfish.1.html \
html/guestmount.1.html \
html/virt-cat.1.html \
-All the examples in the examples/ subdirectory may be freely copied
-without any restrictions.
+All the examples in the 'examples' subdirectory may be freely copied,
+modified and distributed without any restrictions.
-# libguestfs examples
+# libguestfs C examples
+# Copyright (C) 2010 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-include $(top_srcdir)/subdir-rules.mk
+EXTRA_DIST = \
+ LICENSE \
+ guestfs-examples.pod
-noinst_PROGRAMS = hello to-xml
+CLEANFILES = stamp-guestfs-examples.pod
-hello_SOURCES = hello.c
-hello_CFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src -Wall
-hello_LDADD = $(top_builddir)/src/libguestfs.la
+noinst_PROGRAMS = create_disk inspect_vm
-to_xml_SOURCES = to-xml.c
-to_xml_CPPFLAGS = \
- -I$(top_srcdir)/gnulib/lib \
- -I$(top_srcdir)/src -I$(top_builddir)/src -Wall
-to_xml_LDADD = $(top_builddir)/src/libguestfs.la
+create_disk_SOURCES = create_disk.c
+create_disk_CFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src -Wall
+create_disk_LDADD = $(top_builddir)/src/libguestfs.la
-CLEANFILES = $(noinst_PROGRAMS)
+inspect_vm_SOURCES = inspect_vm.c
+inspect_vm_CFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src -Wall
+inspect_vm_LDADD = $(top_builddir)/src/libguestfs.la
+
+man_MANS = guestfs-examples.3
+noinst_DATA = $(top_builddir)/html/guestfs-examples.3.html
+
+guestfs-examples.3 $(top_builddir)/html/guestfs-examples.3.html: stamp-guestfs-examples.pod
+
+stamp-guestfs-examples.pod: guestfs-examples.pod create_disk.c inspect_vm.c
+ $(top_srcdir)/podwrapper.sh \
+ --section 3 \
+ --man guestfs-examples.3 \
+ --html $(top_builddir)/html/guestfs-examples.3.html \
+ --verbatim create_disk.c:@EXAMPLE1@ \
+ --verbatim inspect_vm.c:@EXAMPLE2@ \
+ $<
+ touch $@
+++ /dev/null
-This directory contains various example programs which use the
-libguestfs API.
-
-As they are examples, these are licensed so they can be freely copied
-and used without any restrictions.
-
-Tips:
-
-(1) To enable verbose messages, set environment variable
-LIBGUESTFS_DEBUG=1
-
-(2) If you haven't installed libguestfs, run the examples like this:
-LIBGUESTFS_PATH=appliance examples/to-xml
-(the path should point to the directory containing vmlinuz.* and
-initramfs.* files).
--- /dev/null
+/* 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);
+ }
+
+ /* 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);
+}
--- /dev/null
+=encoding utf8
+
+=head1 NAME
+
+guestfs-examples - Examples of using libguestfs from C
+
+=head1 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`
+
+=head1 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 L<guestfs(3)>.
+
+=head1 EXAMPLE 1: CREATE A DISK IMAGE
+
+@EXAMPLE1@
+
+=head1 EXAMPLE 2: INSPECT A VIRTUAL MACHINE DISK IMAGE
+
+@EXAMPLE2@
+
+=head1 SEE ALSO
+
+L<guestfs(3)>,
+L<guestfs-ocaml(3)>,
+L<http://libguestfs.org/>,
+L<http://caml.inria.fr/>.
+
+=head1 AUTHORS
+
+Richard W.M. Jones (C<rjones at redhat dot com>)
+
+=head1 COPYRIGHT
+
+Copyright (C) 2010 Red Hat Inc. L<http://libguestfs.org/>
+
+The examples in this manual page may be freely copied, modified and
+distributed without any restrictions.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+++ /dev/null
-/* Create a "/hello" file on chosen partition.
- * eg:
- * hello guest.img /dev/sda1
- * hello guest.img /dev/VolGroup00/LogVol00
- */
-
-#if HAVE_CONFIG_H
-# include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <guestfs.h>
-
-int
-main (int argc, char *argv[])
-{
- guestfs_h *g;
-
- if (argc != 3 || access (argv[1], F_OK) != 0) {
- fprintf (stderr, "Usage: hello disk-image partition\n");
- exit (EXIT_FAILURE);
- }
-
- if (!(g = guestfs_create ())) exit (EXIT_FAILURE);
-
- 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_mount_options (g, "", argv[2], "/") == -1) exit (EXIT_FAILURE);
-
- if (guestfs_touch (g, "/hello") == -1) exit (EXIT_FAILURE);
-
- guestfs_sync (g);
- guestfs_close (g);
- return 0;
-}
--- /dev/null
+#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 int
+count_strings (char *const *argv)
+{
+ int 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) {
+ if (guestfs_mount_ro (g, mountpoints[i+1], mountpoints[i]) == -1)
+ exit (EXIT_FAILURE);
+ 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);
+}
+++ /dev/null
-/* This inspects a block device and produces an XML representation of
- * the partitions, LVM, filesystems that we find there. This could be
- * useful as example code of how to do this sort of probing, or to
- * feed the XML to other programs.
- *
- * Usage:
- * to-xml guest.img [guest.img ...]
- */
-
-#if HAVE_CONFIG_H
-# include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <inttypes.h>
-#include <unistd.h>
-#include <ctype.h>
-
-#include <guestfs.h>
-
-/* Note that if any API call fails, we can just exit. The
- * standard error handler will have printed the error message
- * to stderr already.
- */
-#define CALL(call,errcode) \
- if ((call) == (errcode)) exit (EXIT_FAILURE);
-
-static void display_partition (guestfs_h *g, const char *dev);
-static void display_partitions (guestfs_h *g, const char *dev);
-static void display_ext234 (guestfs_h *g, const char *dev, const char *fstype);
-
-int
-main (int argc, char *argv[])
-{
- guestfs_h *g;
- int i;
-
- if (argc < 2 || access (argv[1], F_OK) != 0) {
- fprintf (stderr, "Usage: to-xml guest.img [guest.img ...]\n");
- exit (EXIT_FAILURE);
- }
-
- if (!(g = guestfs_create ())) {
- fprintf (stderr, "Cannot create libguestfs handle.\n");
- exit (EXIT_FAILURE);
- }
-
- for (i = 1; i < argc; ++i)
- CALL (guestfs_add_drive_opts (g, argv[i],
- GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw",
- -1), -1);
-
- CALL (guestfs_launch (g), -1);
-
- printf ("<guestfs-system>\n");
-
- /* list-devices should return the devices that we just attached?
- * Better to find out what the kernel thinks are devices anyway ...
- */
- char **devices;
- CALL (devices = guestfs_list_devices (g), NULL);
- printf ("<devices>\n");
- for (i = 0; devices[i] != NULL; ++i) {
- int64_t size;
- CALL (size = guestfs_blockdev_getsize64 (g, devices[i]), -1);
- printf ("<device dev=\"%s\" size=\"%" PRIi64 "\">\n", devices[i], size);
- display_partitions (g, devices[i]);
- free (devices[i]);
- printf ("</device>\n");
- }
- free (devices);
- printf ("</devices>\n");
-
- /* Now do the same for VGs and LVs. Note that a VG may span
- * multiple PVs / block devices, in arbitrary ways, which is
- * why VGs are in a separate top-level XML class.
- */
- char **vgs;
- char **lvs;
- printf ("<volgroups>\n");
- CALL (vgs = guestfs_vgs (g), NULL);
- CALL (lvs = guestfs_lvs (g), NULL);
- for (i = 0; vgs[i] != NULL; ++i) {
- printf ("<volgroup name=\"%s\">\n", vgs[i]);
-
- /* Just the LVs in this VG. */
- int len = strlen (vgs[i]);
- int j;
- for (j = 0; lvs[j] != NULL; ++j) {
- if (strncmp (lvs[j], "/dev/", 5) == 0 &&
- strncmp (&lvs[j][5], vgs[i], len) == 0 &&
- lvs[j][len+5] == '/') {
- int64_t size;
- CALL (size = guestfs_blockdev_getsize64 (g, lvs[j]), -1);
- printf ("<logvol name=\"%s\" size=\"%" PRIi64 "\">\n", lvs[j], size);
- display_partition (g, lvs[j]);
- printf ("</logvol>\n");
- free (lvs[j]);
- }
- }
-
- free (vgs[i]);
- printf ("</volgroup>\n");
- }
- free (vgs);
- free (lvs);
- printf ("</volgroups>\n");
-
- guestfs_close (g);
- printf ("</guestfs-system>\n");
-
- return 0;
-}
-
-/* Display a partition or LV. */
-static void
-display_partition (guestfs_h *g, const char *dev)
-{
- char *what;
-
- CALL (what = guestfs_file (g, dev), NULL);
-
- if (strcmp (what, "x86 boot sector") == 0)
- /* This is what 'file' program shows for Windows/NTFS partitions. */
- printf ("<windows/>\n");
- else if (strstr (what, "boot sector") != NULL)
- display_partitions (g, dev);
- else if (strncmp (what, "LVM2", 4) == 0)
- printf ("<physvol/>\n");
- else if (strstr (what, "ext2 filesystem data") != NULL)
- display_ext234 (g, dev, "ext2");
- else if (strstr (what, "ext3 filesystem data") != NULL)
- display_ext234 (g, dev, "ext3");
- else if (strstr (what, "ext4 filesystem data") != NULL)
- display_ext234 (g, dev, "ext4");
- else if (strstr (what, "Linux/i386 swap file") != NULL)
- printf ("<linux-swap/>\n");
- else
- printf ("<unknown/>\n");
-
- free (what);
-}
-
-/* Display an MBR-formatted boot sector. */
-static void
-display_partitions (guestfs_h *g, const char *dev)
-{
- /* We can't look into a boot sector which is an LV or partition.
- * That's a limitation of sorts of the Linux kernel. (Actually,
- * we could do this if we add the kpartx program to libguestfs).
- */
- if (strncmp (dev, "/dev/sd", 7) != 0 || isdigit (dev[strlen(dev)-1])) {
- printf ("<vm-image dev=\"%s\"/>\n", dev);
- return;
- }
-
- char **parts;
- int i, len;
- CALL (parts = guestfs_list_partitions (g), NULL);
- printf ("<partitions>\n");
-
- len = strlen (dev);
- for (i = 0; parts[i] != NULL; ++i) {
- /* Only display partition if it's in the device. */
- if (strncmp (parts[i], dev, len) == 0) {
- int64_t size;
- CALL (size = guestfs_blockdev_getsize64 (g, parts[i]), -1);
- printf ("<partition dev=\"%s\" size=\"%" PRIi64 "\">\n", parts[i], size);
- display_partition (g, parts[i]);
- printf ("</partition>\n");
- }
-
- free (parts[i]);
- }
- free (parts);
- printf ("</partitions>\n");
-}
-
-/* Display some details on the ext2/3/4 filesystem on dev. */
-static void
-display_ext234 (guestfs_h *g, const char *dev, const char *fstype)
-{
- char **sbfields;
- int i;
-
- printf ("<fs type=\"%s\">\n", fstype);
- CALL (sbfields = guestfs_tune2fs_l (g, dev), NULL);
-
- for (i = 0; sbfields[i] != NULL; i += 2) {
- /* Just pick out a few important fields to display. There
- * is much more that could be displayed here.
- */
- if (strcmp (sbfields[i], "Filesystem UUID") == 0)
- printf ("<uuid>%s</uuid>\n", sbfields[i+1]);
- else if (strcmp (sbfields[i], "Block size") == 0)
- printf ("<blocksize>%s</blocksize>\n", sbfields[i+1]);
-
- free (sbfields[i]);
- free (sbfields[i+1]);
- }
- free (sbfields);
-
- printf ("</fs>\n");
-}
Libguestfs is a large API because it can do many things. For a gentle
introduction, please read the L</API OVERVIEW> section next.
+There are also some example programs in the L<guestfs-examples(3)>
+manual page.
+
=head1 API OVERVIEW
This section provides a gentler overview of the libguestfs API. We
=head1 SEE ALSO
+L<guestfs-examples(3)>,
L<guestfish(1)>,
L<guestmount(1)>,
L<virt-cat(1)>,