guestfs-internals(1) Virtualization Support guestfs-internals(1)

guestfs-internals - معماری و ساختار درونی libguestfs

این صفحه راهنما برای هکرها و توسعه‌دهندگانی است که می‌خواهند بدانند libguestfs در لایه‌های درونی چگونه کار می‌کند. این متن صرفاً توصیفی از نحوه عملکرد کنونی libguestfs است و ممکن است در هر زمانی در آینده تغییر کند.

در لایه‌های درونی، libguestfs با اجرای یک اپلاینس (نوع خاصی از یک ماشین مجازی کوچک) با استفاده از qemu(1) پیاده‌سازی شده است. Qemu به عنوان یک فرآیند فرزند برنامه اصلی اجرا می‌شود.

┌───────────────────┐
│ main program      │
│                   │
│                   │           child process / appliance
│                   │          ┌──────────────────────────┐
│                   │          │ qemu                     │
├───────────────────┤   RPC    │      ┌─────────────────┐ │
│ libguestfs  ◀╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍▶ guestfsd        │ │
│                   │          │      ├─────────────────┤ │
└───────────────────┘          │      │ Linux kernel    │ │
                               │      └────────┬────────┘ │
                               └───────────────│──────────┘
                                               │
                                               │ virtio-scsi
                                        ┌──────┴──────┐
                                        │  Device or  │
                                        │  disk image │
                                        └─────────────┘

این کتابخانه، که به برنامه اصلی لینک شده است، فرآیند فرزند و در نتیجه اپلاینس را در تابع "guestfs_launch" در guestfs(3) ایجاد می‌کند.

درون اپلاینس، یک هسته لینوکس و مجموعه‌ای کامل از ابزارهای فضای کاربری (مانند برنامه‌های LVM و ext2) به همراه یک دیمن کنترلی کوچک به نام "guestfsd" قرار دارند. این کتابخانه با استفاده از فراخوانی‌های رویه از راه دور (RPC) با "guestfsd" ارتباط برقرار می‌کند. یک تطابق عمدتاً یک‌به‌یک بین فراخوانی‌های API در libguestfs و فراخوانی‌های RPC به دیمن وجود دارد. در نهایت، ایمیج(های) دیسک به پردازش qemu متصل می‌شوند که دسترسی دستگاه توسط هسته لینوکس اپلاینس را به دسترسی‌های ایمیج ترجمه می‌کند.

یک تصور اشتباه رایج این است که اپلاینس همان ماشین مجازی "است". اگرچه ایمیج دیسکی که به آن متصل شده‌اید ممکن است توسط ماشین مجازی دیگری نیز استفاده شود، اما libguestfs از این موضوع اطلاعی ندارد و به آن اهمیت نمی‌دهد. (اما اگر پردازش qemu مربوط به libguestfs و ماشین مجازی شما هر دو تلاش کنند ایمیج دیسک را در یک زمان به‌روز کنند، این موضوع برای شما اهمیت زیادی خواهد داشت؛ زیرا معمولاً به خرابی شدید دیسک منجر می‌شود).

libguestfs برای مدل‌سازی فرآیند فرزند از یک ماشین حالت استفاده می‌کند:

               |
guestfs_create / guestfs_create_flags
               |
               |
           ____V_____
          /          \
          |  CONFIG  |
          \__________/
             ^   ^  \
             |    \  \ guestfs_launch
             |    _\__V______
             |   /           \
             |   | LAUNCHING |
             |   \___________/
             |       /
             |  guestfs_launch
             |     /
           __|____V
          /        \
          | READY  |
          \________/

گذارها (انتقال‌های) معمول عبارتند از: (۱) CONFIG (هنگامی که هندل ایجاد می‌شود اما هنوز هیچ پردازش فرزندی وجود ندارد)، (۲) LAUNCHING (هنگامی که پردازش فرزند در حال بوت شدن است)، (۳) READY به این معنا که اپلاینس راه‌اندازی شده و دستورات می‌توانند به پردازش فرزند ارسال و توسط آن اجرا شوند.

مهمان ممکن است توسط "guestfs_kill_subprocess" در guestfs(3) متوقف شود، یا ممکن است در هر زمانی به صورت ناهمگام (مثلاً به دلیل یک خطای داخلی) خاتمه یابد؛ این امر باعث می‌شود حالت به CONFIG برگردد.

دستورات پیکربندی برای qemu مانند "guestfs_set_path" در guestfs(3) تنها در حالت CONFIG قابل صدور هستند.

