1guestfs-examples(3)         Virtualization Support         guestfs-examples(3)
2
3
4

NAME

6       guestfs-examples - Examples of using libguestfs from C
7

SYNOPSIS

9        #include <guestfs.h>
10
11        guestfs_h *g = guestfs_create ();
12        guestfs_add_drive_ro (g, "disk.img");
13        guestfs_launch (g);
14
15        cc prog.c -o prog -lguestfs
16       or:
17        cc prog.c -o prog `pkg-config libguestfs --cflags --libs`
18

DESCRIPTION

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

EXAMPLE: CREATE A DISK IMAGE

25        /* Example showing how to create a disk image. */
26
27        #include <stdio.h>
28        #include <stdlib.h>
29        #include <string.h>
30        #include <fcntl.h>
31        #include <unistd.h>
32        #include <guestfs.h>
33
34        int
35        main (int argc, char *argv[])
36        {
37          guestfs_h *g;
38          size_t i;
39
40          g = guestfs_create ();
41          if (g == NULL) {
42            perror ("failed to create libguestfs handle");
43            exit (EXIT_FAILURE);
44          }
45
46          /* Set the trace flag so that we can see each libguestfs call. */
47          guestfs_set_trace (g, 1);
48
49          /* Create a raw-format sparse disk image, 512 MB in size. */
50          if (guestfs_disk_create (g, "disk.img", "raw", UINT64_C(512)*1024*1024,
51                                   -1) == -1)
52            exit (EXIT_FAILURE);
53
54          /* Add the disk image to libguestfs. */
55          if (guestfs_add_drive_opts (g, "disk.img",
56                                     GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", /* raw format */
57                                     GUESTFS_ADD_DRIVE_OPTS_READONLY, 0, /* for write */
58                                     -1) /* this marks end of optional arguments */
59              == -1)
60            exit (EXIT_FAILURE);
61
62          /* Run the libguestfs back-end. */
63          if (guestfs_launch (g) == -1)
64            exit (EXIT_FAILURE);
65
66          /* Get the list of devices.  Because we only added one drive
67           * above, we expect that this list should contain a single
68           * element.
69           */
70          char **devices = guestfs_list_devices (g);
71          if (devices == NULL)
72            exit (EXIT_FAILURE);
73          if (devices[0] == NULL || devices[1] != NULL) {
74            fprintf (stderr, "error: expected a single device from list-devices\n");
75            exit (EXIT_FAILURE);
76          }
77
78          /* Partition the disk as one single MBR partition. */
79          if (guestfs_part_disk (g, devices[0], "mbr") == -1)
80            exit (EXIT_FAILURE);
81
82          /* Get the list of partitions.  We expect a single element, which
83           * is the partition we have just created.
84           */
85          char **partitions = guestfs_list_partitions (g);
86          if (partitions == NULL)
87            exit (EXIT_FAILURE);
88          if (partitions[0] == NULL || partitions[1] != NULL) {
89            fprintf (stderr, "error: expected a single partition from list-partitions\n");
90            exit (EXIT_FAILURE);
91          }
92
93          /* Create a filesystem on the partition. */
94          if (guestfs_mkfs (g, "ext4", partitions[0]) == -1)
95            exit (EXIT_FAILURE);
96
97          /* Now mount the filesystem so that we can add files. */
98          if (guestfs_mount (g, partitions[0], "/") == -1)
99            exit (EXIT_FAILURE);
100
101          /* Create some files and directories. */
102          if (guestfs_touch (g, "/empty") == -1)
103            exit (EXIT_FAILURE);
104          const char *message = "Hello, world\n";
105          if (guestfs_write (g, "/hello", message, strlen (message)) == -1)
106            exit (EXIT_FAILURE);
107          if (guestfs_mkdir (g, "/foo") == -1)
108            exit (EXIT_FAILURE);
109
110          /* This one uploads the local file /etc/resolv.conf into
111           * the disk image.
112           */
113          if (guestfs_upload (g, "/etc/resolv.conf", "/foo/resolv.conf") == -1)
114            exit (EXIT_FAILURE);
115
116          /* Because we wrote to the disk and we want to detect write
117           * errors, call guestfs_shutdown.  You don't need to do this:
118           * guestfs_close will do it implicitly.
119           */
120          if (guestfs_shutdown (g) == -1)
121            exit (EXIT_FAILURE);
122
123          guestfs_close (g);
124
125          /* Free up the lists. */
126          for (i = 0; devices[i] != NULL; ++i)
127            free (devices[i]);
128          free (devices);
129          for (i = 0; partitions[i] != NULL; ++i)
130            free (partitions[i]);
131          free (partitions);
132
133          exit (EXIT_SUCCESS);
134        }
135

EXAMPLE: INSPECT A VIRTUAL MACHINE DISK IMAGE

