Merge pull request #14368 from poettering/repart

This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2020-01-23 19:07:02 +01:00
commit 5e176a4dee
32 changed files with 4154 additions and 34 deletions

View File

@ -5,6 +5,9 @@ extraction:
- python3-pip
- python3-setuptools
- python3-wheel
- libfdisk-dev
- libp11-kit-dev
- libssl-dev
after_prepare:
- pip3 install meson
- export PATH="$HOME/.local/bin/:$PATH"

View File

@ -8,7 +8,7 @@ Distribution=fedora
Release=31
[Output]
Format=raw_btrfs
Format=gpt_ext4
Bootable=yes
KernelCommandLine=printk.devkmsg=on
@ -38,19 +38,20 @@ BuildPackages=
libblkid-devel
libcap-devel
libcurl-devel
libfdisk-devel
libgcrypt-devel
libidn2-devel
libmicrohttpd-devel
libmount-devel
libseccomp-devel
libselinux-devel
libtool
libxkbcommon-devel
libxslt
lz4
lz4-devel
m4
meson
openssl-devel
pam-devel
pcre2-devel
pkgconfig
@ -58,10 +59,17 @@ BuildPackages=
python3-lxml
qrencode-devel
tree
valgrind-devel
xz-devel
Packages=
coreutils
cryptsetup-libs
kmod-libs
libidn2
libseccomp
procps-ng
util-linux
BuildDirectory=mkosi.builddir
Cache=mkosi.cache

61
TODO
View File

@ -19,6 +19,11 @@ Janitorial Clean-ups:
Features:
* bootctl:
- teach it to prepare an ESP wholesale, i.e. with mkfs.vfat invocation
- teach it to copy in unified kernel images and maybe type #1 boot loader spec entries from host
- make it operate on loopback files, dissecting enough to find ESP to operate on
* when dissecting images, warn about unrecognized partition flags
* honour specifiers in unit files that resolve to some very basic
@ -27,8 +32,53 @@ Features:
* socket units: allow creating a udev monitor socket with ListenDevices= or so,
with matches, then actviate app thorugh that passing socket oveer
* unify on openssl:
- port sd_id128_get_machine_app_specific() over from khash
- port resolved over from libgcrypt (DNSSEC code)
- port journald + fsprg over from libgcrypt
- port importd over from libgcrypt
- when that's done: kill khash.c
- when that's done: kill gnutls support in resolved
* kill zenata, all hail weblate?
* when we resize disks (homed?) always round up to 4K sectors, not 512K
* add growvol and makevol options for /etc/crypttab, similar to
x-systemd.growfs and x-systemd-makefs.
* hook up the TPM to /etc/crypttab, with a new option that is similar to the
new PKCS#11 option in crypttab, and allows unlocking a LUKS volume via a key
unsealed from the TPM. Optionally, if TPM is not available fall back to
TPM-less mode, and set up linear DM mapping instead (inspired by kpartx), so
that the device paths stay the same, regardless if crypto is used or not.
* move discoverable partitions spec into markdown and our tree
* systemd-repart: by default generate minimized partition tables (i.e. tables
that only covere the space actually used, excluding any free space at the
end), in order to maximize dd'ability. Requires libfdisk work, see
https://github.com/karelzak/util-linux/issues/907
* systemd-repart: optionally, allow specifiying a path to initialize new
partitions from, i.e. an fs image file or a source device node. This would
then turn systemd-repart into a simple installer: with a few .repart files
you could replicate the host system on another device.
* systemd-repart: MBR partition table support. Care needs to be taken regarding
Type=, so that partition definitions can sanely apply to both the GPT and the
MBR case. Idea: accept syntax "Type=gpt:home mbr:0x83" for setting the types
for the two partition types explicitly. And provide an internal mapping so
that "Type=linux-generic" maps to the right types for both partition tables
automatically.
* systemd-repart: allow sizing partitions as factor of available RAM, so that
we can reasonably size swap partitions for hibernation.
* when switching root from initrd to host, set the machine_id env var so that
if the host has no machine ID set yet we continue to use the random one the
initrd had set.
* sd-event: add native support for P_ALL waitid() watching, then move PID 1 to
it fo reaping assigned but unknown children. This needs to some special care
to operate somewhat sensibly in light of priorities: P_ALL will return
@ -175,13 +225,6 @@ Features:
* introduce per-unit (i.e. per-slice, per-service) journal log size limits.
* optionally, if a per-partition GPT flag is set for the root/home/… partitions
format the partition on next boot and unset the flag, in order to implement
factory reset. also, add a second flag that simply indicates whether such a
scheme is supported. then, add a tool (or maybe beef up systemd-dissect) to
show state of these flags, and optionally trigger such a factory reset on
next boot by setting the flag.
* sd-boot: automatically load EFI modules from some drop-in dir, so that people
can add in file system drivers and such
@ -395,10 +438,6 @@ Features:
yogas can be recognized as "convertible" too, even if they predate the DMI
"convertible" form factor
* Maybe add a small tool invoked early at boot, that adds in or resizes
partitions automatically, to be used when the media used is actually larger
than the image written onto it is.
* Maybe add PrivatePIDs= as new unit setting, and do minimal PID namespacing
after all. Be strict however, only support the equivalent of nspawn's
--as-pid2 switch, and sanely proxy sd_notify() messages dropping stuff such

View File

@ -5,6 +5,7 @@ setup:
- sudo apt-get update -y
- sudo apt-get build-dep -y systemd
- sudo apt-get install -y python3-pip
- sudo apt-get install -y libfdisk-dev libp11-kit-dev libssl-dev
# FIXME: temporarily pin the meson version as 0.53 doesn't work with older
# python 3.5
# # See: https://github.com/mesonbuild/meson/issues/6427

388
man/repart.d.xml Normal file
View File

