guestfs-ruby(3)

πŸ’… NAME πŸ’…

okay so this is guestfs-ruby(3) β€” the manual page that teaches you how to call libguestfs from the Ruby programming language 🫢 literally your whole guide to making Ruby talk to libguestfs, bestie.


✨ SYNOPSIS ✨

require 'guestfs'
g = Guestfs::Guestfs.new()
g.add_drive_opts("disk.img",
                 :readonly => true, :format => "raw")
g.launch()

that's the whole vibe right there β€” require, new, add a drive, launch. slay πŸ’…


🌸 DESCRIPTION 🌸

So this page is only about how to call libguestfs from Ruby β€” it documents the differences from the C API plus some examples, no cap. If you've never used libguestfs before in your life, bestie you gotta go read guestfs(3) first, fr fr. This page expects you already know the basics πŸ‘‘

😭 EXCEPTIONS

Errors coming out of libguestfs functions get mapped into the Error exception. It's got a single parameter, which is the error message (a string). That's it. One lil string. iconic.


πŸŽ€ EXAMPLE 1: CREATE A DISK IMAGE πŸŽ€

the classic β€” making a disk image from scratch. here's the full thing, verbatim, don't touch a character:

# Example showing how to create a disk image.

require 'guestfs'

output = "disk.img"

g = Guestfs::Guestfs.new()

# 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")

# 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.
devices = g.list_devices()
if devices.length != 1 then
  raise "error: expected a single device from list-devices"
end

# 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.
partitions = g.list_partitions()
if partitions.length != 1 then
  raise "error: expected a single partition from list-partitions"
end

# 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")
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 the garbage collector.  You only need to call close
# if you want to close the handle right away.
g.close()

quick lil breakdown of the juicy bits:

  • g.disk_create makes a raw-format sparse disk image that's 512 MB in size πŸ’Ύ
  • g.set_trace(1) flips the trace flag so you can literally watch every libguestfs call go by. main character energy for debugging.
  • g.list_devices() should give you exactly one element since you only added one drive above β€” hence the raise if it doesn't.
  • g.part_disk partitions it as one single MBR partition, then g.list_partitions() should hand back one element too.
  • g.mkfs("ext4", ...), g.mount(...), then the fun stuff: g.touch("/empty"), g.write("/hello", message) with message = "Hello, world\n", and g.mkdir("/foo") 🌸
  • g.upload("/etc/resolv.conf", "/foo/resolv.conf") uploads your local /etc/resolv.conf into the disk image. cute.
  • important caveat bestie β€” g.shutdown() is there because we wrote to the disk and want to detect write errors. But you don't need to do this: g.close will do it implicitly. πŸ™ˆ
  • also note: handles are automatically closed if they're reaped by the garbage collector. You only need to call close if you want to close the handle right away. periodt.

πŸ¦‹ EXAMPLE 2: INSPECT A VIRTUAL MACHINE DISK IMAGE πŸ¦‹

now we're snooping on a VM disk. here's the whole example:

# Example showing how to inspect a virtual machine disk.

require 'guestfs'

if ARGV.length == 0
  puts "usage: inspect_vm disk.img"
  exit 1
end
disk = ARGV[0]

g = Guestfs::Guestfs.new()

# Attach the disk image read-only to libguestfs.
g.add_drive_opts(disk, :readonly => true)

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

# Ask libguestfs to inspect for operating systems.
roots = g.inspect_os()
if roots.length == 0
  puts "inspect_vm: no operating systems found"
  exit 1
end

for root in roots do
  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.
  mps = g.inspect_get_mountpoints(root)
  mps = mps.sort {|a,b| a[0].length <=> b[0].length}
  for mp in mps do
    begin
      g.mount_ro(mp[1], mp[0])
    rescue Guestfs::Error => msg
      printf("%s (ignored)\n", msg)
    end
  end

  # If /etc/issue.net file exists, print up to 3 lines.
  filename = "/etc/issue.net"
  if g.is_file filename then
    printf("--- %s ---\n", filename)
    lines = g.head_n(3, filename)
    for line in lines do
      puts line
    end
  end

  # Unmount everything.
  g.umount_all()
end

the tea β˜•:

  • no args? it prints usage: inspect_vm disk.img and bails with exit 1. respect the usage line bestie.
  • g.add_drive_opts(disk, :readonly => true) β€” attached read-only, we're just looking, not touching πŸ”
  • g.inspect_os() does the OS detection; zero roots means inspect_vm: no operating systems found and exit 1.
  • for each root it prints Root device: %s\n plus the product name, version (%d.%d from inspect_get_major_version and inspect_get_minor_version), type, and distro πŸ’–
  • then it mounts the disks like guestfish -i β€” and here's the trick: it sorts the keys by length, shortest first, so the filesystems get mounted in the correct order. mps.sort {|a,b| a[0].length <=> b[0].length} β€” that's the line, don't lose it πŸ‘‘
  • the mount is g.mount_ro(mp[1], mp[0]) inside a begin/rescue Guestfs::Error => msg that just prints %s (ignored)\n. errors get ignored, no drama.
  • if /etc/issue.net exists (g.is_file filename), it prints --- %s ---\n and up to 3 lines via g.head_n(3, filename) ⭐
  • finally g.umount_all() β€” unmount everything, clean exit, we love to see it 🧚

πŸ’œ SEE ALSO πŸ’œ

literally the whole friend group:


πŸ‘‘ AUTHORS πŸ‘‘

Richard W.M. Jones ("rjones at redhat dot com") β€” the legend himself 🫢


Copyright (C) 2010-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. ate and left no crumbs πŸ’…


πŸ’€ BUGS πŸ’€

got beef with libguestfs? here's where to take it:

When reporting a bug, please supply (fr fr, all of it):

  • 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. 😭
ngl an unedited paste is the whole thing β€” don't trim it, don't summarize it, just dump it in there πŸ™

that's the page, bestie πŸŽ€βœ¨ brought to you by libguestfs-1.60.1, dated 2026-07-14, and yes this is still guestfs-ruby(3) β€” go write some Ruby, you got this πŸ’–πŸ¦‹

πŸ“¦ where this page comes from