137        /* Inspect a disk image and display operating systems it may contain. */
138
139        #include <stdio.h>
140        #include <stdlib.h>
141        #include <string.h>
142        #include <guestfs.h>
143
144        static int
145        compare_keys_len (const void *p1, const void *p2)
146        {
147          const char *key1 = * (char * const *) p1;
148          const char *key2 = * (char * const *) p2;
149          return strlen (key1) - strlen (key2);
150        }
151
152        static size_t
153        count_strings (char *const *argv)
154        {
155          size_t c;
156
157          for (c = 0; argv[c]; ++c)
158            ;
159          return c;
160        }
161
162        int
163        main (int argc, char *argv[])
164        {
165          guestfs_h *g;
166          const char *disk;
167          char **roots, *root, *str, **mountpoints, **lines;
168          size_t i, j;
169
170          if (argc != 2) {
171            fprintf (stderr, "usage: inspect_vm disk.img\n");
172            exit (EXIT_FAILURE);
173          }
174          disk = argv[1];
175
176          g = guestfs_create ();
177          if (g == NULL) {
178            perror ("failed to create libguestfs handle");
179            exit (EXIT_FAILURE);
180          }
181
182          /* Attach the disk image read-only to libguestfs. */
183          if (guestfs_add_drive_opts (g, disk,
184                                     /* GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", */
185                                     GUESTFS_ADD_DRIVE_OPTS_READONLY, 1,
186                                     -1) /* this marks end of optional arguments */
187              == -1)
188            exit (EXIT_FAILURE);
189
190          /* Run the libguestfs back-end. */
191          if (guestfs_launch (g) == -1)
192            exit (EXIT_FAILURE);
193
194          /* Ask libguestfs to inspect for operating systems. */
195          roots = guestfs_inspect_os (g);
196          if (roots == NULL)
197            exit (EXIT_FAILURE);
198          if (roots[0] == NULL) {
199            fprintf (stderr, "inspect_vm: no operating systems found\n");
200            exit (EXIT_FAILURE);
201          }
202
203          for (j = 0; roots[j] != NULL; ++j) {
204            root = roots[j];
205
206            printf ("Root device: %s\n", root);
207
208            /* Print basic information about the operating system. */
209            str = guestfs_inspect_get_product_name (g, root);
210            if (str)
211              printf ("  Product name: %s\n", str);
212            free (str);
213
214            printf ("  Version:      %d.%d\n",
215                    guestfs_inspect_get_major_version (g, root),
216                    guestfs_inspect_get_minor_version (g, root));
217
218            str = guestfs_inspect_get_type (g, root);
219            if (str)
220              printf ("  Type:         %s\n", str);
221            free (str);
222            str = guestfs_inspect_get_distro (g, root);
223            if (str)
224              printf ("  Distro:       %s\n", str);
225            free (str);
226
227            /* Mount up the disks, like guestfish -i.
228             *
229             * Sort keys by length, shortest first, so that we end up
230             * mounting the filesystems in the correct order.
231             */
232            mountpoints = guestfs_inspect_get_mountpoints (g, root);
233            if (mountpoints == NULL)
234              exit (EXIT_FAILURE);
235
236            qsort (mountpoints, count_strings (mountpoints) / 2, 2 * sizeof (char *),
237                   compare_keys_len);
238            for (i = 0; mountpoints[i] != NULL; i += 2) {
239              /* Ignore failures from this call, since bogus entries can
240               * appear in the guest's /etc/fstab.
241               */
242              guestfs_mount_ro (g, mountpoints[i+1], mountpoints[i]);
243              free (mountpoints[i]);
244              free (mountpoints[i+1]);
245            }
246            free (mountpoints);
247
248            /* If /etc/issue.net file exists, print up to 3 lines. */
249            if (guestfs_is_file (g, "/etc/issue.net") > 0) {
250              printf ("--- /etc/issue.net ---\n");
251              lines = guestfs_head_n (g, 3, "/etc/issue.net");
252              if (lines == NULL)
253                exit (EXIT_FAILURE);
254              for (i = 0; lines[i] != NULL; ++i) {
255                printf ("%s\n", lines[i]);
256                free (lines[i]);
257              }
258              free (lines);
259            }
260
261            /* Unmount everything. */
262            if (guestfs_umount_all (g) == -1)
263              exit (EXIT_FAILURE);
264
265            free (root);
266          }
267          free (roots);
268
269          guestfs_close (g);
270
271          exit (EXIT_SUCCESS);
272        }
273

EXAMPLE: ENABLE DEBUGGING AND LOGGING

275        /* Example showing how to enable debugging, and capture it into any
276         * custom logging system (syslog in this example, but any could be
277         * used).  Note this uses the event API which is also available in
278         * non-C language bindings.
279         */
280
281        #include <stdio.h>
282        #include <stdlib.h>
283        #include <string.h>
284        #include <unistd.h>
285        #include <syslog.h>
286        #include <guestfs.h>
287
288        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);
289
290        /* Events we are interested in.  This bitmask covers all trace and
291         * debug messages.
292         */
293        static const uint64_t event_bitmask =
294          GUESTFS_EVENT_LIBRARY |
295          GUESTFS_EVENT_WARNING |
296          GUESTFS_EVENT_APPLIANCE |
297          GUESTFS_EVENT_TRACE;
298
299        int
300        main (int argc, char *argv[])
301        {
302          guestfs_h *g;
303
304          g = guestfs_create ();
305          if (g == NULL) {
306            perror ("failed to create libguestfs handle");
307            exit (EXIT_FAILURE);
308          }
309
310          /* By default, debugging information is printed on stderr.  To
311           * capture it somewhere else you have to set up an event handler
312           * which will be called back as debug messages are generated.  To do
313           * this use the event API.
314           *
315           * For more information see EVENTS in guestfs(3).
316           */
317          if (guestfs_set_event_callback (g, message_callback,
318                                          event_bitmask, 0, NULL) == -1)
319            exit (EXIT_FAILURE);
320
321          /* This is how debugging is enabled:
322           *
323           * Setting the 'trace' flag in the handle means that each libguestfs
324           * call is logged (name, parameters, return).  This flag is useful
325           * to see how libguestfs is being used by a program.
326           *
327           * Setting the 'verbose' flag enables a great deal of extra
328           * debugging throughout the system.  This is useful if there is a
329           * libguestfs error which you don't understand.
330           *
331           * Note that you should set the flags early on after creating the
332           * handle.  In particular if you set the verbose flag after launch
333           * then you won't see all messages.
334           *
335           * For more information see:
336           * http://libguestfs.org/guestfs-faq.1.html#debugging-libguestfs
337           *
338           * Error messages raised by APIs are *not* debugging information,
339           * and they are not affected by any of this.  You may have to log
340           * them separately.
341           */
342          guestfs_set_trace (g, 1);
343          guestfs_set_verbose (g, 1);
344
345          /* Do some operations which will generate plenty of trace and debug
346           * messages.
347           */
348          if (guestfs_add_drive (g, "/dev/null") == -1)
349            exit (EXIT_FAILURE);
350
351          printf ("There is no output from this program.  "
352                  "Take a look in your system log file,\n"
353                  "eg. /var/log/messages.\n");
354
355          if (guestfs_launch (g) == -1)
356            exit (EXIT_FAILURE);
357
358          guestfs_close (g);
359
360          exit (EXIT_SUCCESS);
361        }
362
363        /* This function is called back by libguestfs whenever a trace or
364         * debug message is generated.
365         *
366         * For the classes of events we have registered above, 'array' and
367         * 'array_len' will not be meaningful.  Only 'buf' and 'buf_len' will
368         * be interesting and these will contain the trace or debug message.
369         *
370         * This example simply redirects these messages to syslog, but
371         * obviously you could do something more advanced here.
372         */
373        static void
374        message_callback (guestfs_h *g, void *opaque,
375                          uint64_t event, int event_handle,
376                          int flags,
377                          const char *buf, size_t buf_len,
378                          const uint64_t *array, size_t array_len)
379        {
380          const int priority = LOG_USER|LOG_INFO;
381          char *event_name, *msg;
382
383          if (buf_len > 0) {
384            event_name = guestfs_event_to_string (event);
385            msg = strndup (buf, buf_len);
386            syslog (priority, "[%s] %s", event_name, msg);
387            free (msg);
388            free (event_name);
389          }
390        }
391

EXAMPLE: DISPLAY THE OPERATING SYSTEM ICON OF A GUEST

