guestfs-perl(3)

๐Ÿ’… guestfs-perl โ€” like, how to drive libguestfs from Perl (the manual is called guestfs-perl(3), and it lives under the Virtualization Support umbrella, just so you know what you're looking at ๐Ÿซถ)

okay bestie, buckle in โ€” this is the page that teaches you how to call libguestfs from Perl. It's giving "short but iconic." โœจ


๐ŸŒธ SYNOPSIS

use Sys::Guestfs;

my $g = Sys::Guestfs->new ();
$g->add_drive_opts ('guest.img', format => 'raw');
$g->launch ();
$g->mount ('/dev/sda1', '/');
$g->touch ('/hello');
$g->shutdown ();
$g->close ();

like, that's the whole vibe right there. make a handle, add a drive, launch, mount, touch a file, shut down, close. slay. ๐Ÿ’…


๐Ÿฆ‹ DESCRIPTION

This page is literally the "how do I use libguestfs from Perl" tutorial. It only covers the stuff that's different from the C API, plus a couple of examples to get you going. ๐Ÿ’–

If you're not already comfy with libguestfs itself, go read guestfs(3) first, fr fr. And if you want the full Perl API โ€” every single method โ€” that's Sys::Guestfs(3). ๐Ÿ“–

๐ŸŽ€ ERRORS

When a libguestfs function fails, it turns into a call to croak โ€” check Carp(3) for the deets. So yeah, your errors come at you the Perl way. ๐Ÿ˜ญ


โญ EXAMPLE 1: CREATE A DISK IMAGE

okay so this one is the glow-up: you're making a disk image from scratch, partitioning it, putting a filesystem on it, and dropping files in. main character energy. ๐Ÿ‘‘

#!/usr/bin/env perl

# Example showing how to create a disk image.

use strict;
use warnings;
use Sys::Guestfs;

my $output = "disk.img";

my $g = new Sys::Guestfs ();

# Create a raw-format sparse disk image, 512 MB in size.
$g->disk_create ($output, "raw", 512 * 1024 * 1024);

# Set the trace flag so that we can see each libguestfs call.
$g->set_trace (1);

# Attach the disk image to libguestfs.
$g->add_drive_opts ($output, format => "raw", readonly => 0);

# Run the libguestfs back-end.
$g->launch ();

# Get the list of devices.  Because we only added one drive
# above, we expect that this list should contain a single
# element.
my @devices = $g->list_devices ();
if (@devices != 1) {
    die "error: expected a single device from list-devices";
}

# Partition the disk as one single MBR partition.
$g->part_disk ($devices[0], "mbr");

# Get the list of partitions.  We expect a single element, which
# is the partition we have just created.
my @partitions = $g->list_partitions ();
if (@partitions != 1) {
    die "error: expected a single partition from list-partitions";
}

# Create a filesystem on the partition.
$g->mkfs ("ext4", $partitions[0]);

# Now mount the filesystem so that we can add files.
$g->mount ($partitions[0], "/");

# Create some files and directories.
$g->touch ("/empty");
my $message = "Hello, world\n";
$g->write ("/hello", $message);
$g->mkdir ("/foo");

# This one uploads the local file /etc/resolv.conf into
# the disk image.
$g->upload ("/etc/resolv.conf", "/foo/resolv.conf");

# Because we wrote to the disk and we want to detect write
# errors, call $g->shutdown.  You don't need to do this:
# $g->close will do it implicitly.
$g->shutdown ();

# Note also that handles are automatically closed if they are
# reaped by reference counting.  You only need to call close
# if you want to close the handle right away.
$g->close ();

quick notes since the comments lowkey already spilled the tea โ˜•:

  • we make a raw-format sparse disk image, 512 * 1024 * 1024 bytes (that's 512 MB, bestie ๐Ÿงฎ).
  • $g->set_trace (1) so you can watch every single libguestfs call happen. nosy but make it valid. ๐Ÿ‘€
  • we attach the image with format => "raw" and readonly => 0, then launch ().
  • only one drive added โ†’ so list_devices() should hand back exactly one element. we die otherwise, obviously.
  • part_disk ($devices[0], "mbr") โ€” one single MBR partition. iconic.
  • list_partitions() should also be exactly one element โ€” the one we just made. dare I sayโ€ฆ consistency? ๐Ÿ’…
  • mkfs ("ext4", $partitions[0]), then mount ($partitions[0], "/").
  • then the fun part: touch ("/empty"), write ("/hello", $message) with "Hello, world\n", and mkdir ("/foo").
  • upload ("/etc/resolv.conf", "/foo/resolv.conf") โ€” yes, it literally yeets your local /etc/resolv.conf into the image. ๐Ÿš€
  • shutdown () โ€” you call this because we wrote to the disk and we want to detect write errors. you don't have to: $g->close does it implicitly.
  • also!! handles get closed automatically if they're reaped by reference counting. you only need close if you want the handle gone right now. โœจ

๐ŸŒˆ EXAMPLE 2: INSPECT A VIRTUAL MACHINE DISK IMAGE

now we're snooping (respectfully) into an existing VM disk and asking libguestfs "bestie, what OS is this?" ๐Ÿ”๐Ÿฆ‹

#!/usr/bin/env perl

# Example showing how to inspect a virtual machine disk.

use strict;
use warnings;
use Sys::Guestfs;

if (@ARGV < 1) {
    die "usage: inspect_vm disk.img"
}

my $disk = $ARGV[0];

my $g = new Sys::Guestfs ();

# Attach the disk image read-only to libguestfs.
# You could also add an optional format => ... argument here.  This is
# advisable since automatic format detection is insecure.
$g->add_drive_opts ($disk, readonly => 1);

# Run the libguestfs back-end.
$g->launch ();

# Ask libguestfs to inspect for operating systems.
my @roots = $g->inspect_os ();
if (@roots == 0) {
    die "inspect_vm: no operating systems found";
}

for my $root (@roots) {
    printf "Root device: %s\n", $root;

    # Print basic information about the operating system.
    printf "  Product name: %s\n", $g->inspect_get_product_name ($root);
    printf "  Version:      %d.%d\n",
        $g->inspect_get_major_version ($root),
        $g->inspect_get_minor_version ($root);
    printf "  Type:         %s\n", $g->inspect_get_type ($root);
    printf "  Distro:       %s\n", $g->inspect_get_distro ($root);

    # 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.
    my %mps = $g->inspect_get_mountpoints ($root);
    my @mps = sort { length $a <=> length $b } (keys %mps);
    for my $mp (@mps) {
        eval { $g->mount_ro ($mps{$mp}, $mp) };
        if ($@) {
            print "$@ (ignored)\n"
        }
    }

    # If /etc/issue.net file exists, print up to 3 lines.
    my $filename = "/etc/issue.net";
    if ($g->is_file ($filename)) {
        printf "--- %s ---\n", $filename;
        my @lines = $g->head_n (3, $filename);
        print "$_\n" foreach @lines;
    }

    # Unmount everything.
    $g->umount_all ()
}

okay the โœจimportantโœจ bits:

๐Ÿšจ the comment says you could add an optional format => ... argument here, and that it's advisable โ€” because automatic format detection is insecure. not me warning you twice. ๐Ÿ™ˆ
  • attach read-only: add_drive_opts ($disk, readonly => 1). safety first, bestie. ๐Ÿซถ
  • inspect_os () gives you the roots. zero roots โ†’ die "inspect_vm: no operating systems found".
  • for each root we print Root device: %s, then the product name, version (%d.%d from major + minor), type, and distro. very demure, very informative. ๐Ÿ’…
  • inspect_get_mountpoints ($root) gives a hash, and then โ€” the trick โ€” we sort the keys by length, shortest first, so the filesystems get mounted in the right order. the way that sort { length $a <=> length $b } ate. ๐Ÿ“
  • each mount is wrapped in eval { $g->mount_ro ($mps{$mp}, $mp) }, and if $@ is set we just print "$@ (ignored)\n". graceful. ๐Ÿ˜Œ
  • if /etc/issue.net is a file (checked with is_file), print a --- %s --- banner and up to 3 lines via head_n (3, $filename).
  • umount_all () at the end to clean up. no leftover mounts in this house. ๐Ÿงน

๐Ÿ‘€ SEE ALSO

Sys::Guestfs(3), guestfs(3), guestfs-examples(3), guestfs-erlang(3), guestfs-golang(3), guestfs-java(3), guestfs-lua(3), guestfs-ocaml(3), guestfs-python(3), guestfs-recipes(1), guestfs-ruby(3), http://libguestfs.org/.

like, every language said "we're coming too." multilingual icons only. ๐ŸŒ


๐Ÿ’œ AUTHORS

Richard W.M. Jones ("rjones at redhat dot com") โ€” the legend himself. ๐Ÿ‘‘


Copyright (C) 2011-2025 Red Hat Inc.


๐ŸŽ€ LICENSE

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

no cap, take the code, it's yours. ๐Ÿ’…โœจ


๐Ÿ’€ BUGS

To get a list of bugs against libguestfs, use this link:

https://bugzilla.redhat.com/buglist.cgi?component=libguestfs&product=Virtualization+Tools

To report a new bug against libguestfs, use this link:

https://bugzilla.redhat.com/enter_bug.cgi?component=libguestfs&product=Virtualization+Tools

When reporting a bug, please supply:

  • The version of libguestfs.
  • Where you got libguestfs (eg. which Linux distro, compiled from source, etc)
  • Describe the bug accurately and give a way to reproduce it.
  • Run libguestfs-test-tool(1) and paste the complete, unedited output into the bug report.
fr fr though โ€” complete and unedited output. do not crop it, do not paraphrase it, do not "clean it up." the maintainers want the whole thing. ๐Ÿ˜ญ

and that's the page, bestie ๐Ÿซถ this was guestfs-perl(3), from libguestfs-1.61.3, dated 2026-09-16. go forth and script. ๐Ÿฆ‹๐ŸŒธ๐Ÿ’–

๐Ÿ“ฆ where this page comes from