Red Hat Training

A Red Hat training course is available for Red Hat Enterprise Linux

21.10. プログラミング言語からの API の使用

libguestfs API は、Red Hat Enterprise Linux 7 の次の言語から直接使用できます: C、C ++、Perl、Python、Java、Ruby、および OCaml
  • C バインディングおよび C++ バインディングをインストールするには、以下のコマンドを実行します。
    # yum install libguestfs-devel
  • Perl バインディングをインストールするには、以下のコマンドを実行します。
    # yum install 'perl(Sys::Guestfs)'
  • Python バインディングをインストールするには、以下のコマンドを実行します。
    # yum install python-libguestfs
  • Java バインディングをインストールするには、以下のコマンドを実行します。
    # yum install libguestfs-java libguestfs-java-devel libguestfs-javadoc
  • Ruby バインディングをインストールするには、以下のコマンドを実行します。
    # yum install ruby-libguestfs
  • OCaml バインディングをインストールするには、以下のコマンドを実行します。
    # yum install ocaml-libguestfs ocaml-libguestfs-devel
各言語のバインディングは基本的に同じですが、構文が少し変更されています。C ステートメント:
guestfs_launch (g);
Perl では、以下のように表示されます。
$g->launch ()
または、OCaml で以下のようになります。
g#launch ()
本セクションでは、C の API のみを説明します。
C バインディングおよび C++ バインディングでは、エラーを手動で確認する必要があります。他のバインディングでは、エラーは例外に変換されます。以下の例で示している追加のエラーチェックは他の言語には必要ありませんが、逆に例外をキャッチするコードを追加することもできます。libguestfs API のアーキテクチャーに関する肝心な点については、以下のリストを参照してください。
  • libguestfs API は同期的です。各呼び出しは、完了するまでブロックされます。非同期で呼び出しを行う場合は、スレッドを作成する必要があります。
  • libguestfs の API はスレッドセーフではありません。各ハンドルは、1 つのスレッドからのみ使用する必要があります。または、スレッド間でハンドルを共有する場合は、独自のミューテックスを実装して、2 つのスレッドが同時に 1 つのハンドルでコマンドを実行できないようにします。
  • 同じディスクイメージで複数のハンドルを開くことはできません。すべてのハンドルが読み取り専用である場合は許容されますが、推奨されません。
  • そのディスクイメージ (たとえば、ライブ仮想マシン) を使用するものがない場合は、書き込み用にディスクイメージを追加しないでください。これを行うと、ディスクが破損します。
  • 現在使用中のディスクイメージ (ライブ仮想マシンなど) で読み取り専用ハンドルを開くことができます。ただし、特にディスクイメージの読み取り時にそのディスクイメージが大量に書き込まれている場合は、結果が予測できなかったり、矛盾することがあります。

21.10.1. C プログラムを使用した API との相互作用

C プログラムは、<guestfs.h> ヘッダーファイルを含めることから開始して、ハンドルを作成する必要があります。
#include <stdio.h>
#include <stdlib.h>
#include <guestfs.h>

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

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

   /* ... */

   guestfs_close (g);

   exit (EXIT_SUCCESS);
 }
このプログラムをファイル (test.c) に保存します。このプログラムをコンパイルし、以下の 2 つのコマンドを実行します。
gcc -Wall test.c -o test -lguestfs
./test
この段階では、出力はありません。このセクションの残りの部分では、このプログラムを拡張して新しいディスクイメージを作成し、パーティションを作成し、ext4 ファイルシステムでフォーマットして、ファイルシステムにいくつかのファイルを作成する方法を示す例を紹介します。ディスクイメージはdisk.img と呼ばれ、現在のディレクトリーに作成されます。
このプログラムの概要は、以下のとおりです。
  • ハンドルを作成します。
  • ハンドルにディスクを追加します。
  • libguestfs バックエンドを起動します。
  • パーティション、ファイルシステム、およびファイルを作成します。
  • ハンドルを閉じて、終了します。
変更したプログラムを以下に示します。
#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 an ext4 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 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);
 }
このプログラムをコンパイルして、以下の 2 つのコマンドを実行します。
gcc -Wall test.c -o test -lguestfs
./test
プログラムが正常に完了すると、disk.img というディスクイメージが残ります。これは guestfish で調べることができます。
guestfish --ro -a disk.img -m /dev/sda1
><fs> ll /
><fs> cat /foo/resolv.conf
デフォルトでは (C バインディングおよび C++ バインディングのみ)、libguestfs は stderr にエラーを出力します。この動作は、エラーハンドラーを設定することで変更できます。man ページの guestfs(3) では、これを詳細に説明しています。