393        /* This example inspects a guest using libguestfs inspection (see
394         * "INSPECTION" in guestfs(3)), and if possible displays a
395         * representative icon or logo for the guest's operating system.
396         */
397
398        #include <stdio.h>
399        #include <stdlib.h>
400        #include <string.h>
401        #include <guestfs.h>
402
403        static int
404        compare_keys_len (const void *p1, const void *p2)
405        {
406          const char *key1 = * (char * const *) p1;
407          const char *key2 = * (char * const *) p2;
408          return strlen (key1) - strlen (key2);
409        }
410
411        static size_t
412        count_strings (char *const *argv)
413        {
414          size_t c;
415
416          for (c = 0; argv[c]; ++c)
417            ;
418          return c;
419        }
420
421        int
422        main (int argc, char *argv[])
423        {
424          guestfs_h *g;
425          const char *disk;
426          char **roots, *root, **mountpoints, *icon;
427          size_t i, j, icon_size;
428          FILE *fp;
429
430          if (argc != 2) {
431            fprintf (stderr, "usage: display-icon disk.img\n");
432            exit (EXIT_FAILURE);
433          }
434          disk = argv[1];
435
436          g = guestfs_create ();
437          if (g == NULL) {
438            perror ("failed to create libguestfs handle");
439            exit (EXIT_FAILURE);
440          }
441
442          /* Attach the disk image read-only to libguestfs. */
443          if (guestfs_add_drive_opts (g, disk,
444                                     /* GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", */
445                                     GUESTFS_ADD_DRIVE_OPTS_READONLY, 1,
446                                     -1) /* this marks end of optional arguments */
447              == -1)
448            exit (EXIT_FAILURE);
449
450          /* Run the libguestfs back-end. */
451          if (guestfs_launch (g) == -1)
452            exit (EXIT_FAILURE);
453
454          /* Ask libguestfs to inspect for operating systems. */
455          roots = guestfs_inspect_os (g);
456          if (roots == NULL)
457            exit (EXIT_FAILURE);
458          if (roots[0] == NULL) {
459            fprintf (stderr, "display-icon: no operating systems found\n");
460            exit (EXIT_FAILURE);
461          }
462
463          for (j = 0; roots[j] != NULL; ++j) {
464            root = roots[j];
465
466            /* Mount up the disks, like guestfish -i.
467             *
468             * Sort keys by length, shortest first, so that we end up
469             * mounting the filesystems in the correct order.
470             */
471            mountpoints = guestfs_inspect_get_mountpoints (g, root);
472            if (mountpoints == NULL)
473              exit (EXIT_FAILURE);
474
475            qsort (mountpoints, count_strings (mountpoints) / 2, 2 * sizeof (char *),
476                   compare_keys_len);
477            for (i = 0; mountpoints[i] != NULL; i += 2) {
478              /* Ignore failures from this call, since bogus entries can
479               * appear in the guest's /etc/fstab.
480               */
481              guestfs_mount_ro (g, mountpoints[i+1], mountpoints[i]);
482              free (mountpoints[i]);
483              free (mountpoints[i+1]);
484            }
485            free (mountpoints);
486
487            /* Get the icon.
488             * This function returns a buffer ('icon').  Normally it is a png
489             * file, returned as a string, but it can also be a zero length
490             * buffer which has a special meaning, or NULL which means there
491             * was an error.
492             */
493            icon = guestfs_inspect_get_icon (g, root, &icon_size, -1);
494            if (!icon)                  /* actual libguestfs error */
495              exit (EXIT_FAILURE);
496            if (icon_size == 0)         /* no icon available */
497              fprintf (stderr, "%s: %s: no icon available for this operating system\n",
498                       disk, root);
499            else {
500              /* Display the icon. */
501              fp = popen ("display -", "w");
502              if (fp == NULL) {
503                perror ("display");
504                exit (EXIT_FAILURE);
505              }
506              if (fwrite (icon, 1, icon_size, fp) != icon_size) {
507                perror ("write");
508                exit (EXIT_FAILURE);
509              }
510              if (pclose (fp) == -1) {
511                perror ("pclose");
512                exit (EXIT_FAILURE);
513              }
514            }
515            free (icon);
516
517            /* Unmount everything. */
518            if (guestfs_umount_all (g) == -1)
519              exit (EXIT_FAILURE);
520
521            free (root);
522          }
523          free (roots);
524
525          guestfs_close (g);
526
527          exit (EXIT_SUCCESS);
528        }
529

EXAMPLE: THE LIBVIRT AUTHENTICATION API