رابط API یک فراخوانی ارائه می‌دهد که از CONFIG از طریق LAUNCHING به READY می‌رود. تابع "guestfs_launch" در guestfs(3) تا زمانی که پردازش فرزند در وضعیت READY برای پذیرش دستورات قرار گیرد (یا تا زمان بروز خطا یا انقضای زمان) مسدود می‌شود. تابع "guestfs_launch" در guestfs(3) در حین اجرا وضعیت را از CONFIG به LAUNCHING تغییر می‌دهد.

عملیات‌های API مانند "guestfs_mount" در guestfs(3) تنها در حالت READY قابل فراخوانی هستند. این فراخوانی‌های API در انتظار اجرای کامل دستور مسدود می‌شوند. هیچ نسخه غیرمسدودکننده‌ای وجود ندارد و راهی برای صدور بیش از یک دستور در هر هندل در یک زمان وجود ندارد.

در نهایت، فرآیند فرزند پیام‌های ناهمگام مانند لاگ‌های هسته را به برنامه اصلی بازمی‌گرداند. شما می‌توانید برای دریافت این پیام‌ها یک کال‌بک ثبت کنید.

این فرآیند تکامل یافته و به تکامل خود ادامه می‌دهد. توضیحات ارائه‌شده در اینجا تنها با نسخه فعلی libguestfs مطابقت دارد و صرفاً برای اطلاع‌رسانی ارائه شده است.

برای دنبال کردن مراحل ذکرشده در زیر، حالت رفع اشکال libguestfs را فعال کنید (متغیر محیطی "LIBGUESTFS_DEBUG=1" را تنظیم کنید).

ایجاد اپلاینس
دستور "supermin --build" برای ایجاد هسته، یک initrd کوچک و اپلاینس فراخوانی می‌شود.

اپلاینس در مسیر /var/tmp/.guestfs-<UID> کش می‌شود (یا در دایرکتوری دیگری در صورتی که "LIBGUESTFS_CACHEDIR" یا "TMPDIR" تنظیم شده باشند).

برای توصیف کامل نحوه ایجاد و کش شدن اپلاینس، صفحه راهنمای supermin(1) را مطالعه کنید.

راه‌اندازی qemu و بوت هسته
ابزار qemu برای بوت هسته فراخوانی می‌شود.
اجرای initrd
دستور "supermin --build" یک initrd کوچک می‌سازد. این initrd همان اپلاینس نیست. هدف initrd بارگذاری ماژول‌های کافی هسته است تا خود اپلاینس بتواند مونت و راه‌اندازی شود.

فایل initrd یک آرشیو cpio به نام /var/tmp/.guestfs-<UID>/appliance.d/initrd است.

پس از شروع initrd پیام‌هایی مشابه زیر مبنی بر بارگذاری ماژول‌های هسته مشاهده خواهید کرد:

supermin: ext2 mini initrd starting up
supermin: mounting /sys
supermin: internal insmod libcrc32c.ko
supermin: internal insmod crc32c-intel.ko
یافتن و مونت کردن دستگاه اپلاینس
اپلاینس یک فایل پراکنده (sparse file) شامل یک سیستم‌فایل ext2 است که یک سیستم‌عامل لینوکس آشنا (هرچند با حجم کاهش‌یافته) دارد. این فایل معمولاً /var/tmp/.guestfs-<UID>/appliance.d/root نامیده می‌شود.

دیسک‌های معمولی که توسط libguestfs بازرسی می‌شوند، نخستین دستگاه‌هایی هستند که توسط qemu در معرض قرار می‌گیرند (مثلاً به صورت /dev/vda).

آخرین دیسک اضافه‌شده به qemu همان خود اپلاینس است (مثلاً /dev/vdb اگر تنها یک دیسک معمولی وجود داشته باشد).

بنابراین وظیفه نهایی initrd پیدا کردن دیسک اپلاینس، مونت کردن آن، تغییر ریشه (chroot) به درون اپلاینس و اجرای /init از درون اپلاینس است.

اگر این فرآیند با موفقیت انجام شود، پیام‌هایی مشابه زیر مشاهده خواهید کرد:

supermin: picked /sys/block/vdb/dev as root device
supermin: creating /dev/root as block special 252:16
supermin: mounting new root on /root
supermin: chroot
Starting /init script ...

توجه داشته باشید که پیام "Starting /init script ..." نشان می‌دهد که اسکریپت init خود اپلاینس اکنون در حال اجرا است.

مقداردهی اولیه اپلاینس
اکنون خود اپلاینس مقداردهی اولیه می‌شود. این شامل راه‌اندازی فرآیندهای خاصی مانند "udev"، احتمالاً چاپ برخی اطلاعات اشکال‌زدایی و در نهایت اجرای دیمن ("guestfsd") است.
دیمن
در نهایت دیمن ("guestfsd") درون اپلاینس اجرا می‌شود. اگر اجرا شود باید مشاهده کنید:
verbose daemon enabled