@ -0,0 +1,388 @@
<?xml version='1.0'?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<refentry id="repart.d">
<refentryinfo>
<title>repart.d</title>
<productname>systemd</productname>
</refentryinfo>
<refmeta>
<refentrytitle>repart.d</refentrytitle>
<manvolnum>5</manvolnum>
</refmeta>
<refnamediv>
<refname>repart.d</refname>
<refpurpose>Partition Definition Files for Automatic Boot-Time Repartitioning</refpurpose>
</refnamediv>
<refsynopsisdiv>
<para><literallayout><filename>/etc/repart.d/*.conf</filename>
<filename>/run/repart.d/*.conf</filename>
<filename>/usr/lib/repart.d/*.conf</filename>
</literallayout></para>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para><filename>repart.d/*.conf</filename> files describe basic properties of partitions of block
devices of the local system. They may be used to declare types, names and sizes of partitions that shall
exist. The
<citerefentry><refentrytitle>systemd-repart</refentrytitle><manvolnum>8</manvolnum></citerefentry>
service reads these files and attempts to add new partitions currently missing and enlarge existing
partitions according to these definitions. Operation is generally incremental, i.e. when applied, what
exists already is left intact, and partitions are never shrunk, moved or deleted.</para>
<para>These definition files are useful for implementing operating system images that are prepared and
delivered with minimally sized images (for example lacking any state or swap partitions), and which on
first boot automatically take possession of any remaining disk space following a few basic rules.</para>
<para>Currently, support for partition definition files is only implemented for GPT partitition
tables.</para>
<para>Partition files are generally matched against any partitions already existing on disk in a simple
algorithm: the partition files are sorted by their filename (ignoring the directory prefix), and 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 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 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. Any existing partitions that have
no matching partition file are left as they are.</para>
<para>Note that these partition definition files do not describe the contents of the partitions, such as
the file system used. Separate mechanisms, such as
<citerefentry><refentrytitle>systemd-growfs</refentrytitle><manvolnum>8</manvolnum></citerefentry> and
<command>systemd-makefs</command> maybe be used to initialize or grow the file systems inside of these
partitions.</para>
</refsect1>
<refsect1>
<title>[Partition] Section Options</title>
<variablelist>
<varlistentry>
<term><varname>Type=</varname></term>
<listitem><para>The GPT partition type UUID to match. This may be a GPT partition type UUID such as
<constant>4f68bce3-e8cd-4db1-96e7-fbcaf984b709</constant>, or one of the following special
identifiers:</para>
<table>
<title>GPT partition type identifiers</title>
<tgroup cols='2' align='left' colsep='1' rowsep='1'>
<colspec colname="name" />
<colspec colname="explanation" />
<thead>
<row>
<entry>Identifier</entry>
<entry>Explanation</entry>
</row>
</thead>
<tbody>
<row>
<entry><constant>esp</constant></entry>
<entry>EFI System Partition</entry>
</row>
<row>
<entry><constant>xbootldr</constant></entry>
<entry>Extended Boot Loader Partition</entry>
</row>
<row>
<entry><constant>swap</constant></entry>
<entry>Swap partition</entry>
</row>
<row>
<entry><constant>home</constant></entry>
<entry>Home (<filename>/home/</filename>) partition</entry>
</row>
<row>
<entry><constant>srv</constant></entry>
<entry>Server data (<filename>/srv/</filename>) partition</entry>
</row>
<row>
<entry><constant>var</constant></entry>
<entry>Variable data (<filename>/var/</filename>) partition</entry>
</row>
<row>
<entry><constant>tmp</constant></entry>
<entry>Temporary data (<filename>/var/tmp/</filename>) partition</entry>
</row>
<row>
<entry><constant>linux-generic</constant></entry>
<entry>Generic Linux file system partition</entry>
</row>
<row>
<entry><constant>root</constant></entry>
<entry>Root file system partition type appropriate for the local architecture (an alias for an architecture root file system partition type listed below, e.g. <constant>root-x86-64</constant>)</entry>
</row>
<row>
<entry><constant>root-verity</constant></entry>
<entry>Verity data for the root file system partition for the local architecture</entry>
</row>
<row>
<entry><constant>root-secondary</constant></entry>
<entry>Root file system partition of the secondary architecture of the local architecture; usually the matching 32bit architecture for the local 64bit architecture)</entry>
</row>
<row>
<entry><constant>root-secondary-verity</constant></entry>
<entry>Verity data for the root file system partition of the secondary architecture</entry>
</row>
<row>
<entry><constant>root-x86</constant></entry>
<entry>Root file system partition for the x86 (32bit, aka i386) architecture</entry>
</row>
<row>
<entry><constant>root-x86-verity</constant></entry>
<entry>Verity data for the x86 (32bit) root file system partition</entry>
</row>
<row>
<entry><constant>root-x86-64</constant></entry>
<entry>Root file system partition for the x86_64 (64bit, aka amd64) architecture</entry>
</row>
<row>
<entry><constant>root-x86-64-verity</constant></entry>
<entry>Verity data for the x86_64 (64bit) root file system partition</entry>
</row>
<row>
<entry><constant>root-arm</constant></entry>
<entry>Root file system partition for the ARM (32bit) architecture</entry>
</row>
<row>
<entry><constant>root-arm-verity</constant></entry>
<entry>Verity data for the ARM (32bit) root file system partition</entry>
</row>
<row>
<entry><constant>root-arm64</constant></entry>
<entry>Root file system partition for the ARM (64bit, aka aarch64) architecture</entry>
</row>
<row>
<entry><constant>root-arm64-verity</constant></entry>
<entry>Verity data for the ARM (64bit, aka aarch64) root file system partition</entry>
</row>
<row>
<entry><constant>root-ia64</constant></entry>
<entry>Root file system partition for the ia64 architecture</entry>
</row>
<row>
<entry><constant>root-ia64-verity</constant></entry>
<entry>Verity data for the ia64 root file system partition</entry>
</row>
</tbody>
</tgroup>
</table>
<para>This setting defaults to <constant>linux-generic</constant>.</para>
<para>Most of the partition type UUIDs listed above are defined in the <ulink
url="https://systemd.io/DISCOVERABLE_PARTITIONS">Discoverable Partitions
Specification</ulink>.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>Label=</varname></term>
<listitem><para>The textual label to assign to the partition if none is assigned yet. Note that this
setting is not used for matching. It is also not used when a label is already set for an existing
partition. It is thus only used when a partition is newly created or when an existing one had a no
label set (that is: an empty label). If not specified a label derived from the partition type is
automatically used.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>Priority=</varname></term>
<listitem><para>A numeric priority to assign to this partition, in the range -2147483648…2147483647,
with smaller values indicating higher priority, and higher values indicating smaller priority. This
priority is used in case the configured size constraints on the defined partitions do not permit
fitting all partitions onto the available disk space. If the partitions do not fit, the highest
numeric partition priority of all defined partitions is determined, and all defined partitions with
this priority are removed from the list of new partitions to create (which may be multiple, if the
same priority is used for multiple partitions). The fitting algorithm is then tried again. If the
partitions still do not fit, the now highest numeric partition priority is determined, and the
matching partitions removed too, and so on. Partitions of a priority of 0 or lower are never
removed. If all partitions with a priority above 0 are removed and the partitions still do not fit on
the device the operation fails. Note that this priority has no effect on ordering partitions, for
that use the alphabetical order of the filenames of the partition definition files. Defaults to
0.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>Weight=</varname></term>
<listitem><para>A numeric weight to assign to this partition in the range 0…1000000. Available disk
space is assigned the defined partitions according to their relative weights (subject to the size
constraints configured with <varname>SizeMinBytes=</varname>, <varname>SizeMaxBytes=</varname>), so
that a partition with weight 2000 gets double the space as one with weight 1000, and a partition with
weight 333 a third of that. Defaults to 1000.</para>
<para>The <varname>Weight=</varname> setting is used to distribute available disk space in an
"elastic" fashion, based on the disk size and existing partitions. If a partition shall have a fixed
size use both <varname>SizeMinBytes=</varname> and <varname>SizeMaxBytes=</varname> with the same
value in order to fixate the size to one value, in which case the weight has no
effect.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>PaddingWeight=</varname></term>
<listitem><para>Similar to <varname>Weight=</varname> but 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 is summed, and then each partition and padding gets the fraction defined by its
weight. Defaults to 0, i.e. by default no padding is applied.</para>
<para>Padding is useful if empty space shall be left for later additions or a safety margin at the
end of the device or between partitions.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>SizeMinBytes=</varname></term>
<term><varname>SizeMaxBytes=</varname></term>
<listitem><para>Specifies minimum and maximum size constraints in bytes. Takes the usual K, M, G, T,
… suffixes (to the base of 1024). If <varname>SizeMinBytes=</varname> is specified the partition is
created at or grown to at least the specified size. If <varname>SizeMaxBytes=</varname> is specified
the partition is created at or grown to at most the specified size. The precise size is determined
through the weight value value configured with <varname>Weight=</varname>, see above. When
<varname>SizeMinBytes=</varname> is set equal to <varname>SizeMaxBytes=</varname> the configured
weight has no effect as the partition is explicitly sized to the specified fixed value. Note that
partitions are never created smaller than 4096 bytes, and since partitions are never shrunk the
previous size of the partition (in case the partition already exists) is also enforced as lower bound
for the new size. The values should be specified as multiples of 4096 bytes, and are rounded upwards
(in case of <varname>SizeMinBytes=</varname>) or downwards (in case of
<varname>SizeMaxBytes=</varname>) otherwise. If the backing device does not provide enough space to
fulfill the constraints placing the partition will fail. For partitions that shall be created,
depending on the setting of <varname>Priority=</varname> (see above) the partition might be dropped
and the placing algorithm restarted. By default no size constraints are set.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>PaddingMinBytes=</varname></term>
<term><varname>PaddingMaxBytes=</varname></term>
<listitem><para>Specifies minimum and maximum size constrains in bytes for the free space after the
partition (the "padding"). Semantics are similar to <varname>SizeMinBytes=</varname> and
<varname>SizeMaxBytes=</varname>, 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 that only
<varname>PaddingWeight=</varname> determines the size of the padding applied.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>FactoryReset=</varname></term>
<listitem><para>Takes a boolean argument. If specified the partition is marked for removal during a
factory reset operation. This functionality is useful to implement schemes where images can be reset
into their original state by removing partitions and creating them anew. Defaults to off.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Examples</title>
<example>
<title>Grow the root partition to the full disk size at first boot</title>
<para>With the following file the root partition is automatically grown to the full disk if possible during boot.</para>
<para><programlisting># /usr/lib/repart.d/50-root.conf
[Partition]
Type=root
</programlisting></para>
</example>
<example>
<title>Create a swap and home partition automatically on boot, if missing</title>
<para>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.</para>
<para><programlisting># /usr/lib/repart.d/60-home.conf
[Partition]
Type=home
</programlisting></para>
<para><programlisting># /usr/lib/repart.d/70-swap.conf
[Partition]
Type=swap
SizeMinBytes=64M
SizeMaxBytes=1G
Priority=1
Weight=333
</programlisting></para>
</example>
<example>
<title>Create B partitions in an A/B Verity setup, if missing</title>
<para>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.</para>
<para><programlisting># /usr/lib/repart.d/50-root.conf
[Partition]
Type=root
SizeMinBytes=512M
SizeMaxBytes=512M
</programlisting></para>
<para><programlisting># /usr/lib/repart.d/60-root-verity.conf
[Partition]
Type=root-verity
SizeMinBytes=64M
SizeMaxBytes=64M
</programlisting></para>
<para>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.</para>
<para><programlisting># 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
</programlisting></para>
</example>
</refsect1>
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-repart</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>sfdisk</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
</refsect1>
</refentry>

View File

@ -47,6 +47,7 @@ manpages = [
['pam_systemd', '8', [], 'HAVE_PAM'],
['portablectl', '1', [], 'ENABLE_PORTABLED'],
['pstore.conf', '5', ['pstore.conf.d'], 'ENABLE_PSTORE'],
['repart.d', '5', [], ''],
['resolvectl', '1', ['resolvconf'], 'ENABLE_RESOLVE'],
['resolved.conf', '5', ['resolved.conf.d'], 'ENABLE_RESOLVE'],
['runlevel', '8', [], ''],
@ -769,6 +770,7 @@ manpages = [
'ENABLE_RANDOMSEED'],
['systemd-rc-local-generator', '8', [], ''],
['systemd-remount-fs.service', '8', ['systemd-remount-fs'], ''],
['systemd-repart', '8', ['systemd-repart.service'], ''],
['systemd-resolved.service', '8', ['systemd-resolved'], 'ENABLE_RESOLVE'],
['systemd-rfkill.service',
'8',

View File

@ -80,6 +80,7 @@
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-repart</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>mkfs.btrfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>mkfs.cramfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>mkfs.ext4</refentrytitle><manvolnum>8</manvolnum></citerefentry>,

269
man/systemd-repart.xml Normal file
View File

@ -0,0 +1,269 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<!-- SPDX-License-Identifier: LGPL-2.1+ -->
<refentry id="systemd-repart"
xmlns:xi="http://www.w3.org/2001/XInclude">
<refentryinfo>
<title>systemd-repart</title>
<productname>systemd</productname>
</refentryinfo>
<refmeta>
<refentrytitle>systemd-repart</refentrytitle>
<manvolnum>8</manvolnum>
</refmeta>
<refnamediv>
<refname>systemd-repart</refname>
<refname>systemd-repart.service</refname>
<refpurpose>Automatically grow and add partitions</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>systemd-repart</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
<arg choice="opt" rep="repeat"><replaceable><optional>BLOCKDEVICE</optional></replaceable></arg>
</cmdsynopsis>
<para><filename>systemd-repart.service</filename></para>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para><command>systemd-repart</command> grows and adds partitions to a partition table, based on the
configuration files described in
<citerefentry><refentrytitle>repart.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
</para>
<para>If invoked with no arguments, it operates on the block device backing the root file system partition
of the OS, thus growing and adding partitions of the booted OS image itself. When called in the initial
RAM disk it operates on the block device backing <filename>/sysroot/</filename> instead, i.e. on the
block device the system will soon transition into. The <filename>systemd-repart.service</filename>
service is generally run at boot in the initial RAM disk, in order to augment the partition table of the
OS before its partitions are mounted. <command>systemd-repart</command> (mostly) operates in a purely
incremental mode: it only grows existing and adds new partitions; it does not shrink, delete or move
existing partitions. The service is intended to be run on every boot, but when it detects that the
partition table already matches the installed <filename>repart.d/*.conf</filename> configuration
files, it executes no operation.</para>
<para><command>systemd-repart</command> is intended to be used when deploying OS images, to automatically
adjust them to the system they are running on, during first boot. This way the deployed image can be
minimal in size and may be augmented automatically at boot when needed, taking possession of disk space
available but not yet used. Specifically the following use cases are among those covered:</para>
<itemizedlist>
<listitem><para>The root partition may be grown to cover the whole available disk space</para></listitem>
<listitem><para>A <filename>/home/</filename>, swap or <filename>/srv</filename> partition can be added in</para></listitem>
<listitem><para>A second (or third, …) root partition may be added in, to cover A/B style setups
where a second version of the root file system is alternatingly used for implementing update
schemes. The deployed image would carry only a single partition ("A") but on first boot a second
partition ("B") for this purpose is automatically created.</para></listitem>
</itemizedlist>
<para>The algorithm executed by <command>systemd-repart</command> is roughly as follows:</para>
<orderedlist>
<listitem><para>The <filename>repart.d/*.conf</filename> configuration files are loaded and parsed,
and ordered by filename (without the directory suffix). </para></listitem>
<listitem><para>The partition table already existing on the block device is loaded and
parsed.</para></listitem>
<listitem><para>The existing partitions in the partition table are matched up with the
<filename>repart.d/*.conf</filename> files by GPT partition type UUID. The first existing partition
of a specific type is assigned the first configuration file declaring the same type. The second
existing partition of a specific type is then assigned the second configuration file declaring the same
type, and so on. After this iterative assigning is complete any left-over existing partitions that have
no matching configuration file are considered "foreign" and left as they are. And any configuration
files for which no partition currently exists are understood as a request to create such a
partition.</para></listitem>
<listitem><para>Taking the size constraints and weights declared in the configuration files into
account, all partitions that shall be created are now allocated to the disk, taking up all free space,
always respecting the size and padding requests. Similar, existing partitions that are determined to
grow are grown. New partitions are always appended to the end of the existing partition table, taking
the first partition table slot whose index is greater than the indexes of all existing
partitions. Partition table slots are never reordered and thus partition numbers are ensured to remain
stable. Note that this allocation happens in RAM only, the partition table on disk is not updated
yet.</para></listitem>
<listitem><para>All existing partitions for which configuration files exist and which currently have no
GPT partition label set will be assigned a label, either explicitly configured in the configuration or
(if that's missing) derived automatically from the partition type. The same is done for all partitions
that are newly created. These assignments are done in RAM only, too, the disk is not updated
yet.</para></listitem>
<listitem><para>Similarly, all existing partitions for which configuration files exist and which
currently have an all-zero identifying UUID will be assigned a new UUID. This UUID is cryptographically
hashed from a common seed value together with the partition type UUID (and a counter in case multiple
partitions of the same type are defined), see below. The same is done for all partitions that are
created anew. These assignments are done in RAM only, too, the disk is not updated
yet.</para></listitem>
<listitem><para>Similarly, if the disk's volume UUID is all zeroes it is also initialized, also
cryptographically hashed from the same common seed value. Also, in RAM only, too.</para></listitem>
<listitem><para>The disk space assigned to new partitions (i.e. what was previously considered free
space but is no longer) is now erased. Specifically, all file system signatures are removed, and if the
device supports it the <constant>BLKDISCARD</constant> I/O control command is issued to inform the
hardware that the space is empty now. In addition any "padding" between partitions and at the end of
the device is similarly erased.</para></listitem>
<listitem><para>The new partition table is finally written to disk. The kernel is asked to reread the
partition table.</para></listitem>
</orderedlist>
<para>As exception to the normally strictly incremental operation, when called in a special "factory
reset" mode <command>systemd-repart</command> may also be used to erase select existing partitions to
reset an installation back to vendor defaults. This mode of operation is used when either the
<option>--factory-reset=yes</option> switch is passed on the tool's command line, or the
<option>systemd.factory_reset=yes</option> option specified on the kernel command line, or the
<varname>FactoryReset</varname> EFI variable (vendor UUID
<constant>8cf2644b-4b0b-428f-9387-6d876050dc67</constant>) is set to "yes". It alters the algorithm above
slightly: between the 3rd and the 4th step above the any partition marked explicitly via the
<varname>FactoryReset=</varname> boolean is deleted, and the algorithm restarted, thus immediately
re-creating these partitions anew empty.</para>
<para>Note that <command>systemd-repart</command> only changes partition tables, it does not create or
resize any file systems within these partitions. A separate mechanism should be used for that, for
example
<citerefentry><refentrytitle>systemd-growfs</refentrytitle><manvolnum>8</manvolnum></citerefentry> and
<command>systemd-makefs</command>.</para>
<para>The UUIDs identifying the new partitions created (or assigned to existing partitions that have no
UUID yet), as well as the disk as a whole are hashed cryptographically from a common seed value. This
seed value is usually the
<citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry> of the
system, so that the machine ID reproducibly determines the UUIDs assigned to all partitions. If the
machine ID cannot be read (or the user passes <option>--seed=random</option>, see below) the seed is
generated randomly instead, so that the partition UUIDs are also effectively random. The seed value may
also be set explicitly, formatted as UUID via the <option>--seed=</option> option. By hashing these UUIDs
from a common seed images prepared with this tool become reproducible and the result of the algorithm
above deterministic.</para>
</refsect1>
<refsect1>
<title>Options</title>
<para>The following options are understood:</para>
<variablelist>
<varlistentry>
<term><option>--dry-run=</option></term>
<listitem><para>Takes a boolean. If this switch is not specified <option>--dry-run=yes</option> is
the implied default. Controls whether <filename>systemd-repart</filename> executes the requested
re-partition operations or whether it should only show what it would do. Unless
<option>--dry-run=no</option> is specified <filename>systemd-repart</filename> will not actually
touch the device's partition table.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--empty=</option></term>
<listitem><para>Takes one of <literal>refuse</literal>, <literal>allow</literal>,
<literal>require</literal> or <literal>force</literal>. Controls how to operate on block devices that
are entirely empty, i.e. carry no partition table/disk label yet. If this switch is not specified the
implied default is <literal>refuse</literal>.</para>
<para>If <literal>refuse</literal> <command>systemd-repart</command> requires that the block device
it shall operate on already carries a partition table and refuses operation if none is found. If
<literal>allow</literal> the command will extend an existing partition table or create a new one if
none exists. If <literal>require</literal> the command will create a new partition table if none
exists so far, and refuse operation if one already exists. If <literal>force</literal> it will create
a fresh partition table unconditionally, erasing the disk fully in effect. If
<literal>force</literal> no existing partitions will be taken into account or survive the
operation. Hence: use with care, this is a great way to lose all your data.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--discard=</option></term>
<listitem><para>Takes a boolean. If this switch is not specified <option>--discard=yes</option> is
the implied default. Controls whether to issue the <constant>BLKDISCARD</constant> I/O control
command on the space taken up by any added partitions or on the space in between them. Usually, it's
a good idea to issue this request since it tells the underlying hardware that the covered blocks
shall be considered empty, improving performance.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--factory-reset=</option></term>
<listitem><para>Takes boolean. If this switch is not specified <option>--factory=reset=no</option> is
the implied default. Controls whether to operate in "factory reset" mode, see above. If set to true
this will remove all existing partitions marked with <varname>FactoryReset=</varname> set to yes
early while executing the re-partitioning algorithm. Use with care, this is a great way to lose all
your data. Note that partition files need to explicitly turn <varname>FactoryReset=</varname> on, as
the option defaults to off. If no partitions are marked for factory reset this switch has no
effect. Note that there are two other methods to request factory reset operation: via the kernel
command line and via an EFI variable, see above.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--can-factory-reset</option></term>
<listitem><para>If this switch is specified the disk is not re-partitioned. Instead it is determined
if any existing partitions are marked with <varname>FactoryReset=</varname>. If there are the tool
will exit with exit status zero, otherwise non-zero. This switch may be used to quickly determine
whether the running system supports a factory reset mechanism built on
<command>systemd-repart</command>.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--root=</option></term>
<listitem><para>Takes a path to a directory to use as root file system when searching for
<filename>repart.d/*.conf</filename> files and for the machine ID file to use as seed. By default
when invoked on the regular system this defaults to the host's root file system
<filename>/</filename>. If invoked from the initial RAM disk this defaults to
<filename>/sysroot/</filename>, so that the tool operates on the configuration and machine ID stored
in the root file system later transitioned into itself.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--seed=</option></term>
<listitem><para>Takes a UUID as argument or the special value <constant>random</constant>. If a UUID
is specified the UUIDs to assign to partitions and the partition table itself are derived via
cryptographic hashing from it. If not specified it is attempted to read the machine ID from the host
(or more precisely, the root directory configured via <option>--root=</option>) and use it as seed
instead, falling back to a randomized seed otherwise. Use <option>--seed=random</option> to force a
randomized seed. Explicitly specifying the seed may be used to generated strictly reproducible
partition tables.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--pretty=</option></term>
<listitem><para>Takes a boolean argument. If this switch is not specified, it defaults to on when
called from an interactive terminal and off otherwise. Controls whether to show a user friendly table
and graphic illustrating the changes applied.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--definitions=</option></term>
<listitem><para>Takes a file system path. If specified the <filename>*.conf</filename> are directly
read from the specified directory instead of searching in
<filename>/usr/lib/repart.d/*.conf</filename>, <filename>/etc/repart.d/*.conf</filename>,
<filename>/run/repart.d/*.conf</filename>.</para></listitem>
</varlistentry>
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
</variablelist>
</refsect1>
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>repart.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>
</para>
</refsect1>
</refentry>

View File

@ -873,6 +873,17 @@ endif
libmount = dependency('mount',
version : fuzzer_build ? '>= 0' : '>= 2.30')
want_libfdisk = get_option('fdisk')
if want_libfdisk != 'false' and not skip_deps
libfdisk = dependency('fdisk',
required : want_libfdisk == 'true')
have = libfdisk.found()
else
have = false
libfdisk = []
endif
conf.set10('HAVE_LIBFDISK', have)
want_seccomp = get_option('seccomp')
if want_seccomp != 'false' and not skip_deps
libseccomp = dependency('libseccomp',
@ -1279,6 +1290,18 @@ conf.set('DEFAULT_DNS_OVER_TLS_MODE',
'DNS_OVER_TLS_' + default_dns_over_tls.underscorify().to_upper())
substs.set('DEFAULT_DNS_OVER_TLS_MODE', default_dns_over_tls)
want_repart = get_option('repart')
if want_repart != 'false'
have = (conf.get('HAVE_OPENSSL') == 1 and
conf.get('HAVE_LIBFDISK') == 1)
if want_repart == 'true' and not have
error('repart support was requested, but dependencies are not available')
endif
else
have = false
endif
conf.set10('ENABLE_REPART', have)
want_importd = get_option('importd')
if want_importd != 'false'
have = (conf.get('HAVE_LIBCURL') == 1 and
@ -1535,6 +1558,7 @@ subdir('src/coredump')
subdir('src/pstore')
subdir('src/hostname')
subdir('src/import')
subdir('src/partition')
subdir('src/kernel-install')
subdir('src/locale')
subdir('src/machine')
@ -2381,6 +2405,21 @@ if conf.get('ENABLE_BINFMT') == 1
mkdir_p.format(join_paths(sysconfdir, 'binfmt.d')))
endif
if conf.get('ENABLE_REPART') == 1
executable('systemd-repart',
systemd_repart_sources,
include_directories : includes,
link_with : [libshared],
dependencies : [threads,
libcryptsetup,
libblkid,
libfdisk,
libopenssl],
install_rpath : rootlibexecdir,
install : true,
install_dir : rootbindir)
endif
if conf.get('ENABLE_VCONSOLE') == 1
executable('systemd-vconsole-setup',
'src/vconsole/vconsole-setup.c',
@ -3276,6 +3315,7 @@ foreach tuple : [
['libiptc'],
['elfutils'],
['binfmt'],
['repart'],
['vconsole'],
['quotacheck'],
['tmpfiles'],

View File

@ -80,6 +80,8 @@ option('environment-d', type : 'boolean',
description : 'support for environment.d')
option('binfmt', type : 'boolean',
description : 'support for custom binary formats')
option('repart', type : 'combo', choices : ['auto', 'true', 'false'],
description : 'install the systemd-repart tool')
option('coredump', type : 'boolean',
description : 'install the coredump handler')
option('pstore', type : 'boolean',
@ -260,6 +262,8 @@ option('audit', type : 'combo', choices : ['auto', 'true', 'false'],
description : 'libaudit support')
option('blkid', type : 'combo', choices : ['auto', 'true', 'false'],
description : 'libblkid support')
option('fdisk', type : 'combo', choices : ['auto', 'true', 'false'],
description : 'libfdisk support')
option('kmod', type : 'combo', choices : ['auto', 'true', 'false'],
description : 'support for loadable modules')
option('pam', type : 'combo', choices : ['auto', 'true', 'false'],

View File

@ -35,6 +35,8 @@ while [ -z "\$(ip route list 0/0)" ]; do sleep 1; done
apt-get -q --allow-releaseinfo-change update
apt-get -y dist-upgrade
apt-get install -y eatmydata
# The following four are needed as long as these deps are not covered by Debian's own packaging
apt-get install -y libfdisk-dev libp11-kit-dev libssl-dev
apt-get purge --auto-remove -y unattended-upgrades
systemctl unmask systemd-networkd
systemctl enable systemd-networkd

View File

@ -345,6 +345,9 @@ const char *special_glyph(SpecialGlyph code) {
[SPECIAL_GLYPH_MU] = "u",
[SPECIAL_GLYPH_CHECK_MARK] = "+",
[SPECIAL_GLYPH_CROSS_MARK] = "-",
[SPECIAL_GLYPH_LIGHT_SHADE] = "-",
[SPECIAL_GLYPH_DARK_SHADE] = "X",
[SPECIAL_GLYPH_SIGMA] = "S",
[SPECIAL_GLYPH_ARROW] = "->",
[SPECIAL_GLYPH_ELLIPSIS] = "...",
[SPECIAL_GLYPH_ECSTATIC_SMILEY] = ":-]",
@ -371,6 +374,9 @@ const char *special_glyph(SpecialGlyph code) {
[SPECIAL_GLYPH_MU] = "\316\274", /* μ (actually called: GREEK SMALL LETTER MU) */
[SPECIAL_GLYPH_CHECK_MARK] = "\342\234\223", /* ✓ */
[SPECIAL_GLYPH_CROSS_MARK] = "\342\234\227", /* ✗ (actually called: BALLOT X) */
[SPECIAL_GLYPH_LIGHT_SHADE] = "\342\226\221", /* ░ */
[SPECIAL_GLYPH_DARK_SHADE] = "\342\226\223", /* ▒ */
[SPECIAL_GLYPH_SIGMA] = "\316\243", /* Σ */
/* Single glyph in Unicode, two in ASCII */
[SPECIAL_GLYPH_ARROW] = "\342\206\222", /* → (actually called: RIGHTWARDS ARROW) */

View File

@ -51,6 +51,9 @@ typedef enum {
SPECIAL_GLYPH_CROSS_MARK,
SPECIAL_GLYPH_ARROW,
SPECIAL_GLYPH_ELLIPSIS,
SPECIAL_GLYPH_LIGHT_SHADE,
SPECIAL_GLYPH_DARK_SHADE,
SPECIAL_GLYPH_SIGMA,
_SPECIAL_GLYPH_FIRST_SMILEY,
SPECIAL_GLYPH_ECSTATIC_SMILEY = _SPECIAL_GLYPH_FIRST_SMILEY,
SPECIAL_GLYPH_HAPPY_SMILEY,

View File

@ -190,4 +190,17 @@ int id128_compare_func(const sd_id128_t *a, const sd_id128_t *b) {
return memcmp(a, b, 16);
}
sd_id128_t id128_make_v4_uuid(sd_id128_t id) {
/* Stolen from generate_random_uuid() of drivers/char/random.c
* in the kernel sources */
/* Set UUID version to 4 --- truly random generation */
id.bytes[6] = (id.bytes[6] & 0x0F) | 0x40;
/* Set the UUID variant to DCE */
id.bytes[8] = (id.bytes[8] & 0x3F) | 0x80;
return id;
}
DEFINE_HASH_OPS(id128_hash_ops, sd_id128_t, id128_hash_func, id128_compare_func);

View File

@ -30,3 +30,5 @@ int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync);
void id128_hash_func(const sd_id128_t *p, struct siphash *state);
int id128_compare_func(const sd_id128_t *a, const sd_id128_t *b) _pure_;
extern const struct hash_ops id128_hash_ops;
sd_id128_t id128_make_v4_uuid(sd_id128_t id);

View File

@ -250,19 +250,6 @@ _public_ int sd_id128_get_invocation(sd_id128_t *ret) {
return 0;
}
static sd_id128_t make_v4_uuid(sd_id128_t id) {
/* Stolen from generate_random_uuid() of drivers/char/random.c
* in the kernel sources */
/* Set UUID version to 4 --- truly random generation */
id.bytes[6] = (id.bytes[6] & 0x0F) | 0x40;
/* Set the UUID variant to DCE */
id.bytes[8] = (id.bytes[8] & 0x3F) | 0x80;
return id;
}
_public_ int sd_id128_randomize(sd_id128_t *ret) {
sd_id128_t t;
int r;
@ -279,7 +266,7 @@ _public_ int sd_id128_randomize(sd_id128_t *ret) {
* only guarantee this for newly generated UUIDs, not for
* pre-existing ones. */
*ret = make_v4_uuid(t);
*ret = id128_make_v4_uuid(t);
return 0;
}
@ -306,7 +293,7 @@ static int get_app_specific(sd_id128_t base, sd_id128_t app_id, sd_id128_t *ret)
/* We chop off the trailing 16 bytes */
memcpy(&result, p, MIN(khash_get_size(h), sizeof(result)));
*ret = make_v4_uuid(result);
*ret = id128_make_v4_uuid(result);
return 0;
}