531        /* Example of using the libvirt authentication event-driven API.
532         *
533         * See "LIBVIRT AUTHENTICATION" in guestfs(3).
534         */
535
536        #include <stdio.h>
537        #include <stdlib.h>
538        #include <string.h>
539        #include <unistd.h>
540
541        #include <guestfs.h>
542
543        static void
544        usage (void)
545        {
546          fprintf (stderr,
547                  "Usage:\n"
548                  "\n"
549                  "  libvirt-auth URI domain\n"
550                  "\n"
551                  "where:\n"
552                  "\n"
553                  "  URI     is the libvirt URI, eg. qemu+libssh2://USER@localhost/system\n"
554                  "  domain  is the name of the guest\n"
555                  "\n"
556                  "Example:\n"
557                  "\n"
558                  "  libvirt-auth 'qemu+libssh2://USER@localhost/system' 'foo'\n"
559                  "\n"
560                  "would connect (read-only) to libvirt URI given and open the guest\n"
561                  "called 'foo' and list some information about its filesystems.\n"
562                  "\n"
563                  "The important point of this example is that any libvirt authentication\n"
564                  "required to connect to the server should be done.\n"
565                  "\n");
566        }
567
568        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);
569
570        int
571        main (int argc, char *argv[])
572        {
573          const char *uri, *dom;
574          guestfs_h *g;
575          const char *creds[] = { "authname", "passphrase",
576                                  "echoprompt", "noechoprompt", NULL };
577          int r, eh;
578          char **filesystems;
579          size_t i;
580
581          if (argc != 3) {
582            usage ();
583            exit (EXIT_FAILURE);
584          }
585          uri = argv[1];
586          dom = argv[2];
587
588          g = guestfs_create ();
589          if (!g)
590            exit (EXIT_FAILURE);
591
592          r = guestfs_set_libvirt_supported_credentials (g, (char **) creds);
593          if (r == -1)
594            exit (EXIT_FAILURE);
595
596          /* Set up the event handler. */
597          eh = guestfs_set_event_callback (g, auth_callback,
598                                           GUESTFS_EVENT_LIBVIRT_AUTH, 0, NULL);
599          if (eh == -1)
600            exit (EXIT_FAILURE);
601
602          /* Add the named domain. */
603          r = guestfs_add_domain (g, dom,
604                                  GUESTFS_ADD_DOMAIN_LIBVIRTURI, uri,
605                                  -1);
606          if (r == -1)
607            exit (EXIT_FAILURE);
608
609          /* Launch and do some simple inspection. */
610          r = guestfs_launch (g);
611          if (r == -1)
612            exit (EXIT_FAILURE);
613
614          filesystems = guestfs_list_filesystems (g);
615          if (filesystems == NULL)
616            exit (EXIT_FAILURE);
617
618          for (i = 0; filesystems[i] != NULL; i += 2) {
619            printf ("%s:%s is a %s filesystem\n",
620                    dom, filesystems[i], filesystems[i+1]);
621            free (filesystems[i]);
622            free (filesystems[i+1]);
623          }
624          free (filesystems);
625
626          exit (EXIT_SUCCESS);
627        }
628
629        static void
630        auth_callback (guestfs_h *g,
631                       void *opaque,
632                       uint64_t event,
633                       int event_handle,
634                       int flags,
635                       const char *buf, size_t buf_len,
636                       const uint64_t *array, size_t array_len)
637        {
638          char **creds;
639          size_t i;
640          char *prompt;
641          char *reply = NULL;
642          size_t allocsize = 0;
643          char *pass;
644          ssize_t len;
645          int r;
646
647          printf ("libvirt-auth.c: authentication required for libvirt URI '%s'\n\n",
648                  buf);
649
650          /* Ask libguestfs what credentials libvirt is demanding. */
651          creds = guestfs_get_libvirt_requested_credentials (g);
652          if (creds == NULL)
653            exit (EXIT_FAILURE);
654
655          /* Now ask the user for answers. */
656          for (i = 0; creds[i] != NULL; ++i)
657          {
658            printf ("libvirt-auth.c: credential '%s'\n", creds[i]);
659
660            if (strcmp (creds[i], "authname") == 0 ||
661                strcmp (creds[i], "echoprompt") == 0) {
662              prompt = guestfs_get_libvirt_requested_credential_prompt (g, i);
663              if (prompt && strcmp (prompt, "") != 0)
664                printf ("%s: ", prompt);
665              free (prompt);
666
667              len = getline (&reply, &allocsize, stdin);
668              if (len == -1) {
669                perror ("getline");
670                exit (EXIT_FAILURE);
671              }
672              if (len > 0 && reply[len-1] == '\n')
673                reply[--len] = '\0';
674
675              r = guestfs_set_libvirt_requested_credential (g, i, reply, len);
676              if (r == -1)
677                exit (EXIT_FAILURE);
678            } else if (strcmp (creds[i], "passphrase") == 0 ||
679                       strcmp (creds[i], "noechoprompt") == 0) {
680              prompt = guestfs_get_libvirt_requested_credential_prompt (g, i);
681              if (prompt && strcmp (prompt, "") != 0)
682                printf ("%s: ", prompt);
683              free (prompt);
684
685              pass = getpass ("");
686              if (pass == NULL) {
687                perror ("getpass");
688                exit (EXIT_FAILURE);
689              }
690              len = strlen (pass);
691
692              r = guestfs_set_libvirt_requested_credential (g, i, pass, len);
693              if (r == -1)
694                exit (EXIT_FAILURE);
695            }
696
697            free (creds[i]);
698          }
699
700          free (reply);
701          free (creds);
702        }
703

EXAMPLE: THE MOUNT LOCAL API