دیمن انتظار دارد یک پورت virtio-serial نام‌گذاری شده را که توسط qemu ارائه شده و در سمت دیگر به کتابخانه متصل است، ببیند.

دیمن به این پورت (و در نتیجه به کتابخانه) متصل می‌شود و پیام چهار بایتی "GUESTFS_LAUNCH_FLAG" را ارسال می‌کند که پروتکل ارتباطی را آغاز می‌نماید (به زیر مراجعه کنید).

به استفاده مستقیم از این پروتکل اتکا نکنید. این بخش نحوه عملکرد فعلی آن را مستند می‌کند، اما ممکن است در هر زمانی تغییر یابد.

پروتکل مورداستفاده برای گفتگو میان کتابخانه و دیمن در حال اجرا درون ماشین مجازی qemu، یک مکانیزم ساده RPC است که روی XDR (استانداردهای RFC 1014، RFC 1832، RFC 4506) ساخته شده است.

قالب دقیق ساختارها در فایل common/protocol/guestfs_protocol.x آمده است (توجه: این فایل به صورت خودکار تولید می‌شود).

دو حالت کلی وجود دارد: توابع عادی که پارامترهای "FileIn" و "FileOut" ندارند، که با پیام‌های درخواست/پاسخ بسیار ساده مدیریت می‌شوند. سپس توابعی وجود دارند که پارامترهای "FileIn" یا "FileOut" دارند، که از همان پیام‌های درخواست و پاسخ استفاده می‌کنند، اما ممکن است فایل‌های ارسالی با استفاده از انکودینگ تکه‌تکه (chunked encoding) نیز در ادامه آن‌ها بیایند.

توابع عادی (بدون پارامترهای FILEIN/FILEOUT)

برای توابع عادی، پیام درخواست به صورت زیر است:

total length (header + arguments,
     but not including the length word itself)
struct guestfs_message_header (encoded as XDR)
struct guestfs_<foo>_args (encoded as XDR)

فیلد طول کل (total length) به دیمن اجازه می‌دهد یک بافر با اندازه ثابت اختصاص دهد که بقیه پیام را درون آن بخواند. در نتیجه، طول کل به "GUESTFS_MESSAGE_MAX" بایت (در حال حاضر ۴ مگابایت) محدود می‌شود، به این معنی که اندازه مؤثر هر درخواست به مقداری کمتر از این اندازه محدود است.

همچنین توجه داشته باشید که بسیاری از توابع هیچ آرگومانی نمی‌گیرند، که در این صورت ساختار "guestfs_foo_args" به طور کامل حذف می‌شود.

هدر شامل شماره رویه ("guestfs_proc") است که گیرنده از طریق آن متوجه می‌شود چه نوع ساختار آرگومانی را انتظار داشته باشد، یا اینکه هیچ ساختاری وجود ندارد.

برای توابعی که آرگومان‌های اختیاری می‌گیرند، آرگومان‌های اختیاری در همان ساختار "guestfs_foo_args" مانند آرگومان‌های معمولی کدگذاری می‌شوند. یک ماسک بیتی در هدر مشخص می‌کند که کدام آرگومان‌های اختیاری معنادار هستند. همچنین این ماسک بیتی بررسی می‌شود تا مشخص شود آیا بیت‌هایی در آن تنظیم شده است که دیمن از آن‌ها اطلاعی ندارد (مثلاً اگر در نسخه‌های بعدی کتابخانه آرگومان‌های اختیاری بیشتری اضافه شده باشد)؛ این موضوع باعث رد فراخوانی می‌شود.

پیام پاسخ برای توابع عادی عبارت است از:

total length (header + ret,
     but not including the length word itself)
struct guestfs_message_header (encoded as XDR)
struct guestfs_<foo>_ret (encoded as XDR)

مشابه موارد بالا، ساختار "guestfs_foo_ret" ممکن است برای توابعی که مقادیر بازگشتی رسمی ندارند به طور کامل حذف شود.

مشابه موارد بالا، طول کل پاسخ به "GUESTFS_MESSAGE_MAX" محدود می‌شود.

در صورت بروز خطا، یک پرچم در هدر تنظیم می‌شود و پیام پاسخ کمی تغییر می‌کند:

total length (header + error,
     but not including the length word itself)
struct guestfs_message_header (encoded as XDR)
struct guestfs_message_error (encoded as XDR)

