Rouge User Reference Manual¶
About¶
rouge is a companion tool for moulin. Its purpose is to simplify the creation of bootable images. It can create a partition table, fill partitions with predefined files or raw data. It supports GPT, ext4fs, raw images, and Android sparse images. Further formats can be added if needed.
Right now, it can be used only as a separate tool, but there are plans to integrate it into moulin output.
Design Principles¶
rouge shares ideas (and code) with moulin. Thus, it is very
similar in configuring and invoking to moulin. It can be used as a
stand-alone tool: provide only images: section in your
YAML file. Or you can include this section in the same file, which
is used by moulin to share common options or variables. In the latter
case, moulin will generate additional image-{image_name}
rules so that you can build images with Ninja.
Requirements¶
To perform its function, rouge invokes several external utilities. Most of them are available on every system, with the following exceptions:
To work with vfat, install the mtools package.
To work with Android, install the simg2img package.
There is a list of external tools used for the generation of images:
dd - used to copy raw images
mkfs.ext4 - creates ext4 FS
mkfs.vfat - creates vfat FS
simg2img - used to unpack Android sparse image files
mcopy and mdd - to handle vfat images
Invoking rouge¶
rouge uses the same design ideas as moulin, and part of the
command line options are shared with moulin. This includes
--help-config, -v, and --dump arguments. Please
refer to moulin documentation for more
details. This document describes only arguments specific to rouge.
rouge [-h] [--help-config] [-v] [--dump] [-l] [-f] [-s] [-o FILE]
[-l | -i image_name]
build.yaml image_name
-i image_name- name of one of the images described inimages:section of your build configuration file (build.yaml). Basically, this is the image you want to create.
-l,--list-images- list available images and their descriptions. Please note that the actual list of images can depend on build config parameter values. For example, your build config may provide an option to enable Android build. If this option is enabled, you may have a separate image for Android.
-f,--force- force overwrite existing file. If this option is not given, rouge will refuse to create an image if the output file already exists.
-s,--special- allow to write to a special file, like a block device. Without this option, rouge will refuse to write to, say,/dev/sda. Use this option with care and always double-check the device name, as rouge will overwrite anything that is stored on that device.
-o- provides output file name. This is an optional parameter, by default, rouge will write to<image_name>.img.
Apart from these options, rouge will read and parse all YAML file-related
parameters in the same way as moulin does. You can check
available parameters with --help-config.
Principles of Operation¶
rouge works in a very simple way. It uses moulin’s YAML processor
that applies parameters and substitutes variables, then reads
images: section, finds the requested image specification.
For a given image, it checks if all mentioned files are present, then calculates the sizes of partitions (if any) and the total image size. Then it writes data to a given file/block device according to the specifications.
rouge tries to use sparse files whenever possible. A sparse file is a
file with “holes” in it. It allows you to have a huge file that
represents a whole disk image with a tiny bit of actual information in
it. This speeds up the image creation process and decreases the used disk
space. If you are writing the resulting image file to your SD card
manually, try adding conv=sparse option to your dd
command line. This will speed up the writing process. If you want to
distribute resulting images, take a look at Intel’s bmap
tool. It allows you to share sparse files across devices.
YAML Sections¶
Image specifications¶
Images are specified in the following way:
images:
image_name_a:
desc: "Description for the first image"
image_size: 512 MiB
type: gpt
... block description ...
image_name_b:
desc: "Description for the second image"
type: raw_image
... block description ...
image_name_c:
desc: "Description for the third image"
type: empty
... block description ...
images: section contains one or more keys, which serve as
image names. Every image can have a description, which will be displayed
when rouge lists available images. type: key is mandatory as
it defines the type of block. Supported block types are described in the
following sections.
Also, you may specify the required size of the image using
image_size:. Please see the section ‘Size Designation’ below for
supported notation. If the actual size of all partitions will be less than
image_size: then image will be blown up to image_size:.
If the actual size is bigger than specified, an error will be printed with
an explanation like “Actual size (20000) of image is bigger than requested
one (10000).”
Block descriptions¶
“Block” is a basic rouge entity that describes one partition or partition table. Some block types can be nested. Supported block types are described below.
Size Designation¶
All blocks have size parameter. For some block types, this
parameter is mandatory, for some - optional. The basic unit for size is a byte.
For example
type: empty
size: 4096
defines an empty block with a size of 4096 bytes. rouge supports some SI suffixes:
KB- kilobyte - 1000 bytes
MB- megabyte - 1000 kilobytes or 1 000 000 bytes
GB- gigabyte - 1000 megabytes or 1 000 000 000 bytes
KiB- kibibyte - 1024 bytes
MiB- mebibyte - 1024 kibibytes or 1 048 576 bytes
GiB- gibibyte - 1024 mebibytes or 1 073 741 824 bytes
The suffix must be separated from the number by a space. For example:
size: 4 MiB defines the size of 4 mebibytes or 4 194 304 bytes.
On the sparse option¶
Almost all block descriptions support boolean sparse option,
which is enabled by default. You can disable it to generate
non-sparse parts of the resulting images. This will create images that
are bigger while stored on disk, because they physically store all
non-needed NUL regions. But this may be used in cases when you need to
zero out some regions on flash storage. Bear in mind that in this
case, you can’t write the result image with
dd of=image.img of=/dev/outdevce conv=sparse
because with conv=sparse option dd will “un-sparse”
the image file, effectively skipping big zeroed regions. So, you
either need to remove conv=sparse option when calling
dd, increasing writing time significantly, or use
bmaptool which should be less aggressive with sparsed regions
detection.
Empty block¶
An empty block is a block that does not contain any file or
raw image. rouge will write nothing into this block if
filled: zeroes option is not specified.
type: empty # defines empty block
size: 4096
filled: zeroes
size is mandatory, as rouge can’t infer it.
filled is optional, with only zeroes value allowed for now.
This option may be used if you need the block to be filled with zeroes.
For example, this is used for some Android partitions, like ‘rpmbemul’.
You can use this option only if absolutely necessary. Otherwise, you will
needlessly increase the size and upload time of an image.
Raw Image Block¶
The purpose of this block type is to include any binary data from another file. For example, if your build system creates a .ext4 image with the root file system, you can use this block to place that image into a GPT partition (which is described below).
type: raw_image # defines raw image block
size: 400 MiB
resize: false
image_path: "some/path/rootfs.ext4"
image_path is mandatory. This is a file to be included in
resulting image.
size is optional. If it is omitted, rouge will use the size of
the file. If provided size is smaller than file size, rouge will
stop with an error. If provided size is bigger than file size,
rouge will try to resize the file to match size. This rule
applies to ext2..ext4 format now.
Note that host tools perform resizing, and you may meet some
compatibility issues if the newer tools generate the ext4 image.
For example, if the ext4 image is generated by the yocto scarthgap
with e2fsprogs 1.47, then such an image can be resized only on the host
with Ubuntu 23+. The lower versions of Ubuntu have e2fsprogs that
can’t resize such an image.
resize is optional. If set to false, it will prevent
rouge from resizing the image to the size of the block. This is
useful when you want to include a file that is smaller than the block
and leave the rest of the block empty.
sparse is optional. If it is set to to false, the raw image
will be copied in non-sparse mode. This may increase the final image
size on disk and processing time. Use this option only when absolutely
necessary, i.e, when some piece of software (like a bootloader) depends
on values in unallocated sectors.
Android Sparse Image Block¶
It is similar to Raw Image Block, but it handles files in Android Sparse image format.
type: android_sparse # defines android sparse block
size: 3000 MiB
image_path: "android/out/target/product/xenvm/userdata.img"
image_path is mandatory. This is a file to be included in
the resulting image. rouge will call simg2img2 tool to
unpack it before writing it to a resulting image.
size is optional. If it is omitted, rouge will use the data
size read from the file. If provided size is smaller than
read size, rouge will stop with an error. Thus, you can create a block
that is bigger than the unpacked file, but not smaller.
sparse is optional. If it is set to false, Android
sparsed image will be completely unsparsed, up to creating a fully
mapped file. It is seldom used, but it is added for completeness.
Filesystem Image With Files¶
This block type allows you to create a new filesystem with some files included from your disk. This is ideal for creating boot partitions, where you store the kernel, initial ramdisk, and so on.
type: ext4 # defines ext4 partition block
size: 30 MiB
items:
"remote_file1": "path/to/local/file1"
"remote_file2": "path/to/local/file2"
"remote_file3": "path/to/local/file3"
"remote_file4": "path/to/local/file4"
"remote_dir": "path/to/local/directory/"
type is required. Defines the filesystem type,
currently ext4 and vfat are supported.
You need to install the mtools package to work with vfat.
items: section is optional. It defines remote:local
mapping of files that should be presented on the newly created
filesystem. remote part is how the file will be named on the new
filesystem, while local is a path on your disk.
You can specify parent folders for remote and these folders
will be created on the destination filesystem.
You may specify not only files but also directories. If the local
directory contains subdirectories, they will be created under the
remote directory.
Older versions of rouge used files: as the name of the
section. This name is still possible to use, but it is deprecated.
Also, only items: can contain directories.
size is optional. rouge will calculate the total file size and
add some space for the filesystem metadata to determine the block size.
You can increase the size if you wish.
sparse is optional. If it is set to false, the filesystem
image will be copied in non-sparse mode. This may increase the final image
size on disk and processing time. Use this option only when absolutely
necessary, i.e, when some piece of software (like a bootloader) depends
on values in unallocated sectors.
GUID Partition Table (GPT) block¶
This block type defines GPT along with all partitions. In most cases, this will be your top-level block definition. It can (and should) include other blocks, including other GPT. Inner GPT can come in handy in cases when you are creating an image that holds data for multiple virtual machines and wish to provide each VM with its own GPT.
type: gpt # defines GPT block
partitions:
boot: # partition label
gpt_type: 21686148-6449-6E6F-744E-656564454649 # BIOS boot partition (kinda...)
gpt_guid: 8DA63339-0007-60C0-C436-083AC8230900 # Partition GUID
type: empty
size: 30 MiB
rootfs:
gpt_type: B921B045-1DF0-41C3-AF44-4C6F280D3FAE # Linux aarch64 root
type: raw_image
image_path: "rootfs.ext4"
This example defines GPT with two partitions: boot and
rootfs. boot is an empty block and rootfs
includes Raw Image block.
partitions: section is mandatory. It defines a list of
partitions, where the key is a partition label.
hybrid_mbr forces rouge to create a Hybrid MBR instead of
the default Protective MBR. Just so you know, this is an experimental feature,
as different OSes handle Hybrid MBR differently; in other words, this
type of MBR is not standardized and is not guaranteed to work on your
setup. It is mainly added to enable support of older Raspberry PI
models, whose bootloader can’t parse GPT. When Hybrid MBR is enabled,
the first three partition entries should contain mbr_type property
with MBR Partitions type code. In most cases, you will need
0x0C for FAT32 partitions and 0x83 for Linux file
systems.
Each partition contains the definition of another block type plus optional keys:
gpt_type: (which we strongly suggest providing) key holds GPT Partition
Type GUID. A list of widely used types can be found on
Wikipedia,
for example.
gpt_guid: key sets the GPT Partition GUID. By default, this GUID is generated
automatically to ensure that every partition in the world would have a unique
identifier. But there are some cases when external software depends on the exact value
of a partition GUID. In such cases, it is possible to hard-code this value. We
strongly recommend not to use this key except for the cases when this is necessary
because, according to page 121 of
Specification
the software that makes copies of GPT-formatted disks and partitions must generate
new Unique Partition GUID in each GPT Partition Entry.
sector_size is a custom sector size, 512 by default, but some devices
(e.g., fancy flash storage) might have a sector of a different size.
This key allows tuning for such cases.
mbr_type is used only when hybrid_mbr is set for the
GPT block entry. It corresponds to the MBR partition type byte. A list of
partition types can be found on Wikipedia.
rouge will place partitions one after another, aligning each partition start at 1 MiB (as per standard recommendation) and partition size to sector size, which defaults to 512 bytes.
Examples¶
The following example provides multiple different images:
min_ver: 0.3
desc: "rouge sample images"
images:
empty_image:
desc: "Just empty 32MB file"
type: empty
size: 32 MiB
unpacked_userdata:
desc: "Unpacked Android userspace image"
type: android_sparse
image_path: "android/out/target/product/xenvm/userdata.img"
simple_bootable_sd:
type: gpt
desc: "Full SD-card/eMMC image"
partitions:
boot:
gpt_type: 21686148-6449-6E6F-744E-656564454649 # BIOS boot partition (kinda...)
type: ext4
size: 30 MiB
items:
"Image": "yocto/build/tmp/deploy/images/generic-armv8-xt/Image"
"initrd": "yocto/build/tmp/deploy/images/generic-armv8-xt/uInitrd"
domd_rootfs:
gpt_type: B921B045-1DF0-41C3-AF44-4C6F280D3FAE # Linux aarch64 root
gpt_guid: 8DA63339-0007-60C0-C436-083AC8230900 # Partition GUID
type: raw_image
image_path: "yocto/build-domd/tmp/deploy/images/machine/core-image-weston.ext4"
rouge sample_images.yaml -i empty_imagewill generate just an empty file. This is the simplest example.
rouge sample_images.yaml -i unpacked_userdatawill use simg2img to unpack Android userdata image.
rouge sample_images.yaml -i unpacked_userdatawill generate a sort of usable image with two GPT partitions: one with data for the bootloader, and the other will contain an ext4 root image created by Yocto.