705        /* Demonstrate the use of the 'mount-local' API.
706         *
707         * Run this program as (eg) mount-local /tmp/test.img.  Note that
708         * '/tmp/test.img' is created or overwritten.  Follow the instructions
709         * on screen.
710         *
711         * See "MOUNT LOCAL" in guestfs(3).
712         */
713
714        #include <stdio.h>
715        #include <stdlib.h>
716        #include <string.h>
717        #include <unistd.h>
718        #include <fcntl.h>
719        #include <sys/wait.h>
720
721        #include <guestfs.h>
722
723        #ifndef O_CLOEXEC
724        #define O_CLOEXEC 0
725        #endif
726
727        /* Define a list of filesystem mount options (used on the libguestfs
728         * side, nothing to do with FUSE).  An empty string may be used here
729         * instead.
730         */
731        #define MOUNT_OPTIONS "acl,user_xattr"
732
733        /* Size of the disk (megabytes). */
734        #define SIZE_MB 512
735
736        static void
737        usage (void)
738        {
739          fprintf (stderr,
740                   "Usage: mount-local disk.img\n"
741                   "\n"
742                   "NOTE: disk.img will be created or overwritten.\n"
743                   "\n");
744        }
745
746        int
747        main (int argc, char *argv[])
748        {
749          guestfs_h *g;
750          int r;
751          char tempdir[] = "/tmp/mlXXXXXX";
752          pid_t pid;
753          char *shell, *p;
754
755          if (argc != 2) {
756            usage ();
757            exit (EXIT_FAILURE);
758          }
759
760          if (argv[1][0] == '-') {
761            usage ();
762            exit (EXIT_FAILURE);
763          }
764
765          printf ("\n"
766                  "This is the 'mount-local' demonstration program.  Follow the\n"
767                  "instructions on screen.\n"
768                  "\n"
769                  "Creating and formatting the disk image, please wait a moment ...\n");
770          fflush (stdout);
771
772          /* Guestfs handle. */
773          g = guestfs_create ();
774          if (g == NULL) {
775            perror ("could not create libguestfs handle");
776            exit (EXIT_FAILURE);
777          }
778
779          /* Create the output disk image: raw sparse. */
780          if (guestfs_disk_create (g, argv[1], "raw", SIZE_MB * 1024 * 1024, -1) == -1)
781            exit (EXIT_FAILURE);
782
783          /* Create the disk image and format it with a partition and a filesystem. */
784          if (guestfs_add_drive_opts (g, argv[1],
785                                      GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw",
786                                      -1) == -1)
787            exit (EXIT_FAILURE);
788
789          if (guestfs_launch (g) == -1)
790            exit (EXIT_FAILURE);
791
792          if (guestfs_part_disk (g, "/dev/sda", "mbr") == -1)
793            exit (EXIT_FAILURE);
794
795          if (guestfs_mkfs (g, "ext2", "/dev/sda1") == -1)
796            exit (EXIT_FAILURE);
797
798          /* Mount the empty filesystem. */
799          if (guestfs_mount_options (g, MOUNT_OPTIONS, "/dev/sda1", "/") == -1)
800            exit (EXIT_FAILURE);
801
802          /* Create a file in the new filesystem. */
803          if (guestfs_touch (g, "/PUT_FILES_AND_DIRECTORIES_HERE") == -1)
804            exit (EXIT_FAILURE);
805
806          /* Create a temporary mount directory. */
807          if (mkdtemp (tempdir) == NULL) {
808            perror ("mkdtemp");
809            exit (EXIT_FAILURE);
810          }
811
812          /* Mount the filesystem. */
813          if (guestfs_mount_local (g, tempdir, -1) == -1)
814            exit (EXIT_FAILURE);
815
816          /* Fork the shell for the user. */
817          pid = fork ();
818          if (pid == -1) {
819            perror ("fork");
820            exit (EXIT_FAILURE);
821          }
822
823          if (pid == 0) {               /* Child. */
824            if (chdir (tempdir) == -1) {
825              perror (tempdir);
826              _exit (EXIT_FAILURE);
827            }
828
829            printf ("\n"
830                    "The *current directory* is a FUSE filesystem backed by the disk\n"
831                    "image which is managed by libguestfs.  Any files or directories\n"
832                    "you copy into here (up to %d MB) will be saved into the disk\n"
833                    "image.  You can also delete files, create certain special files\n"
834                    "and so on.\n"
835                    "\n"
836                    "When you have finished adding files, hit ^D or type 'exit' to\n"
837                    "exit the shell and return to the mount-local program.\n"
838                    "\n",
839                    SIZE_MB);
840
841            shell = getenv ("SHELL");
842            if (!shell)
843              r = system ("/bin/sh");
844            else {
845              /* Set a magic prompt.  We only know how to do this for bash. */
846              p = strrchr (shell, '/');
847              if (p && strcmp (p+1, "bash") == 0) {
848                const size_t len = 64 + strlen (shell);
849                char *buf;
850
851                buf = malloc (len);
852                if (buf == NULL) {
853                  perror ("malloc");
854                  _exit (EXIT_FAILURE);
855                }
856                snprintf (buf, len, "PS1='mount-local-shell> ' %s --norc -i", shell);
857                r = system (buf);
858                free (buf);
859              } else
860                r = system (shell);
861            }
862            if (r == -1) {
863              fprintf (stderr, "error: failed to run sub-shell (%s) "
864                       "(is $SHELL set correctly?)\n",
865                       shell);
866              //FALLTHROUGH
867            }
868
869            if (chdir ("/") == -1)
870              perror ("chdir: /");
871            guestfs_umount_local (g, GUESTFS_UMOUNT_LOCAL_RETRY, 1, -1);
872            _exit (EXIT_SUCCESS);
873          }
874
875          /* Note that we are *not* waiting for the child yet.  We want to
876           * run the FUSE code in parallel with the subshell.
877           */
878
879          /* We're going to hide libguestfs errors here, but in a real program
880           * you would probably want to log them somewhere.
881           */
882          guestfs_push_error_handler (g, NULL, NULL);
883
884          /* Now run the FUSE thread. */
885          if (guestfs_mount_local_run (g) == -1)
886            exit (EXIT_FAILURE);
887
888          guestfs_pop_error_handler (g);
889
890          waitpid (pid, NULL, 0);
891
892          /* Shutdown the handle explicitly so write errors can be detected. */
893          if (guestfs_shutdown (g) == -1)
894            exit (EXIT_FAILURE);
895
896          guestfs_close (g);
897
898          printf ("\n"
899                  "Any files or directories that you copied in have been saved into\n"
900                  "the disk image called '%s'.\n"
901                  "\n"
902                  "Try opening the disk image with guestfish to see those files:\n"
903                  "\n"
904                  "  guestfish -a %s -m /dev/sda1\n"
905                  "\n",
906                  argv[1], argv[1]);
907
908          exit (EXIT_SUCCESS);
909        }
910

EXAMPLE: MULTIPLE HANDLES AND THREADS