View File

@ -1,6 +1,4 @@
/***
SPDX-License-Identifier: LGPL-2.1+
***/
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <fcntl.h>
#include <sys/prctl.h>

View File

@ -0,0 +1,5 @@
# SPDX-License-Identifier: LGPL-2.1+
systemd_repart_sources = files('''
repart.c
'''.split())

3096
src/partition/repart.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -515,6 +515,7 @@ DEFINE_PARSER(long, long, safe_atoli);
DEFINE_PARSER(uint8, uint8_t, safe_atou8);
DEFINE_PARSER(uint16, uint16_t, safe_atou16);
DEFINE_PARSER(uint32, uint32_t, safe_atou32);
DEFINE_PARSER(int32, int32_t, safe_atoi32);
DEFINE_PARSER(uint64, uint64_t, safe_atou64);
DEFINE_PARSER(unsigned, unsigned, safe_atou);
DEFINE_PARSER(double, double, safe_atod);

View File

@ -115,6 +115,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_long);
CONFIG_PARSER_PROTOTYPE(config_parse_uint8);
CONFIG_PARSER_PROTOTYPE(config_parse_uint16);
CONFIG_PARSER_PROTOTYPE(config_parse_uint32);
CONFIG_PARSER_PROTOTYPE(config_parse_int32);
CONFIG_PARSER_PROTOTYPE(config_parse_uint64);
CONFIG_PARSER_PROTOTYPE(config_parse_double);
CONFIG_PARSER_PROTOTYPE(config_parse_iec_size);

