* dbus: when a unit failed to load (i.e. is in UNIT_ERROR state), we
should be able to safely try another attempt when the bus call LoadUnit() is invoked.
+* document org.freedesktop.MemoryAllocation1
+
* maybe do not install getty@tty1.service symlink in /etc but in /usr?
* print a nicer explanation if people use variable/specifier expansion in ExecStart= for the first word
</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>no-journal</option></term>
+
+ <listitem><para>
+ Disable the journal. Corresponds to the "direct writes" mode documented in
+ <ulink url="https://docs.kernel.org/admin-guide/device-mapper/dm-integrity.html">the dm-integrity documentation</ulink>.
+ Note that without a journal, if there is a crash, it is possible that the integrity tags and data will not match. If used, the journal-*
+ options below will have no effect if passed.
+ </para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>journal-watermark=[0..100]%</option></term>
<varlistentry>
<term><varname>ExcludeFiles=</varname></term>
+ <term><varname>ExcludeFilesTarget=</varname></term>
<listitem><para>Takes an absolute file system path 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
contents are excluded but not the directory itself. If the path is a directory and does not end with
<literal>/</literal>, both the directory and its contents are excluded.</para>
+ <para><varname>ExcludeFilesTarget=</varname> is like <varname>ExcludeFiles=</varname> except that
+ instead of excluding the path on the host from being copied into the partition, we exclude any files
+ and directories from being copied into the given path in the partition.</para>
+
<para>When
<citerefentry><refentrytitle>systemd-repart</refentrytitle><manvolnum>8</manvolnum></citerefentry>
is invoked with the <option>--image=</option> or <option>--root=</option> command line switches the
<title><command>systemd-analyze malloc [<replaceable>D-Bus service</replaceable>…]</command></title>
<para>This command can be used to request the output of the internal memory state (as returned by
- <citerefentry><refentrytitle>malloc_info</refentrytitle><manvolnum>3</manvolnum></citerefentry>) of
- a D-Bus service implementing this pattern. If no service is specified, the command will be sent to
+ <citerefentry project='man-pages'><refentrytitle>malloc_info</refentrytitle><manvolnum>3</manvolnum></citerefentry>)
+ of a D-Bus service. If no service is specified, the query will be sent to
<filename>org.freedesktop.systemd1</filename> (the system or user service manager). The output format
- is subject to change without notice and should not be parsed by applications.</para>
+ is not guaranteed to be stable and should not be parsed by applications.</para>
+
+ <para>The service must implement the <filename>org.freedesktop.MemoryAllocation1</filename> interface.
+ In the systemd suite, it is currently only implemented by the manager.</para>
</refsect2>
<refsect2>
Failed to prepare filename /tmp/source: Invalid argument
$ systemd-analyze verify /tmp/source:alias.service
-/tmp/systemd-analyze-XXXXXX/alias.service:7: Unknown key name 'MysteryKey' in section 'Service', ignoring.
+alias.service:7: Unknown key name 'MysteryKey' in section 'Service', ignoring.
</programlisting>
</example>
Packaging Metadata</ulink> documentation for more information.</para>
<example>
- <title>Table output</title>
+ <title>Print information about a core file as JSON</title>
- <programlisting>$ systemd-analyze inspect-elf --json=pretty /tmp/core.fsverity.1000.f77dac5dc161402aa44e15b7dd9dcf97.58561.1637106137000000
+ <programlisting>$ systemd-analyze inspect-elf --json=pretty \
+ core.fsverity.1000.f77dac5dc161402aa44e15b7dd9dcf97.58561.1637106137000000
{
"elfType" : "coredump",
"elfArchitecture" : "AMD x86-64",
<title>Description</title>
<para><filename>systemd-gpt-auto-generator</filename> is a unit generator that automatically discovers
- root, <filename>/home/</filename>, <filename>/srv/</filename>, <filename>/var/</filename>,
- <filename>/var/tmp/</filename>, the EFI System Partition, the Extended Boot Loader Partition and swap
+ the root partition, <filename>/home/</filename>, <filename>/srv/</filename>, <filename>/var/</filename>,
+ <filename>/var/tmp/</filename>, the EFI System Partition, the Extended Boot Loader Partition, and swap
partitions and creates mount and swap units for them, based on the partition type GUIDs of GUID partition
- tables (GPT), see <ulink url="https://uefi.org/specifications">UEFI Specification</ulink>, chapter 5. It
- implements the <ulink url="https://uapi-group.org/specifications/specs/discoverable_partitions_specification">Discoverable Partitions
- Specification</ulink>. Note that this generator has no effect on non-GPT systems, and on specific mount
- points that are directories already containing files. Also, on systems where the units are explicitly
- configured (for example, listed in <citerefentry
- project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>), the
- units this generator creates are overridden, but additional implicit dependencies might be
- created.</para>
+ tables (GPT). See <ulink url="https://uefi.org/specifications">UEFI Specification</ulink>, chapter 5 for
+ more details. It implements the <ulink
+ url="https://uapi-group.org/specifications/specs/discoverable_partitions_specification">Discoverable
+ Partitions Specification</ulink>.</para>
+
+ <para>Note that this generator has no effect on non-GPT systems. It will also not create mount point
+ configuration for directories which already contain files or if the mount point is explicitly configured
+ in <citerefentry
+ project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>. If
+ the units this generator creates are overridden, for example by units in directories with higher
+ precedence, drop-ins and additional dependencies created by this generator might still be used.</para>
<para>This generator will only look for the root partition on the same physical disk where the EFI System
Partition (ESP) is located. Note that support from the boot loader is required: the EFI variable
<varname>LoaderDevicePartUUID</varname> of the <constant>4a67b082-0a4c-41cf-b6c7-440b29bb8c4f</constant>
- vendor UUID is used to determine from which partition, and hence the disk from which the system was
- booted. If the boot loader does not set this variable, this generator will not be able to autodetect the
- root partition. See the <ulink url="https://systemd.io/BOOT_LOADER_INTERFACE">Boot Loader
- Interface</ulink> for details.</para>
+ vendor UUID is used to determine from which partition, and hence the disk, from which the system was
+ booted. If the boot loader does not set this variable, this generator will not be able to detect the root
+ partition. See the <ulink url="https://systemd.io/BOOT_LOADER_INTERFACE">Boot Loader Interface</ulink>
+ for details.</para>
<para>Similarly, this generator will only look for the other partitions on the same physical disk as the
root partition. In this case, boot loader support is not required. These partitions will not be searched
listed in <filename>/etc/crypttab</filename> with a different device mapper device name.</para>
<para>When systemd is running in the initrd the <filename>/</filename> partition may be encrypted in LUKS
- format as well. In this case, a device mapper device is set up under the name <filename>/dev/mapper/root</filename>,
- and a <filename>sysroot.mount</filename> is set up that mounts the device under <filename>/sysroot</filename>.
- For more information, see <citerefentry><refentrytitle>bootup</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
+ format as well. In this case, a device mapper device is set up under the name
+ <filename>/dev/mapper/root</filename>, and a <filename>sysroot.mount</filename> is set up that mounts the
+ device under <filename>/sysroot</filename>. For more information, see
+ <citerefentry><refentrytitle>bootup</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
</para>
<para>The root partition can be specified by symlinking <filename>/run/systemd/volatile-root</filename>
replaced by some form of volatile file system (overlayfs).
</para>
- <para>Mount and automount units for the EFI System Partition (ESP) are generated on EFI systems. The ESP
- is mounted to <filename>/boot/</filename> (except if an Extended Boot Loader partition exists, see
- below), unless a mount point directory <filename>/efi/</filename> exists, in which case it is mounted
- there. Since this generator creates an automount unit, the mount will only be activated on-demand, when
- accessed. On systems where <filename>/boot/</filename> (or <filename>/efi/</filename> if it exists) is an
- explicitly configured mount (for example, listed in <citerefentry
- project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>) or where
- the <filename>/boot/</filename> (or <filename>/efi/</filename>) mount point is non-empty, no mount units
- are generated.</para>
-
- <para>If the disk contains an Extended Boot Loader partition, as defined in the <ulink
- url="https://uapi-group.org/specifications/specs/boot_loader_specification">Boot Loader Specification</ulink>, it is made
- available at <filename>/boot/</filename> (by means of an automount point, similar to the ESP, see
- above). If both an EFI System Partition and an Extended Boot Loader partition exist the latter is
- preferably mounted to <filename>/boot/</filename>. Make sure to create both <filename>/efi/</filename>
- and <filename>/boot/</filename> to ensure both partitions are mounted.</para>
+ <para>Mount and automount units for the EFI System Partition (ESP) and Extended Boot Loader Partition
+ (XBOOTLDR) are generated on EFI systems. If the disk contains an XBOOTLDR partition, as defined in the
+ <ulink url="https://uapi-group.org/specifications/specs/boot_loader_specification">Boot Loader
+ Specification</ulink>, it is made available at <filename>/boot/</filename>. This generator creates an
+ automount unit; the mount will only be activated on-demand when accessed. The mount point will be created
+ if necessary.</para>
+
+ <para>The ESP is mounted to <filename>/boot/</filename> if that directory exists and is not used for
+ XBOOTLDR, and otherwise to <filename>/efi/</filename>. Same as for <filename>/boot/</filename>, an
+ automount unit is used. The mount point will be created if necessary.</para>
+
+ <para>No configuration is created for mount points that are configured in <citerefentry
+ project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry> or when
+ the target directory contains files.</para>
<para>When using this generator in conjunction with btrfs file
systems, make sure to set the correct default subvolumes on them,
<varlistentry>
<term><varname>e</varname></term>
<listitem><para>Adjust the mode and ownership of existing directories and remove their contents
- based on age.
- Lines of this type accept shell-style globs in place of normal path names. Contents of the
- directories are subject to time-based cleanup if the age argument is specified. If the age argument
- is <literal>0</literal>, contents will be unconditionally deleted every time
- <command>systemd-tmpfiles --clean</command> is run.</para>
+ based on age. Lines of this type accept shell-style globs in place of normal path names. Contents
+ of the directories are subject to time-based cleanup if the age argument is specified. If the age
+ argument is <literal>0</literal>, contents will be unconditionally deleted every time
+ <citerefentry><refentrytitle>systemd-tmpfiles</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <option>--clean</option> is run.</para>
<para>For this entry to be useful, at least one of the mode, user, group, or age arguments must be
specified, since otherwise this entry has no effect. As an exception, an entry with no effect may
<varlistentry>
<term><varname>a</varname></term>
<term><varname>a+</varname></term>
- <listitem><para>Set POSIX ACLs (access control lists), see <citerefentry
- project='man-pages'><refentrytitle>acl</refentrytitle>
- <manvolnum>5</manvolnum></citerefentry>. Additionally, if 'X' is used, the execute bit is set only
- if the file is a directory or already has execute permission for some user, as mentioned in
+ <listitem><para>Set POSIX ACLs (access control lists), see
+ <citerefentry project='man-pages'><refentrytitle>acl</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+ Additionally, if 'X' is used, the execute bit is set only if the file is a directory or already has
+ execute permission for some user, as mentioned in
<citerefentry project='man-pages'><refentrytitle>setfacl</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
If suffixed with <varname>+</varname>, the specified entries will be added to the existing set.
- <command>systemd-tmpfiles</command> will automatically add the required base entries for user
- and group based on the access mode of the file, unless base entries already exist or are explicitly
- specified. The mask will be added if not specified explicitly or already present. Lines of this type
- accept shell-style globs in place of normal path names. This can be useful for allowing additional
- access to certain files. Does not follow symlinks.</para></listitem>
+ <citerefentry><refentrytitle>systemd-tmpfiles</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ will automatically add the required base entries for user and group based on the access mode of the
+ file, unless base entries already exist or are explicitly specified. The mask will be added if not
+ specified explicitly or already present. Lines of this type accept shell-style globs in place of
+ normal path names. This can be useful for allowing additional access to certain files. Does not
+ follow symlinks.</para></listitem>
</varlistentry>
<varlistentry>
<para>If the exclamation mark (<literal>!</literal>) is used, this line is only safe to execute during
boot, and can break a running system. Lines without the exclamation mark are presumed to be safe to
- execute at any time, e.g. on package upgrades. <command>systemd-tmpfiles</command> will take lines with
- an exclamation mark only into consideration, if the <option>--boot</option> option is given.</para>
+ execute at any time, e.g. on package upgrades.
+ <citerefentry><refentrytitle>systemd-tmpfiles</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ will take lines with an exclamation mark only into consideration, if the <option>--boot</option> option
+ is given.</para>
<para>For example:
<programlisting># Make sure these are created by default so that nobody else can
<para>The user and group to use for this file or directory. This may either be a numeric ID or a
user/group name. If omitted or when set to <literal>-</literal>, the user and group of the user who
- invokes <command>systemd-tmpfiles</command> is used. For <varname>z</varname> and <varname>Z</varname>
- lines, when omitted or when set to <literal>-</literal>, the file ownership will not be modified. These
- parameters are ignored for <varname>x</varname>, <varname>r</varname>, <varname>R</varname>,
- <varname>L</varname>, <varname>t</varname>, and <varname>a</varname> lines.</para>
+ invokes
+ <citerefentry><refentrytitle>systemd-tmpfiles</refentrytitle><manvolnum>8</manvolnum></citerefentry> is
+ used. For <varname>z</varname> and <varname>Z</varname> lines, when omitted or when set to
+ <literal>-</literal>, the file ownership will not be modified. These parameters are ignored for
+ <varname>x</varname>, <varname>r</varname>, <varname>R</varname>, <varname>L</varname>,
+ <varname>t</varname>, and <varname>a</varname> lines.</para>
<para>This field should generally only reference system users/groups, i.e. users/groups that are
guaranteed to be resolvable during early boot. If this field references users/groups that only become
…
</title>
- <para>Verify syntactic and semantic correctness of udev rules files.</para>
+ <para>Verify syntactic, semantic, and stylistic correctness of udev rules files.</para>
<para>Positional arguments could be used to specify one or more files to check.
If no files are specified, the udev rules are read from the files located in
the same udev/rules.d directories that are processed by the udev daemon.</para>
- <para>The exit status is <constant>0</constant> if all specified udev rules files
- are syntactically and semantically correct, and a non-zero error code otherwise.</para>
+ <para>The exit status is <constant>0</constant> if all specified udev
+ rules files are syntactically, semantically, and stylistically correct,
+ and a non-zero error code otherwise.</para>
<variablelist>
<varlistentry>
clang_supports_bpf = run_command(clang, '-target', 'bpf', '--print-supported-cpus', check : false).returncode() == 0
endif
elif bpf_compiler == 'gcc'
- warning('GCC BPF Compiler support is experimental and not recommended.')
bpf_gcc = find_program('bpf-gcc',
+ 'bpf-none-gcc',
required : true,
- version : '>= 12.1.0')
+ version : '>= 13.1.0')
bpf_gcc_found = bpf_gcc.found()
endif
# there.
meson.add_install_script('sh', '-c', mkdir_p.format(credstoredir))
if install_sysconfdir
+ # Keep in sync with tmpfiles.d/credstore.conf
meson.add_install_script('sh', '-c', mkdir_p_mode.format(sysconfdir / 'credstore', '0700'))
+ meson.add_install_script('sh', '-c', mkdir_p_mode.format(sysconfdir / 'credstore.encrypted', '0700'))
endif
executable(
description : 'install systemd-analyze')
option('bpf-compiler', type : 'combo', choices : ['clang', 'gcc'],
- description: 'compiler used to build BPF programs, note: gcc is experimental')
+ description: 'compiler used to build BPF programs')
option('bpf-framework', type : 'combo', choices : ['auto', 'true', 'false'],
description: 'build BPF programs from source code in restricted C')
)
fi
+ if grep -q '^ID="opensuse' /etc/os-release; then
+ CONFIGURE_OPTS+=(
+ -Dbpf-compiler=gcc
+ )
+ fi
+
( set -x; meson setup "$BUILDDIR" "${CONFIGURE_OPTS[@]}" )
fi
BuildPackages=
audit-devel
bpftool
+ cross-bpf-gcc13
dbus-1-devel
docbook-xsl-stylesheets
fdupes
request_key
restart_syscall
riscv_flush_icache
+riscv_hwprobe
rmdir
rseq
rt_sigaction
request_key 440
restart_syscall 412
riscv_flush_icache
+riscv_hwprobe
rmdir 137
rseq 527
rt_sigaction 352
request_key 218
restart_syscall 128
riscv_flush_icache
+riscv_hwprobe
rmdir
rseq 293
rt_sigaction 134
request_key 310
restart_syscall 0
riscv_flush_icache
+riscv_hwprobe
rmdir 40
rseq 398
rt_sigaction 174
request_key 218
restart_syscall 128
riscv_flush_icache
+riscv_hwprobe
rmdir
rseq 293
rt_sigaction 134
request_key 287
restart_syscall 0
riscv_flush_icache
+riscv_hwprobe
rmdir 40
rseq 386
rt_sigaction 174
request_key 1272
restart_syscall 1246
riscv_flush_icache
+riscv_hwprobe
rmdir 1056
rseq 1357
rt_sigaction 1177
request_key 218
restart_syscall 128
riscv_flush_icache
+riscv_hwprobe
rmdir
rseq 293
rt_sigaction 134
request_key 280
restart_syscall 0
riscv_flush_icache
+riscv_hwprobe
rmdir 40
rseq 384
rt_sigaction 174
request_key 5240
restart_syscall 5213
riscv_flush_icache
+riscv_hwprobe
rmdir 5082
rseq 5327
rt_sigaction 5013
request_key 6244
restart_syscall 6214
riscv_flush_icache
+riscv_hwprobe
rmdir 6082
rseq 6331
rt_sigaction 6013
request_key 4281
restart_syscall 4253
riscv_flush_icache
+riscv_hwprobe
rmdir 4040
rseq 4367
rt_sigaction 4194
request_key 265
restart_syscall 0
riscv_flush_icache
+riscv_hwprobe
rmdir 40
rseq 354
rt_sigaction 174
request_key 270
restart_syscall 0
riscv_flush_icache
+riscv_hwprobe
rmdir 40
rseq 387
rt_sigaction 173
request_key 270
restart_syscall 0
riscv_flush_icache
+riscv_hwprobe
rmdir 40
rseq 387
rt_sigaction 173
request_key 218
restart_syscall 128
riscv_flush_icache 259
+riscv_hwprobe 258
rmdir
rseq 293
rt_sigaction 134
request_key 218
restart_syscall 128
riscv_flush_icache 259
+riscv_hwprobe 258
rmdir
rseq 293
rt_sigaction 134
mbind 268
membarrier 356
memfd_create 350
-memfd_secret
+memfd_secret 447
memory_ordering
migrate_pages 287
mincore 218
request_key 279
restart_syscall 7
riscv_flush_icache
+riscv_hwprobe
rmdir 40
rseq 383
rt_sigaction 174
mbind 268
membarrier 356
memfd_create 350
-memfd_secret
+memfd_secret 447
memory_ordering
migrate_pages 287
mincore 218
request_key 279
restart_syscall 7
riscv_flush_icache
+riscv_hwprobe
rmdir 40
rseq 383
rt_sigaction 174
request_key 282
restart_syscall 0
riscv_flush_icache
+riscv_hwprobe
rmdir 137
rseq 365
rt_sigaction 102
request_key 249
restart_syscall 219
riscv_flush_icache
+riscv_hwprobe
rmdir 84
rseq 334
rt_sigaction 13
#include "gpt.h"
#include "image-policy.h"
#include "initrd-util.h"
-#include "mkdir.h"
#include "mountpoint-util.h"
#include "parse-util.h"
#include "path-util.h"
r = efi_stub_measured(LOG_WARNING);
if (r == 0)
- log_debug("Will not measure volume key of volume '%s', because not booted via systemd-stub with measurements enabled.", id);
+ log_debug("Will not measure volume key of volume '%s', not booted via systemd-stub with measurements enabled.", id);
else if (r > 0) {
if (!strextend_with_separator(&options, ",", "tpm2-measure-pcr=yes"))
return log_oom();
if (r < 0)
return r;
- const char *dmname;
- dmname = strjoina("dev-mapper-", e, ".device");
+ const char *dmname = strjoina("dev-mapper-", e, ".device");
if (require) {
r = generator_add_symlink(arg_dest, "cryptsetup.target", "requires", n);
return 0;
#else
- return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Partition is encrypted, but the project was compiled without libcryptsetup support");
+ return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+ "Partition is encrypted, but systemd-gpt-auto-generator was compiled without libcryptsetup support");
#endif
}
static int path_is_busy(const char *where) {
int r;
+ assert(where);
+
/* already a mountpoint; generators run during reload */
r = path_is_mount_point(where, NULL, AT_SYMLINK_FOLLOW);
if (r > 0)
return false;
-
- /* the directory might not exist on a stateless system */
+ /* The directory will be created by the mount or automount unit when it is started. */
if (r == -ENOENT)
return false;
/* not a mountpoint but it contains files */
r = dir_is_empty(where, /* ignore_hidden_or_backup= */ false);
- if (r < 0)
+ if (r == -ENOTDIR) {
+ log_debug("\"%s\" is not a directory, ignoring.", where);
+ return true;
+ } else if (r < 0)
return log_warning_errno(r, "Cannot check if \"%s\" is empty: %m", where);
- if (r > 0)
- return false;
+ else if (r == 0) {
+ log_debug("\"%s\" already populated, ignoring.", where);
+ return true;
+ }
- log_debug("\"%s\" already populated, ignoring.", where);
- return true;
+ return false;
}
static int add_partition_mount(
return generator_add_symlink(arg_dest, SPECIAL_LOCAL_FS_TARGET, "wants", unit);
}
+static int slash_boot_in_fstab(void) {
+ static int cache = -1;
+
+ if (cache >= 0)
+ return cache;
+
+ cache = fstab_is_mount_point("/boot");
+ if (cache < 0)
+ return log_error_errno(cache, "Failed to parse fstab: %m");
+ return cache;
+}
+
+static int slash_efi_in_fstab(void) {
+ static int cache = -1;
+
+ if (cache >= 0)
+ return cache;
+
+ cache = fstab_is_mount_point("/efi");
+ if (cache < 0)
+ return log_error_errno(cache, "Failed to parse fstab: %m");
+ return cache;
+}
+
+static bool slash_boot_exists(void) {
+ static int cache = -1;
+
+ if (cache >= 0)
+ return cache;
+
+ if (access("/boot", F_OK) >= 0)
+ return (cache = true);
+ if (errno != ENOENT)
+ log_error_errno(errno, "Failed to determine whether /boot/ exists, assuming no: %m");
+ else
+ log_debug_errno(errno, "/boot/: %m");
+ return (cache = false);
+}
+
static int add_partition_xbootldr(DissectedPartition *p) {
_cleanup_free_ char *options = NULL;
int r;
return 0;
}
- r = fstab_is_mount_point("/boot");
+ r = slash_boot_in_fstab();
if (r < 0)
- return log_error_errno(r, "Failed to parse fstab: %m");
+ return r;
if (r > 0) {
- log_debug("/boot specified in fstab, ignoring XBOOTLDR partition.");
+ log_debug("/boot/ specified in fstab, ignoring XBOOTLDR partition.");
return 0;
}
&options,
/* ret_ms_flags= */ NULL);
if (r < 0)
- return log_error_errno(r, "Failed to determine default mount options for Boot Loader Partition: %m");
-
- return add_automount("boot",
- p->node,
- "/boot",
- p->fstype,
- /* rw= */ true,
- /* growfs= */ false,
- options,
- "Boot Loader Partition",
- 120 * USEC_PER_SEC);
+ return log_error_errno(r, "Failed to determine default mount options for /boot/: %m");
+
+ return add_automount(
+ "boot",
+ p->node,
+ "/boot",
+ p->fstype,
+ /* rw= */ true,
+ /* growfs= */ false,
+ options,
+ "Boot Loader Partition",
+ 120 * USEC_PER_SEC);
}
#if ENABLE_EFI
return 0;
}
- /* If /efi exists we'll use that. Otherwise we'll use /boot, as that's usually the better choice, but
- * only if there's no explicit XBOOTLDR partition around. */
- if (access("/efi", F_OK) < 0) {
- if (errno != ENOENT)
- return log_error_errno(errno, "Failed to determine whether /efi exists: %m");
-
- /* Use /boot as fallback, but only if there's no XBOOTLDR partition and /boot exists */
- if (!has_xbootldr) {
- if (access("/boot", F_OK) < 0) {
- if (errno != ENOENT)
- return log_error_errno(errno, "Failed to determine whether /boot exists: %m");
- } else {
+ /* If /boot/ is present, unused, and empty, we'll take that.
+ * Otherwise, if /efi/ is unused and empty (or missing), we'll take that.
+ * Otherwise, we do nothing.
+ */
+ if (!has_xbootldr && slash_boot_exists()) {
+ r = slash_boot_in_fstab();
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ r = path_is_busy("/boot");
+ if (r < 0)
+ return r;
+ if (r == 0) {
esp_path = "/boot";
id = "boot";
}
}
}
- if (!esp_path)
+
+ if (!esp_path) {
+ r = slash_efi_in_fstab();
+ if (r < 0)
+ return r;
+ if (r > 0)
+ return 0;
+
+ r = path_is_busy("/efi");
+ if (r < 0)
+ return r;
+ if (r > 0)
+ return 0;
+
esp_path = "/efi";
- if (!id)
id = "efi";
-
- /* We create an .automount which is not overridden by the .mount from the fstab generator. */
- r = fstab_is_mount_point(esp_path);
- if (r < 0)
- return log_error_errno(r, "Failed to parse fstab: %m");
- if (r > 0) {
- log_debug("%s specified in fstab, ignoring.", esp_path);
- return 0;
}
- r = path_is_busy(esp_path);
- if (r < 0)
- return r;
- if (r > 0)
- return 0;
-
if (is_efi_boot()) {
sd_id128_t loader_uuid;
&options,
/* ret_ms_flags= */ NULL);
if (r < 0)
- return log_error_errno(r, "Failed to determine default mount options for EFI System Partition: %m");
-
- return add_automount(id,
- p->node,
- esp_path,
- p->fstype,
- /* rw= */ true,
- /* growfs= */ false,
- options,
- "EFI System Partition Automount",
- 120 * USEC_PER_SEC);
+ return log_error_errno(r, "Failed to determine default mount options for %s: %m", esp_path);
+
+ return add_automount(
+ id,
+ p->node,
+ esp_path,
+ p->fstype,
+ /* rw= */ true,
+ /* growfs= */ false,
+ options,
+ "EFI System Partition Automount",
+ 120 * USEC_PER_SEC);
}
#else
static int add_partition_esp(DissectedPartition *p, bool has_xbootldr) {
assert(o);
assert(o->type == OPERATION_ACQUIRE);
- assert(!h->current_operation);
-
switch (home_get_state(h)) {
case HOME_UNFIXATED:
return 0;
}
+ assert(!h->current_operation);
+
r = home_ratelimit(h, &error);
if (r >= 0)
r = call(h, o->secret, for_state, &error);
else if (streq(word, "allow-discards")) {
if (ret_activate_flags)
*ret_activate_flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
+ } else if (streq(word, "no-journal")) {
+ if (ret_activate_flags)
+ *ret_activate_flags |= CRYPT_ACTIVATE_NO_JOURNAL;
} else if ((val = startswith(word, "journal-watermark="))) {
r = parse_percent(val);
if (r < 0)
char *format;
char **copy_files;
- char **exclude_files;
+ char **exclude_files_source;
+ char **exclude_files_target;
char **make_directories;
EncryptMode encrypt;
VerityMode verity;
free(p->format);
strv_free(p->copy_files);
- strv_free(p->exclude_files);
+ strv_free(p->exclude_files_source);
+ strv_free(p->exclude_files_target);
strv_free(p->make_directories);
free(p->verity_match_key);
p->format = mfree(p->format);
p->copy_files = strv_free(p->copy_files);
- p->exclude_files = strv_free(p->exclude_files);
+ p->exclude_files_source = strv_free(p->exclude_files_source);
+ p->exclude_files_target = strv_free(p->exclude_files_target);
p->make_directories = strv_free(p->make_directories);
p->verity_match_key = mfree(p->verity_match_key);
static int partition_read_definition(Partition *p, const char *path, const char *const *conf_file_dirs) {
ConfigTableItem table[] = {
- { "Partition", "Type", config_parse_type, 0, &p->type },
- { "Partition", "Label", config_parse_label, 0, &p->new_label },
- { "Partition", "UUID", config_parse_uuid, 0, p },
- { "Partition", "Priority", config_parse_int32, 0, &p->priority },
- { "Partition", "Weight", config_parse_weight, 0, &p->weight },
- { "Partition", "PaddingWeight", config_parse_weight, 0, &p->padding_weight },
- { "Partition", "SizeMinBytes", config_parse_size4096, 1, &p->size_min },
- { "Partition", "SizeMaxBytes", config_parse_size4096, -1, &p->size_max },
- { "Partition", "PaddingMinBytes", config_parse_size4096, 1, &p->padding_min },
- { "Partition", "PaddingMaxBytes", config_parse_size4096, -1, &p->padding_max },
- { "Partition", "FactoryReset", config_parse_bool, 0, &p->factory_reset },
- { "Partition", "CopyBlocks", config_parse_copy_blocks, 0, p },
- { "Partition", "Format", config_parse_fstype, 0, &p->format },
- { "Partition", "CopyFiles", config_parse_copy_files, 0, &p->copy_files },
- { "Partition", "ExcludeFiles", config_parse_exclude_files, 0, &p->exclude_files },
- { "Partition", "MakeDirectories", config_parse_make_dirs, 0, p },
- { "Partition", "Encrypt", config_parse_encrypt, 0, &p->encrypt },
- { "Partition", "Verity", config_parse_verity, 0, &p->verity },
- { "Partition", "VerityMatchKey", config_parse_string, 0, &p->verity_match_key },
- { "Partition", "Flags", config_parse_gpt_flags, 0, &p->gpt_flags },
- { "Partition", "ReadOnly", config_parse_tristate, 0, &p->read_only },
- { "Partition", "NoAuto", config_parse_tristate, 0, &p->no_auto },
- { "Partition", "GrowFileSystem", config_parse_tristate, 0, &p->growfs },
- { "Partition", "SplitName", config_parse_string, 0, &p->split_name_format },
- { "Partition", "Minimize", config_parse_minimize, 0, &p->minimize },
+ { "Partition", "Type", config_parse_type, 0, &p->type },
+ { "Partition", "Label", config_parse_label, 0, &p->new_label },
+ { "Partition", "UUID", config_parse_uuid, 0, p },
+ { "Partition", "Priority", config_parse_int32, 0, &p->priority },
+ { "Partition", "Weight", config_parse_weight, 0, &p->weight },
+ { "Partition", "PaddingWeight", config_parse_weight, 0, &p->padding_weight },
+ { "Partition", "SizeMinBytes", config_parse_size4096, 1, &p->size_min },
+ { "Partition", "SizeMaxBytes", config_parse_size4096, -1, &p->size_max },
+ { "Partition", "PaddingMinBytes", config_parse_size4096, 1, &p->padding_min },
+ { "Partition", "PaddingMaxBytes", config_parse_size4096, -1, &p->padding_max },
+ { "Partition", "FactoryReset", config_parse_bool, 0, &p->factory_reset },
+ { "Partition", "CopyBlocks", config_parse_copy_blocks, 0, p },
+ { "Partition", "Format", config_parse_fstype, 0, &p->format },
+ { "Partition", "CopyFiles", config_parse_copy_files, 0, &p->copy_files },
+ { "Partition", "ExcludeFiles", config_parse_exclude_files, 0, &p->exclude_files_source },
+ { "Partition", "ExcludeFilesTarget", config_parse_exclude_files, 0, &p->exclude_files_target },
+ { "Partition", "MakeDirectories", config_parse_make_dirs, 0, p },
+ { "Partition", "Encrypt", config_parse_encrypt, 0, &p->encrypt },
+ { "Partition", "Verity", config_parse_verity, 0, &p->verity },
+ { "Partition", "VerityMatchKey", config_parse_string, 0, &p->verity_match_key },
+ { "Partition", "Flags", config_parse_gpt_flags, 0, &p->gpt_flags },
+ { "Partition", "ReadOnly", config_parse_tristate, 0, &p->read_only },
+ { "Partition", "NoAuto", config_parse_tristate, 0, &p->no_auto },
+ { "Partition", "GrowFileSystem", config_parse_tristate, 0, &p->growfs },
+ { "Partition", "SplitName", config_parse_string, 0, &p->split_name_format },
+ { "Partition", "Minimize", config_parse_minimize, 0, &p->minimize },
{}
};
int r;
/* Add the user configured excludes. */
- STRV_FOREACH(e, p->exclude_files) {
+ STRV_FOREACH(e, p->exclude_files_source) {
r = add_exclude_path(*e, &denylist, endswith(*e, "/") ? DENY_CONTENTS : DENY_INODE);
if (r < 0)
return r;
}
+ STRV_FOREACH(e, p->exclude_files_target) {
+ _cleanup_free_ char *path = NULL;
+
+ const char *s = path_startswith(*e, target);
+ if (!s)
+ continue;
+
+ path = path_join(source, s);
+ if (!path)
+ return log_oom();
+
+ r = add_exclude_path(path, &denylist, endswith(*e, "/") ? DENY_CONTENTS : DENY_INODE);
+ if (r < 0)
+ return r;
+ }
+
/* If we're populating a root partition, we don't want any files to end up under the APIVFS mount
* points. While we already exclude <source>/proc, users could still do something such as
* "CopyFiles=/abc:/". Now, if /abc has a proc subdirectory with files in it, those will end up in
TABLE_UINT64, n_dnssec_insecure,
TABLE_FIELD, "Bogus",
TABLE_UINT64, n_dnssec_bogus,
- TABLE_FIELD, "Indeterminate:",
+ TABLE_FIELD, "Indeterminate",
TABLE_UINT64, n_dnssec_indeterminate);
if (r < 0)
return table_log_add_error(r);
return 1;
}
+static int mount_point_is_available(const char *where, const char *path, bool missing_ok) {
+ _cleanup_free_ char *p = NULL;
+ int r;
+
+ /* Check whether <path> is suitable as a mountpoint, i.e. is an empty directory
+ * or does not exist at all (when missing_ok). */
+
+ r = chase(path, where, CHASE_PREFIX_ROOT, &p, NULL);
+ if (r == -ENOENT)
+ return missing_ok;
+ if (r < 0)
+ return log_debug_errno(r, "Failed to chase \"%s\": %m", path);
+
+ r = dir_is_empty(p, /* ignore_hidden_or_backup= */ false);
+ if (r == -ENOTDIR)
+ return false;
+ if (r < 0)
+ return log_debug_errno(r, "Failed to check directory \"%s\": %m", p);
+ return true;
+}
+
int dissected_image_mount(
DissectedImage *m,
const char *where,
uid_t uid_range,
DissectImageFlags flags) {
- int r, xbootldr_mounted;
+ int r;
assert(m);
assert(where);
if (r < 0)
return r;
- xbootldr_mounted = mount_partition(PARTITION_XBOOTLDR, m->partitions + PARTITION_XBOOTLDR, where, "/boot", uid_shift, uid_range, flags);
- if (xbootldr_mounted < 0)
- return xbootldr_mounted;
+ int slash_boot_is_available;
+ r = slash_boot_is_available = mount_point_is_available(where, "/boot", /* missing_ok = */ true);
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ r = mount_partition(PARTITION_XBOOTLDR, m->partitions + PARTITION_XBOOTLDR, where, "/boot", uid_shift, uid_range, flags);
+ if (r < 0)
+ return r;
+ slash_boot_is_available = !r;
+ }
if (m->partitions[PARTITION_ESP].found) {
- int esp_done = false;
+ const char *esp_path = NULL;
- /* Mount the ESP to /efi if it exists. If it doesn't exist, use /boot instead, but only if it
- * exists and is empty, and we didn't already mount the XBOOTLDR partition into it. */
+ /* Mount the ESP to /boot/ if it exists and is empty and we didn't already mount the XBOOTLDR
+ * partition into it. Otherwise, use /efi instead, but only if it exists and is empty. */
- r = chase("/efi", where, CHASE_PREFIX_ROOT, NULL, NULL);
- if (r < 0) {
- if (r != -ENOENT)
+ if (slash_boot_is_available) {
+ r = mount_point_is_available(where, "/boot", /* missing_ok = */ false);
+ if (r < 0)
return r;
-
- /* /efi doesn't exist. Let's see if /boot is suitable then */
-
- if (!xbootldr_mounted) {
- _cleanup_free_ char *p = NULL;
-
- r = chase("/boot", where, CHASE_PREFIX_ROOT, &p, NULL);
- if (r < 0) {
- if (r != -ENOENT)
- return r;
- } else if (dir_is_empty(p, /* ignore_hidden_or_backup= */ false) > 0) {
- /* It exists and is an empty directory. Let's mount the ESP there. */
- r = mount_partition(PARTITION_ESP, m->partitions + PARTITION_ESP, where, "/boot", uid_shift, uid_range, flags);
- if (r < 0)
- return r;
-
- esp_done = true;
- }
- }
+ if (r > 0)
+ esp_path = "/boot";
}
- if (!esp_done) {
- /* OK, let's mount the ESP now to /efi (possibly creating the dir if missing) */
+ if (!esp_path) {
+ r = mount_point_is_available(where, "/efi", /* missing_ok = */ true);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ esp_path = "/efi";
+ }
- r = mount_partition(PARTITION_ESP, m->partitions + PARTITION_ESP, where, "/efi", uid_shift, uid_range, flags);
+ if (esp_path) {
+ /* OK, let's mount the ESP now (possibly creating the dir if missing) */
+ r = mount_partition(PARTITION_ESP, m->partitions + PARTITION_ESP, where, esp_path, uid_shift, uid_range, flags);
if (r < 0)
return r;
}
_GPT_ARCH_SEXTET(ALPHA, "alpha"),
_GPT_ARCH_SEXTET(ARC, "arc"),
_GPT_ARCH_SEXTET(ARM, "arm"),
+ _GPT_ARCH_SEXTET(ARM, "armv7l"), /* Alias: must be listed after arm */
_GPT_ARCH_SEXTET(ARM64, "arm64"),
_GPT_ARCH_SEXTET(ARM64, "aarch64"), /* Alias: must be listed after arm64 */
_GPT_ARCH_SEXTET(IA64, "ia64"),
_GPT_ARCH_SEXTET(PPC, "ppc"),
_GPT_ARCH_SEXTET(PPC64, "ppc64"),
_GPT_ARCH_SEXTET(PPC64_LE, "ppc64-le"),
+ _GPT_ARCH_SEXTET(PPC64_LE, "ppc64le"), /* Alias: must be listed after ppc64-le */
_GPT_ARCH_SEXTET(RISCV32, "riscv32"),
_GPT_ARCH_SEXTET(RISCV64, "riscv64"),
_GPT_ARCH_SEXTET(S390, "s390"),
_GPT_ARCH_SEXTET(TILEGX, "tilegx"),
_GPT_ARCH_SEXTET(X86, "x86"),
_GPT_ARCH_SEXTET(X86_64, "x86-64"),
+ _GPT_ARCH_SEXTET(X86_64, "x86_64"), /* Alias: must be listed after x86-64 */
_GPT_ARCH_SEXTET(X86_64, "amd64"), /* Alias: must be listed after x86-64 */
#ifdef SD_GPT_ROOT_NATIVE
{ SD_GPT_ROOT_NATIVE, "root", native_architecture(), .designator = PARTITION_ROOT },
}
/* Now that the block device is released, let's also try to remove it */
- if (control >= 0)
- for (unsigned n_attempts = 0;;) {
+ if (control >= 0) {
+ useconds_t delay = 5 * USEC_PER_MSEC;
+
+ for (unsigned attempt = 1;; attempt++) {
if (ioctl(control, LOOP_CTL_REMOVE, d->nr) >= 0)
break;
- if (errno != EBUSY || ++n_attempts >= 64) {
+ if (errno != EBUSY || attempt > 38) {
log_debug_errno(errno, "Failed to remove device %s: %m", strna(d->node));
break;
}
- (void) usleep(50 * USEC_PER_MSEC);
+ if (attempt % 5 == 0) {
+ log_debug("Device is still busy after %u attempts…", attempt);
+ delay *= 2;
+ }
+
+ (void) usleep(delay);
}
+ }
free(d->node);
sd_device_unref(d->dev);
the test, etc.)
The kernel and initrd can be specified with $KERNEL_BIN and $INITRD. (Fedora's
-or Debian's default kernel path and initrd are used by default)
+or Debian's default kernel path and initrd are used by default.)
A script will try to find your qemu binary. If you want to specify a different
one with $QEMU_BIN.
Debugging the qemu image
========================
-If you want to log in the testsuite virtual machine, you can specify additional
-kernel command line parameter with $KERNEL_APPEND and then log in as root.
+If you want to log in the testsuite virtual machine, use INTERACTIVE_DEBUG=1
+and log in as root:
-$ sudo make -C test/TEST-01-BASIC KERNEL_APPEND="systemd.unit=multi-user.target" run
+$ sudo make -C test/TEST-01-BASIC INTERACTIVE_DEBUG=1 run
-Root password is empty.
+The root password is empty.
Ubuntu CI
=========
# fsck(8) is located in /usr/sbin on Debian
PATH=$PATH:/usr/sbin
+# systemd-pcrfs@.service could be enabled or not, depending on the host state
+# of the host system. Override the measurement to avoid the issue.
+export SYSTEMD_FORCE_MEASURE=0
+
for f in "$src"/test-*.input; do
echo "*** Running $f"
local defs imgs output
local loop volume
- defs="$(runas testuser mktemp --directory "/tmp/test-repart.XXXXXXXXXX")"
- imgs="$(runas testuser mktemp --directory "/var/tmp/test-repart.XXXXXXXXXX")"
+ defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")"
+ imgs="$(runas testuser mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs'" RETURN
+ chmod a+rx "$defs"
- # 1. create an empty image
+ echo "*** 1. create an empty image ***"
runas testuser systemd-repart --empty=create \
--size=1G \
first-lba: 2048
last-lba: 2097118"
- # 2. Testing with root, root2, home, and swap
+ echo "*** 2. Testing with root, root2, home, and swap ***"
- runas testuser tee "$defs/root.conf" <<EOF
+ tee "$defs/root.conf" <<EOF
[Partition]
Type=root
EOF
ln -s root.conf "$defs/root2.conf"
- runas testuser tee "$defs/home.conf" <<EOF
+ tee "$defs/home.conf" <<EOF
[Partition]
Type=home
Label=home-first
Label=home-always-too-long-xxxxxxxxxxxxxx-%v
EOF
- runas testuser tee "$defs/swap.conf" <<EOF
+ tee "$defs/swap.conf" <<EOF
[Partition]
Type=swap
SizeMaxBytes=64M
$imgs/zzz3 : start= 1185760, size= 591864, type=${root_guid}, uuid=${root_uuid2}, name=\"root-${architecture}-2\", attrs=\"GUID:59\"
$imgs/zzz4 : start= 1777624, size= 131072, type=0657FD6D-A4AB-43C4-84E5-0933C84B4F4F, uuid=78C92DB8-3D2B-4823-B0DC-792B78F66F1E, name=\"swap\""
- # 3. Testing with root, root2, home, swap, and another partition
+ echo "*** 3. Testing with root, root2, home, swap, and another partition ***"
- runas testuser tee "$defs/swap.conf" <<EOF
+ tee "$defs/swap.conf" <<EOF
[Partition]
Type=swap
SizeMaxBytes=64M
EOF
- runas testuser tee "$defs/extra.conf" <<EOF
+ tee "$defs/extra.conf" <<EOF
[Partition]
Type=linux-generic
Label=custom_label
$imgs/zzz4 : start= 1777624, size= 131072, type=0657FD6D-A4AB-43C4-84E5-0933C84B4F4F, uuid=78C92DB8-3D2B-4823-B0DC-792B78F66F1E, name=\"swap\"
$imgs/zzz5 : start= 1908696, size= 188416, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=A0A1A2A3-A4A5-A6A7-A8A9-AAABACADAEAF, name=\"custom_label\""
- # 4. Resizing to 2G
+ echo "*** 4. Resizing to 2G ***"
runas testuser systemd-repart --definitions="$defs" \
--size=2G \
$imgs/zzz4 : start= 1777624, size= 131072, type=0657FD6D-A4AB-43C4-84E5-0933C84B4F4F, uuid=78C92DB8-3D2B-4823-B0DC-792B78F66F1E, name=\"swap\"
$imgs/zzz5 : start= 1908696, size= 2285568, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=A0A1A2A3-A4A5-A6A7-A8A9-AAABACADAEAF, name=\"custom_label\""
- # 5. Testing with root, root2, home, swap, another partition, and partition copy
+ echo "*** 5. Testing with root, root2, home, swap, another partition, and partition copy ***"
dd if=/dev/urandom of="$imgs/block-copy" bs=4096 count=10240
- runas testuser tee "$defs/extra2.conf" <<EOF
+ tee "$defs/extra2.conf" <<EOF
[Partition]
Type=linux-generic
Label=block-copy
cmp --bytes=$((4096*10240)) --ignore-initial=0:$((512*4194264)) "$imgs/block-copy" "$imgs/zzz"
- # 6. Testing Format=/Encrypt=/CopyFiles=
+ echo "*** 6. Testing Format=/Encrypt=/CopyFiles= ***"
- runas testuser tee "$defs/extra3.conf" <<EOF
+ tee "$defs/extra3.conf" <<EOF
[Partition]
Type=linux-generic
Label=luks-format-copy
SizeMinBytes=48M
EOF
+ # CopyFiles will fail if we try to chown the target file to root.
+ # Make the files owned by the user so that the invocation below works.
+ chown testuser -R "$defs"
+
runas testuser systemd-repart --definitions="$defs" \
--size=auto \
--dry-run=no \
testcase_dropin() {
local defs imgs output
- defs="$(runas testuser mktemp --directory "/tmp/test-repart.XXXXXXXXXX")"
- imgs="$(runas testuser mktemp --directory "/var/tmp/test-repart.XXXXXXXXXX")"
+ defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")"
+ imgs="$(runas testuser mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs'" RETURN
+ chmod a+rx "$defs"
- runas testuser tee "$defs/root.conf" <<EOF
+ tee "$defs/root.conf" <<EOF
[Partition]
Type=swap
SizeMaxBytes=64M
UUID=837c3d67-21b3-478e-be82-7e7f83bf96d3
EOF
- runas testuser mkdir -p "$defs/root.conf.d"
- runas testuser tee "$defs/root.conf.d/override1.conf" <<EOF
+ mkdir -p "$defs/root.conf.d"
+ tee "$defs/root.conf.d/override1.conf" <<EOF
[Partition]
Label=label1
SizeMaxBytes=32M
EOF
- runas testuser tee "$defs/root.conf.d/override2.conf" <<EOF
+ tee "$defs/root.conf.d/override2.conf" <<EOF
[Partition]
Label=label2
EOF
testcase_multiple_definitions() {
local defs imgs output
- defs="$(runas testuser mktemp --directory "/tmp/test-repart.XXXXXXXXXX")"
- imgs="$(runas testuser mktemp --directory "/var/tmp/test-repart.XXXXXXXXXX")"
+ defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")"
+ imgs="$(runas testuser mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs'" RETURN
+ chmod a+rx "$defs"
- runas testuser mkdir -p "$defs/1"
-
- runas testuser tee "$defs/1/root1.conf" <<EOF
+ mkdir -p "$defs/1"
+ tee "$defs/1/root1.conf" <<EOF
[Partition]
Type=swap
SizeMaxBytes=32M
Label=label1
EOF
- runas testuser mkdir -p "$defs/2"
-
- runas testuser tee "$defs/2/root2.conf" <<EOF
+ mkdir -p "$defs/2"
+ tee "$defs/2/root2.conf" <<EOF
[Partition]
Type=swap
SizeMaxBytes=32M
testcase_copy_blocks() {
local defs imgs output
- defs="$(runas testuser mktemp --directory "/tmp/test-repart.XXXXXXXXXX")"
- imgs="$(runas testuser mktemp --directory "/var/tmp/test-repart.XXXXXXXXXX")"
+ defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")"
+ imgs="$(runas testuser mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs'" RETURN
+ chmod a+rx "$defs"
- # First, create a disk image and verify its in order
+ echo "*** First, create a disk image and verify its in order ***"
- runas testuser tee "$defs/esp.conf" <<EOF
+ tee "$defs/esp.conf" <<EOF
[Partition]
Type=esp
SizeMinBytes=10M
Format=vfat
EOF
- runas testuser tee "$defs/usr.conf" <<EOF
+ tee "$defs/usr.conf" <<EOF
[Partition]
Type=usr-${architecture}
SizeMinBytes=10M
ReadOnly=yes
EOF
- runas testuser tee "$defs/root.conf" <<EOF
+ tee "$defs/root.conf" <<EOF
[Partition]
Type=root-${architecture}
SizeMinBytes=10M
return
fi
- # Then, create another image with CopyBlocks=auto
+ echo "*** Second, create another image with CopyBlocks=auto ***"
- runas testuser tee "$defs/esp.conf" <<EOF
+ tee "$defs/esp.conf" <<EOF
[Partition]
Type=esp
CopyBlocks=auto
EOF
- runas testuser tee "$defs/usr.conf" <<EOF
+ tee "$defs/usr.conf" <<EOF
[Partition]
Type=usr-${architecture}
ReadOnly=yes
CopyBlocks=auto
EOF
- runas testuser tee "$defs/root.conf" <<EOF
+ tee "$defs/root.conf" <<EOF
[Partition]
Type=root-${architecture}
CopyBlocks=auto
testcase_unaligned_partition() {
local defs imgs output
- defs="$(runas testuser mktemp --directory "/tmp/test-repart.XXXXXXXXXX")"
- imgs="$(runas testuser mktemp --directory "/var/tmp/test-repart.XXXXXXXXXX")"
+ defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")"
+ imgs="$(runas testuser mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs'" RETURN
+ chmod a+rx "$defs"
- # Operate on an image with unaligned partition.
+ echo "*** Operate on an image with unaligned partition ***"
- runas testuser tee "$defs/root.conf" <<EOF
+ tee "$defs/root.conf" <<EOF
[Partition]
Type=root-${architecture}
EOF
testcase_issue_21817() {
local defs imgs output
- # testcase for #21817
-
- defs="$(runas testuser mktemp --directory "/tmp/test-repart.XXXXXXXXXX")"
- imgs="$(runas testuser mktemp --directory "/var/tmp/test-repart.XXXXXXXXXX")"
+ defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")"
+ imgs="$(runas testuser mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs'" RETURN
+ chmod a+rx "$defs"
- runas testuser tee "$defs/test.conf" <<EOF
+ echo "*** testcase for #21817 ***"
+
+ tee "$defs/test.conf" <<EOF
[Partition]
Type=root
EOF
testcase_issue_24553() {
local defs imgs output
- # testcase for #24553
-
- defs="$(runas testuser mktemp --directory "/tmp/test-repart.XXXXXXXXXX")"
- imgs="$(runas testuser mktemp --directory "/var/tmp/test-repart.XXXXXXXXXX")"
+ defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")"
+ imgs="$(runas testuser mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs'" RETURN
+ chmod a+rx "$defs"
+
+ echo "*** testcase for #24553 ***"
- runas testuser tee "$defs/root.conf" <<EOF
+ tee "$defs/root.conf" <<EOF
[Partition]
Type=root
SizeMinBytes=10G
SizeMaxBytes=120G
EOF
- runas testuser tee "$imgs/partscript" <<EOF
+ tee "$imgs/partscript" <<EOF
label: gpt
label-id: C9FFE979-A415-C449-B729-78C7AA664B10
unit: sectors
start=524328, size=14848000, type=${root_guid}, uuid=${root_uuid}, name="root-${architecture}"
EOF
- # 1. Operate on a small image compared with SizeMinBytes=.
+ echo "*** 1. Operate on a small image compared with SizeMinBytes= ***"
runas testuser truncate -s 8g "$imgs/zzz"
sfdisk "$imgs/zzz" <"$imgs/partscript"
output=$(sfdisk --dump "$imgs/zzz")
assert_in "$imgs/zzz2 : start= 524328, size= 14848000, type=${root_guid}, uuid=${root_uuid}, name=\"root-${architecture}\"" "$output"
- # 2. Operate on an larger image compared with SizeMinBytes=.
+ echo "*** 2. Operate on an larger image compared with SizeMinBytes= ***"
rm -f "$imgs/zzz"
runas testuser truncate -s 12g "$imgs/zzz"
sfdisk "$imgs/zzz" <"$imgs/partscript"
output=$(sfdisk --dump "$imgs/zzz")
assert_in "$imgs/zzz2 : start= 524328, size= 24641456, type=${root_guid}, uuid=${root_uuid}, name=\"root-${architecture}\"" "$output"
- # 3. Multiple partitions with Priority= (small disk)
- runas testuser tee "$defs/root.conf" <<EOF
+ echo "*** 3. Multiple partitions with Priority= (small disk) ***"
+ tee "$defs/root.conf" <<EOF
[Partition]
Type=root
SizeMinBytes=10G
Priority=100
EOF
- runas testuser tee "$defs/usr.conf" <<EOF
+ tee "$defs/usr.conf" <<EOF
[Partition]
Type=usr
SizeMinBytes=10M
assert_in "$imgs/zzz2 : start= 524328, size= 14848000, type=${root_guid}, uuid=${root_uuid}, name=\"root-${architecture}\"" "$output"
assert_in "$imgs/zzz3 : start= 15372328, size= 1404848, type=${usr_guid}, uuid=${usr_uuid}, name=\"usr-${architecture}\", attrs=\"GUID:59\"" "$output"
- # 4. Multiple partitions with Priority= (large disk)
+ echo "*** 4. Multiple partitions with Priority= (large disk) ***"
rm -f "$imgs/zzz"
runas testuser truncate -s 12g "$imgs/zzz"
sfdisk "$imgs/zzz" <"$imgs/partscript"
testcase_zero_uuid() {
local defs imgs output
- defs="$(runas testuser mktemp --directory "/tmp/test-repart.XXXXXXXXXX")"
- imgs="$(runas testuser mktemp --directory "/var/tmp/test-repart.XXXXXXXXXX")"
+ defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")"
+ imgs="$(runas testuser mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs'" RETURN
+ chmod a+rx "$defs"
- # Test image with zero UUID.
+ echo "*** Test image with zero UUID ***"
- runas testuser tee "$defs/root.conf" <<EOF
+ tee "$defs/root.conf" <<EOF
[Partition]
Type=root-${architecture}
UUID=null
testcase_verity() {
local defs imgs output
- defs="$(runas testuser mktemp --directory "/tmp/test-repart.XXXXXXXXXX")"
- imgs="$(runas testuser mktemp --directory "/var/tmp/test-repart.XXXXXXXXXX")"
+ defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")"
+ imgs="$(runas testuser mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs'" RETURN
+ chmod a+rx "$defs"
- runas testuser tee "$defs/verity-data.conf" <<EOF
+ echo "*** dm-verity ***"
+
+ tee "$defs/verity-data.conf" <<EOF
[Partition]
Type=root-${architecture}
CopyFiles=${defs}
Minimize=guess
EOF
- runas testuser tee "$defs/verity-hash.conf" <<EOF
+ tee "$defs/verity-hash.conf" <<EOF
[Partition]
Type=root-${architecture}-verity
Verity=hash
Minimize=yes
EOF
- runas testuser tee "$defs/verity-sig.conf" <<EOF
+ tee "$defs/verity-sig.conf" <<EOF
[Partition]
Type=root-${architecture}-verity-sig
Verity=signature
EOF
# Unfortunately OpenSSL insists on reading some config file, hence provide one with mostly placeholder contents
- runas testuser tee >"$defs/verity.openssl.cnf" <<EOF
+ tee >"$defs/verity.openssl.cnf" <<EOF
[ req ]
prompt = no
distinguished_name = req_distinguished_name
emailAddress = test@email.com
EOF
- runas testuser openssl req -config "$defs/verity.openssl.cnf" \
- -new -x509 \
- -newkey rsa:1024 \
- -keyout "$defs/verity.key" \
- -out "$defs/verity.crt" \
- -days 365 \
- -nodes
+ openssl req \
+ -config "$defs/verity.openssl.cnf" \
+ -new -x509 \
+ -newkey rsa:1024 \
+ -keyout "$defs/verity.key" \
+ -out "$defs/verity.crt" \
+ -days 365 \
+ -nodes
mkdir -p /run/verity.d
ln -s "$defs/verity.crt" /run/verity.d/ok.crt
+ # CopyFiles will fail if we try to chown the target file to root.
+ # Make the files owned by the user so that the invocation below works.
+ chown testuser -R "$defs"
+
output=$(runas testuser systemd-repart --definitions="$defs" \
--seed="$seed" \
--dry-run=no \
--certificate="$defs/verity.crt" \
"$imgs/verity")
- drh=$(jq -r ".[] | select(.type == \"root-${architecture}\") | .roothash" <<< "$output")
- hrh=$(jq -r ".[] | select(.type == \"root-${architecture}-verity\") | .roothash" <<< "$output")
- srh=$(jq -r ".[] | select(.type == \"root-${architecture}-verity-sig\") | .roothash" <<< "$output")
+ drh=$(jq -r ".[] | select(.type == \"root-${architecture}\") | .roothash" <<<"$output")
+ hrh=$(jq -r ".[] | select(.type == \"root-${architecture}-verity\") | .roothash" <<<"$output")
+ srh=$(jq -r ".[] | select(.type == \"root-${architecture}-verity-sig\") | .roothash" <<<"$output")
assert_eq "$drh" "$hrh"
assert_eq "$hrh" "$srh"
testcase_exclude_files() {
local defs imgs root output
- defs="$(runas testuser mktemp --directory "/tmp/test-repart.XXXXXXXXXX")"
- imgs="$(runas testuser mktemp --directory "/var/tmp/test-repart.XXXXXXXXXX")"
- root="$(runas testuser mktemp --directory "/var/tmp/test-repart.XXXXXXXXXX")"
+ defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")"
+ imgs="$(runas testuser mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
+ root="$(runas testuser mktemp --directory "/var/tmp/test-repart.root.XXXXXXXXXX")"
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs' '$root'" RETURN
-
- runas testuser touch "$root/abc"
- runas testuser mkdir "$root/usr"
- runas testuser touch "$root/usr/def"
- runas testuser touch "$root/usr/qed"
- runas testuser mkdir "$root/tmp"
- runas testuser touch "$root/tmp/prs"
- runas testuser mkdir "$root/proc"
- runas testuser touch "$root/proc/prs"
- runas testuser mkdir "$root/zzz"
- runas testuser mkdir "$root/zzz/usr"
- runas testuser touch "$root/zzz/usr/prs"
- runas testuser mkdir "$root/zzz/proc"
- runas testuser touch "$root/zzz/proc/prs"
-
- runas testuser tee "$defs/00-root.conf" <<EOF
+ chmod a+rx "$defs"
+
+ echo "*** file exclusion ***"
+
+ touch "$root/abc"
+ mkdir "$root/usr"
+ touch "$root/usr/def"
+ touch "$root/usr/qed"
+ mkdir "$root/tmp"
+ touch "$root/tmp/prs"
+ mkdir "$root/proc"
+ touch "$root/proc/prs"
+ mkdir "$root/zzz"
+ mkdir "$root/zzz/usr"
+ touch "$root/zzz/usr/prs"
+ mkdir "$root/zzz/proc"
+ touch "$root/zzz/proc/prs"
+
+ tee "$defs/00-root.conf" <<EOF
[Partition]
Type=root-${architecture}
CopyFiles=/
CopyFiles=/zzz:/
+CopyFiles=/:/oiu
+ExcludeFilesTarget=/oiu/usr
EOF
- runas testuser tee "$defs/10-usr.conf" <<EOF
+ tee "$defs/10-usr.conf" <<EOF
[Partition]
Type=usr-${architecture}
CopyFiles=/usr:/
ExcludeFiles=/usr/qed
EOF
+ # CopyFiles will fail if we try to chown the target file to root.
+ # Make the files owned by the user so that the invocation below works.
+ chown testuser -R "$root"
+
output=$(runas testuser systemd-repart --definitions="$defs" \
--seed="$seed" \
--dry-run=no \
# Test that /zzz/usr/prs did not end up in the usr partition.
assert_rc 2 ls "$imgs/mnt/usr/prs"
+ # Test that /oiu/ and /oiu/zzz ended up in the root partition but /oiu/usr did not.
+ assert_rc 0 ls "$imgs/mnt/oiu"
+ assert_rc 0 ls "$imgs/mnt/oiu/zzz"
+ assert_rc 2 ls "$imgs/mnt/oiu/usr"
+
umount -R "$imgs/mnt"
losetup -d "$loop"
}
return
fi
- defs="$(mktemp --directory "/tmp/test-repart.XXXXXXXXXX")"
- imgs="$(mktemp --directory "/var/tmp/test-repart.XXXXXXXXXX")"
+ echo "*** minimization ***"
+
+ defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")"
+ imgs="$(mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs'" RETURN
return
fi
- defs="$(mktemp --directory "/tmp/test-repart.XXXXXXXXXX")"
- imgs="$(mktemp --directory "/var/tmp/test-repart.XXXXXXXXXX")"
+ echo "*** sector sizes ***"
+
+ defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")"
+ imgs="$(mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs'" RETURN
# See tmpfiles.d(5) for details
-d /etc/credstore 0000 root root
-d /etc/credstore.encrypted 0000 root root
-z /run/credstore 0000 root root
-z /run/credstore.encrypted 0000 root root
+d /etc/credstore 0700 root root
+d /etc/credstore.encrypted 0700 root root
+z /run/credstore 0700 root root
+z /run/credstore.encrypted 0700 root root