NAME

Sys::Export - Export a subset of an OS file tree, for chroot/initrd

SYNOPSIS

use Sys::Export -src => '/', -dst => [ CPIO => "initrd.cpio" ];

rewrite_path '/sbin'     => '/bin';
rewrite_path '/usr/sbin' => '/bin';
rewrite_path '/usr/bin'  => '/bin';

# Add files and their dependencies
add '/bin/busybox';
add qw( bin/sh bin/date bin/cat bin/mount );

# tell 'add' to ignore specific files
skip 'usr/share/zoneinfo/tzdata.zi';

# recurse and filter directories with 'find'
add find 'usr/share/zoneinfo', sub { ! /(leapseconds|\.tab|\.list)$/ };

# Inject dynamically generated files
add [ file400 => "/etc/some-service.conf", <<~END ];
    # Some config file
    secret = $secret
    END

# Inject files that come from a different name, or outside the 'src' tree
add [ file644 => "/opt/some-app/data", filedata("/path/to/some/data") ];

# For Linux, generate minimal /etc/passwd /etc/group /etc/shadow according
# to UID/GID which were exported so far.
exporter->add_passwd;

finish;

DESCRIPTION

This module is designed to export a subset of an operating system to a new directory, automatically detecting and including any libraries or interpreters required by the requested subset, and optionally rewriting paths and users/groups and updating the copied files to refer to the rewritten paths, when possible.

The actual export implementation is handled by a OS-specific module, like Sys::Export::Linux. This top-level module just exports methods. You can configure a global exporter instance on the use line, and then call its methods via exported functions. For instance,

use Sys::Export \%options;

is roughly equivalent to:

BEGIN {
  if ($^O eq 'linux') {
    require Sys::Export::Linux;
    $Sys::Export::exporter= Sys::Export::Linux->new(\%options);
  } else {
    ...
  }
  sub exporter      { $Sys::Export::exporter }
  sub add           { $Sys::Export::exporter->add(@_) }
  sub rewrite_path  { $Sys::Export::exporter->rewrite_path(@_) }
  sub rewrite_user  { $Sys::Export::exporter->rewrite_user(@_) }
  sub rewrite_group { $Sys::Export::exporter->rewrite_group(@_) }
  sub finish        { $Sys::Export::exporter->finish }
}

In other words, just a convenience for creating an exporter instance and giving you access to most of its important methods without needing to reference the object. You can skip this module entirely and just directly use a Sys::Export::Linux object, if you prefer.

Currently, only Linux is fully supported.

CONFIGURATION

The following can be passed on the use line to configure a global exporter object:

A Hashref
use Sys::Export { ... };

The keys of the hashref will be passed to the exporter constructor (aside from the key 'type' which is used to override the default class)

-type

Specify a class of exporter, like 'Linux' or 'Sys::Export::Linux'. Names without colons imply a prefix of Sys::Export::.

-src

Source directory; see "src" in Sys::Export::Unix.

-dst

Destination directory or CPIO instance; see "dst" in Sys::Export::Unix.

-src_userdb

Defines UID/GID of source filesystem; see "src_userdb" in Sys::Export::Unix.

-dst_userdb

Defines UID/GID of destination; see "dst_userdb" in Sys::Export::Unix.

-rewrite_path

Hashref of rewrites; see "rewrite_path" in Sys::Export::Unix.

-rewrite_user

Hashref of rewrites; see "rewrite_user" in Sys::Export::Unix.

-rewrite_group

Hashref of rewrites; see "rewrite_group" in Sys::Export::Unix.

EXPORTS

exporter

A function to access $Sys::Exporter::exporter

init_global_exporter

init_global_exporter(\%config);

A function to initialize $Sys::Exporter::exporter, which also handles autoselecting the type of the exporter.

:basic_methods bundle

You get this bundle by default if you configured a global exporter. The following methods of the global exporter object get exported as functions:

add
skip
find
which
finish
rewrite_path
rewrite_user
rewrite_group

:isa bundle

use Sys::Export ":isa";

These boolean functions are useful for type inspection.

isa_exporter

Is it an object and an instance of Sys::Export::Exporter?

isa_export_dst

Is it an object which can receive exported files? (add and finish methods)

isa_userdb

Is it an instance of Sys::Export::Unix::UserDB?

isa_user

Is it an instance of Sys::Export::Unix::UserDB::User?

isa_group

Is it an instance of Sys::Export::Unix::UserDB::Group?

isa_hash

Is it a hashref?

isa_array

Is it an arrayref?

isa_data_ref

Is it a scalar ref or an object with method as_scalarref?

isa_handle

Is it a GLOB ref or IO::Handle?

isa_int

Is it an integer?

isa_pow2

Is it a power of 2?

:stat_modes bundle

S_IFREG S_IFDIR S_IFLNK S_IFBLK S_IFCHR S_IFIFO  S_IFSOCK S_IFWHT S_IFMT

These are like the exports from Fcntl, but return 0 if the macro is not defined on this platform.

:stat_tests bundle

S_ISREG S_ISDIR S_ISLNK S_ISBLK S_ISCHR S_ISFIFO S_ISSOCK S_ISWHT

These are like the exports from Fcntl, but return false if the macro is not defined on this platform.

expand_stat_shorthand

@kv_list= expand_stat_shorthand($arrayref);
@kv_list= expand_stat_shorthand($mode, $name);
@kv_list= expand_stat_shorthand($mode, $name, $mode_specific_data);
@kv_list= expand_stat_shorthand($mode, $name, \%other_attrs);
@kv_list= expand_stat_shorthand($mode, $name, $mode_specific_data, \%other_attrs);

This is a utility function that takes a shorthand array notation for a directory entry, and expands it to the file attribute names as used in "add" in Sys::Export::Unix or "add" in Sys::Export::CPIO.

The $mode can either be a numeric Unix mode like use Fcntl 'S_IFDIR'; (S_IFDIR|0755) or a name like 'dir' (with default permissions) or a name with a permission suffix like 'dir755'.

For example:

[ file644 => "foo", $literal_data ],
[ file644 => "foo", { data_path => $filename } ],
[ dir700  => "root/.ssh" ],
[ dir1777 => "tmp" ],
[ sym     => "bar" => "foo" ],
[ chr777  => "dev/null" => [1,3] ],
[ blk660  => "dev/sda"  => [8,0], { group => "disk" } ],
[ fifo    => "run/queue" ],
[ sock    => "run/mysqld/mysql.sock", { user => "mysql", group => "mysql" } ],

The default permissions are 0777 & ~umask for a directory, 0777 for symlinks, and 0666 & ~umask for others.

round_up_to_pow2

$pow2= round_up_to_pow2($number);

Return a number rounded up to the next power of 2, or itself if it was already a power of 2. Dies if the number is less than 0. Returns 1 when $number is 0.

round_up_to_multiple

$aligned= round_up_to_multiple($n, $pow2);

Return a number rounded up to the next multiple of a power of 2. Dies if the number is less than 0.

map_or_load_file

$scalar_ref= map_or_load_file($path);
$scalar_ref= map_or_load_file($path, $offset);
$scalar_ref= map_or_load_file($path, $offset, $length);

If File::Map is available, this creates a read-only memory map of the file (from the specified offset) and rreturns a scalar ref to it. If not, it simply loads the file into a scalar and returns a ref to that. You should assume the data in the scalar is read-only.

filedata

$filedata= filedata($path);
$filedata= filedata($path, $offset);
$filedata= filedata(\$scalar_ref, $offset, $length);

This is a shortcut for creating Sys::Export::LazyFileData objects. These objects delay the memory-mapping of a file (or substr operation on a large scalar) until it is needed. This is a convenient way to pass file data to various methods such as "add".

write_file_extent

write_file_extent($fh, $file_addr, $size, $data_ref, $data_ofs, $description=undef);

This utility method writes a full extent of a file, padding the supplied data with NUL bytes if needed. It first seeks to $file_addr, then writes a full $size bytes from $$data_ref from offset $data_ofs if possible. If the length of the scalar in $$data_ref is too short, this pads the write with NUL bytes. If $$data_ref is especially large (>1MiB) it first performs a syswrite of as many whole pages of the data as possible, then pads the final page with NUL bytes on a second syswrite.

You can skip the seek operation with an undefined $file_addr, in which case it just syswrites from the current position of the file.

$description is for debug-logging purposes and can be undef.

If any syscall fails, or can't write the full size, this croaks.

VERSION

version 0.004

AUTHOR

Michael Conrad <mike@nrdvana.net>

COPYRIGHT AND LICENSE

This software is copyright (c) 2026 by Michael Conrad.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.