912        /* Copy a directory from one libvirt guest to another.
913         *
914         * This is a more substantial example of using the libguestfs API,
915         * demonstrating amongst other things:
916         *
917         * - using multiple handles with threads
918         * - upload and downloading (using a pipe between handles)
919         * - inspection
920         */
921
922        #include <stdio.h>
923        #include <stdlib.h>
924        #include <stdint.h>
925        #include <inttypes.h>
926        #include <string.h>
927        #include <unistd.h>
928        #include <fcntl.h>
929        #include <errno.h>
930        #include <sys/time.h>
931
932        #include <pthread.h>
933
934        #include <guestfs.h>
935
936        struct threaddata {
937          const char *src;
938          const char *srcdir;
939          int fd;
940          pthread_t mainthread;
941        };
942
943        static void *start_srcthread (void *);
944        static int open_guest (guestfs_h *g, const char *dom, int readonly);
945        static int64_t timeval_diff (const struct timeval *x, const struct timeval *y);
946        static int compare_keys_len (const void *p1, const void *p2);
947        static size_t count_strings (char *const *argv);
948
949        static void
950        usage (void)
951        {
952          fprintf (stderr,
953                  "Usage: copy-over source srcdir dest destdir\n"
954                  "\n"
955                  "  source  : the source domain (a libvirt guest name)\n"
956                  "  srcdir  : the directory to copy from the source guest\n"
957                  "  dest    : the destination domain (a libvirt guest name)\n"
958                  "  destdir : the destination directory (must exist at destination)\n"
959                  "\n"
960                  "eg: copy-over Src /home/rjones Dest /tmp/dir\n"
961                  "would copy /home/rjones from Src to /tmp/dir on Dest\n"
962                  "\n"
963                  "The destination guest cannot be running.\n");
964        }
965
966        int
967        main (int argc, char *argv[])
968        {
969          const char *src, *srcdir, *dest, *destdir;
970          guestfs_h *destg;
971          int fd[2];
972          pthread_t srcthread;
973          struct threaddata threaddata;
974          int err;
975          char fdname[128];
976          struct timeval start_t, end_t;
977          int64_t ms;
978
979          if (argc != 5) {
980            usage ();
981            exit (EXIT_FAILURE);
982          }
983
984          src = argv[1];
985          srcdir = argv[2];
986          dest = argv[3];
987          destdir = argv[4];
988
989          /* Instead of downloading to local disk and uploading, we are going
990           * to connect the source download and destination upload using a
991           * pipe.  Create that pipe.
992           */
993          if (pipe (fd) == -1) {
994            perror ("pipe");
995            exit (EXIT_FAILURE);
996          }
997
998          /* We don't want the pipe to be passed to subprocesses. */
999          if (fcntl (fd[0], F_SETFD, FD_CLOEXEC) == -1 ||
1000              fcntl (fd[1], F_SETFD, FD_CLOEXEC) == -1) {
1001            perror ("fcntl");
1002            exit (EXIT_FAILURE);
1003          }
1004
1005          /* The libguestfs API is synchronous, so if we want to use two
1006           * handles concurrently, then we have to have two threads.  In this
1007           * case the main thread (this one) is handling the destination
1008           * domain (uploading), and we create one more thread to handle the
1009           * source domain (downloading).
1010           */
1011          threaddata.src = src;
1012          threaddata.srcdir = srcdir;
1013          threaddata.fd = fd[1];
1014          threaddata.mainthread = pthread_self ();
1015          err = pthread_create (&srcthread, NULL, start_srcthread, &threaddata);
1016          if (err != 0) {
1017            fprintf (stderr, "pthread_create: %s\n", strerror (err));
1018            exit (EXIT_FAILURE);
1019          }
1020
1021          /* Open the destination domain. */
1022          destg = guestfs_create ();
1023          if (!destg) {
1024            perror ("failed to create libguestfs handle");
1025            pthread_cancel (srcthread);
1026            exit (EXIT_FAILURE);
1027          }
1028          if (open_guest (destg, dest, 0) == -1) {
1029            pthread_cancel (srcthread);
1030            exit (EXIT_FAILURE);
1031          }
1032
1033          gettimeofday (&start_t, NULL);
1034
1035          /* Begin the upload. */
1036          snprintf (fdname, sizeof fdname, "/dev/fd/%d", fd[0]);
1037          if (guestfs_tar_in (destg, fdname, destdir) == -1) {
1038            pthread_cancel (srcthread);
1039            exit (EXIT_FAILURE);
1040          }
1041
1042          /* Close our end of the pipe.  The other thread will close the
1043           * other side of the pipe.
1044           */
1045          close (fd[0]);
1046
1047          /* Wait for the other thread to finish. */
1048          err = pthread_join (srcthread, NULL);
1049          if (err != 0) {
1050            fprintf (stderr, "pthread_join: %s\n", strerror (err));
1051            exit (EXIT_FAILURE);
1052          }
1053
1054          /* Clean up. */
1055          if (guestfs_shutdown (destg) == -1)
1056            exit (EXIT_FAILURE);
1057          guestfs_close (destg);
1058
1059          gettimeofday (&end_t, NULL);
1060
1061          /* Print the elapsed time. */
1062          ms = timeval_diff (&start_t, &end_t);
1063          printf ("copy finished, elapsed time (excluding launch) was "
1064                  "%" PRIi64 ".%03" PRIi64 " s\n",
1065                  ms / 1000, ms % 1000);
1066
1067          exit (EXIT_SUCCESS);
1068        }
1069
1070        static void *
1071        start_srcthread (void *arg)
1072        {
1073          struct threaddata *threaddata = arg;
1074          guestfs_h *srcg;
1075          char fdname[128];
1076
1077          /* Open the source domain. */
1078          srcg = guestfs_create ();
1079          if (!srcg) {
1080            perror ("failed to create libguestfs handle");
1081            pthread_cancel (threaddata->mainthread);
1082            exit (EXIT_FAILURE);
1083          }
1084          if (open_guest (srcg, threaddata->src, 1) == -1) {
1085            pthread_cancel (threaddata->mainthread);
1086            exit (EXIT_FAILURE);
1087          }
1088
1089          /* Begin the download. */
1090          snprintf (fdname, sizeof fdname, "/dev/fd/%d", threaddata->fd);
1091          if (guestfs_tar_out (srcg, threaddata->srcdir, fdname) == -1) {
1092            pthread_cancel (threaddata->mainthread);
1093            exit (EXIT_FAILURE);
1094          }
1095
1096          /* Close the pipe; this will cause the receiver to finish the upload. */
1097          if (close (threaddata->fd) == -1) {
1098            pthread_cancel (threaddata->mainthread);
1099            exit (EXIT_FAILURE);
1100          }
1101
1102          /* Clean up. */
1103          guestfs_close (srcg);
1104
1105          return NULL;
1106        }
1107
1108        /* This function deals with the complexity of adding the domain,
1109         * launching the handle, and mounting up filesystems.  See
1110         * 'examples/inspect-vm.c' to understand how this works.
1111         */
1112        static int
1113        open_guest (guestfs_h *g, const char *dom, int readonly)
1114        {
1115          char **roots, *root, **mountpoints;
1116          size_t i;
1117
1118          /* Use libvirt to find the guest disks and add them to the handle. */
1119          if (guestfs_add_domain (g, dom,
1120                                  GUESTFS_ADD_DOMAIN_READONLY, readonly,
1121                                  -1) == -1)
1122            return -1;
1123
1124          if (guestfs_launch (g) == -1)
1125            return -1;
1126
1127          /* Inspect the guest, looking for operating systems. */
1128          roots = guestfs_inspect_os (g);
1129          if (roots == NULL)
1130            return -1;
1131
1132          if (roots[0] == NULL || roots[1] != NULL) {
1133            fprintf (stderr, "copy-over: %s: no operating systems or multiple operating systems found\n", dom);
1134            return -1;
1135          }
1136
1137          root = roots[0];
1138
1139          /* Mount up the filesystems (like 'guestfish -i'). */
1140          mountpoints = guestfs_inspect_get_mountpoints (g, root);
1141          if (mountpoints == NULL)
1142            return -1;
1143
1144          qsort (mountpoints, count_strings (mountpoints) / 2, 2 * sizeof (char *),
1145                 compare_keys_len);
1146          for (i = 0; mountpoints[i] != NULL; i += 2) {
1147            /* Ignore failures from this call, since bogus entries can
1148             * appear in the guest's /etc/fstab.
1149             */
1150            (readonly ? guestfs_mount_ro : guestfs_mount)
1151              (g, mountpoints[i+1], mountpoints[i]);
1152            free (mountpoints[i]);
1153            free (mountpoints[i+1]);
1154          }
1155
1156          free (mountpoints);
1157
1158          free (root);
1159          free (roots);
1160
1161          /* Everything ready, no error. */
1162          return 0;
1163        }
1164
1165        /* Compute Y - X and return the result in milliseconds.
1166         * Approximately the same as this code:
1167         * http://www.mpp.mpg.de/~huber/util/timevaldiff.c
1168         */
1169        static int64_t
1170        timeval_diff (const struct timeval *x, const struct timeval *y)
1171        {
1172          int64_t msec;
1173
1174          msec = (y->tv_sec - x->tv_sec) * 1000;
1175          msec += (y->tv_usec - x->tv_usec) / 1000;
1176          return msec;
1177        }
1178
1179        static int
1180        compare_keys_len (const void *p1, const void *p2)
1181        {
1182          const char *key1 = * (char * const *) p1;
1183          const char *key2 = * (char * const *) p2;
1184          return strlen (key1) - strlen (key2);
1185        }
1186
1187        static size_t
1188        count_strings (char *const *argv)
1189        {
1190          size_t c;
1191
1192          for (c = 0; argv[c]; ++c)
1193            ;
1194          return c;
1195        }
1196