ساختار "guestfs_message_error" شامل پیام خطا به صورت یک رشته متنی است.

توابعی که دارای پارامترهای FILEIN هستند

یک پارامتر "FileIn" نشان می‌دهد که ما یک فایل را به درون مهمان انتقال می‌دهیم. پیام درخواست عادی ارسال می‌شود (به بالا مراجعه کنید). با این حال، در ادامه آن دنباله‌ای از تکه‌های فایل ارسال می‌شود.

total length (header + arguments,
     but not including the length word itself,
     and not including the chunks)
struct guestfs_message_header (encoded as XDR)
struct guestfs_<foo>_args (encoded as XDR)
sequence of chunks for FileIn param #0
sequence of chunks for FileIn param #1 etc.

"دنباله تکه‌ها" عبارت است از:

length of chunk (not including length word itself)
struct guestfs_chunk (encoded as XDR)
length of chunk
struct guestfs_chunk (encoded as XDR)
  ...
length of chunk
struct guestfs_chunk (with data.data_len == 0)

در آخرین تکه، فیلد "data_len" روی صفر تنظیم شده است. علاوه بر این، یک پرچم در تکه نهایی تنظیم می‌شود تا نشان‌دهنده تکمیل موفقیت‌آمیز یا لغو زودهنگام باشد.

در زمان نگارش این مستند، هیچ تابعی وجود ندارد که بیش از یک پارامتر FileIn داشته باشد. با این حال، این مورد (از نظر تئوری) با ارسال توالی تکه‌ها برای هر پارامتر FileIn یکی پس از دیگری (از چپ به راست) پشتیبانی می‌شود.

هم کتابخانه (فرستنده) و هم دیمن (گیرنده) می‌توانند انتقال را لغو کنند. کتابخانه این کار را با ارسال تکه‌ای با یک پرچم خاص برای نشان دادن لغو انجام می‌دهد. هنگامی که دیمن این را مشاهده می‌کند، کل RPC را لغو می‌کند، هیچ پاسخی ارسال نمی‌کند، و به خواندن درخواست بعدی بازمی‌گردد.

دیمن نیز ممکن است عملیات را لغو کند. این کار را با نوشتن کلمه خاص "GUESTFS_CANCEL_FLAG" روی سوکت انجام می‌دهد. کتابخانه در طول انتقال به این گوش می‌دهد و اگر آن را دریافت کند، انتقال را لغو خواهد کرد (یک تکه لغو ارسال می‌کند). این کلمه خاص به گونه‌ای انتخاب شده است که حتی اگر لغو درست در انتهای انتقال رخ دهد (پس از اینکه کتابخانه نوشتن را به پایان رسانده و گوش دادن به پاسخ را آغاز کرده است)، پرچم لغو "کاذب" با پیام پاسخ اشتباه گرفته نخواهد شد.

این پروتکل امکان انتقال فایل‌هایی با هر اندازه دلخواه (بدون محدودیت ۳۲ بیتی) و همچنین فایل‌هایی را که اندازه آن‌ها از قبل مشخص نیست (مانند داده‌های پایپ‌ها یا سوکت‌ها) فراهم می‌کند. با این حال تکه‌ها نسبتاً کوچک هستند ("GUESTFS_MAX_CHUNK_SIZE")، به طوری که نه کتابخانه و نه دیمن نیازی به نگه‌داشتن داده‌های زیادی در حافظه ندارند.

توابعی که دارای پارامترهای FILEOUT هستند

پروتکل مربوط به پارامترهای FileOut دقیقاً همانند پارامترهای FileIn است، با این تفاوت که نقش‌های دیمن و کتابخانه معکوس شده است.

total length (header + ret,
     but not including the length word itself,
     and not including the chunks)
struct guestfs_message_header (encoded as XDR)
struct guestfs_<foo>_ret (encoded as XDR)
sequence of chunks for FileOut param #0
sequence of chunks for FileOut param #1 etc.

پیام اولیه

هنگامی که دیمن راه‌اندازی می‌شود، یک کلمه اولیه ("GUESTFS_LAUNCH_FLAG") ارسال می‌کند که نشان می‌دهد مهمان و دیمن زنده هستند. این همان چیزی است که تابع "guestfs_launch" در guestfs(3) در انتظار آن می‌ماند.

پیام‌های اعلان پیشرفت

دیمن ممکن است در هر زمان پیام‌های اعلان پیشرفت را ارسال کند. این پیام‌ها با جایگزین شدن کلمه طول معمولی با "GUESTFS_PROGRESS_FLAG"، و به دنبال آن یک پیام پیشرفت با اندازه ثابت، متمایز می‌شوند.