View File

@ -4,12 +4,15 @@
#include <net/if.h>
#include <unistd.h>
#include "sd-id128.h"
#include "alloc-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "format-table.h"
#include "format-util.h"
#include "gunicode.h"
#include "id128-util.h"
#include "in-addr-util.h"
#include "locale-util.h"
#include "memory-util.h"
@ -94,6 +97,7 @@ typedef struct TableData {
int percent; /* we use 'int' as datatype for percent values in order to match the result of parse_percent() */
int ifindex;
union in_addr_union address;
sd_id128_t id128;
/* … add more here as we start supporting more cell data types … */
};
} TableData;
@ -289,6 +293,10 @@ static size_t table_data_size(TableDataType type, const void *data) {
case TABLE_IN6_ADDR:
return sizeof(struct in6_addr);
case TABLE_UUID:
case TABLE_ID128:
return sizeof(sd_id128_t);
default:
assert_not_reached("Uh? Unexpected cell type");
}
@ -335,7 +343,6 @@ static bool table_data_matches(
k = table_data_size(type, data);
l = table_data_size(d->type, d->data);
if (k != l)
return false;
@ -778,6 +785,7 @@ int table_add_many_internal(Table *t, TableDataType first_type, ...) {
int ifindex;
bool b;
union in_addr_union address;
sd_id128_t id128;
} buffer;
switch (type) {
@ -901,6 +909,12 @@ int table_add_many_internal(Table *t, TableDataType first_type, ...) {
data = &buffer.address.in6;
break;
case TABLE_UUID:
case TABLE_ID128:
buffer.id128 = va_arg(ap, sd_id128_t);
data = &buffer.id128;
break;
case TABLE_SET_MINIMUM_WIDTH: {
size_t w = va_arg(ap, size_t);
@ -1137,6 +1151,10 @@ static int cell_data_compare(TableData *a, size_t index_a, TableData *b, size_t
case TABLE_IN6_ADDR:
return memcmp(&a->address.in6, &b->address.in6, FAMILY_ADDRESS_SIZE(AF_INET6));
case TABLE_UUID:
case TABLE_ID128:
return memcmp(&a->id128, &b->id128, sizeof(sd_id128_t));
default:
;
}
@ -1451,6 +1469,28 @@ static const char *table_data_format(Table *t, TableData *d) {
break;
}
case TABLE_ID128: {
char *p;
p = new(char, SD_ID128_STRING_MAX);
if (!p)
return NULL;
d->formatted = sd_id128_to_string(d->id128, p);
break;
}
case TABLE_UUID: {
char *p;
p = new(char, ID128_UUID_STRING_MAX);
if (!p)
return NULL;
d->formatted = id128_to_uuid_string(d->id128, p);
break;
}
default:
assert_not_reached("Unexpected type?");
}
@ -2155,6 +2195,16 @@ static int table_data_to_json(TableData *d, JsonVariant **ret) {
case TABLE_IN6_ADDR:
return json_variant_new_array_bytes(ret, &d->address, FAMILY_ADDRESS_SIZE(AF_INET6));
case TABLE_ID128: {
char buf[SD_ID128_STRING_MAX];
return json_variant_new_string(ret, sd_id128_to_string(d->id128, buf));
}
case TABLE_UUID: {
char buf[ID128_UUID_STRING_MAX];
return json_variant_new_string(ret, id128_to_uuid_string(d->id128, buf));
}
default:
return -EINVAL;
}

View File

@ -35,6 +35,8 @@ typedef enum TableDataType {
TABLE_IFINDEX,
TABLE_IN_ADDR, /* Takes a union in_addr_union (or a struct in_addr) */
TABLE_IN6_ADDR, /* Takes a union in_addr_union (or a struct in6_addr) */
TABLE_ID128,
TABLE_UUID,
_TABLE_DATA_TYPE_MAX,
/* The following are not really data types, but commands for table_add_cell_many() to make changes to

View File

@ -0,0 +1 @@
../TEST-01-BASIC/Makefile

37
test/TEST-45-REPART/test.sh Executable file
View File

@ -0,0 +1,37 @@
#!/bin/bash
set -e
TEST_DESCRIPTION="test systemd-repart"
. $TEST_BASE_DIR/test-functions
test_setup() {
create_empty_image_rootdir
(
LOG_LEVEL=5
eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
setup_basic_environment
mask_supporting_services
dracut_install truncate sfdisk
# setup the testsuite service
cat >$initdir/etc/systemd/system/testsuite.service <<EOF
[Unit]
Description=Testsuite service
Before=getty-pre.target
Wants=getty-pre.target
[Service]
ExecStart=/testsuite.sh
Type=oneshot
EOF
cp testsuite.sh $initdir/
setup_testsuite
)
setup_nspawn_root
}
do_test "$@"

124
test/TEST-45-REPART/testsuite.sh Executable file
View File

@ -0,0 +1,124 @@
#!/bin/bash
set -ex
# Check if repart is installed, and if it isn't bail out early instead of failing
if ! test -x /usr/bin/systemd-repart ; then
echo OK > /testok
exit 0
fi
systemd-analyze log-level debug
truncate -s 1G /tmp/zzz
SEED=e2a40bf9-73f1-4278-9160-49c031e7aef8
systemd-repart /tmp/zzz --empty=force --dry-run=no --seed=$SEED
sfdisk -d /tmp/zzz > /tmp/empty
cmp /tmp/empty - <<EOF
label: gpt
label-id: EF7F7EE2-47B3-4251-B1A1-09EA8BF12D5D
device: /tmp/zzz
unit: sectors
first-lba: 2048
last-lba: 2097118
EOF
mkdir /tmp/definitions
cat > /tmp/definitions/root.conf <<EOF
[Partition]
Type=root
EOF
ln -s root.conf /tmp/definitions/root2.conf
cat > /tmp/definitions/home.conf <<EOF
[Partition]
Type=home
EOF
cat > /tmp/definitions/swap.conf <<EOF
[Partition]
Type=swap
SizeMaxBytes=64M
PaddingMinBytes=92M
EOF
systemd-repart /tmp/zzz --dry-run=no --seed=$SEED --definitions=/tmp/definitions
sfdisk -d /tmp/zzz > /tmp/populated
cmp /tmp/populated - <<EOF
label: gpt
label-id: EF7F7EE2-47B3-4251-B1A1-09EA8BF12D5D
device: /tmp/zzz
unit: sectors
first-lba: 2048
last-lba: 2097118
/tmp/zzz1 : start= 2048, size= 591856, type=933AC7E1-2EB4-4F13-B844-0E14E2AEF915, uuid=A6005774-F558-4330-A8E5-D6D2C01C01D6, name="home"
/tmp/zzz2 : start= 593904, size= 591856, type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=CE9C76EB-A8F1-40FF-813C-11DCA6C0A55B, name="root-x86-64"
/tmp/zzz3 : start= 1185760, size= 591864, type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=AC60A837-550C-43BD-B5C4-9CB73B884E79, name="root-x86-64-2"
/tmp/zzz4 : start= 1777624, size= 131072, type=0657FD6D-A4AB-43C4-84E5-0933C84B4F4F, uuid=2AA78CDB-59C7-4173-AF11-C7453737A5D1, name="swap"
EOF
cat > /tmp/definitions/swap.conf <<EOF
[Partition]
Type=swap
SizeMaxBytes=64M
EOF
cat > /tmp/definitions/extra.conf <<EOF
[Partition]
Type=linux-generic
EOF
systemd-repart /tmp/zzz --dry-run=no --seed=$SEED --definitions=/tmp/definitions
sfdisk -d /tmp/zzz > /tmp/populated2
cmp /tmp/populated2 - <<EOF
label: gpt
label-id: EF7F7EE2-47B3-4251-B1A1-09EA8BF12D5D
device: /tmp/zzz
unit: sectors
first-lba: 2048
last-lba: 2097118
/tmp/zzz1 : start= 2048, size= 591856, type=933AC7E1-2EB4-4F13-B844-0E14E2AEF915, uuid=A6005774-F558-4330-A8E5-D6D2C01C01D6, name="home"
/tmp/zzz2 : start= 593904, size= 591856, type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=CE9C76EB-A8F1-40FF-813C-11DCA6C0A55B, name="root-x86-64"
/tmp/zzz3 : start= 1185760, size= 591864, type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=AC60A837-550C-43BD-B5C4-9CB73B884E79, name="root-x86-64-2"
/tmp/zzz4 : start= 1777624, size= 131072, type=0657FD6D-A4AB-43C4-84E5-0933C84B4F4F, uuid=2AA78CDB-59C7-4173-AF11-C7453737A5D1, name="swap"
/tmp/zzz5 : start= 1908696, size= 188416, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=03477476-06AD-44E8-9EF4-BC2BD7771289, name="linux-generic"
EOF
truncate -s 2G /tmp/zzz
systemd-repart /tmp/zzz --dry-run=no --seed=$SEED --definitions=/tmp/definitions
sfdisk -d /tmp/zzz > /tmp/populated3
cmp /tmp/populated3 - <<EOF
label: gpt
label-id: EF7F7EE2-47B3-4251-B1A1-09EA8BF12D5D
device: /tmp/zzz
unit: sectors
first-lba: 2048
last-lba: 4194270
/tmp/zzz1 : start= 2048, size= 591856, type=933AC7E1-2EB4-4F13-B844-0E14E2AEF915, uuid=A6005774-F558-4330-A8E5-D6D2C01C01D6, name="home"
/tmp/zzz2 : start= 593904, size= 591856, type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=CE9C76EB-A8F1-40FF-813C-11DCA6C0A55B, name="root-x86-64"
/tmp/zzz3 : start= 1185760, size= 591864, type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=AC60A837-550C-43BD-B5C4-9CB73B884E79, name="root-x86-64-2"
/tmp/zzz4 : start= 1777624, size= 131072, type=0657FD6D-A4AB-43C4-84E5-0933C84B4F4F, uuid=2AA78CDB-59C7-4173-AF11-C7453737A5D1, name="swap"
/tmp/zzz5 : start= 1908696, size= 2285568, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=03477476-06AD-44E8-9EF4-BC2BD7771289, name="linux-generic"
EOF
systemd-analyze log-level info
echo OK > /testok
exit 0

View File

@ -18,7 +18,10 @@ REPO_ROOT="${REPO_ROOT:-$PWD}"
ADDITIONAL_DEPS=(python3-libevdev
python3-pyparsing
clang
perl)
perl
libfdisk-dev
libp11-kit-dev
libssl-dev)
function info() {
echo -e "\033[33;1m$1\033[0m"

View File

@ -23,7 +23,10 @@ ADDITIONAL_DEPS=(dnf-plugins-core
libubsan
clang
llvm
perl)
perl
libfdisk-devel
openssl-devel
p11-kit-devel)
function info() {
echo -e "\033[33;1m$1\033[0m"

View File

@ -10,6 +10,8 @@ sudo bash -c "echo 'deb-src http://archive.ubuntu.com/ubuntu/ xenial main restri
sudo apt-get update -y
sudo apt-get build-dep systemd -y
sudo apt-get install -y ninja-build python3-pip python3-setuptools quota
# The following should be dropped when debian packaging has been updated to include them
sudo apt-get install -y libfdisk-dev libp11-kit-dev libssl-dev
# FIXME: temporarily pin the meson version as 0.53 doesn't work with older python 3.5
# See: https://github.com/mesonbuild/meson/issues/6427
pip3 install meson==0.52.1

View File

@ -14,6 +14,8 @@ sudo bash -c "echo 'deb-src http://archive.ubuntu.com/ubuntu/ xenial main restri
sudo apt-get update -y
sudo apt-get build-dep systemd -y
sudo apt-get install -y ninja-build python3-pip python3-setuptools
# The following should be dropped when debian packaging has been updated to include them
sudo apt-get install -y libfdisk-dev libp11-kit-dev libssl-dev
# FIXME: temporarily pin the meson version as 0.53 doesn't work with older python 3.5
# See: https://github.com/mesonbuild/meson/issues/6427
pip3 install meson==0.52.1

View File

@ -220,6 +220,8 @@ in_units = [
'multi-user.target.wants/'],
['systemd-vconsole-setup.service', 'ENABLE_VCONSOLE'],
['systemd-volatile-root.service', ''],
['systemd-repart.service', 'ENABLE_REPART',
'sysinit.target.wants/ initrd-root-fs.target.wants/'],
['user-runtime-dir@.service', ''],
['user@.service', ''],
]

View File

@ -0,0 +1,25 @@
# SPDX-License-Identifier: LGPL-2.1+
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Repartition Root Disk
Documentation=man:systemd-repart.service(8)
DefaultDependencies=no
Conflicts=shutdown.target
After=sysroot.mount
Before=initrd-root-fs.target shutdown.target
ConditionVirtualization=!container
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=@rootbindir@/systemd-repart --dry-run=no
# The tool returns 77 if there's no GPT partition table pre-existing
SuccessExitStatus=77