EXAMPLE: FETCH DHCP ADDRESS FROM A GUEST

1198        /* This is a more significant example of a tool which can grab the
1199         * DHCP address from some types of virtual machine.  Since there are
1200         * so many possible ways to do this, without clarity on which is the
1201         * best way, I don't want to make this into an official virt tool.
1202         *
1203         * For more information, see:
1204         *
1205         * https://rwmj.wordpress.com/2010/10/26/tip-find-the-ip-address-of-a-virtual-machine/
1206         * https://rwmj.wordpress.com/2011/03/30/tip-another-way-to-get-the-ip-address-of-a-virtual-machine/
1207         */
1208
1209        #include <stdio.h>
1210        #include <stdlib.h>
1211        #include <string.h>
1212        #include <errno.h>
1213        #include <unistd.h>
1214        #include <assert.h>
1215
1216        #include <guestfs.h>
1217
1218        static int compare_keys_len (const void *p1, const void *p2);
1219        static size_t count_strings (char *const *argv);
1220        static void free_strings (char **argv);
1221        static void mount_disks (guestfs_h *g, char *root);
1222        static void print_dhcp_address (guestfs_h *g, char *root);
1223        static void print_dhcp_address_linux (guestfs_h *g, char *root, const char *logfile);
1224        static void print_dhcp_address_windows (guestfs_h *g, char *root);
1225
1226        int
1227        main (int argc, char *argv[])
1228        {
1229          guestfs_h *g;
1230          size_t i;
1231          char **roots, *root;
1232
1233          if (argc < 2) {
1234            fprintf (stderr,
1235                     "Usage: virt-dhcp-address disk.img [disk.img [...]]\n"
1236                     "Note that all disks must come from a single virtual machine.\n");
1237            exit (EXIT_FAILURE);
1238          }
1239
1240          g = guestfs_create ();
1241          if (g == NULL) {
1242            perror ("failed to create libguestfs handle");
1243            exit (EXIT_FAILURE);
1244          }
1245
1246          for (i = 1; i < (size_t) argc; ++i) {
1247            /* Attach the disk image(s) read-only to libguestfs. */
1248            if (guestfs_add_drive_opts (g, argv[i],
1249                                        /* GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", */
1250                                        GUESTFS_ADD_DRIVE_OPTS_READONLY, 1,
1251                                        -1) /* this marks end of optional arguments */
1252                == -1)
1253              exit (EXIT_FAILURE);
1254          }
1255
1256          /* Run the libguestfs back-end. */
1257          if (guestfs_launch (g) == -1)
1258            exit (EXIT_FAILURE);
1259
1260          /* Ask libguestfs to inspect for operating systems. */
1261          roots = guestfs_inspect_os (g);
1262          if (roots == NULL)
1263            exit (EXIT_FAILURE);
1264          if (roots[0] == NULL) {
1265            fprintf (stderr, "virt-dhcp-address: no operating systems found\n");
1266            exit (EXIT_FAILURE);
1267          }
1268          if (count_strings (roots) > 1) {
1269            fprintf (stderr, "virt-dhcp-address: multi-boot operating system\n");
1270            exit (EXIT_FAILURE);
1271          }
1272
1273          root = roots[0];
1274
1275          /* Mount up the guest's disks. */
1276          mount_disks (g, root);
1277
1278          /* Print DHCP address. */
1279          print_dhcp_address (g, root);
1280
1281          /* Close handle and exit. */
1282          guestfs_close (g);
1283          free_strings (roots);
1284
1285          exit (EXIT_SUCCESS);
1286        }
1287
1288        static void
1289        mount_disks (guestfs_h *g, char *root)
1290        {
1291          char **mountpoints;
1292          size_t i;
1293
1294          /* Mount up the disks, like guestfish -i.
1295           *
1296           * Sort keys by length, shortest first, so that we end up
1297           * mounting the filesystems in the correct order.
1298           */
1299          mountpoints = guestfs_inspect_get_mountpoints (g, root);
1300          if (mountpoints == NULL)
1301            exit (EXIT_FAILURE);
1302
1303          qsort (mountpoints, count_strings (mountpoints) / 2, 2 * sizeof (char *),
1304                 compare_keys_len);
1305
1306          for (i = 0; mountpoints[i] != NULL; i += 2) {
1307            /* Ignore failures from this call, since bogus entries can
1308             * appear in the guest's /etc/fstab.
1309             */
1310            guestfs_mount_ro (g, mountpoints[i+1], mountpoints[i]);
1311          }
1312
1313          free_strings (mountpoints);
1314        }
1315
1316        static void
1317        print_dhcp_address (guestfs_h *g, char *root)
1318        {
1319          char *guest_type, *guest_distro;
1320
1321          /* Depending on the guest type, try to get the DHCP address. */
1322          guest_type = guestfs_inspect_get_type (g, root);
1323          if (guest_type == NULL)
1324            exit (EXIT_FAILURE);
1325
1326          if (strcmp (guest_type, "linux") == 0) {
1327            guest_distro = guestfs_inspect_get_distro (g, root);
1328            if (guest_distro == NULL)
1329              exit (EXIT_FAILURE);
1330
1331            if (strcmp (guest_distro, "fedora") == 0 ||
1332                strcmp (guest_distro, "rhel") == 0 ||
1333                strcmp (guest_distro, "redhat-based") == 0) {
1334              print_dhcp_address_linux (g, root, "/var/log/messages");
1335            }
1336            else if (strcmp (guest_distro, "debian") == 0 ||
1337                     strcmp (guest_distro, "ubuntu") == 0) {
1338              print_dhcp_address_linux (g, root, "/var/log/syslog");
1339            }
1340            else {
1341              fprintf (stderr, "virt-dhcp-address: don't know how to get DHCP address from '%s'\n",
1342                       guest_distro);
1343              exit (EXIT_FAILURE);
1344            }
1345
1346            free (guest_distro);
1347          }
1348          else if (strcmp (guest_type, "windows") == 0) {
1349            print_dhcp_address_windows (g, root);
1350          }
1351          else {
1352            fprintf (stderr, "virt-dhcp-address: don't know how to get DHCP address from '%s'\n",
1353                     guest_type);
1354            exit (EXIT_FAILURE);
1355          }
1356
1357          free (guest_type);
1358        }
1359
1360        /* Look for dhclient messages in logfile.
1361         */
1362        static void
1363        print_dhcp_address_linux (guestfs_h *g, char *root, const char *logfile)
1364        {
1365          char **lines, *p;
1366          size_t len;
1367
1368          lines = guestfs_grep_opts (g, "dhclient.*: bound to ", logfile,
1369                                     GUESTFS_GREP_OPTS_EXTENDED, 1,
1370                                     -1);
1371          if (lines == NULL)
1372            exit (EXIT_FAILURE);
1373
1374          len = count_strings (lines);
1375          if (len == 0) {
1376            fprintf (stderr, "virt-dhcp-address: cannot find DHCP address for this guest.\n");
1377            exit (EXIT_FAILURE);
1378          }
1379
1380          /* Only want the last message. */
1381          p = strstr (lines[len-1], "bound to ");
1382          assert (p);
1383          p += 9;
1384          len = strcspn (p, " ");
1385          p[len] = '\0';
1386
1387          printf ("%s\n", p);
1388
1389          free_strings (lines);
1390        }
1391
1392        /* Download the Windows SYSTEM hive and find DHCP configuration in there. */
1393        static void
1394        print_dhcp_address_windows (guestfs_h *g, char *root_fs)
1395        {
1396          char *system_path;
1397          int64_t root, node, value;
1398          struct guestfs_hivex_node_list *nodes;
1399          char *controlset;
1400          size_t i;
1401          char *p;
1402
1403          /* Locate the SYSTEM hive. */
1404          system_path = guestfs_inspect_get_windows_system_hive (g, root_fs);
1405          if (!system_path)
1406            exit (EXIT_FAILURE);
1407
1408          /* Open the hive to parse it.  Note that before libguestfs 1.19.35
1409           * you had to download the file and parse it using hivex(3).  Since
1410           * libguestfs 1.19.35, parts of the hivex(3) API are now exposed
1411           * through libguestfs, and that is what we'll use here because it is
1412           * more convenient and avoids having to download the hive.
1413           */
1414          if (guestfs_hivex_open (g, system_path, -1) == -1)
1415            exit (EXIT_FAILURE);
1416
1417          free (system_path);
1418
1419          root = guestfs_hivex_root (g);
1420          if (root == -1)
1421            exit (EXIT_FAILURE);
1422
1423          /* Get ControlSetXXX\Services\Tcpip\Parameters\Interfaces. */
1424          controlset = guestfs_inspect_get_windows_current_control_set (g, root_fs);
1425          if (controlset == NULL)
1426            exit (EXIT_FAILURE);
1427          const char *path[] = { controlset, "Services", "Tcpip", "Parameters",
1428                                 "Interfaces" };
1429          node = root;
1430          for (i = 0; node > 0 && i < sizeof path / sizeof path[0]; ++i)
1431            node = guestfs_hivex_node_get_child (g, node, path[i]);
1432
1433          if (node == -1)
1434            exit (EXIT_FAILURE);
1435
1436          if (node == 0) {
1437            fprintf (stderr, "virt-dhcp-address: HKLM\\System\\%s\\Services\\Tcpip\\Parameters\\Interfaces not found.", controlset);
1438            exit (EXIT_FAILURE);
1439          }
1440
1441          free (controlset);
1442
1443          /* Look for a node under here which has a "DhcpIPAddress" entry in it. */
1444          nodes = guestfs_hivex_node_children (g, node);
1445          if (nodes == NULL)
1446            exit (EXIT_FAILURE);
1447
1448          value = 0;
1449          for (i = 0; value == 0 && i < nodes->len; ++i) {
1450            value = guestfs_hivex_node_get_value (g, nodes->val[i].hivex_node_h,
1451                                                  "DhcpIPAddress");
1452            if (value == -1)
1453              exit (EXIT_FAILURE);
1454          }
1455
1456          if (value == 0) {
1457            fprintf (stderr, "virt-dhcp-address: cannot find DHCP address for this guest.\n");
1458            exit (EXIT_FAILURE);
1459          }
1460
1461          guestfs_free_hivex_node_list (nodes);
1462
1463          /* Get the string and use libguestfs's auto-conversion to convert it
1464           * to UTF-8 for output.
1465           */
1466          p = guestfs_hivex_value_string (g, value);
1467          if (!p)
1468            exit (EXIT_FAILURE);
1469
1470          printf ("%s\n", p);
1471
1472          free (p);
1473
1474          /* Close the hive handle. */
1475          guestfs_hivex_close (g);
1476        }
1477
1478        static int
1479        compare_keys_len (const void *p1, const void *p2)
1480        {
1481          const char *key1 = * (char * const *) p1;
1482          const char *key2 = * (char * const *) p2;
1483          return strlen (key1) - strlen (key2);
1484        }
1485
1486        static size_t
1487        count_strings (char *const *argv)
1488        {
1489          size_t c;
1490
1491          for (c = 0; argv[c]; ++c)
1492            ;
1493          return c;
1494        }
1495
1496        static void
1497        free_strings (char **argv)
1498        {
1499          size_t i;
1500
1501          for (i = 0; argv[i]; ++i)
1502            free (argv[i]);
1503          free (argv);
1504        }
1505

SEE ALSO

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

AUTHORS

1512       Richard W.M. Jones ("rjones at redhat dot com")
1513
1515       Copyright (C) 2010-2020 Red Hat Inc.
1516

LICENSE

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

BUGS

1523       To get a list of bugs against libguestfs, use this link:
1524       https://bugzilla.redhat.com/buglist.cgi?component=libguestfs&product=Virtualization+Tools
1525
1526       To report a new bug against libguestfs, use this link:
1527       https://bugzilla.redhat.com/enter_bug.cgi?component=libguestfs&product=Virtualization+Tools
1528
1529       When reporting a bug, please supply:
1530
1531       •   The version of libguestfs.
1532
1533       •   Where you got libguestfs (eg. which Linux distro, compiled from
1534           source, etc)
1535
1536       •   Describe the bug accurately and give a way to reproduce it.
1537
1538       •   Run libguestfs-test-tool(1) and paste the complete, unedited output
1539           into the bug report.
1540
1541
1542
1543libguestfs-1.49.9                 2023-01-19               guestfs-examples(3)
Impressum