کتابخانه اگر کال‌بکی ثبت شده باشد، این پیام‌ها را به کال‌بک‌های پیشرفت (ببینید "GUESTFS_EVENT_PROGRESS" در guestfs(3)) تبدیل می‌کند، یا در غیر این صورت آن‌ها را نادیده می‌گیرد.

دیمن فرکانس پیام‌های پیشرفتی را که ارسال می‌کند خود محدود می‌سازد (ببینید "daemon/proto.c:notify_progress"). همه فراخوانی‌ها پیام‌های پیشرفت تولید نمی‌کنند.

هنگامی که libguestfs (یا ابزارهای libguestfs) اجرا می‌شوند، مسیری را برای یافتن یک اپلاینس جستجو می‌کنند. این مسیر درون libguestfs تعبیه شده است، یا می‌توان آن را با استفاده از متغیر محیطی "LIBGUESTFS_PATH" تنظیم کرد.

به‌طور معمول یک اپلاینس supermin در این مسیر قرار دارد (ببینید "SUPERMIN APPLIANCE" در supermin(1)). libguestfs با اجرای "supermin --build" آن را به یک اپلاینس کامل بازسازی می‌کند.

با این حال، می‌توان از یک "اپلاینس ثابت" ساده‌تر نیز استفاده کرد. libguestfs این موضوع را با جستجوی دایرکتوری در مسیر که شامل تمام فایل‌های زیر باشد تشخیص می‌دهد:

  • kernel
  • initrd
  • root
  • README.fixed (توجه داشته باشید که این فایل نیز باید حتماً وجود داشته باشد)

اگر اپلاینس ثابت پیدا شود، libguestfs به‌طور کامل از supermin صرف‌نظر کرده و فقط ماشین مجازی را (با استفاده از qemu یا بک‌اند فعلی، ببینید "BACKEND" در guestfs(3)) به همراه کرنل، initrd و دیسک ریشه از اپلاینس ثابت اجرا می‌کند.

بنابراین اپلاینس ثابت را می‌توان زمانی استفاده کرد که یک پلتفرم یا توزیع لینوکس از supermin پشتیبانی نمی‌کند. شما اپلاینس ثابت را روی پلتفرمی که از supermin پشتیبانی می‌کند با استفاده از libguestfs-make-fixed-appliance(1) می‌سازید، آن را کپی کرده و برای اجرای libguestfs استفاده می‌کنید.

guestfs(3), guestfs-hacking(1), guestfs-examples(3), libguestfs-test-tool(1), libguestfs-make-fixed-appliance(1), http://libguestfs.org

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

Copyright (C) 2009-2025 Red Hat Inc.

این کتابخانه نرم‌افزار آزاد است؛ شما می‌توانید آن را تحت شرایط مجوز عمومی کمتر گنو (LGPL) که توسط بنیاد نرم‌افزارهای آزاد منتشر شده است، چه نسخه 2 مجوز و چه (به دلخواه خود) هر نسخه بالاتر، بازتوزیع کرده و/یا تغییر دهید.

این کتابخانه به این امید توزیع شده است که مفید واقع شود، اما بدون هیچ‌گونه ضمانت؛ حتی بدون ضمانت ضمنی قابل فروش بودن یا مناسب بودن برای یک هدف خاص. برای جزئیات بیشتر به مجوز عمومی کمتر گنو مراجعه کنید.

شما باید یک نسخه از مجوز عمومی کمتر گنو را به همراه این کتابخانه دریافت کرده باشید؛ در غیر این صورت، به بنیاد نرم‌افزارهای آزاد به نشانی زیر نامه بنویسید: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

برای دریافت فهرست باگ‌های گزارش‌شده در رابطه با libguestfs، از این پیوند استفاده کنید: https://bugzilla.redhat.com/buglist.cgi?component=libguestfs&product=Virtualization+Tools

برای ارسال گزارش باگ جدید علیه libguestfs، از این پیوند استفاده کنید: https://bugzilla.redhat.com/enter_bug.cgi?component=libguestfs&product=Virtualization+Tools

هنگام گزارش باگ، لطفاً اطلاعات زیر را درج نمایید:

  • نسخه libguestfs.
  • محل دریافت libguestfs (برای مثال کدام توزیع لینوکس، کامپایل‌شده از کد منبع و غیره).
  • توصیف دقیق باگ و ارائه راهکاری برای بازتولید آن.
  • اجرای دستور libguestfs-test-tool(1) و قرار دادن خروجی کامل و دست‌نخورده آن در گزارش باگ.
2026-07-14 libguestfs-1.60.1