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
각 언어에 대한 바인딩은 본질적으로 동일하지만 약간의 합성 변경 사항이 있습니다. A C 문:
guestfs_launch (g);
Perl에서 다음과 같이 표시 됩니다.
$g->launch ()
또는 OCaml에서 다음과 같습니다.
g#launch ()
이 섹션에는 C의 API만 자세히 설명되어 있습니다.
C 및 C++ 바인딩에서 오류를 수동으로 확인해야 합니다.In the C and C++ bindings, you must manually check for errors. 다른 바인딩에서는 오류가 예외로 변환됩니다. 아래 예에 표시된 추가 오류 검사는 다른 언어에는 필요하지 않지만 반대로 예외를 catch하도록 코드를 추가할 수 있습니다. libguestfs API의 아키텍처와 관련된 몇 가지 관심 사항은 다음 목록을 참조하십시오.
  • libguestfs API가 동기화됩니다. 각 호출은 완료될 때까지 차단됩니다. 호출을 비동기적으로 수행하려는 경우 스레드를 만들어야 합니다.If you want to make calls asynchronously, you have to create a thread.
  • libguestfs API는 스레드가 안전하지 않습니다. 각 핸들은 단일 스레드에서만 사용하거나 스레드 간 처리를 공유하려는 경우 두 스레드가 동시에 하나의 처리에서 명령을 실행할 수 없도록 자체 semaphore를 구현해야 합니다.
  • 동일한 디스크 이미지에서 여러 개의 처리를 열 수 없습니다. 모든 처리가 읽기 전용인 경우 허용되지만 여전히 권장되지는 않습니다.
  • 해당 디스크 이미지(예: 라이브 VM)를 사용할 수 있는 경우 쓰기 위해 디스크 이미지를 추가하지 않아야 합니다. 이렇게 하면 디스크 손상이 발생합니다.
  • 현재 사용 중인 디스크 이미지에서 읽기 전용(예: 실시간 VM)을 열 수 있습니다. 그러나 결과는 예측할 수 없거나 일관되지 않을 수 있습니다. 특히 디스크 이미지를 읽는 시점에 디스크 이미지가 많이 기록되는 경우 특히 그렇습니다.

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). 이 프로그램을 컴파일하고 다음 두 가지 명령으로 실행합니다.
gcc -Wall test.c -o test -lguestfs
./test
이 단계에서는 출력을 출력하지 않아야 합니다. 이 섹션의 나머지 부분에서는 이 프로그램을 확장하여 새 디스크 이미지를 만들고 파티션을 지정하고 ext4 파일 시스템으로 포맷한 다음 파일 시스템에 일부 파일을 생성하는 방법을 보여주는 예제를 보여줍니다. 디스크 이미지는 disk.img 라고 하며 현재 디렉터리에 생성됩니다.
이 프로그램의 개요는 다음과 같습니다.
  • 핸들을 만듭니다.
  • 디스크 추가Add disk(s) to the handle.
  • 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);
 }
다음 두 가지 명령을 사용하여 이 프로그램을 컴파일하고 실행합니다.
gcc -Wall test.c -o test -lguestfs
./test
프로그램이 성공적으로 완료되는 경우 disk.img.img 라는 디스크 이미지로 남아 있어야 합니다.
guestfish --ro -a disk.img -m /dev/sda1
><fs> ll /
><fs> cat /foo/resolv.conf
기본적으로 (C 및 C++ 바인딩 전용) libguestfs는 stderr에 오류를 출력합니다. 오류 처리기를 설정하여 이 동작을 변경할 수 있습니다. guestfs(3) 도움말 페이지에는 이 내용에 대해 자세히 설명합니다.