REPART.D(5)
๐ NAME ๐
okay so bestie, welcome to repart.d โ it's literally the Partition Definition Files for Automatic Boot-Time Repartitioning. yes that's a mouthful, i know. it's REPART.D(5) in the manual, and it's about to be your new hyperfixation. ๐ฆ
โจ SYNOPSIS โจ
/etc/repart.d/*.conf
/run/repart.d/*.conf
/usr/local/lib/repart.d/*.conf
/usr/lib/repart.d/*.conf
that's it. those four directories, those four globs. the way that these files just live in four places and the system picks them upโฆ iconic behavior tbh. ๐
๐ DESCRIPTION ๐
okay so repart.d/*.conf files describe the basic properties of partitions on the block devices of your local system. like, they declare the types, names, and sizes of partitions that shall exist. systemd-repart(8) reads these files and then goes and attempts to add any new partitions that are currently missing, and enlarge existing partitions according to these definitions. slay.
and here's the part that lowkey saves you: operation is generally incremental, meaning when it's applied, what already exists is left intact, and partitions are never shrunk, moved, or deleted. never ever. periodt. ๐
these definition files are useful for implementing operating system images that are prepared and delivered with minimally sized images (for example, ones lacking any state or swap partitions), and which on first boot automatically take possession of any remaining disk space following a few basic rules. it's giving "glow up on first boot" ngl.
heads up bestie: currently, support for partition definition files is only implemented for GPT partition tables. no GPT, no service. ๐
partition files are generally matched against any partitions already existing on disk in a simple algorithm, and honestly the algorithm is giving group-chat-roll-call:
- the partition files are sorted by their filename (ignoring the directory prefix) ๐๏ธ
- then compared in order against existing partitions matching the same partition type UUID
- specifically, the first existing partition with a specific partition type UUID is assigned the first definition file with the same partition type UUID, and the second existing partition with a specific type UUID gets the second partition file with the same type UUID, and so on. โจ
any left-over partition files that have no matching existing partition are assumed to define a new partition that shall be created. such partitions are appended to the end of the partition table, in the order defined by their names, utilizing the first partition slot greater than the highest slot number currently in use. bestie they're just getting tacked onto the end, respectfully. ๐ซถ
any existing partitions that have no matching partition file are left as they are. untouched. living their best life. ๐ธ
IMPORTANT: note that these definitions may only be used to create and initialize new partitions or to grow existing ones. in the latter case, it will not grow the contained file systems however โ separate mechanisms, such assystemd-growfs(8), may be used to grow the file systems inside of these partitions. partitions may also be marked for automatic growing via theGrowFileSystem=setting, in which case the file system is grown on first mount by tools that respect this flag. see below for details. ๐
๐ [PARTITION] SECTION OPTIONS ๐
okay now the good part. the actual settings. let's get into it ๐
Type=โ the GPT partition type UUID to match. this may be a GPT partition type UUID such as4f68bce3-e8cd-4db1-96e7-fbcaf984b709, or an identifier. ๐
the supported identifiers are:
๐ Table 1. GPT partition type identifiers ๐
okay so bestie, this is THE list ๐
every identifier you can throw into Type= when you're defining a partition. Each one is basically a little name tag that tells the world what that partition is. Iconic behaviour honestly. Here we go:
espโ EFI System Partition ๐ฅพxbootldrโ Extended Boot Loader Partition ๐swapโ Swap partition ๐homeโ Home (/home/) partition ๐srvโ Server data (/srv/) partition ๐ฅ๏ธvarโ Variable data (/var/) partition ๐ฆtmpโ Temporary data (/var/tmp/) partition ๐๏ธlinux-genericโ Generic Linux file system partition ๐งrootโ Root file system partition type appropriate for the local architecture (an alias for an architecture root file system partition type listed below, e.g.root-x86-64) ๐root-verityโ Verity data for the root file system partition for the local architecture ๐root-verity-sigโ Verity signature data for the root file system partition for the local architecture โ๏ธroot-secondaryโ Root file system partition of the secondary architecture of the local architecture (usually the matching 32-bit architecture for the local 64-bit architecture)root-secondary-verityโ Verity data for the root file system partition of the secondary architectureroot-secondary-verity-sigโ Verity signature data for the root file system partition of the secondary architectureroot-{arch}โ Root file system partition of the given architecture (such asroot-x86-64orroot-riscv64)root-{arch}-verityโ Verity data for the root file system partition of the given architectureroot-{arch}-verity-sigโ Verity signature data for the root file system partition of the given architectureusrโ/usr/file system partition type appropriate for the local architecture (an alias for an architecture/usr/file system partition type listed below, e.g.usr-x86-64) ๐งusr-verityโ Verity data for the/usr/file system partition for the local architectureusr-verity-sigโ Verity signature data for the/usr/file system partition for the local architectureusr-secondaryโ/usr/file system partition of the secondary architecture of the local architecture (usually the matching 32-bit architecture for the local 64-bit architecture)usr-secondary-verityโ Verity data for the/usr/file system partition of the secondary architectureusr-secondary-verity-sigโ Verity signature data for the/usr/file system partition of the secondary architectureusr-{arch}โ/usr/file system partition of the given architectureusr-{arch}-verityโ Verity data for the/usr/file system partition of the given architectureusr-{arch}-verity-sigโ Verity signature data for the/usr/file system partition of the given architecture ๐
โ โ architecture โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
When a partition type is architecture-specific, it can use one of these identifiers: alpha, arc, arm (32-bit), arm64 (64-bit, aka aarch64), ia64, loongarch64, mips-le, mips64-le, parisc, ppc, ppc64, ppc64-le, riscv32, riscv64, s390, s390x, tilegx, x86 (32-bit, aka i386) and x86-64 (64-bit, aka amd64). โจ
Most of the partition type UUIDs up above are defined in the UAPI.2 Discoverable Partitions Specification[1]. ๐
Added in version 245.
Label=
The textual label you wanna slap onto the partition, but only if nothing's been assigned yet. Bestie, listen: this setting is not used for matching. It's also not used when a label is already set on an existing partition. So it literally only kicks in when a partition is brand new, or when an existing one had no label at all (as in: an empty label). If you don't specify anything, a label derived from the partition type gets used automatically. Simple specifier expansion is supported โ see below. ๐
Added in version 245.
VolumeLabel=
The textual label for the LUKS superblock, if that applies to you. If you don't set it, it defaults to the same string as the partition label (that's Label= up there โฌ๏ธ), except prefixed with "luks-". This setting does absolutely nothing if encryption isn't enabled for this partition, no cap. ๐
Added in version 259.
UUID=
The UUID to assign to the partition, again only if none is assigned yet. Same energy as Label=: it's not used for matching, and it's not used when a UUID is already set on an existing partition. So it's only relevant when a partition is newly created, or when an existing one had an all-zero UUID. If you set it to "null", the UUID gets set to all zeroes. If you don't specify it, a UUID derived from the partition type is used automatically. ๐ฆ
Added in version 246.
Priority=
A numeric priority for this partition, ranging from -2147483648 to 2147483647. Smaller values mean higher priority, higher values mean smaller priority โ yes it's backwards, iykyk. ๐
This priority comes into play when the size constraints you configured on the partitions don't allow fitting everything onto the available disk space. If the partitions don't fit, the highest numeric partition priority of all defined partitions is determined, and all defined partitions with that priority are removed from the list of new partitions to create (which can be multiple, if several partitions share that same priority). Then the fitting algorithm gets tried again. Still don't fit? The now-highest numeric priority is determined, matching partitions get removed too, and on it goes.
Partitions with a priority of 0 or lower are never removed. If all partitions with a priority above 0 have been removed and things still don't fit on the device, the operation fails. ๐
Oh and heads up: this priority has no effect on ordering partitions. For ordering, it's the alphabetical order of the filenames of the partition definition files. Defaults to 0. ๐ธ
Added in version 245.
Weight=
A numeric weight for this partition, ranging 0...1000000. Available disk space gets handed out to the defined partitions according to their relative weights (subject to the size constraints from SizeMinBytes= and SizeMaxBytes=), so a partition with weight 2000 gets double the space of one with weight 1000, and a partition with weight 333 gets a third of that. Defaults to 1000. โจ
Weight= is what distributes available disk space in an "elastic" fashion, based on the disk size and existing partitions. If you want a partition to have a fixed size, use both SizeMinBytes= and SizeMaxBytes= with the same value to lock the size to one number โ and in that case the weight has no effect at all. ๐
Added in version 245.
PaddingWeight=
Same vibe as Weight=, but it sets a weight for the free space after the partition (the "padding"). When distributing available space, the weights of all partitions and all defined padding get summed, and then each partition and each padding gets the fraction defined by its weight. Defaults to 0, meaning by default no padding is applied. ๐
Padding is your bestie if you wanna leave empty space for later additions, or just want a safety margin at the end of the device or between partitions. ๐ซถ
Added in version 245.
SizeMinBytes=, SizeMaxBytes=
These specify minimum and maximum size constraints in bytes. They take the usual K, M, G, T, ... suffixes (base 1024, obviously ๐
). If SizeMinBytes= is specified, the partition is created at, or grown to, at least that size. If SizeMaxBytes= is specified, the partition is created at, or grown to, at most that size. The precise size is figured out through the weight from Weight= โ see above.
When SizeMinBytes= equals SizeMaxBytes=, the configured weight has no effect, because the partition is explicitly sized to that one fixed value. ๐
Now the real talk: partitions are never created smaller than 4096 bytes, and since partitions are never shrunk, the previous size of the partition (if it already exists) is also enforced as a lower bound for the new size. Values should be multiples of 4096 bytes, and get rounded upwards otherwise (for SizeMinBytes=) or downwards (for SizeMaxBytes=).
If the backing device doesn't have enough space to fulfill the constraints, placing the partition will fail. And for partitions that are yet to be created, depending on Priority= (see above), the partition might get dropped and the placing algorithm restarted. By default, a minimum size constraint of 10M is set and no maximum size constraint. ๐
If Format= is set, the minimum size is automatically raised to the minimum file system size for the selected file system type, if that's known. Also, for ESP/XBOOTLDR partitions the minimum gets raised to 100M (for 512b sector images) or 260M (for 4K sector images) automatically, if you specified something smaller. ๐ฅ
Added in version 245.
PaddingMinBytes=, PaddingMaxBytes=
Minimum and maximum size constraints in bytes for the free space after the partition (the "padding"). Semantics are similar to SizeMinBytes= and SizeMaxBytes=, except that unlike partition sizes, free space can be shrunk and can be as small as zero. By default, no size constraints on padding are set, so only PaddingWeight= decides how big the padding ends up. ๐
Added in version 245.
CopyBlocks=
Takes a path to a regular file, block device node, char device node or directory โ or the special value "auto". If specified and the partition is newly created, the data from that path gets written to the newly created partition, on the block level. If a directory is specified, the backing block device of the file system that directory lives on is determined, and the data is read directly from that. ๐ง
This option is chef's kiss for efficiently replicating existing file systems onto new partitions on the block level โ like for building a simple OS installer or an OS image builder. And yes, you can specify /dev/urandom as the value to initialize a partition with random data. ๐ฒ
If the special value "auto" is specified, the source to copy from gets picked up automatically from the running system (or the image specified with --image=, if that's being used). A partition that matches both the configured partition type (as declared with Type=, described above) and the currently mounted directory appropriate for that partition type is determined. For example, if the partition type is set to "root", the partition backing the root directory (/) is used as the source to copy from โ if its partition type is set to "root" as well. If the declared type is "usr", the partition backing /usr/ is used as source to copy blocks from โ if its partition type is set to "usr" too. The logic is capable of automatically tracking down the backing partitions for encrypted and Verity-enabled volumes. "CopyBlocks=auto" is your girl for implementing "self-replicating" systems, i.e. systems that are their own installer. ๐
The file specified here must have a size that's a multiple of the basic block size 512 and must not be empty. If this option is used, the size allocation algorithm is slightly altered: the partition is created at least as big as required to fit the data in, i.e. the data size becomes an additional minimum size value taken into consideration for the allocation algorithm, similar to and in addition to the SizeMinBytes= value configured above.
This option has no effect if the partition it's declared for already exists, i.e. existing data is never overwritten. ๐ Note that the data is copied in before the partition table is updated, i.e. before the partition actually is persistently created. That's for robustness: it's guaranteed that the partition either doesn't exist or exists fully populated. It is not possible that the partition exists but is not populated, or only partially populated. ๐ฏ
This option cannot be combined with Format= or CopyFiles=. โ ๏ธ
Added in version 246.
Format=
Takes a file system name, such as "ext4", "btrfs", "xfs", "vfat", "erofs", "squashfs" โ or the special value "swap". If specified and the partition is newly created, it gets formatted with the specified file system (or as a swap device). The file system UUID and label are automatically derived from the partition UUID and label. If this option is used, the size allocation algorithm is slightly altered: the partition is created at least as big as required for the minimal file system of the specified type (or 4KiB if the minimal size isn't known). ๐
It also takes a special meta value "empty". If specified, this is equivalent to specifying "Label=_empty" and "NoAuto=1". ๐คซ
This option has no effect if the partition already exists.
Just like the behaviour of CopyBlocks=, the file system is formatted before the partition is created, ensuring the partition only ever exists with a fully initialized file system. โจ
This option cannot be combined with CopyBlocks=. โ ๏ธ
Added in version 247.
๐ CopyFiles=
Okay bestie, this one is the main character of the whole copy situation. It takes a colon-separated triplet that looks like this:
source[:target[:options]]
sourceโ an absolute path pointing at a file or directory on the host.targetโ an absolute path in the file system of the newly created partition and formatted file system.optionsโ a comma-separated list of options, where each option is shaped likekey[=value].
This setting is literally how you copy files or directories off the host into the file system that gets created thanks to the Format= option. And listen: if you use CopyFiles= without specifying Format= explicitly, then "Format=" with a suitable default is implied โ currently "vfat" for "ESP" and "XBOOTLDR" partitions, and "ext4" otherwise, but this may change in the future, so don't come for me. ๐ธ This option may be used multiple times to copy multiple files or directories from host into the newly formatted file system. Stack 'em up, queen.
The target path may be omitted, in which case the source path is also used as the target path (relative to the root of the newly created file system). And if the source path refers to a directory, it is copied recursively ๐ฆ.
The options may contain the following values:
fsverity=โ May be set to the value"off"(the default if the option is not present) or"copy". If set to"off"then no files copied into the filesystem from this source will have fs-verity enabled. If set to"copy"then the fs-verity information for each file will be copied from the corresponding source file.
Added in version 258.
This option has no effect if the partition already exists โ it cannot be used to copy additional files into an existing partition, it may only be used to populate a file system created anew. ๐ญ
The copy operation is executed before the file system is registered in the partition table, which is the whole reason a file system populated this way only ever exists fully initialized. Iconic behaviour, honestly. ๐
Note that CopyFiles= will skip copying files that are not supported by the target filesystem (e.g symlinks, fifos, sockets and devices on vfat). When an unsupported file type is encountered, systemd-repart will skip copying this file and write a log message about it. No drama, just a lil note in the logs. ๐
Note that systemd-repart does not change the UIDs/GIDs of any copied files and directories. When running systemd-repart as an unprivileged user to build an image of files and directories owned by the same user, you can run systemd-repart in a user namespace with the current user mapped to the root user to make sure the files and directories in the image are owned by the root user. Sneaky but legal. โจ
This option cannot be combined with CopyBlocks=.
When systemd-repart(8) is invoked with the --copy-source= command line switch the file paths are taken relative to the specified directory. If --copy-source= is not used, but the --image= or --root= switches are used, the source paths are taken relative to the specified root directory or disk image root.
Note that when CopyFiles= is used with Format=xfs, xfsprogs 6.17 or newer is required.
Note that systemd-repart always excludes the contents of a number of API file systems and temporary directories, namely /proc/, /sys/, /dev/, /tmp/, /run/, and /var/tmp/, as their contents are not expected to be part of a disk image. The directories themselves are still created (empty) in the new file system though โ they're just empty lil shells. ๐
When a root partition is populated, the contents below the mount points of any other partitions that are part of the same image are excluded too, so that data belonging to a separate partition is not duplicated into the root file system. For example, if an esp partition is part of the image, the contents of /boot/ and /efi/ are not copied into the root partition.
To copy a directory that is excluded by the mount-point rule above, add an explicit CopyFiles= entry for it. For example, "CopyFiles=/boot:/boot" overrides the implicit exclusion and copies /boot/ into the root partition. You can just decide to override the rules, slay. ๐
Added in version 247.
๐ ExcludeFiles=, ExcludeFilesTarget=
Takes one or more absolute paths, separated by whitespace, each referring to a source file or directory on the host. This setting may be used to exclude files or directories from the host from being copied into the file system when CopyFiles= is used. This option may be used multiple times to exclude multiple files or directories from host from being copied into the newly formatted file system. It's the "not you, bestie" list. ๐
Here's the crucial detail, don't miss it:
- If the path is a directory and ends with
"/", only the directory's contents are excluded but not the directory itself. - If the path is a directory and does not end with
"/", both the directory and its contents are excluded.
ExcludeFilesTarget= is like ExcludeFiles= except that instead of excluding the path on the host from being copied into the partition, it excludes any files and directories from being copied into the given path in the partition.
When systemd-repart(8) is invoked with the --image= or --root= command line switches the paths specified are taken relative to the specified root directory or disk image root.
Added in version 254.
๐ MakeDirectories=
Takes one or more absolute paths, separated by whitespace, each declaring a directory to create within the new file system. Behaviour is similar to CopyFiles=, but instead of copying in a set of files this just creates the specified directories with the default mode 0755 owned by the root user and group, plus all their parent directories (with the same ownership and access mode). To configure directories with different ownership or access mode, use CopyFiles= and specify a source tree to copy containing appropriately owned/configured directories. This option may be used more than once to create multiple directories. When CopyFiles= and MakeDirectories= are used together the former is applied first. If a directory listed already exists no operation is executed (in particular, the ownership/access mode of the directories is left as is). Not me touching your existing perms โ I would never. ๐
The primary use case for this option is to create a minimal set of directories that may be mounted over by other partitions contained in the same disk image. For example, a disk image where the root file system is formatted at first boot might want to automatically pre-create /usr/ in it this way, so that the "usr" partition may over-mount it.
Consider using systemd-tmpfiles(8) with its --image= option to pre-create other, more complex directory hierarchies (as well as other inodes) with fine-grained control of ownership, access modes and other file attributes.
Added in version 249.
๐ฆ MakeSymlinks=
Takes one or more arguments, separated by whitespace, each declaring a symlink to create within the new file system. Each argument is a pair of symlink source and target paths, separated by a colon. This option may be used more than once to create multiple symlinks. When CopyFiles= and MakeSymlinks= are used together the former is applied first.
The primary use case for this option is to create symlinks that need to exist before systemd-tmpfiles(8) is executed. For example, when using systemd-confext(8), this setting can be used to create symlinks in /var/lib/extensions.mutable to redirect writes to mutable confexts to a custom location. Very "redirecting the vibe" of it all. โจ
Consider using systemd-tmpfiles(8) with its --image= option to pre-create other symlinks (as well as other inodes) with fine-grained control of ownership, access modes and other file attributes.
Added in version 257.
๐ Subvolumes=
Takes one or more absolute paths, separated by whitespace, each declaring a directory that should be a subvolume within the new file system. Each path may optionally be followed by a colon and a list of comma-separated subvolume flags. The following flags are understood:
Table 2. Subvolume Flags
"ro"โ Make this subvolume read-only."nodatacow"โ Disable data CoW for this subvolume.
Note that this option does not create the directories themselves, that can be configured with MakeDirectories= and CopyFiles=. It's giving "I decorate, I don't build". ๐
Note that this option only takes effect if the target filesystem supports subvolumes, such as btrfs(8).
Note that this option is only supported in combination with --offline=yes since btrfs-progs 6.12 or newer.
Added in version 255.
๐ธ DefaultSubvolume=
Takes an absolute path specifying the default subvolume within the new filesystem. Note that this setting does not create the subvolume itself, that can be configured with Subvolumes=.
Note that this option only takes effect if the target filesystem supports subvolumes, such as btrfs(8).
Note that this option is only supported in combination with --offline=yes since btrfs-progs 6.12 or newer.
Added in version 256.
๐ฅ BlockDeviceReplace=
Takes a path to a mountpoint. Its filesystem's backing device will be replaced with the newly created partition. This works only for btrfs filesystems. This option is ignored for already existing partitions.
Okay this next bit is important, so read it properly: if after moving the filesystem, an error happens before the writing of the partition table is finished, there will be an attempt to move the filesystem back to its original device. But if that attempt also fails, the filesystem might be living on a partition that does not exist in the partition table and will be lost on reboot. ๐ This feature is intended to save initially volatile mounted filesystems into the new disk with no important data, like a live boot system. They might need to be recreated after a failure writing the partition table. So like... use it on things you're chill about losing, bestie.
This option is not compatible with --offline=yes.
Added in version 261.
VolumeName=โ okay so bestie, if you're making an encrypted partition withEncrypt=, and it's gonna stay activated aftersystemd-repartis done (that's theBlockDeviceReplace=situation), then the device mapper volume it creates gets the name you put here. โจ
It's gotta be a valid filename. If you don't set it, it defaults to whatever VolumeLabel= is (which might itself come from Label=) โ as long as that's valid.
Added in version 261.
Encrypt=โ takes one of"off","key-file","tpm2"and"key-file+tpm2". (It also accepts a boolean, which maps to"off"when false and"key-file"when true, iykyk.) Defaults to"off". If it's not"off", the partition gets formatted with a LUKS2 superblock before the blocks fromCopyBlocks=are copied in or the file system fromFormat=is created. ๐
The LUKS2 UUID is automatically derived from the partition UUID in a stable fashion โ cute, no cap. If "key-file" or "key-file+tpm2" is used, a key is added to the LUKS2 superblock, configurable with the --key-file= option to systemd-repart. If "tpm2" or "key-file+tpm2" is used, a key is added to the LUKS2 superblock that's enrolled to the local TPM2 chip, as configured with the --tpm2-device= and --tpm2-pcrs= options to systemd-repart.
Heads up: using this slightly alters the size allocation logic, because the implicit, minimal size limits of Format= and CopyBlocks= get increased by the space needed for the LUKS2 superblock (see above).
This option has no effect if the partition already exists.
This option may be combined with Verity=data to place the encrypted partition inside a dm-verity protection envelope โ see the Verity= description below. ๐
Added in version 247.
Discard=โ takes a boolean. The default is"no"if--discard=nois used for the invocation ofsystemd-repartor ifIntegrity=inlineis set. It's"yes"otherwise.
If set to "yes", when the LUKS2 superblock is created for the partition, the "allow-discards" activation flag gets set, so future activations will allow discards by default.
No effect if the partition already exists or if Encrypt=off is used.
Added in version 261.
EncryptKDF=โ picks the key derivation function (KDF) to use for LUKS2 encryption keyslots. Takes one of"argon2id","pbkdf2", or"minimal". If you don't specify it, the default comes from the cryptsetup library (typically"argon2id"). This option does nothing ifEncrypt=is"off". ๐ง
When set to "argon2id" or "pbkdf2", that KDF is used with parameters benchmarked by the cryptsetup library. When set to "minimal", PBKDF2 is used with SHA-512, 1000 iterations, and no benchmarking โ this is the move for high-entropy keys (like ones generated by a hardware key manager or sealed to a TPM) where the KDF only needs to satisfy the LUKS2 format requirement, not strengthen a weak passphrase.
Real talk: Argon2-based KDFs may need a lot of memory (up to 1GB) during key derivation. In memory-constrained environments like kdump with limited crashkernel memory,"minimal"or"pbkdf2"may be more appropriate. And whenEncrypt=includes"tpm2", the TPM2 keyslot always uses a minimal PBKDF2 configuration regardless of this setting.
Added in version 261.
Verity=โ takes one of"off","data","hash"or"signature". Defaults to"off". If set to"off"or"data", the partition gets populated with content as specified byCopyBlocks=orCopyFiles=. If set to"hash", the partition gets populated with verity hashes from the matching verity data partition. If set to"signature", the partition gets populated with a JSON object containing a signature of the verity root hash of the matching verity hash partition. ๐
A matching verity partition is a partition with the same verity match key (as configured with VerityMatchKey=).
If not explicitly configured, the data partition's UUID is set to the first 128 bits of the verity root hash. Similarly, if not configured, the hash partition's UUID is set to the final 128 bits of the verity root hash. The verity root hash itself will be included in the output of systemd-repart.
This option has no effect if the partition already exists.
"data" may be combined with Encrypt=, in which case the partition is first encrypted with LUKS2 and the verity hash data is then generated from the resulting ciphertext โ i.e. Verity is the outer protection envelope and LUKS2 the inner. Tools such as systemd-dissect(1) will then set up the dm-verity device first, and open the LUKS2 volume on top of it, so that all encrypted data read is also authenticated via the verity root hash. Note that in this case the verity hashes necessarily cover freshly generated ciphertext, hence the root hash (and thus the default partition UUIDs derived from it) will change on every build, even if the plaintext contents are fully reproducible. ๐ Encrypt= may not be combined with "Verity=hash" or "Verity=signature". And since the ciphertext is only generated while the final image is built, Minimize= cannot be used for the hash partition of an encrypted data partition; use SizeMaxBytes= on the data partition to size the hash partition instead.
For each unique VerityMatchKey= value, a single verity data partition ("Verity=data") and a single verity hash partition ("Verity=hash") must be defined.
Added in version 252.
VerityMatchKey=โ takes a short, user-chosen identifier string. This setting is used to find sibling verity partitions for the current verity partition. See the description forVerity=. ๐ซถ
Added in version 252.
VerityDataBlockSizeBytes=โ configures the data block size of the generated verity hash partition. Must be between 512 and 4096 bytes and must be a power of 2. Defaults to the sector size if configured explicitly, or the underlying block device sector size, or 4K ifsystemd-repartis not operating on a block device.
Added in version 255.
VerityHashBlockSizeBytes=โ configures the hash block size of the generated verity hash partition. Must be between 512 and 4096 bytes and must be a power of 2. Defaults to the sector size if configured explicitly, or the underlying block device sector size, or 4K ifsystemd-repartis not operating on a block device.
Added in version 255.
FactoryReset=โ takes a boolean. If specified, the partition is marked for removal during a factory reset operation. This is the vibe for schemes where images can be reset into their original state by removing partitions and creating them anew. Defaults to off. ๐
Added in version 245.
Flags=โ configures the 64-bit GPT partition flags field to set for the partition when creating it. This option has no effect if the partition already exists. If not specified, the flags value is set to all zeroes, except for the three bits that can also be configured viaNoAuto=,ReadOnly=andGrowFileSystem=; see below for the deets on those three flags' defaults. Specify the flags value in hexadecimal (prefix"0x"), binary (prefix"0b") or decimal (no prefix).
Added in version 249.
NoAuto=,ReadOnly=,GrowFileSystem=โ configures the No-Auto, Read-Only and Grow-File-System partition flags (bit 63, 60 and 59) of the partition table entry, as defined by the UAPI.2 Discoverable Partitions Specification[1]. Only available for partition types supported by the specification. This option is the friendly lil way to set bits 63, 60 and 59 of the partition flags value without touching any of the other bits, and it may be set viaFlags=too, see above. ๐
If Flags= is used in conjunction with one or more of NoAuto=/ReadOnly=/GrowFileSystem=, the latter control the value of the relevant flags โ i.e. the high-level settings NoAuto=/ReadOnly=/GrowFileSystem= override the relevant bits of the low-level setting Flags=.
Important: these three flags only affect automatic partition mounting, as implemented bysystemd-gpt-auto-generator(8)or the--image=option of various commands (such assystemd-nspawn(1)). It has no effect on explicit mounts, like the ones done viamount(8)orfstab(5).
If both bit 60 and 59 are set for a partition (i.e. it's marked both read-only and marked for file system growing), the latter is typically without effect: the read-only flag takes precedence in most tools reading these flags, and since growing the file system involves writing to the partition it's consequently ignored.
NoAuto= defaults to off. ReadOnly= defaults to on for Verity partition types, and off for all others. GrowFileSystem= defaults to on for all partition types that support it, except if the partition is marked read-only (and thus effectively, defaults to off for Verity partitions).
Added in version 249.
SplitName=โ configures the suffix to append to split artifacts when the--splitoption ofsystemd-repart(8)is used. Simple specifier expansion is supported, see below. Defaults to"%t". To disable split artifact generation for a partition, setSplitName=to"-". โ๏ธ
Added in version 252.
Minimize=โ takes one of"off","best", and"guess"(it also accepts a boolean, which maps to"off"when false and"best"when true). Defaults to"off". If set to"best", the partition will have the minimal size required to store the sources configured withCopyFiles=."best"is currently only supported for read-only filesystems and btrfs. If set to"guess", the partition is created at least as big as required to store the sources configured withCopyFiles=. Note that unless the filesystem is a read-only filesystem or btrfs,systemd-repartwill have to populate the filesystem twice to guess the minimal required size, so enabling this option might slow down repart when populating large partitions. ๐
Added in version 253.
MountPoint=โ tells a partition where it should be mounted, and how. ๐ You give it at least one and at most two fields, split apart by a colon (":"). Field one is where the partition gets mounted. Field two is extra mount options that get appended onto the default mount options. These two fields map exactly onto the second and fourth column of thefstab(5)format, so if you already vibe with fstab you already vibe with this. โจ And bc a colon is what separates the fields, any field that has a colon inside it has to be quoted. Like so:
MountPoint="/path/with:colon":"zstd:1,noatime,lazytime"
You can drop this setting multiple times to mount the partition multiple times โ that's literally how you add mounts for different btrfs(8) subvolumes sitting on the same btrfs partition. ๐ธ Just know that this setting only gets taken into account when --generate-fstab= is specified on the systemd-repart command line. No flag, no fstab, no cap. ๐
Added in version 256.
EncryptedVolume=โ this one controls how an encrypted partition gets set up. ๐ Takes at least one and at most four fields, separated with a colon (":").- Field one: the encrypted volume name under
/dev/mapper/. If you don't specify it,"luks-UUID"gets used, where"UUID"is the LUKS UUID. ๐ - Field two: the keyfile to use, following the same format as specified in crypttab.
- Field three: a comma-delimited list of crypttab options.
- Those first three fields line up with the first, third and fourth column of the
crypttab(5)format. - Field four: extra options that aren't directly reflected into crypttab options. Right now the only supported extra option is
fixate-volume-key. When you specify it, the volume key hash gets taken upon LUKS volume formatting, and the result gets added to the list of crypttab options โ i.e.fixate-volume-key=expected-hashgets added to the fourth column of the generated crypttab.
- Field one: the encrypted volume name under
Heads up bestie: this setting is only taken into account when --generate-crypttab= is specified on the systemd-repart command line. And bc the crypttab with the expected hashes can only be generated after LUKS volumes are formatted, the crypttab itself cannot be put into the generated volume. Timing is timing. ๐ญ
Added in version 256.
TPM2PCRs=โ sets up the list of PCRs to use for LUKS2 volumes that are configured with theEncrypt=tpm2setting in partition files. ๐ฆ It takes the same parameters as the similarly named options tosystemd-cryptenroll(1), and has the same effect on partitions where TPM2 enrollment is requested. One thing tho: this option gets overridden by the global--tpm2-pcrs=option. Global always wins, that's just the hierarchy. โจ
Added in version 259.
KeyFile=โ takes a file system path. This path has to be absolute, otherwise the option is just ignored (rude, but okay ๐). It configures the encryption key to use when setting up LUKS2 volumes configured with theEncrypt=key-filesetting in partition files. Please refer to the documentation of--key-file=for more details. And yeah โ this option gets overridden by the global--key-file=option too.
Added in version 259.
Integrity=โ turns on integrity checking for the partition. ๐ก๏ธ Currently the only supported option isIntegrity=inline, which enables authenticated disk encryption for LUKS2 devices. It requires theEncrypt=setting, and it can only be used in online image build. Defaults to"off", i.e. integrity protection is disabled.
Note: authenticated disk encryption is considered EXPERIMENTAL by cryptsetup. Like, don't say we didn't warn you. ๐
Added in version 260.
IntegrityAlgorithm=โ picks the integrity algorithm used for integrity verification. ForIntegrity=inlinethe supported values are:"hmac-sha1","hmac-sha256"(default), and"hmac-sha512". โจ
Added in version 260.
Compression=โ specifies the compression algorithm to use for the filesystem configured withFormat=. Takes a single argument naming the compression algorithm. ๐๏ธ
Note that this setting is only taken into account when the filesystem configured with Format= supports compression (btrfs(8), squashfs, erofs(5)). Here's an incomplete list of compression algorithms supported by the filesystems that systemd-repart knows about โ incomplete, so don't come for me:
Table 3. File System Compression Algorithms
- squashfs โ
gzip,lzo,lz4,xz,zstd,lzmaโ documentation:mksquashfs(1) - erofs โ
lz4,lz4hc,lzma,deflate,libdeflate,zstdโ documentation:mkfs.erofs(1) - btrfs โ
zlib,lzo,zstdโ documentation:mkfs.btrfs(8)
Added in version 257.
CompressionLevel=โ specifies the compression level to use for the filesystem configured withFormat=. Takes a single argument naming the compression level for the configured compression algorithm. The possible compression levels and what they actually mean are filesystem specific โ so go read that filesystem's documentation for the exact meaning of a particular level. ๐ง
Note that this setting is only taken into account when the filesystem configured with Format= supports compression and the Compression= setting is configured explicitly. Both, or nothing. ๐
Added in version 257.
SupplementFor=โ takes a partition definition name, like"10-esp". If you set it,systemd-repartwill avoid creating this partition and instead prefer to partially merge the two definitions together. ๐ซถ But depending on the existing layout of partitions on disk,systemd-repartmay be forced to fall back onto un-merging the definitions and using them as originally written โ which potentially creates this partition after all. Specifically, it falls back if this partition is found to already exist on disk, or if the target partition already exists on disk but is too small, or if it cannot allocate space for the merged partition for some other reason. So many reasons, so little space. ๐ญ
Here's how the fields get merged into the target definition:
Weight=andPaddingWeight=are simply overwritten.SizeMinBytes=andPaddingMinBytes=use the larger of the two values.SizeMaxBytes=andPaddingMaxBytes=use the smaller value.CopyFiles=,ExcludeFiles=,ExcludeFilesTarget=,MakeDirectories=, andSubvolumes=are concatenated.
Using this option in combination withCopyBlocks=,Encrypt=, orVerity=is not supported. The target definition cannot set these settings either. A definition cannot simultaneously be a supplement and act as a target for some other supplement definition. And a target cannot have more than one supplement partition associated with it. Periodt. โ
Example one โ distributions can use this to implement $BOOT as defined in the UAPI.1 Boot Loader Specification[2]. ๐ Distributions may prefer to use the ESP as $BOOT whenever possible, but to adhere to the spec XBOOTLDR must sometimes be used instead. So they should create two definitions: the first defining an ESP big enough to hold just the bootloader, and a second for the XBOOTLDR that's sufficiently large to hold kernels and configured as a supplement for the ESP. Whenever possible, systemd-repart(8) will try to merge the two definitions into one large ESP โ but if that's not allowable due to the existing conditions on disk, a small ESP and a large XBOOTLDR get created instead. Slay, either way. โจ
Example two โ distributions can also use this to seamlessly share a single /home partition in a multi-boot scenario, while preferring to keep /home on the root partition by default. ๐ Having a /home partition separated from the root partition entails some extra complexity: someone has to decide how to split the space between the two partitions. On the other hand, it lets a user share their home area between multiple installed OSs (i.e. via systemd-homed.service(8)). Distributions should create two definitions: the first for a root partition that takes up some relatively small percentage of the disk, and the second as a supplement for the first, to create a /home partition that takes up all the remaining free space. On first boot, if systemd-repart finds an existing /home partition on disk, it'll un-merge the definitions and create just a small root partition. Otherwise, the definitions get merged and a single large root partition gets created. The way that works is honestly iconic. ๐
Added in version 257.
AddValidateFS=โ takes a boolean argument. If enabled, it will set theuser.validatefs.gpt_label,user.validatefs.gpt_type_uuidanduser.validatefs.mount_pointextended attributes on the root inode of the formatted file system, to the partition labels, partition type UUIDs and the intended mount point for the file system. โจ Defaults to on ifFormat=is used and the specified argument is neither"swap"nor"vfat".
These extended attributes are read by systemd-validatefs@.service(8) and may encode constraints on mounted file systems that must be fulfilled for the system to successfully boot. This is particular important in systemd-gpt-auto-generator(8) scenarios, which puts together the mount hierarchy from untrusted data from the GPT partition table. ๐ณ Since these extended attributes are stored inside the file system, they're typically authenticated as part of the file system (assuming it is contained in a protected volume; i.e. LUKS or dm-verity), and hence may be used to securely validate the matching partition table fields. Trust the fs, verify the table. ๐ฆ
Added in version 258.
FileSystemSectorSize=โ bestie this one sets the sector size for any file system, LUKS volume or Verity volume that gets formatted on this partition. It wants a power of 2, and that value has to be equal or larger than512. ๐
And the tea on what to actually pick: the glow-up recommendation is to set the file system sector size to 4096, even on 512 sector disks โ and especially for images that are only ever gonna live as a file on disks โ because that's what optimizes performance. โจ But (and this is the plot twist ๐ซ ) for compatibility with foreign operating systems or firmware, it might be advisable to just use the native sector size of the backing disk instead.
Now, the defaults, because you know we love a default:
- If it's unspecified and you're operating on a block device โ defaults to the native sector size of the device.
- If it's unspecified and you're operating on a disk image file โ defaults to
4096.
And here's the part nobody can dodge, no matter what you configure here or which default gets picked: the file system sector size is always increased to be equal or larger than the disk sector size. Always. Periodt. ๐
Added in version 258. ๐
โจ SPECIFIERS โจ
Ok so specifiers are basically little glow-up macros you can drop into certain settings and repart.d will expand them for you. ๐ช
You're allowed to use specifiers in these settings:
Label=CopyBlocks=CopyFiles=MakeDirectories=MakeSymlinks=SplitName=
The following expansions are understood: ๐
โจ Table 4. Specifiers available โจ
Okay bestie, here's the big one โ every single specifier you can drop into your partition definitions. Go off. ๐
"%a"โ Architecture. A short string identifying the architecture of the local system. A string such asx86,x86-64orarm64. See the architectures defined forConditionArchitecture=insystemd.unit(5)for a full list. ๐ฅ๏ธ"%A"โ Operating system image version. The operating system image version identifier of the running system, as read from theIMAGE_VERSION=field of/etc/os-release. If not set, resolves to an empty string. Seeos-release(5)for more information."%b"โ Boot ID. The boot ID of the running system, formatted as string. Seerandom(4)for more information. ๐ฅ"%B"โ Operating system build ID. The operating system build identifier of the running system, as read from theBUILD_ID=field of/etc/os-release. If not set, resolves to an empty string. Seeos-release(5)for more information."%H"โ Host name. The hostname of the running system."%l"โ Short host name. The hostname of the running system, truncated at the first dot to remove any domain component. โ๏ธ"%m"โ Machine ID. The machine ID of the running system, formatted as string. Seemachine-id(5)for more information."%M"โ Operating system image identifier. The operating system image identifier of the running system, as read from theIMAGE_ID=field of/etc/os-release. If not set, resolves to an empty string. Seeos-release(5)for more information."%o"โ Operating system ID. The operating system identifier of the running system, as read from theID=field of/etc/os-release. Seeos-release(5)for more information. ๐ง"%q"โ Pretty host name. The pretty hostname of the running system, as read from thePRETTY_HOSTNAME=field of/etc/machine-info. If not set, resolves to the short hostname. Seemachine-info(5)for more information. ๐"%v"โ Kernel release. Identical touname -routput."%w"โ Operating system version ID. The operating system version identifier of the running system, as read from theVERSION_ID=field of/etc/os-release. If not set, resolves to an empty string. Seeos-release(5)for more information."%W"โ Operating system variant ID. The operating system variant identifier of the running system, as read from theVARIANT_ID=field of/etc/os-release. If not set, resolves to an empty string. Seeos-release(5)for more information."%T"โ Directory for temporary files. This is either/tmpor the path"$TMPDIR","$TEMP"or"$TMP"are set to. (Note that the directory may be specified without a trailing slash.)"%V"โ Directory for larger and persistent temporary files. This is either/var/tmpor the path"$TMPDIR","$TEMP"or"$TMP"are set to. (Note that the directory may be specified without a trailing slash.) ๐ซถ
lowkey obsessed with how%Tand%Vboth peek at$TMPDIR,$TEMPand$TMPโ and yes, the trailing slash is optional, no cap.
"%%"โ Single percent sign. Use"%%"in place of"%"to specify a single percent sign. ๐
ok and NOW, bestie, here's the lil bonus round: if you're messing with the SplitName= setting specifically, these extra specifiers clock in too โจ
๐ธ Table 5. Specifiers available ๐ธ
"%T"โ Partition Type UUID โ that's the partition type UUID, exactly as you configured it withType=๐"%t"โ Partition Type Identifier โ the partition type identifier that corresponds to the partition type UUID ๐"%U"โ Partition UUID โ the partition UUID, as configured withUUID=โจ"%n"โ Partition Number โ the partition number assigned to the partition, no cap ๐ฅ
๐ ENVIRONMENT ๐
Extra filesystem formatting options can be handed over using filesystem-specific environment variables, and honestly? it's giving backstage pass:
$SYSTEMD_REPART_MKFS_OPTIONS_BTRFS$SYSTEMD_REPART_MKFS_OPTIONS_XFS$SYSTEMD_REPART_MKFS_OPTIONS_VFAT$SYSTEMD_REPART_MKFS_OPTIONS_EROFS$SYSTEMD_REPART_MKFS_OPTIONS_SQUASHFS
Each variable accepts valid mkfs.filesystem command-line arguments.
โ ๏ธ Important bestie: the content of those variables is passed as-is to the command, without any verification. No vibe check, no nothing. So type carefully, okay? ๐ญ
๐ฆ EXAMPLES ๐ฆ
โจ Example 1. Grow the root partition to the full disk size at first boot โจ
With the following file the root partition is automatically grown to the full disk if possible during boot. Iconic behaviour, honestly.
# /usr/lib/repart.d/50-root.conf
[Partition]
Type=root
โจ Example 2. Create a swap and home partition automatically on boot, if missing โจ
The home partition gets all available disk space while the swap partition gets 1G at most and 64M at least. We set a priority > 0 on the swap partition to ensure the swap partition is not used if not enough space is available. For every three bytes assigned to the home partition the swap partition gets assigned one. Math girlies rise ๐ซถ
# /usr/lib/repart.d/60-home.conf
[Partition]
Type=home
# /usr/lib/repart.d/70-swap.conf
[Partition]
Type=swap
SizeMinBytes=64M
SizeMaxBytes=1G
Priority=1
Weight=333
โจ Example 3. Create B partitions in an A/B Verity setup, if missing โจ
Let's say the vendor intends to update OS images in an A/B setup, i.e. with two root partitions (and two matching Verity partitions) that shall be used alternatingly during upgrades. To minimize image sizes the original image is shipped only with one root and one Verity partition (the "A" set), and the second root and Verity partitions (the "B" set) shall be created on first boot on the free space on the medium. main character energy tbh ๐
# /usr/lib/repart.d/50-root.conf
[Partition]
Type=root
SizeMinBytes=512M
SizeMaxBytes=512M
# /usr/lib/repart.d/60-root-verity.conf
[Partition]
Type=root-verity
SizeMinBytes=64M
SizeMaxBytes=64M
The definitions above cover the "A" set of root partition (of a fixed 512M size) and Verity partition for the root partition (of a fixed 64M size).
Let's use symlinks to create the "B" set of partitions, since after all they shall have the same properties and sizes as the "A" set. symlink slay ๐
# ln -s 50-root.conf /usr/lib/repart.d/70-root-b.conf
# ln -s 60-root-verity.conf /usr/lib/repart.d/80-root-verity-b.conf
โจ Example 4. Create a data partition and corresponding verity partitions from a OS tree โจ
Assuming we have an OS tree at /var/tmp/os-tree that we want to package in a root partition together with matching verity partitions, we can do so as follows:
# 50-root.conf
[Partition]
Type=root
CopyFiles=/var/tmp/os-tree
Verity=data
VerityMatchKey=root
Minimize=guess
# 60-root-verity.conf
[Partition]
Type=root-verity
Verity=hash
VerityMatchKey=root
# Explicitly set the hash and data block size to 4K
VerityDataBlockSizeBytes=4096
VerityHashBlockSizeBytes=4096
Minimize=best
# 70-root-verity-sig.conf
[Partition]
Type=root-verity-sig
Verity=signature
VerityMatchKey=root
๐ SEE ALSO ๐
systemd(1), systemd-repart(8), sfdisk(8), systemd-cryptenroll(1)
๐ NOTES ๐
- UAPI.2 Discoverable Partitions Specification
https://uapi-group.org/specifications/specs/discoverable_partitions_specification - UAPI.1 Boot Loader Specification
https://uapi-group.org/specifications/specs/boot_loader_specification/
and that's a wrap bestie!!! ๐โจ๐ this whole thing came from systemd 262.1, and the page you just devoured is REPART.D(5) โ go forth and partition, you absolute icon ๐๐ฆ๐
๐ฆ where this page comes from
- arch rolling: systemd 262.1-1 ยท LGPL-2.1-or-later AND CC0-1.0 AND GPL-2.0-or-later AND MIT-0
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms