- libp11-kit-dev
- libssl-dev
- python3-jinja2
+ after_prepare:
+ - pip3 install meson==0.53.2
+ - export PATH="/opt/work/.local/bin:$PATH"
python:
python_setup:
version: 3
targets:
- fedora-rawhide-aarch64
- fedora-rawhide-i386
+ - fedora-rawhide-ppc64le
- fedora-rawhide-x86_64
python-jinja2
python-lxml (optional, required to build the indices)
python >= 3.5
- meson >= 0.46 (>= 0.49 is required to build position-independent executables)
+ meson >= 0.47 (>= 0.49 is required to build position-independent executables)
ninja
gcc, awk, sed, grep, and similar tools
clang >= 10.0, llvm >= 10.0 (optional, required to build BPF programs
Features:
+* use credentials logic/TPM2 logic to store homed signing key
+
* New udev block device symlink names:
/dev/disk/by-parttypelabel/<pttype>/<ptlabel>. Use case: if pt label is used
as partition image version string, this is a safe way to reference a specific
* pid1: support new clone3() fork-into-cgroup feature
+* pid1: support new cgroup.kill to terminate all processes in a cgroup
+
* pid1: also remove PID files of a service when the service starts, not just
when it exits
https://docs.microsoft.com/en-us/windows-hardware/design/device-experiences/modern-standby-wake-sources
at the end).
-* We should probably replace /var/log/README, /etc/rc.d/README with symlinks
- that are linked to these places instead of copied. After all they are
- constant vendor data.
+* We should probably replace /etc/rc.d/README with a symlink to doc
+ content. After all it is constant vendor data.
* maybe add kernel cmdline params: to force random seed crediting
* paranoia: whenever we process passwords, call mlock() on the memory
first. i.e. look for all places we use free_and_erasep() and
augment them with mlock(). Also use MADV_DONTDUMP.
+ Alternatively (preferably?) use memfd_secret().
* Move RestrictAddressFamily= to the new cgroup create socket
* bootctl,sd-boot: actually honour the "architecture" key
-* sd-boot: add service that automatically runs "bootctl update" on every boot,
- in a graceful way, so that updated /usr trees automatically propagate into
- updated boot loaders on reboot.
-
* 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
- introduce API for "making room", that grows/shrinks home directory
according to elastic parameters, discards blocks, and removes additional snapshots. Call it
either from UI when disk space gets low
+ - when homed is in use, maybe start the user session manager in a mount namespace with MS_SLAVE,
+ so that mounts propagate down but not up - eg, user A setting up a backup volume
+ doesn't mean user B sees it
* homed: during login resize fs automatically towards size goal. Specifically,
resize to diskSize if possible, but leave a certain amount (configured by a
* `1 << 6` → The boot loader supports passing a random seed to the OS.
* The EFI variable `LoaderRandomSeed` contains a binary random seed if set. It
- is set by the boot loader to pass an entropy seed read from the ESP partition
- to the OS. The system manager then credits this seed to the kernel's entropy
- pool. It is the responsibility of the boot loader to ensure the quality and
- integrity of the random seed.
+ is set by the boot loader to pass an entropy seed read from the ESP to the OS.
+ The system manager then credits this seed to the kernel's entropy pool. It is
+ the responsibility of the boot loader to ensure the quality and integrity of
+ the random seed.
* The EFI variable `LoaderSystemToken` contains binary random data,
persistently set by the OS installer. Boot loaders that support passing
* On disks with GPT (GUID Partition Table)
* If the OS is installed on a disk with GPT, and an Extended Boot Loader Partition or XBOOTLDR partition for short, i.e. a partition with GPT type GUID of `bc13c2ff-59e6-4262-a352-b275fd6f7172`, already exists, it should be used as `$BOOT`.
* Otherwise, if the OS is installed on a disk with GPT, and an EFI System Partition or ESP for short, i.e. a partition with GPT type UID of `c12a7328-f81f-11d2-ba4b-00a0c93ec93b`) already exists and is large enough (let's say 250MB) and otherwise qualifies, it should be used as `$BOOT`.
- * Otherwise, if the OS is installed on a disk with GPT, and if the ESP partition already exists but is too small, a new suitably sized (let's say 500MB) XBOOTLDR partition shall be created and used as `$BOOT`.
- * Otherwise, if the OS is installed on a disk with GPT, and no ESP partition exists yet, a new suitably sized (let's say 500MB) ESP should be created and used as `$BOOT`.
+ * Otherwise, if the OS is installed on a disk with GPT, and if the ESP already exists but is too small, a new suitably sized (let's say 500MB) XBOOTLDR partition shall be created and used as `$BOOT`.
+ * Otherwise, if the OS is installed on a disk with GPT, and no ESP exists yet, a new suitably sized (let's say 500MB) ESP should be created and used as `$BOOT`.
This placeholder file system shall be determined during _installation time_, and an fstab entry may be created. It should be mounted to either `/boot/` or `/efi/`. Additional locations like `/boot/efi/`, with `/boot/` being a separate file system, might be supported by implementations. This is not recommended because the mounting of `$BOOT` is then dependent on and requires the mounting of the intermediate file system.
| `69dad710-2ce4-4e3c-b16c-21a1d49abed3` | _Root Partition (32-bit ARM)_ | ditto | ditto |
| `b921b045-1df0-41c3-af44-4c6f280d3fae` | _Root Partition (64-bit ARM/AArch64)_ | ditto | ditto |
| `993d8d3d-f80e-4225-855a-9daf8ed7ea97` | _Root Partition (Itanium/IA-64)_ | ditto | ditto |
+| `77055800-792c-4f94-b39a-98c91b762bb6` | _Root Partition (LoongArch 64-bit)_ | ditto | ditto |
| `60d5a7fe-8e7d-435c-b714-3dd8162144e1` | _Root Partition (RISC-V 32-bit)_ | ditto | ditto |
| `72ec70a6-cf74-40e6-bd49-4bda08e8f224` | _Root Partition (RISC-V 64-bit)_ | ditto | ditto |
| `d13c5d3b-b5d1-422a-b29f-9454fdc89d76` | _Root Verity Partition (x86)_ | A dm-verity superblock followed by hash data | On systems with matching architecture, contains dm-verity integrity hash data for the matching root partition. If this feature is used the partition UUID of the root partition should be the first 128bit of the root hash of the dm-verity hash data, and the partition UUID of this dm-verity partition should be the final 128bit of it, so that the root partition and its verity partition can be discovered easily, simply by specifying the root hash. |
| `7386cdf2-203c-47a9-a498-f2ecce45a2d6` | _Root Verity Partition (32-bit ARM)_ | ditto | ditto |
| `df3300ce-d69f-4c92-978c-9bfb0f38d820` | _Root Verity Partition (64-bit ARM/AArch64)_ | ditto | ditto |
| `86ed10d5-b607-45bb-8957-d350f23d0571` | _Root Verity Partition (Itanium/IA-64)_ | ditto | ditto |
+| `f3393b22-e9af-4613-a948-9d3bfbd0c535` | _Root Verity Partition (LoongArch 64-bit)_ | ditto | ditto |
| `ae0253be-1167-4007-ac68-43926c14c5de` | _Root Verity Partition (RISC-V 32-bit)_ | ditto | ditto |
| `b6ed5582-440b-4209-b8da-5ff7c419ea3d` | _Root Verity Partition (RISC-V 64-bit)_ | ditto | ditto |
| `75250d76-8cc6-458e-bd66-bd47cc81a812` | _`/usr/` Partition (x86)_ | Any native, optionally in LUKS | Similar semantics to root partition, but just the `/usr/` partition. |
| `7d0359a3-02b3-4f0a-865c-654403e70625` | _`/usr/` Partition (32-bit ARM)_ | ditto | ditto |
| `b0e01050-ee5f-4390-949a-9101b17104e9` | _`/usr/` Partition (64-bit ARM/AArch64)_ | ditto | ditto |
| `4301d2a6-4e3b-4b2a-bb94-9e0b2c4225ea` | _`/usr/` Partition (Itanium/IA-64)_ | ditto | ditto |
+| `e611c702-575c-4cbe-9a46-434fa0bf7e3f` | _`/usr/` Partition (LoongArch 64-bit)_ | ditto | ditto |
| `b933fb22-5c3f-4f91-af90-e2bb0fa50702` | _`/usr/` Partition (RISC-V 32-bit)_ | ditto | ditto |
| `beaec34b-8442-439b-a40b-984381ed097d` | _`/usr/` Partition (RISC-V 64-bit)_ | ditto | ditto |
| `8f461b0d-14ee-4e81-9aa9-049b6fb97abd` | _`/usr/` Verity Partition (x86)_ | A dm-verity superblock followed by hash data | Similar semantics to root Verity partition, but just for the `/usr/` partition. |
| `c215d751-7bcd-4649-be90-6627490a4c05` | _`/usr/` Verity Partition (32-bit ARM)_ | ditto | ditto |
| `6e11a4e7-fbca-4ded-b9e9-e1a512bb664e` | _`/usr/` Verity Partition (64-bit ARM/AArch64)_ | ditto | ditto |
| `6a491e03-3be7-4545-8e38-83320e0ea880` | _`/usr/` Verity Partition (Itanium/IA-64)_ | ditto | ditto |
+| `f46b2c26-59ae-48f0-9106-c50ed47f673d` | _`/usr/` Verity Partition (LoongArch 64-bit)_ | ditto | ditto |
| `cb1ee4e3-8cd0-4136-a0a4-aa61a32e8730` | _`/usr/` Verity Partition (RISC-V 32-bit)_ | ditto | ditto |
| `8f1056be-9b05-47c4-81d6-be53128e5b54` | _`/usr/` Verity Partition (RISC-V 64-bit)_ | ditto | ditto |
| `933ac7e1-2eb4-4f13-b844-0e14e2aef915` | _Home Partition_ | Any native, optionally in LUKS | The first partition with this type UUID on the disk containing the root partition is automatically mounted to `/home/`. If the partition is encrypted with LUKS, the device mapper file will be named `/dev/mapper/home`. |
mentioned in the specifications. We are simply trying to make the boot and
installation processes of Linux a bit more robust and self-descriptive.
-### Why did you only define the root partition for x86, x86-64, ARM, ARM64, ia64, riscv32, riscv64?
+### Why did you only define the root partition for these listed architectures?
The automatic discovery of the root partition is defined to operate on the disk
containing the current EFI System Partition (ESP). Since EFI only exists on
-x86, x86-64, ia64, ARM and RISC-V so far, we only defined root partition UUIDs for
-these architectures. Should EFI become more common on other architectures, we
-can define additional UUIDs for them.
+x86, x86-64, ia64, ARM, LoongArch and RISC-V so far, we only defined root
+partition UUIDs for these architectures. Should EFI become more common on
+other architectures, we can define additional UUIDs for them.
### Why define distinct root partition UUIDs for the various architectures?
# SPDX-License-Identifier: LGPL-2.1-or-later
if conf.get('HAVE_SYSV_COMPAT') == 1 and get_option('create-log-dirs')
- install_data('README',
- install_dir : '/var/log')
+ install_data('README.logs',
+ install_dir : docdir)
endif
# Keymaps MSI Prestige And MSI Modern FnKeys and Special keys
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*Prestige*:*
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*Modern*:*
- KEYBOARD_KEY_56=backslash # Secondary backslash key
KEYBOARD_KEY_f1=f20 # Fn+F5 Micmute
KEYBOARD_KEY_76=f21 # Fn+F4 Toggle touchpad, sends meta+ctrl+toggle
KEYBOARD_KEY_91=prog1 # Fn+F7 Creation Center, sometime F7
sensor:modalias:platform:HID-SENSOR-200073:dmi:*svnDell*:pnVostro5581:*
ACCEL_LOCATION=base
-sensor:modalias:platform:HID-SENSOR-200073:dmi:*svnDell*:pnLatitude9520:*:ct10:*
+sensor:modalias:platform:HID-SENSOR-200073:dmi:*svnDell*:sku0A3E:*
ACCEL_LOCATION=base
-sensor:modalias:platform:HID-SENSOR-200073:dmi:*svnDell*:pnLatitude7420:*
+sensor:modalias:platform:HID-SENSOR-200073:dmi:*svnDell*:sku0B0B:*
ACCEL_LOCATION=base
# Dell Venue 8 Pro 3845
sensor:modalias:acpi:KIOX000A*:dmi:*:svnTREKSTOR*:pnPrimetabS11B:*
sensor:modalias:acpi:KIOX000A*:dmi:*:svnTREKSTOR:pnPrimetabT13B:*
sensor:modalias:acpi:BOSC0200*:dmi:*:svnTrekStor*:pnSurfTabtwin11.6:*
+sensor:modalias:acpi:BOSC0200*:dmi:*:svnTrekStor*:pnSurfTabduoW110.1(VT4):*
ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
# alternative version of Trekstor's SurfTab Twin 11.6
if install_sysconfdir
meson.add_install_script('sh', '-c',
- mkdir_p.format(join_paths(sysconfdir, 'udev/hwdb.d')))
+ mkdir_p.format(sysconfdir / 'udev/hwdb.d'))
meson.add_install_script('sh', '-c',
'test -n "$DESTDIR" || @0@/systemd-hwdb update'.format(rootbindir))
<varlistentry>
<term><option>--graceful</option></term>
- <listitem><para>Ignore failure when the EFI System Partition cannot be found, or when EFI variables
- cannot be written. Currently only applies to random seed operations.</para></listitem>
+ <listitem><para>Ignore failure when the EFI System Partition cannot be found, when EFI variables
+ cannot be written, or a different or newer boot loader is already installed. Currently only applies
+ to random seed and update operations.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--make-machine-id-directory=yes|no|auto</option></term>
<listitem><para>Control creation and deletion of the top-level machine ID directory on the file
- system containing boot loader entries (i.e. beneath the file system returned by
- <option>--print-boot-path</option> above) during <option>install</option> and
+ system containing boot loader entries (i.e. beneath the file system returned by the
+ <option>--print-boot-path</option> option, see above) during <option>install</option> and
<option>remove</option>, respectively. <literal>auto</literal> is equivalent to
<literal>yes</literal> if <filename>/etc/machine-id</filename> resides on a filesystem other than
tmpfs and <literal>no</literal> otherwise (in the latter case the machine ID is likely transient and
<varlistentry>
<term><varname>ProcessSizeMax=</varname></term>
- <listitem><para>The maximum size in bytes of a core
- which will be processed. Core dumps exceeding this size
- may be stored, but the backtrace will not be generated.
- Like other sizes in this same config file, the usual
- suffixes to the base of 1024 are allowed (B, K, M,
- G, T, P, and E.)</para>
+ <listitem><para>The maximum size in bytes of a core which will be processed. Core dumps exceeding
+ this size may be stored, but the backtrace will not be generated. Like other sizes in this same
+ config file, the usual suffixes to the base of 1024 are allowed (B, K, M, G, T, P, and E).</para>
<para>Setting <varname>Storage=none</varname> and <varname>ProcessSizeMax=0</varname>
disables all coredump handling except for a log entry.</para>
<term><varname>ExternalSizeMax=</varname></term>
<term><varname>JournalSizeMax=</varname></term>
- <listitem><para>The maximum (compressed or uncompressed) size in bytes of a
- core to be saved. Unit suffixes are allowed just as in
- <option>ProcessSizeMax=</option></para></listitem>.
+ <listitem><para>The maximum (compressed or uncompressed) size in bytes of a core to be saved. Unit
+ suffixes are allowed just as in <option>ProcessSizeMax=</option>.</para></listitem>
</varlistentry>
<varlistentry>
by core dumps might temporarily exceed these limits while
core dumps are processed. Note that old core dumps are also
removed based on time via
- <citerefentry><refentrytitle>systemd-tmpfiles</refentrytitle><manvolnum>8</manvolnum></citerefentry>. Set
- either value to 0 to turn off size-based
- clean-up.</para></listitem>
+ <citerefentry><refentrytitle>systemd-tmpfiles</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
+ Set either value to 0 to turn off size-based cleanup.</para></listitem>
</varlistentry>
</variablelist>
<term><option>-1</option></term>
<listitem><para>Show information of the most recent core dump only, instead of listing all known core
- dumps. (Equivalent to <option>--reverse -n 1</option></para></listitem>
+ dumps. Equivalent to <option>--reverse -n 1</option>.</para></listitem>
</varlistentry>
<varlistentry>
<ulink url="https://tools.ietf.org/html/rfc1035#section-5">RFC 1035, Section 5</ulink>. One <constant
class='dns'>DS</constant> or <constant class='dns'>DNSKEY</constant> resource record may be listed per
line. Empty lines and lines starting with <literal>#</literal> or <literal>;</literal> are ignored, which
- may be used for commenting. A <consant class='dns'>DS</consant> resource record is specified like in the
+ may be used for commenting. A <constant class='dns'>DS</constant> resource record is specified like in the
following example:</para>
<programlisting>. IN DS 19036 8 2 49aac11d7b6f6446702e54a1607371607a1a41855200fd2ce1cdde32f24e8fb5</programlisting>
html_pages = []
source_xml_files = []
dbus_docs = []
-foreach tuple : xsltproc.found() ? manpages : []
+foreach tuple : manpages
stem = tuple[0]
section = tuple[1]
aliases = tuple[2]
htmlaliases += alias + '.html'
endforeach
- mandirn = join_paths(get_option('mandir'), 'man' + section)
+ mandirn = get_option('mandir') / ('man' + section)
if condition == '' or conf.get(condition) == 1
- p1 = custom_target(
- man,
- input : xml,
- output : [man] + manaliases,
- command : xslt_cmd + [custom_man_xsl, '@INPUT@'],
- depends : custom_entities_ent,
- install : want_man,
- install_dir : mandirn)
- man_pages += p1
-
- p2 = []
- foreach htmlalias : htmlaliases
- link = custom_target(
- htmlalias,
- output : htmlalias,
- command : [ln, '-fs', html, '@OUTPUT@'])
- if want_html
- dst = join_paths(docdir, 'html', htmlalias)
- cmd = 'ln -fs @0@ $DESTDIR@1@'.format(html, dst)
- meson.add_install_script('sh', '-c', cmd)
- p2 += link
- endif
- html_pages += link
- endforeach
-
- p3 = custom_target(
- html,
- input : xml,
- output : html,
- command : xslt_cmd + [custom_html_xsl, '@INPUT@'],
- depends : [custom_entities_ent, p2],
- install : want_html,
- install_dir : join_paths(docdir, 'html'))
- html_pages += p3
-
file = files(tuple[0] + '.xml')
- source_xml_files += file
if tuple[0].startswith('org.freedesktop.')
dbus_docs += file
endif
+
+ if xsltproc.found()
+ p1 = custom_target(
+ man,
+ input : xml,
+ output : [man] + manaliases,
+ command : xslt_cmd + [custom_man_xsl, '@INPUT@'],
+ depends : custom_entities_ent,
+ install : want_man,
+ install_dir : mandirn)
+ man_pages += p1
+
+ p2 = []
+ foreach htmlalias : htmlaliases
+ link = custom_target(
+ htmlalias,
+ output : htmlalias,
+ command : [ln, '-fs', html, '@OUTPUT@'])
+ if want_html
+ dst = docdir / 'html' / htmlalias
+ cmd = 'ln -fs @0@ $DESTDIR@1@'.format(html, dst)
+ meson.add_install_script('sh', '-c', cmd)
+ p2 += link
+ endif
+ html_pages += link
+ endforeach
+
+ p3 = custom_target(
+ html,
+ input : xml,
+ output : html,
+ command : xslt_cmd + [custom_html_xsl, '@INPUT@'],
+ depends : [custom_entities_ent, p2],
+ install : want_html,
+ install_dir : docdir / 'html')
+ html_pages += p3
+ endif
else
message('Skipping @0@.@1@ because @2@ is false'.format(stem, section, condition))
endif
html = stem + '.html'
man = stem + '.' + section
- mandirn = join_paths(get_option('mandir'), 'man' + section)
+ mandirn = get_option('mandir') / ('man' + section)
p1 = custom_target(
man,
output : htmlalias,
command : [ln, '-fs', html, '@OUTPUT@'])
if want_html
- dst = join_paths(docdir, 'html', htmlalias)
+ dst = docdir / 'html' / htmlalias
cmd = 'ln -fs @0@ $DESTDIR@1@'.format(html, dst)
meson.add_install_script('sh', '-c', cmd)
p2 += link
command : xslt_cmd + [custom_html_xsl, '@INPUT@'],
depends : [custom_entities_ent, p2],
install : want_html and have_lxml,
- install_dir : join_paths(docdir, 'html'))
+ install_dir : docdir / 'html')
html_pages += p3
endforeach
input : 'html.in',
output : 'html',
configuration : buildroot_substs)
+
+############################################################
+
+update_dbus_docs = custom_target(
+ 'update-dbus-docs',
+ output : 'update-dbus-docs',
+ command : [update_dbus_docs_py, '--build-dir', project_build_root, '@INPUT@'],
+ input : dbus_docs)
+
+if conf.get('BUILD_MODE_DEVELOPER') == 1
+ test('dbus-docs-fresh',
+ update_dbus_docs_py,
+ args : ['--build-dir', project_build_root, '--test', dbus_docs])
+endif
+
+update_man_rules = custom_target(
+ 'update-man-rules',
+ output : 'update-man-rules',
+ command : [sh, '-c',
+ 'cd @0@ && '.format(project_build_root) +
+ 'python3 @0@/tools/update-man-rules.py $(find @0@ -wholename "*/man/*.xml") >t && '.format(project_source_root) +
+ 'mv t @0@/rules/meson.build'.format(meson.current_source_dir())],
+ depends : custom_entities_ent)
<para>To activate the NSS modules, add <literal>myhostname</literal> to the line starting with
<literal>hosts:</literal> in <filename>/etc/nsswitch.conf</filename>.</para>
- <para>It is recommended to place <literal>myhostname</literal> either between <literal>resolve</literal>
- and "traditional" modules like <literal>dns</literal>, or after them. In the first version, well-known
- names like <literal>localhost</literal> and the machine hostname are given higher priority than the
- external configuration. This is recommended when the external DNS servers and network are not absolutely
- trusted. In the second version, external configuration is given higher priority and
- <command>nss-myhostname</command> only provides a fallback mechanism. This might be suitable in closely
- controlled networks, for example on a company LAN.</para>
+ <para>It is recommended to place <literal>myhostname</literal> after <literal>file</literal> and before <literal>dns</literal>.
+ This resolves well-known hostnames like <literal>localhost</literal>
+ and the machine hostnames locally. It is consistent with the behaviour
+ of <command>nss-resolve</command>, and still allows overriding via
+ <filename>/etc/hosts</filename>.</para>
+
+ <para>Please keep in mind that <command>nss-myhostname</command> (and <command>nss-resolve</command>) also resolve
+ in the other direction — from locally attached IP adresses to
+ hostnames. If you rely on that lookup being provided by DNS, you might
+ want to order things differently.
+ </para>
</refsect1>
<refsect1>
gshadow: files systemd
-# Either (untrusted network, see above):
hosts: mymachines resolve [!UNAVAIL=return] files <command>myhostname</command> dns
-# Or (only trusted networks):
-hosts: mymachines resolve [!UNAVAIL=return] files dns <command>myhostname</command>
networks: files
protocols: db files
it is still recommended (see examples below) to keep <command>nss-myhostname</command> configured in
<filename>/etc/nsswitch.conf</filename>, to keep those names resolveable if
<command>systemd-resolved</command> is not running.</para>
+
+ <para>Please keep in mind that <command>nss-myhostname</command> (and <command>nss-resolve</command>) also resolve
+ in the other direction — from locally attached IP adresses to
+ hostnames. If you rely on that lookup being provided by DNS, you might
+ want to order things differently.
+ </para>
</refsect1>
<refsect1>
<para>This is a simple mechanism to provide static user and group records via JSON drop-in files. Such
user records should be defined in the format described by the <ulink
- url="https://systemd.io/USER_RECORD">JSON User Record</ulink> specification and be placed in one of the
+ url="https://systemd.io/USER_RECORD">JSON User Records</ulink> specification and be placed in one of the
aforementioned directories under a file name composed of the user name suffixed with
<filename>.user</filename>, with a world-readable access mode. A symlink named after the user record's
UID formatted in decimal and suffixed with <filename>.user</filename> pointing to the primary record file
<listitem><para>A lower-case string (mostly numeric, no spaces or other characters outside of 0–9,
a–z, ".", "_" and "-") identifying the operating system extensions support level, to indicate which
- extension images are supported. See:
+ extension images are supported. See
<citerefentry><refentrytitle>systemd-sysext</refentrytitle><manvolnum>8</manvolnum></citerefentry>)
for more information.</para>
and hence the systemd control group hierarchy.</para>
<para>The module also applies various resource management and runtime parameters to the new session, as
- configured in the <ulink url="https://systemd.io/USER_RECORD">JSON User Record</ulink> of the user, when
+ configured in the <ulink url="https://systemd.io/USER_RECORD">JSON User Records</ulink> of the user, when
one is defined.</para>
<para>On login, this module — in conjunction with <filename>systemd-logind.service</filename> — ensures the
<entry>Verity data for the ia64 root file system partition</entry>
</row>
+ <row>
+ <entry><constant>root-loongarch64</constant></entry>
+ <entry>Root file system partition for the LoongArch 64-bit architecture</entry>
+ </row>
+
+ <row>
+ <entry><constant>root-loongarch64-verity</constant></entry>
+ <entry>Verity data for the LoongArch 64-bit root file system partition</entry>
+ </row>
+
<row>
<entry><constant>root-riscv32</constant></entry>
<entry>Root file system partition for the RISC-V 32-bit architecture</entry>
<entry>Verity data for the ia64 <filename>/usr/</filename> file system partition</entry>
</row>
+ <row>
+ <entry><constant>usr-loongarch64</constant></entry>
+ <entry><filename>/usr/</filename> file system partition for the LoongArch 64-bit architecture</entry>
+ </row>
+
+ <row>
+ <entry><constant>usr-loongarch64-verity</constant></entry>
+ <entry>Verity data for the LoongArch 64-bit <filename>/usr/</filename> file system partition</entry>
+ </row>
+
<row>
<entry><constant>usr-riscv32</constant></entry>
<entry><filename>/usr/</filename> file system partition for the RISC-V 32-bit architecture</entry>
<para>If the special value <literal>auto</literal> is specified, the source to copy from is
automatically picked up from the running system (or the image specified with
<option>--image=</option> — if used). A partition that matches both the configured partition type (as
- declared with <varname>Type=</varname> above), and the currently mounted directory appropriate for
- that partition type is determined. For example, if the partition type is set to
+ declared with <varname>Type=</varname> described above), and the currently mounted directory
+ appropriate for that partition type is determined. For example, if the partition type is set to
<literal>root</literal> the partition backing the root directory (<filename>/</filename>) is used as
source to copy from — if its partition type is set to <literal>root</literal> as well. If the
declared type is <literal>usr</literal> the partition backing <filename>/usr/</filename> is used as
<varlistentry>
<term><varname>MakeDirectories=</varname></term>
- <listitem><para>akes one or more absolute paths, separated by whitespace, each declaring a directory
+ <listitem><para>Takes one or more absolute paths, separated by whitespace, each declaring a directory
to create within the new file system. Behaviour is similar to <varname>CopyFiles=</varname>, but
instead of copying in a set of files this just creates the specified directories with the default
mode of 0755 owned by the root user and group, plus all their parent directories (with the same
are copied in or the file system configured with <varname>Format=</varname> is created.</para>
<para>The LUKS2 UUID is automatically derived from the partition UUID in a stable fashion. If
- <literal>key-file</literal> or <literal>key-file+tpm2</literal> is used a key is added to the LUKS2
- superblock, configurable with the <option>--key-file=</option> switch to
+ <literal>key-file</literal> or <literal>key-file+tpm2</literal> is used, a key is added to the LUKS2
+ superblock, configurable with the <option>--key-file=</option> option to
<command>systemd-repart</command>. If <literal>tpm2</literal> or <literal>key-file+tpm2</literal> is
- used a key is added to the LUKS2 superblock that is enrolled to the local TPM2 chip, as configured
+ used, a key is added to the LUKS2 superblock that is enrolled to the local TPM2 chip, as configured
with the <option>--tpm2-device=</option> and <option>--tpm2-pcrs=</option> options to
<command>systemd-repart</command>.</para>
has no effect on explicit mounts, such as those done via <citerefentry
project='man-pages'><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry> or
<citerefentry
- project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry></para>
+ project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
<para>If both bit 50 and 59 are set for a partition (i.e. the partition is marked both read-only and
marked for file system growing) the latter is typically without effect: the read-only flag takes
<paramdef>const char *<parameter>interface</parameter></paramdef>
<paramdef>const char *<parameter>member</parameter></paramdef>
<paramdef>sd_bus_error *<parameter>ret_error</parameter></paramdef>
- <paramdef>sd_bus_message **<parameter>reply</parameter></paramdef>
<paramdef>const char *<parameter>type</parameter></paramdef>
<paramdef>...</paramdef>
</funcprototype>
<paramdef>const char *<parameter>interface</parameter></paramdef>
<paramdef>const char *<parameter>member</parameter></paramdef>
<paramdef>sd_bus_error *<parameter>ret_error</parameter></paramdef>
- <paramdef>sd_bus_message **<parameter>reply</parameter></paramdef>
<paramdef>const char *<parameter>type</parameter></paramdef>
<paramdef>va_list <parameter>ap</parameter></paramdef>
</funcprototype>
<citerefentry><refentrytitle>sd_bus_call_method</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
</para>
- <para><function>sd_bus_set_property()</function> sets a D-Bus property. On success, the response
- is stored in <parameter>reply</parameter>. If setting the property fails or an internal error
- occurs, an error is returned and an extended description of the error is optionally stored in
- <parameter>ret_error</parameter> if it is not <constant>NULL</constant>.
+ <para><function>sd_bus_set_property()</function> sets a D-Bus property. If setting the property
+ fails or an internal error occurs, an error is returned and an extended description of the error
+ is optionally stored in <parameter>ret_error</parameter> if it is not <constant>NULL</constant>.
<parameter>type</parameter> and the arguments that follow it describe the new value of the
property and must follow the format described in
<citerefentry><refentrytitle>sd_bus_message_append</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
</varlistentry>
<varlistentry>
- <term><command>bind</command> <replaceable>UNIT</replaceable> <replaceable>PATH</replaceable> [<replaceable>PATH</replaceable>]</term>
-
- <listitem><para>Bind mounts a file or directory from the host into the specified unit's view. The first path
- argument is the source file or directory on the host, the second path argument is the destination file or
- directory in the unit's view. When the latter is omitted, the destination path in the unit's view is the same as
- the source path on the host. When combined with the <option>--read-only</option> switch, a ready-only bind
- mount is created. When combined with the <option>--mkdir</option> switch, the destination path is first created
- before the mount is applied. Note that this option is currently only supported for units that run within a mount
- namespace (e.g.: with <option>RootImage=</option>, <option>PrivateMounts=</option>, etc.). This command supports bind
- mounting directories, regular files, device nodes, <constant>AF_UNIX</constant> socket nodes, as well as FIFOs.
- The bind mount is ephemeral, and it is undone as soon as the current unit process exists.
- Note that the namespace mentioned here, where the bind mount will be added to, is the one where the main service
- process runs, as other processes run in distinct namespaces (e.g.: <option>ExecReload=</option>,
- <option>ExecStartPre=</option>, etc.) </para></listitem>
- </varlistentry>
-
- <varlistentry>
- <term><command>mount-image</command> <replaceable>UNIT</replaceable> <replaceable>IMAGE</replaceable> [<replaceable>PATH</replaceable> [<replaceable>PARTITION_NAME</replaceable>:<replaceable>MOUNT_OPTIONS</replaceable>]]</term>
-
- <listitem><para>Mounts an image from the host into the specified unit's view. The first path argument is the source
- image on the host, the second path argument is the destination directory in the unit's view (ie: inside
- <option>RootImage=</option>/<option>RootDirectory=</option>). Any following argument is interpreted as a
- colon-separated tuple of partition name and comma-separated list of mount options for that partition. The format is the
- same as the service <option>MountImages=</option> setting. When combined with the <option>--read-only</option> switch, a
- ready-only mount is created. When combined with the <option>--mkdir</option> switch, the destination path is first
- created before the mount is applied. Note that this option is currently only supported for units that run within a mount
- namespace (e.g.: with <option>RootImage=</option>, <option>PrivateMounts=</option>, etc.).
- Note that the namespace mentioned here, where the image mount will be added to, is the one where the main service
- process runs, as other processes run in distinct namespaces (e.g.: <option>ExecReload=</option>,
- <option>ExecStartPre=</option>, etc.). Example:
+ <term>
+ <command>bind</command>
+ <replaceable>UNIT</replaceable>
+ <replaceable>PATH</replaceable>
+ [<replaceable>PATH</replaceable>]
+ </term>
+
+ <listitem><para>Bind-mounts a file or directory from the host into the specified unit's mount
+ namespace. The first path argument is the source file or directory on the host, the second path
+ argument is the destination file or directory in the unit's mount namespace. When the latter is
+ omitted, the destination path in the unit's mount namespace is the same as the source path on the
+ host. When combined with the <option>--read-only</option> switch, a ready-only bind mount is
+ created. When combined with the <option>--mkdir</option> switch, the destination path is first
+ created before the mount is applied.</para>
+
+ <para>Note that this option is currently only supported for units that run within a mount namespace
+ (e.g.: with <option>RootImage=</option>, <option>PrivateMounts=</option>, etc.). This command
+ supports bind-mounting directories, regular files, device nodes, <constant>AF_UNIX</constant>
+ socket nodes, as well as FIFOs. The bind mount is ephemeral, and it is undone as soon as the
+ current unit process exists. Note that the namespace mentioned here, where the bind mount will be
+ added to, is the one where the main service process runs. Other processes (those exececuted by
+ <option>ExecReload=</option>, <option>ExecStartPre=</option>, etc.) run in distinct namespaces.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <command>mount-image</command>
+ <replaceable>UNIT</replaceable>
+ <replaceable>IMAGE</replaceable>
+ [<replaceable>PATH</replaceable>
+ [<replaceable>PARTITION_NAME</replaceable>:<replaceable>MOUNT_OPTIONS</replaceable>]]
+ </term>
+
+ <listitem><para>Mounts an image from the host into the specified unit's mount namespace. The first
+ path argument is the source image on the host, the second path argument is the destination
+ directory in the unit's mount namespace (i.e. inside
+ <option>RootImage=</option>/<option>RootDirectory=</option>). The following argument, if any, is
+ interpreted as a colon-separated tuple of partition name and comma-separated list of mount options
+ for that partition. The format is the same as the service <option>MountImages=</option>
+ setting. When combined with the <option>--read-only</option> switch, a ready-only mount is
+ created. When combined with the <option>--mkdir</option> switch, the destination path is first
+ created before the mount is applied.</para>
+
+ <para>Note that this option is currently only supported for units that run within a mount namespace
+ (i.e. with <option>RootImage=</option>, <option>PrivateMounts=</option>, etc.). Note that the
+ namespace mentioned here where the image mount will be added to, is the one where the main service
+ process runs. Note that the namespace mentioned here, where the bind mount will be
+ added to, is the one where the main service process runs. Other processes (those exececuted by
+ <option>ExecReload=</option>, <option>ExecStartPre=</option>, etc.) run in distinct namespaces.
+ </para>
+
+ <para>Example:
<programlisting>systemctl mount-image foo.service /tmp/img.raw /var/lib/image root:ro,nosuid</programlisting>
- <programlisting>systemctl mount-image --mkdir bar.service /tmp/img.raw /var/lib/baz/img</programlisting></para></listitem>
+ <programlisting>systemctl mount-image --mkdir bar.service /tmp/img.raw /var/lib/baz/img</programlisting>
+ </para></listitem>
</varlistentry>
<varlistentry>
<term><option>--lines=</option></term>
<listitem>
- <para>When used with <command>status</command>, controls the number of journal lines to show, counting from
- the most recent ones. Takes a positive integer argument, or 0 to disable journal output. Defaults to
- 10.</para>
+ <para>When used with <command>status</command>, controls the number of journal lines to show,
+ counting from the most recent ones. Takes a positive integer argument, or 0 to disable journal
+ output. Defaults to 10.</para>
</listitem>
</varlistentry>
<term><option>--firmware-setup</option></term>
<listitem>
- <para>When used with the <command>reboot</command> command, indicate to the system's firmware to reboot into
- the firmware setup interface. Note that this functionality is not available on all systems.</para>
+ <para>When used with the <command>reboot</command> command, indicate to the system's firmware to
+ reboot into the firmware setup interface. Note that this functionality is not available on all
+ systems.</para>
</listitem>
</varlistentry>
<term><option>--boot-loader-menu=</option></term>
<listitem>
- <para>When used with the <command>reboot</command> command, indicate to the system's boot loader to show the
- boot loader menu on the following boot. Takes a time value as parameter — indicating the menu timeout. Pass
- zero in order to disable the menu timeout. Note that not all boot loaders support this
- functionality.</para>
+ <para>When used with the <command>reboot</command> command, indicate to the system's boot loader to
+ show the boot loader menu on the following boot. Takes a time value as parameter — indicating the
+ menu timeout. Pass zero in order to disable the menu timeout. Note that not all boot loaders
+ support this functionality.</para>
</listitem>
</varlistentry>
<term><option>--boot-loader-entry=</option></term>
<listitem>
- <para>When used with the <command>reboot</command> command, indicate to the system's boot loader to boot into
- a specific boot loader entry on the following boot. Takes a boot loader entry identifier as argument, or
- <literal>help</literal> in order to list available entries. Note that not all boot loaders support this
- functionality.</para>
+ <para>When used with the <command>reboot</command> command, indicate to the system's boot loader to
+ boot into a specific boot loader entry on the following boot. Takes a boot loader entry identifier
+ as argument, or <literal>help</literal> in order to list available entries. Note that not all boot
+ loaders support this functionality.</para>
</listitem>
</varlistentry>
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
details.</para></listitem>
- <listitem><para>An EFI variable set by the boot loader informs the OS about the ESP partition used
- during boot. This is then used to automatically mount the correct ESP partition to
+ <listitem><para>An EFI variable set by the boot loader informs the OS about the EFI System Partition used
+ during boot. This is then used to automatically mount the correct EFI System Partition to
<filename>/efi/</filename> or <filename>/boot/</filename> during OS runtime. See
<citerefentry><refentrytitle>systemd-gpt-auto-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
for details.</para></listitem>
<title>EFI Variables</title>
<para>The following EFI variables are defined, set and read by <command>systemd-boot</command>, under the vendor
- UUID <literal>4a67b082-0a4c-41cf-b6c7-440b29bb8c4</literal>, for communication between the OS and the boot
+ UUID <literal>4a67b082-0a4c-41cf-b6c7-440b29bb8c4f</literal>, for communication between the OS and the boot
loader:</para>
<variablelist class='efi-variables'>
<term><option>--pkcs11-token-uri=</option><replaceable>URI</replaceable></term>
<listitem><para>Enroll a PKCS#11 security token or smartcard (e.g. a YubiKey). Expects a PKCS#11
- smart card URI referring to the token. Alternatively the special value <literal>auto</literal> may
+ smartcard URI referring to the token. Alternatively the special value <literal>auto</literal> may
be specified, in order to automatically determine the URI of a currently plugged in security token
(of which there must be exactly one). The special value <literal>list</literal> may be used to
enumerate all suitable PKCS#11 tokens currently plugged in. The security token must contain an RSA
<varlistentry>
<term><literal>passwd.shell.root</literal></term>
- <listitem><para>Specifies the shell binary to use for the specified account when creating it.
+ <listitem><para>Specifies the shell binary to use for the specified account.
Equivalent to the credential of the same name defined for the
<citerefentry><refentrytitle>systemd-sysusers.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
service.</para></listitem>
<entry><filename>/</filename></entry>
<entry>On Itanium systems, the first Itanium root partition on the disk the EFI ESP is located on is mounted to the root directory <filename>/</filename>.</entry>
</row>
+ <row>
+ <entry>77055800-792c-4f94-b39a-98c91b762bb6</entry>
+ <entry><filename>Root Partition (LoongArch 64)</filename></entry>
+ <entry><filename>/</filename></entry>
+ <entry>On LoongArch 64-bit systems, the first LoongArch 64-bit root partition on the disk the EFI ESP is located on is mounted to the root directory <filename>/</filename>.</entry>
+ </row>
<row>
<entry>60d5a7fe-8e7d-435c-b714-3dd8162144e1</entry>
<entry><filename>Root Partition (RISCV-V 32)</filename></entry>
<varlistentry>
<term><option>--image=<replaceable>path</replaceable></option></term>
- <listitem><para>Takes a path to a device node or refular file as argument. This is similar to
+ <listitem><para>Takes a path to a device node or regular file as argument. This is similar to
<option>--root=</option> as described above, but operates on a disk image instead of a directory
tree.</para></listitem>
</varlistentry>
</orderedlist>
<para>The combination of the three operations above ensures that it is possible to log into the
- host's user account inside the container as if it was local to the container. The user is only mapped
- transiently, while the container is running and the mapping itself does not result in persistent
- changes to the container (except maybe for generated log messages at login time, and similar). Note
- that in particular the UID/GID assignment in the container is not made persistently. If the user is
- mapped transiently, it is best to not allow the user to make persistent changes to the container. If
- the user leaves files or directories owned by the user, and those UIDs/GIDs are recycled during later
+ container using the same account information as on the host. The user is only mapped transiently,
+ while the container is running, and the mapping itself does not result in persistent changes to the
+ container (except maybe for log messages generated at login time, and similar). Note that in
+ particular the UID/GID assignment in the container is not made persistently. If the user is mapped
+ transiently, it is best to not allow the user to make persistent changes to the container. If the
+ user leaves files or directories owned by the user, and those UIDs/GIDs are reused during later
container invocations (possibly with a different <option>--bind-user=</option> mapping), those files
and directories will be accessible to the "new" user.</para>
-b</programlisting>
<para>The above command line will invoke the specified image file <filename>image.raw</filename> in
- volatile mode, i.e with an empty <filename>/etc/</filename> and <filename>/var/</filename>, so that
- the container's payload recognizes this as first boot condition, and will invoke
- <filename>systemd-firstboot.service</filename>, which then read the two passed credentials to
+ volatile mode, i.e. with empty <filename>/etc/</filename> and <filename>/var/</filename>. The
+ container payload will recognize this as a first boot, and will invoke
+ <filename>systemd-firstboot.service</filename>, which then reads the two passed credentials to
configure the system's initial locale and root password.</para>
</listitem>
</varlistentry>
<para>Most of <command>systemd-portabled</command>'s functionality is accessible through the
<citerefentry><refentrytitle>portablectl</refentrytitle><manvolnum>1</manvolnum></citerefentry> command.</para>
- <para>See the <ulink url="https://systemd.io/PORTABLE_SERVICES">Portable
- Services Documentation</ulink> for details about the concepts this service implements.</para>
+ <para>See <ulink url="https://systemd.io/PORTABLE_SERVICES">Portable Services</ulink> for details about
+ the concepts this service implements.</para>
</refsect1>
<refsect1>
turn. Additionally, lookup of single-label names via unicast DNS may be enabled with the
<varname>ResolveUnicastSingleLabel=yes</varname> setting. The details of which servers are queried and
how the final reply is chosen are described below. Note that this means that address queries for
- single-label names are never sent out to remote DNS servers by default, and resoulution is only
+ single-label names are never sent out to remote DNS servers by default, and resolution is only
possible if search domains are defined.</para></listitem>
<listitem><para>Multi-label names with the domain suffix <literal>.local</literal> are resolved using
fragility in both directions: a valid global name could be obscured by a local name, and resolution of
a relative local name could suddenly break when a new top-level domain is created, or when a new
subdomain of a top-level domain in registered. Resolving any given name as either relative or absolute
- avoids this ambiguity.)</para></footnote></para></listitem>
+ avoids this ambiguity.</para></footnote></para></listitem>
<listitem><para>This resolver has a notion of the special <literal>.local</literal> domain used for
MulticastDNS, and will not route queries with that suffix to unicast DNS servers unless explicitly
operating system tree. When one or more system extension images are activated, their
<filename>/usr/</filename> and <filename>/opt/</filename> hierarchies are combined via
<literal>overlayfs</literal> with the same hierarchies of the host OS, and the host
- <filename>/usr/</filename> and <filename>/opt</filename> overmounted with it ("merging"). When they are
+ <filename>/usr/</filename> and <filename>/opt/</filename> overmounted with it ("merging"). When they are
deactivated, the mount point is disassembled — again revealing the unmodified original host version of
the hierarchy ("unmerging"). Merging thus makes the extension's resources suddenly appear below the
<filename>/usr/</filename> and <filename>/opt/</filename> hierarchies as if they were included in the
<orderedlist>
<listitem><para>Plain directories or btrfs subvolumes containing the OS tree</para></listitem>
<listitem><para>Disk images with a GPT disk label, following the <ulink
- url="https://systemd.io/DISCOVERABLE_PARTITIONS">Discoverable Partition Specification</ulink></para></listitem>
+ url="https://systemd.io/DISCOVERABLE_PARTITIONS">Discoverable Partitions Specification</ulink></para></listitem>
<listitem><para>Disk images lacking a partition table, with a naked Linux file system (e.g. squashfs or ext4)</para></listitem>
</orderedlist>
<title>Uses</title>
<para>The primary use case for system images are immutable environments where debugging and development
- tools shall optionally be made available, but not included in the immutable base OS image itself
- (e.g. <filename>strace</filename> and <filename>gdb</filename> shall be an optionally installable
- addition in order to make debugging/development easier). System extension images should not be
- misunderstood as a generic software packaging framework, as no dependency scheme is available: system
- extensions should carry all files they need themselves, except for those already shipped in the
- underlying host system image. Typically, system extension images are built at the same time as the base
- OS image — within the same build system.</para>
+ tools shall optionally be made available, but not included in the immutable base OS image itself (e.g.
+ <citerefentry project='man-pages'><refentrytitle>strace</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ and
+ <citerefentry project='man-pages'><refentrytitle>gdb</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ shall be an optionally installable addition in order to make debugging/development easier). System
+ extension images should not be misunderstood as a generic software packaging framework, as no dependency
+ scheme is available: system extensions should carry all files they need themselves, except for those
+ already shipped in the underlying host system image. Typically, system extension images are built at the
+ same time as the base OS image — within the same build system.</para>
<para>Another use case for the system extension concept is temporarily overriding OS supplied resources
with newer ones, for example to install a locally compiled development version of some low-level
names in status messages (e.g. <literal>systemd-journald.service</literal>), instead of the longer
and more informative descriptions set with <varname>Description=</varname> (e.g. <literal>Journal
Logging Service</literal>). If <option>combined</option>, the system manager will use both unit names
- and descriptions in status messages (e.g. <literal>systemdmd-jouranld.service - Journal Logging
+ and descriptions in status messages (e.g. <literal>systemd-journald.service - Journal Logging
Service</literal>).</para>
<para>See
JSON user/group records from classic UNIX/glibc NSS user/group records in order to provide full backwards
compatibility. It may also pick up statically defined JSON user/group records from drop-in files in
<filename>/etc/userdb/</filename>, <filename>/run/userdb/</filename>,
- <filename>/run/host/userdb/</filename> and <filename>/use/lib/userdb/</filename>.</para>
+ <filename>/run/host/userdb/</filename> and <filename>/usr/lib/userdb/</filename>.</para>
<para>Most of <command>systemd-userdbd</command>'s functionality is accessible through the
<citerefentry><refentrytitle>userdbctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
command.</para>
<para>The user and group records this service provides access to follow the <ulink
- url="https://systemd.io/USER_RECORD">JSON User Record</ulink> and <ulink
+ url="https://systemd.io/USER_RECORD">JSON User Records</ulink> and <ulink
url="https://systemd.io/GROUP_RECORD">JSON Group Record</ulink> definitions. This service implements the
<ulink url="https://systemd.io/USER_GROUP_API">User/Group Record Lookup API via Varlink</ulink>, and
multiplexes access other services implementing this API, too. It is thus both server and client of this
<para>At early boot and when the system manager configuration is reloaded kernel command line configuration for
integrity protected block devices is translated into <filename>systemd-veritysetup@.service</filename> units by
<citerefentry><refentrytitle>systemd-veritysetup-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
+
+ <para><filename>systemd-veritysetup@.service</filename> calls <command>systemd-veritysetup</command>.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Commands</title>
+
+ <para>The following commands are understood by <command>systemd-veritysetup</command>:</para>
+
+ <variablelist>
+ <varlistentry>
+ <term>
+ <option>attach</option>
+ <replaceable>volume</replaceable>
+ <replaceable>datadevice</replaceable>
+ <replaceable>hashdevice</replaceable>
+ <replaceable>roothash</replaceable>
+ [<replaceable>option</replaceable>...]
+ </term>
+
+ <listitem><para>Create a block device <replaceable>volume</replaceable> using
+ <replaceable>datadevice</replaceable> and <replaceable>hashdevice</replaceable> as the backing
+ devices. <replaceable>roothash</replaceable> forms the root of the tree of hashes stored on
+ <replaceable>hashdevice</replaceable>. See
+ <ulink url="https://www.kernel.org/doc/html/latest/admin-guide/device-mapper/verity.html">
+ Kernel dm-verity</ulink> documentation for details.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>detach</option>
+ <replaceable>volume</replaceable>
+ </term>
+
+ <listitem><para>Detach (destroy) the block device
+ <replaceable>volume</replaceable>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>help</option>
+ </term>
+
+ <listitem><para>Print short information about command syntax.</para></listitem>
+ </varlistentry>
+ </variablelist>
</refsect1>
<refsect1>
<para>This option is supported only for disk images that contain a single file system, without an
enveloping partition table. Images that contain a GPT partition table should instead include both
root file system and matching Verity data in the same image, implementing the <ulink
- url="https://systemd.io/DISCOVERABLE_PARTITIONS">Discoverable Partition Specification</ulink>.</para>
+ url="https://systemd.io/DISCOVERABLE_PARTITIONS">Discoverable Partitions Specification</ulink>.</para>
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
</varlistentry>
<term><varname>ExtensionImages=</varname></term>
<listitem><para>This setting is similar to <varname>MountImages=</varname> in that it mounts a file
- system hierarchy from a block device node or loopback file, but instead of providing a destination path,
- an overlay will be set up. This option expects a whitespace separated list of mount definitions. Each
- definition consists of a source path, optionally followed by a colon and a list of mount options.</para>
+ system hierarchy from a block device node or loopback file, but instead of providing a destination
+ path, an overlay will be set up. This option expects a whitespace separated list of mount
+ definitions. Each definition consists of a source path, optionally followed by a colon and a list of
+ mount options.</para>
<para>A read-only OverlayFS will be set up on top of <filename>/usr/</filename> and
- <filename>/opt/</filename> hierarchies from the root. The order in which the images are listed
- will determine the order in which the overlay is laid down: images specified first to last will result
- in overlayfs layers bottom to top.</para>
+ <filename>/opt/</filename> hierarchies. The order in which the images are listed will determine the
+ order in which the overlay is laid down: images specified first to last will result in overlayfs
+ layers bottom to top.</para>
<para>Mount options may be defined as a single comma-separated list of options, in which case they
will be implicitly applied to the root partition on the image, or a series of colon-separated tuples
<listitem><para>Sets environment variables for executed processes. Each line is unquoted using the
rules described in "Quoting" section in
- <citerefentry><refentrytitle>systemd.syntax</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ <citerefentry><refentrytitle>systemd.syntax</refentrytitle><manvolnum>7</manvolnum></citerefentry>
and becomes a list of variable assignments. If you need to assign a value containing spaces or the
equals sign to a variable, put quotes around the whole assignment. Variable expansion is not
performed inside the strings and the <literal>$</literal> character has no special meaning. Specifier
<term><varname>MTUBytes=</varname></term>
<listitem>
<para>The maximum transmission unit in bytes to set for the
- device. The usual suffixes K, M, G, are supported and are
+ device. The usual suffixes K, M, G are supported and are
understood to the base of 1024.</para>
</listitem>
</varlistentry>
<term><varname>BitsPerSecond=</varname></term>
<listitem>
<para>The speed to set for the device, the value is rounded
- down to the nearest Mbps. The usual suffixes K, M, G, are
+ down to the nearest Mbps. The usual suffixes K, M, G are
supported and are understood to the base of 1000.</para>
</listitem>
</varlistentry>
<term><varname>GenericSegmentOffloadMaxBytes=</varname></term>
<listitem>
<para>Specifies the maximum size of a Generic Segment Offload (GSO) packet the
- device should accept. The usual suffixes K, M, G, are supported and are
+ device should accept. The usual suffixes K, M, G are supported and are
understood to the base of 1024. An unsigned integer in the range 1…65536.
Defaults to unset.</para>
</listitem>
<varlistentry>
<term><varname>GenericSegmentOffloadMaxSegments=</varname></term>
<listitem>
- <para>Specifies the maximum number of a Generic Segment Offload (GSO) segments the device should
- accept. An unsigned integer in the range 1…65535. Defaults to unset.</para>
+ <para>Specifies the maximum number of Generic Segment Offload (GSO) segments the device should
+ accept. An unsigned integer in the range 1…65535. Defaults to unset.</para>
</listitem>
</varlistentry>
<term><varname>DefaultPVID=</varname></term>
<listitem>
<para>This specifies the default port VLAN ID of a newly attached bridge port.
- Set this to an integer in the range 1â\80\934094 or <literal>none</literal> to disable the PVID.</para>
+ Set this to an integer in the range 1â\80¦4094 or <literal>none</literal> to disable the PVID.</para>
</listitem>
</varlistentry>
<varlistentry>
<varlistentry>
<term><varname>Id=</varname></term>
<listitem>
- <para>The VLAN ID to use. An integer in the range 0â\80\934094.
+ <para>The VLAN ID to use. An integer in the range 0â\80¦4094.
This setting is compulsory.</para>
</listitem>
</varlistentry>
<term><varname>TTL=</varname></term>
<listitem>
<para>A fixed Time To Live N on Virtual eXtensible Local Area Network packets.
- Takes <literal>inherit</literal> or a number in the range 0â\80\93255. 0 is a special
+ Takes <literal>inherit</literal> or a number in the range 0â\80¦255. 0 is a special
value meaning inherit the inner protocol's TTL value. <literal>inherit</literal>
means that it will inherit the outer protocol's TTL value.</para>
</listitem>
<varlistentry>
<term><varname>TunnelId=</varname></term>
<listitem>
- <para>Specifies the tunnel identifier. Takes an number in the range 1â\80\934294967295. The value used
+ <para>Specifies the tunnel identifier. Takes an number in the range 1â\80¦4294967295. The value used
must match the <literal>PeerTunnelId=</literal> value being used at the peer. This setting is
compulsory.</para>
</listitem>
<varlistentry>
<term><varname>SessionId=</varname></term>
<listitem>
- <para>Specifies the session identifier. Takes an number in the range 1â\80\934294967295. The value used
+ <para>Specifies the session identifier. Takes an number in the range 1â\80¦4294967295. The value used
must match the <literal>SessionId=</literal> value being used at the peer. This setting is
compulsory.</para>
</listitem>
<varlistentry>
<term><varname>PeerSessionId=</varname></term>
<listitem>
- <para>Specifies the peer session identifier. Takes an number in the range 1â\80\934294967295.
+ <para>Specifies the peer session identifier. Takes an number in the range 1â\80¦4294967295.
The value used must match the <literal>PeerSessionId=</literal> value being used at the peer.
This setting is compulsory.</para>
</listitem>
<term><varname>TTL=</varname></term>
<listitem>
<para>A fixed Time To Live N on tunneled packets. N is a
- number in the range 1â\80\93255. 0 is a special value meaning that
+ number in the range 1â\80¦255. 0 is a special value meaning that
packets inherit the TTL value. The default value for IPv4
tunnels is 0 (inherit). The default value for IPv6 tunnels is
64.</para>
It is only used for IPv6 tunnels.
A flow label of zero is used to indicate packets that have
not been labeled.
- It can be configured to a value in the range 0â\80\930xFFFFF, or be
+ It can be configured to a value in the range 0â\80¦0xFFFFF, or be
set to <literal>inherit</literal>, in which case the original flowlabel is used.</para>
</listitem>
</varlistentry>
<para>Sets a comma-separated list of IP (v4 or v6) addresses with CIDR masks
from which this peer is allowed to send incoming traffic and to
which outgoing traffic for this peer is directed.</para>
+
<para>The catch-all 0.0.0.0/0 may be specified for matching all IPv4 addresses,
and ::/0 may be specified for matching all IPv6 addresses.</para>
- <para>Note that this only affects "routing inside the network interface itself",
- as in, which wireguard peer packets with a specific destination address are sent to,
- and what source addresses are accepted from which peer.</para>
- <para>To cause packets to be sent via wireguard in first place, a route needs
- to be added, as well - either in the <literal>[Routes]</literal> section on the
- <literal>.network</literal> matching the wireguard interface, or outside of networkd.
- </para>
+
+ <para>Note that this only affects <emphasis>routing inside the network interface itself</emphasis>,
+ i.e. the packets that pass through the tunnel itself. To cause packets to be sent via the tunnel in
+ the first place, an appropriate route needs to be added as well — either in the
+ <literal>[Routes]</literal> section on the <literal>.network</literal> matching the wireguard
+ interface, or externally to <filename>systemd-networkd</filename>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>AdUserPortKey=</varname></term>
<listitem>
<para>Specifies the 802.3ad user defined portion of the port key. Takes a number in the range
- 0â\80\931023.</para>
+ 0â\80¦1023.</para>
</listitem>
</varlistentry>
<refsect1>
<title>[BatmanAdvanced] Section Options</title>
- <para>The [BatmanAdvanced] section only applies for
- netdevs of kind <literal>batadv</literal> and accepts the
- following keys:</para>
+
+ <para>The [BatmanAdvanced] section only applies for netdevs of kind <literal>batadv</literal> and accepts
+ the following keys:</para>
<variablelist class='network-directives'>
<varlistentry>
</para>
</listitem>
</varlistentry>
- <varlistentry>
- <term><varname>Xfrm=</varname></term>
- <listitem>
- <para>The name of the xfrm to create on the link. See
- <citerefentry><refentrytitle>systemd.netdev</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
- This option may be specified more than once.</para>
- </listitem>
- </varlistentry>
<varlistentry>
<term><varname>KeepConfiguration=</varname></term>
<listitem>
<term><varname>Metric=</varname></term>
<listitem>
<para>The metric of the route. Takes an unsigned integer in the range 0…4294967295.
- Defaluts to unset, and the kernel's default will be used.</para>
+ Defaults to unset, and the kernel's default will be used.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>SendHostname=</varname></term>
<listitem>
<para>When true (the default), the machine's hostname (or the value specified with
- <varname>Hostname=</varname> below) will be sent to the DHCP server. Note that the hostname must
- consist only of 7-bit ASCII lower-case characters and no spaces or dots, and be formatted as a
- valid DNS domain name. Otherwise, the hostname is not sent even if this option is true.</para>
+ <varname>Hostname=</varname>, described below) will be sent to the DHCP server. Note that the
+ hostname must consist only of 7-bit ASCII lower-case characters and no spaces or dots, and be
+ formatted as a valid DNS domain name. Otherwise, the hostname is not sent even if this option is
+ true.</para>
</listitem>
</varlistentry>
<term><varname>FallbackLeaseLifetimeSec=</varname></term>
<listitem>
<para>Allows to set DHCPv4 lease lifetime when DHCPv4 server does not send the lease lifetime.
- Takes one of <literal>forever</literal> or <literal>infinity</literal> means that the address
- never expires. Defaults to unset.</para>
+ Takes one of <literal>forever</literal> or <literal>infinity</literal>. The latter means that the
+ address never expires. Defaults to unset.</para>
</listitem>
</varlistentry>
DHCP server. After a new IP is received, the DHCPv4 client performs IPv4 Duplicate Address
Detection. If duplicate use is detected, the DHCPv4 client rejects the IP by sending a
<constant>DHCPDECLINE</constant> packet and tries to obtain an IP address again. See <ulink
- url="https://tools.ietf.org/html/rfc5227">RFC 5224</ulink>. Defaults to
+ url="https://tools.ietf.org/html/rfc5227">RFC 5227</ulink>. Defaults to
<literal>unset</literal>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>ServerAddress=</varname></term>
<listitem><para>Specifies server address for the DHCP server. Takes an IPv4 address with prefix
- length, e.g., <literal>192.168.0.1/24</literal>. This setting may be useful when the link which
- DHCP server running on has multiple static addresses. When unset, one of static addresses in
- the link will be automatically selected. Defaults to unset.</para></listitem>
+ length, for example <literal>192.168.0.1/24</literal>. This setting may be useful when the link on
+ which the DHCP server is running has multiple static addresses. When unset, one of static addresses
+ in the link will be automatically selected. Defaults to unset.</para></listitem>
</varlistentry>
<varlistentry>
<refsect1>
<title>[DHCPServerStaticLease] Section Options</title>
- <para>The <literal>[DHCPServerStaticLease]</literal> section configures a static DHCP lease to
- assign a pre-set IPv4 address to a specific device based on its MAC address. This section can be
- specified multiple times.</para>
+ <para>The <literal>[DHCPServerStaticLease]</literal> section configures a static DHCP lease to assign a
+ fixed IPv4 address to a specific device based on its MAC address. This section can be specified multiple
+ times.</para>
<variablelist class='network-directives'>
<varlistentry>
<term><varname>MACAddress=</varname></term>
- <listitem><para>The hardware address of a device which should be assigned IPv4 address
- specified in <varname>Address=</varname>. This key is mandatory.</para></listitem>
+ <listitem><para>The hardware address of a device to match. This key is mandatory.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>Address=</varname></term>
- <listitem><para>IPv4 address that should be assigned to a device with a hardware address
- specified in <varname>MACAddress=</varname>. This key is mandatory.</para></listitem>
+ <listitem><para>The IPv4 address that should be assigned to the device that was matched with
+ <varname>MACAddress=</varname>. This key is mandatory.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
capabilities (see
<citerefentry project='man-pages'><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
for details). The <varname>AmbientCapability=</varname> setting
- specifies capability which will be passed to to started program
+ specifies capability which will be passed to the started program
in the inheritable and ambient capability sets. This will grant
these capabilities to this process. This setting correspond to
the <option>--ambient-capability=</option> command line switch.
<citerefentry><refentrytitle>systemd-delta</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
- <para><citerefentry><refentrytitle>daemon</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <para><citerefentry><refentrytitle>daemon</refentrytitle><manvolnum>7</manvolnum></citerefentry>
has a discussion of packaging scriptlets.</para>
<para>Fedora page introducing the use of presets:
<literal>\;</literal>.</para>
<para>Each command line is unquoted using the rules described in "Quoting" section in
- <citerefentry><refentrytitle>systemd.syntax</refentrytitle><manvolnum>5</manvolnum></citerefentry>. The
+ <citerefentry><refentrytitle>systemd.syntax</refentrytitle><manvolnum>7</manvolnum></citerefentry>. The
first item becomes the command to execute, and the subsequent items the arguments.</para>
<para>This syntax is inspired by shell syntax, but only the meta-characters and expansions
<varlistentry>
<term><varname>Upholds=</varname></term>
- <listitem><para>Configures dependencies similar to <varname>Wants=</varname>, but as long a this unit
+ <listitem><para>Configures dependencies similar to <varname>Wants=</varname>, but as long as this unit
is up, all units listed in <varname>Upholds=</varname> are started whenever found to be inactive or
failed, and no job is queued for them. While a <varname>Wants=</varname> dependency on another unit
has a one-time effect when this units started, a <varname>Upholds=</varname> dependency on it has a
<varlistentry>
<term><varname>ConditionControlGroupController=</varname></term>
- <listitem><para>Check whether given cgroup controllers (eg. <literal>cpu</literal>) are available
+ <listitem><para>Check whether given cgroup controllers (e.g. <literal>cpu</literal>) are available
for use on the system or whether the legacy v1 cgroup or the modern v2 cgroup hierarchy is used.
</para>
configuration files, whose syntax and basic set of options is
described in
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
- however some are created automatically from other configuration,
- dynamically from system state or programmatically at runtime.
+ however some are created automatically from other configuration
+ files, dynamically from system state or programmatically at runtime.
Units may be "active" (meaning started, bound, plugged in, …,
depending on the unit type, see below), or "inactive" (meaning
stopped, unbound, unplugged, …), as well as in the process of
for --user instances).</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><constant>SIGRTMIN+25</constant></term>
+
+ <listitem><para>Upon receiving this signal the systemd manager will reexecute itself. This
+ is mostly equivalent to <command>systemctl daemon-reexec</command> except that it will be
+ done asynchronously.</para>
+
+ <para>The systemd system manager treats this signal the same way as
+ <constant>SIGTERM</constant>.</para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><constant>SIGRTMIN+26</constant></term>
<refsect2>
<title>Age</title>
+
<para>The date field, when set, is used to decide what files to
delete when cleaning. If a file or directory is older than the
current time minus the age field, it is deleted. The field
and <varname>X</varname>. If omitted or set to
<literal>-</literal>, no automatic clean-up is done.</para>
- <para>If the age field starts with a tilde character
- <literal>~</literal>, the clean-up is only applied to files and
- directories one level inside the directory specified, but not
- the files and directories immediately inside it.</para>
+ <para>If the age field starts with a tilde character <literal>~</literal>, clean-up is only applied to
+ files and directories one level inside the directory specified, but not the files and directories
+ immediately inside it.</para>
<para>The age of a file system entry is determined from its last
modification timestamp (mtime), its last access timestamp (atime),
the age field. To restrict the deletion based on particular type
of file timestamps, the age-by argument can be used.</para>
- <para>The age-by argument, when (optionally) specified along
- with age will check if the file system entry has aged by the
- type of file timestamp(s) provided. It can be specified by
- prefixing the age argument with a set of file timestamp types
- followed by a colon character <literal>:</literal>, i.e.,
- <literal><replaceable>age-by</replaceable>:<replaceable>cleanup-age</replaceable></literal>.
- The argument can be a set of:
- <constant>a</constant> (<constant>A</constant> for directories),
- <constant>b</constant> (<constant>B</constant> for directories),
- <constant>c</constant> (<constant>C</constant> for directories; ignored by default), or
- <constant>m</constant> (<constant>M</constant> for directories),
- indicating access, creation, last status change, and last
- modification times of a file system entry respectively. See
- <citerefentry project='man-pages'><refentrytitle>statx</refentrytitle><manvolnum>2</manvolnum></citerefentry>
- file timestamp fields for more details.</para>
-
- <para>If unspecified, the age-by field defaults to
- <constant>abcmABM</constant>,
- i.e., by default all file timestamps are taken into consideration,
- with the exception of the last status change timestamp (ctime) for
- directories. This is because the aging logic itself will alter the
- ctime whenever it deletes a file inside it. To ensure that running
- the aging logic does not feed back into the next iteration of it,
- ctime for directories is ignored by default.</para>
+ <para>The age-by argument overrides the timestamp types to be used for the age check. It can be
+ specified by prefixing the age argument with a sequence of characters to specify the timestamp types
+ and a colon (<literal>:</literal>):
+ <literal><replaceable>age-by</replaceable>...:<replaceable>cleanup-age</replaceable></literal>. The
+ argument can consist of <constant>a</constant> (<constant>A</constant> for directories),
+ <constant>b</constant> (<constant>B</constant> for directories), <constant>c</constant>
+ (<constant>C</constant> for directories), or <constant>m</constant> (<constant>M</constant> for
+ directories). Those respectively indicate access, creation, last status change, and last modification
+ time of a file system entry. The lower-case letter signifies that the given timestamp type should be
+ considered for files, while the upper-case letter signifies that the given timestamp type should be
+ considered for directories. See <citerefentry
+ project='man-pages'><refentrytitle>statx</refentrytitle><manvolnum>2</manvolnum></citerefentry> file
+ timestamp fields for more details about timestamp types.</para>
+
+ <para>If not specified, the age-by field defaults to <constant>abcmABM</constant>, i.e. by default all
+ file timestamps are taken into consideration, with the exception of the last status change timestamp
+ (ctime) for directories. This is because the aging logic itself will alter the ctime whenever it
+ deletes a file inside it. To ensure that running the aging logic does not feed back into the next
+ iteration of itself, ctime for directories is ignored by default.</para>
<para>For example:<programlisting>
# Files created and modified, and directories accessed more than
url="https://systemd.io/USER_GROUP_API">User/Group Record Lookup API via Varlink</ulink>, and may also
pick up drop-in JSON user and group records from <filename>/etc/userdb/</filename>,
<filename>/run/userdb/</filename>, <filename>/run/host/userdb/</filename>,
- <filename>/use/lib/userdb/</filename>.</para>
+ <filename>/usr/lib/userdb/</filename>.</para>
</refsect1>
<refsect1>
<listitem><para>Controls whether to include user/group lookups in the output that are defined using
drop-in files in <filename>/etc/userdb/</filename>, <filename>/run/userdb/</filename>,
- <filename>/run/host/userdb/</filename>, <filename>/use/lib/userdb/</filename>. If
+ <filename>/run/host/userdb/</filename>, <filename>/usr/lib/userdb/</filename>. If
<option>--with-dropin=no</option> is used these records are suppressed. If
<option>--with-dropin=yes</option> is specified such users/groups are included in the output (which
is the default).</para></listitem>
<citerefentry><refentrytitle>systemd-userdbd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
and picks up JSON user/group records from <filename>/etc/userdb/</filename>,
<filename>/run/userdb/</filename>, <filename>/run/host/userdb/</filename>,
- <filename>/use/lib/userdb/</filename>.</para></listitem>
+ <filename>/usr/lib/userdb/</filename>.</para></listitem>
</varlistentry>
</variablelist>
'localstatedir=/var',
'warning_level=2',
],
- meson_version : '>= 0.46',
+ meson_version : '>= 0.53.2',
)
libsystemd_version = '0.32.0'
sysvrcnd_path = get_option('sysvrcnd-path')
conf.set10('HAVE_SYSV_COMPAT', sysvinit_path != '' and sysvrcnd_path != '',
description : 'SysV init scripts and rcN.d links are supported')
+conf.set10('CREATE_LOG_DIRS', get_option('create-log-dirs'))
if get_option('hibernate') and not get_option('initrd')
error('hibernate depends on initrd')
conf.set10('BUMP_PROC_SYS_FS_NR_OPEN', get_option('bump-proc-sys-fs-nr-open'))
conf.set('HIGH_RLIMIT_NOFILE', 512*1024)
-# join_paths ignores the preceding arguments if an absolute component is
-# encountered, so this should canonicalize various paths when they are
-# absolute or relative.
+# Meson ignores the preceding arguments when joining paths if an absolute
+# component is encountered, so this should canonicalize various paths when they
+# are absolute or relative.
prefixdir = get_option('prefix')
if not prefixdir.startswith('/')
error('Prefix is not absolute: "@0@"'.format(prefixdir))
rootprefixdir, prefixdir))
endif
-bindir = join_paths(prefixdir, get_option('bindir'))
-libdir = join_paths(prefixdir, get_option('libdir'))
-sysconfdir = join_paths(prefixdir, get_option('sysconfdir'))
-includedir = join_paths(prefixdir, get_option('includedir'))
-datadir = join_paths(prefixdir, get_option('datadir'))
-localstatedir = join_paths('/', get_option('localstatedir'))
+bindir = prefixdir / get_option('bindir')
+libdir = prefixdir / get_option('libdir')
+sysconfdir = prefixdir / get_option('sysconfdir')
+includedir = prefixdir / get_option('includedir')
+datadir = prefixdir / get_option('datadir')
+localstatedir = '/' / get_option('localstatedir')
-rootbindir = join_paths(rootprefixdir, 'bin')
-rootsbindir = join_paths(rootprefixdir, split_bin ? 'sbin' : 'bin')
-rootlibexecdir = join_paths(rootprefixdir, 'lib/systemd')
+rootbindir = rootprefixdir / 'bin'
+rootsbindir = rootprefixdir / (split_bin ? 'sbin' : 'bin')
+rootlibexecdir = rootprefixdir / 'lib/systemd'
rootlibdir = get_option('rootlibdir')
if rootlibdir == ''
- rootlibdir = join_paths(rootprefixdir, libdir.split('/')[-1])
+ rootlibdir = rootprefixdir / libdir.split('/')[-1]
endif
install_sysconfdir = get_option('install-sysconfdir') != 'false'
install_sysconfdir_samples = get_option('install-sysconfdir') == 'true'
# Dirs of external packages
-pkgconfigdatadir = get_option('pkgconfigdatadir') == '' ? join_paths(datadir, 'pkgconfig') : get_option('pkgconfigdatadir')
-pkgconfiglibdir = get_option('pkgconfiglibdir') == '' ? join_paths(libdir, 'pkgconfig') : get_option('pkgconfiglibdir')
-polkitpolicydir = join_paths(datadir, 'polkit-1/actions')
-polkitrulesdir = join_paths(datadir, 'polkit-1/rules.d')
-polkitpkladir = join_paths(localstatedir, 'lib/polkit-1/localauthority/10-vendor.d')
-xinitrcdir = get_option('xinitrcdir') == '' ? join_paths(sysconfdir, 'X11/xinit/xinitrc.d') : get_option('xinitrcdir')
+pkgconfigdatadir = get_option('pkgconfigdatadir') != '' ? get_option('pkgconfigdatadir') : datadir / 'pkgconfig'
+pkgconfiglibdir = get_option('pkgconfiglibdir') != '' ? get_option('pkgconfiglibdir') : libdir / 'pkgconfig'
+polkitpolicydir = datadir / 'polkit-1/actions'
+polkitrulesdir = datadir / 'polkit-1/rules.d'
+polkitpkladir = localstatedir / 'lib/polkit-1/localauthority/10-vendor.d'
+xinitrcdir = get_option('xinitrcdir') != '' ? get_option('xinitrcdir') : sysconfdir / 'X11/xinit/xinitrc.d'
rpmmacrosdir = get_option('rpmmacrosdir')
if rpmmacrosdir != 'no'
- rpmmacrosdir = join_paths(prefixdir, rpmmacrosdir)
+ rpmmacrosdir = prefixdir / rpmmacrosdir
endif
-modprobedir = join_paths(rootprefixdir, 'lib/modprobe.d')
+modprobedir = rootprefixdir / 'lib/modprobe.d'
# Our own paths
-pkgdatadir = join_paths(datadir, 'systemd')
-environmentdir = join_paths(prefixdir, 'lib/environment.d')
-pkgsysconfdir = join_paths(sysconfdir, 'systemd')
-userunitdir = join_paths(prefixdir, 'lib/systemd/user')
-userpresetdir = join_paths(prefixdir, 'lib/systemd/user-preset')
-tmpfilesdir = join_paths(prefixdir, 'lib/tmpfiles.d')
-sysusersdir = join_paths(prefixdir, 'lib/sysusers.d')
-sysctldir = join_paths(prefixdir, 'lib/sysctl.d')
-binfmtdir = join_paths(prefixdir, 'lib/binfmt.d')
-modulesloaddir = join_paths(prefixdir, 'lib/modules-load.d')
-networkdir = join_paths(rootprefixdir, 'lib/systemd/network')
-pkgincludedir = join_paths(includedir, 'systemd')
-systemgeneratordir = join_paths(rootlibexecdir, 'system-generators')
-usergeneratordir = join_paths(prefixdir, 'lib/systemd/user-generators')
-systemenvgeneratordir = join_paths(prefixdir, 'lib/systemd/system-environment-generators')
-userenvgeneratordir = join_paths(prefixdir, 'lib/systemd/user-environment-generators')
-systemshutdowndir = join_paths(rootlibexecdir, 'system-shutdown')
-systemsleepdir = join_paths(rootlibexecdir, 'system-sleep')
-systemunitdir = join_paths(rootprefixdir, 'lib/systemd/system')
-systempresetdir = join_paths(rootprefixdir, 'lib/systemd/system-preset')
-udevlibexecdir = join_paths(rootprefixdir, 'lib/udev')
-udevrulesdir = join_paths(udevlibexecdir, 'rules.d')
-udevhwdbdir = join_paths(udevlibexecdir, 'hwdb.d')
-catalogdir = join_paths(prefixdir, 'lib/systemd/catalog')
-kernelinstalldir = join_paths(prefixdir, 'lib/kernel/install.d')
-factorydir = join_paths(datadir, 'factory')
-bootlibdir = join_paths(prefixdir, 'lib/systemd/boot/efi')
-testsdir = join_paths(prefixdir, 'lib/systemd/tests')
-systemdstatedir = join_paths(localstatedir, 'lib/systemd')
-catalogstatedir = join_paths(systemdstatedir, 'catalog')
-randomseeddir = join_paths(localstatedir, 'lib/systemd')
-profiledir = join_paths(rootlibexecdir, 'portable', 'profile')
-ntpservicelistdir = join_paths(rootprefixdir, 'lib/systemd/ntp-units.d')
+pkgdatadir = datadir / 'systemd'
+environmentdir = prefixdir / 'lib/environment.d'
+pkgsysconfdir = sysconfdir / 'systemd'
+userunitdir = prefixdir / 'lib/systemd/user'
+userpresetdir = prefixdir / 'lib/systemd/user-preset'
+tmpfilesdir = prefixdir / 'lib/tmpfiles.d'
+sysusersdir = prefixdir / 'lib/sysusers.d'
+sysctldir = prefixdir / 'lib/sysctl.d'
+binfmtdir = prefixdir / 'lib/binfmt.d'
+modulesloaddir = prefixdir / 'lib/modules-load.d'
+networkdir = rootprefixdir / 'lib/systemd/network'
+pkgincludedir = includedir / 'systemd'
+systemgeneratordir = rootlibexecdir / 'system-generators'
+usergeneratordir = prefixdir / 'lib/systemd/user-generators'
+systemenvgeneratordir = prefixdir / 'lib/systemd/system-environment-generators'
+userenvgeneratordir = prefixdir / 'lib/systemd/user-environment-generators'
+systemshutdowndir = rootlibexecdir / 'system-shutdown'
+systemsleepdir = rootlibexecdir / 'system-sleep'
+systemunitdir = rootprefixdir / 'lib/systemd/system'
+systempresetdir = rootprefixdir / 'lib/systemd/system-preset'
+udevlibexecdir = rootprefixdir / 'lib/udev'
+udevrulesdir = udevlibexecdir / 'rules.d'
+udevhwdbdir = udevlibexecdir / 'hwdb.d'
+catalogdir = prefixdir / 'lib/systemd/catalog'
+kernelinstalldir = prefixdir / 'lib/kernel/install.d'
+factorydir = datadir / 'factory'
+bootlibdir = prefixdir / 'lib/systemd/boot/efi'
+testsdir = prefixdir / 'lib/systemd/tests'
+systemdstatedir = localstatedir / 'lib/systemd'
+catalogstatedir = systemdstatedir / 'catalog'
+randomseeddir = localstatedir / 'lib/systemd'
+profiledir = rootlibexecdir / 'portable' / 'profile'
+ntpservicelistdir = rootprefixdir / 'lib/systemd/ntp-units.d'
docdir = get_option('docdir')
if docdir == ''
- docdir = join_paths(datadir, 'doc/systemd')
+ docdir = datadir / 'doc/systemd'
endif
dbuspolicydir = get_option('dbuspolicydir')
if dbuspolicydir == ''
- dbuspolicydir = join_paths(datadir, 'dbus-1/system.d')
+ dbuspolicydir = datadir / 'dbus-1/system.d'
endif
dbussessionservicedir = get_option('dbussessionservicedir')
if dbussessionservicedir == ''
- dbussessionservicedir = join_paths(datadir, 'dbus-1/services')
+ dbussessionservicedir = datadir / 'dbus-1/services'
endif
dbussystemservicedir = get_option('dbussystemservicedir')
if dbussystemservicedir == ''
- dbussystemservicedir = join_paths(datadir, 'dbus-1/system-services')
+ dbussystemservicedir = datadir / 'dbus-1/system-services'
endif
pamlibdir = get_option('pamlibdir')
if pamlibdir == ''
- pamlibdir = join_paths(rootlibdir, 'security')
+ pamlibdir = rootlibdir / 'security'
endif
pamconfdir = get_option('pamconfdir')
if pamconfdir == ''
- pamconfdir = join_paths(prefixdir, 'lib/pam.d')
+ pamconfdir = prefixdir / 'lib/pam.d'
+endif
+
+libcryptsetup_plugins_dir = get_option('libcryptsetup-plugins-dir')
+if libcryptsetup_plugins_dir == ''
+ libcryptsetup_plugins_dir = rootlibdir / 'cryptsetup'
endif
memory_accounting_default = get_option('memory-accounting-default')
conf.set_quoted('BINFMT_DIR', binfmtdir)
conf.set_quoted('BOOTLIBDIR', bootlibdir)
-conf.set_quoted('CATALOG_DATABASE', join_paths(catalogstatedir, 'database'))
+conf.set_quoted('CATALOG_DATABASE', catalogstatedir / 'database')
conf.set_quoted('CERTIFICATE_ROOT', get_option('certificate-root'))
-conf.set_quoted('DOCUMENT_ROOT', join_paths(pkgdatadir, 'gatewayd'))
+conf.set_quoted('DOC_DIR', docdir)
+conf.set_quoted('DOCUMENT_ROOT', pkgdatadir / 'gatewayd')
conf.set_quoted('ENVIRONMENT_DIR', environmentdir)
conf.set_quoted('INCLUDE_DIR', includedir)
conf.set_quoted('LIBDIR', libdir)
conf.set_quoted('MODPROBE_DIR', modprobedir)
conf.set_quoted('MODULESLOAD_DIR', modulesloaddir)
conf.set_quoted('PKGSYSCONFDIR', pkgsysconfdir)
-conf.set_quoted('POLKIT_AGENT_BINARY_PATH', join_paths(bindir, 'pkttyagent'))
+conf.set_quoted('POLKIT_AGENT_BINARY_PATH', bindir / 'pkttyagent')
conf.set_quoted('PREFIX', prefixdir)
-conf.set_quoted('RANDOM_SEED', join_paths(randomseeddir, 'random-seed'))
+conf.set_quoted('RANDOM_SEED', randomseeddir / 'random-seed')
conf.set_quoted('RANDOM_SEED_DIR', randomseeddir)
conf.set_quoted('RC_LOCAL_PATH', get_option('rc-local'))
conf.set_quoted('ROOTBINDIR', rootbindir)
conf.set_quoted('ROOTPREFIX_NOSLASH', rootprefixdir_noslash)
conf.set_quoted('SYSCONF_DIR', sysconfdir)
conf.set_quoted('SYSCTL_DIR', sysctldir)
-conf.set_quoted('SYSTEMCTL_BINARY_PATH', join_paths(rootbindir, 'systemctl'))
-conf.set_quoted('SYSTEMD_BINARY_PATH', join_paths(rootlibexecdir, 'systemd'))
+conf.set_quoted('SYSTEMCTL_BINARY_PATH', rootbindir / 'systemctl')
+conf.set_quoted('SYSTEMD_BINARY_PATH', rootlibexecdir / 'systemd')
conf.set_quoted('SYSTEMD_CATALOG_DIR', catalogdir)
-conf.set_quoted('SYSTEMD_CGROUPS_AGENT_PATH', join_paths(rootlibexecdir, 'systemd-cgroups-agent'))
-conf.set_quoted('SYSTEMD_CRYPTSETUP_PATH', join_paths(rootlibexecdir, 'systemd-cryptsetup'))
-conf.set_quoted('SYSTEMD_EXPORT_PATH', join_paths(rootlibexecdir, 'systemd-export'))
-conf.set_quoted('SYSTEMD_FSCK_PATH', join_paths(rootlibexecdir, 'systemd-fsck'))
-conf.set_quoted('SYSTEMD_GROWFS_PATH', join_paths(rootlibexecdir, 'systemd-growfs'))
-conf.set_quoted('SYSTEMD_HOMEWORK_PATH', join_paths(rootlibexecdir, 'systemd-homework'))
-conf.set_quoted('SYSTEMD_IMPORT_FS_PATH', join_paths(rootlibexecdir, 'systemd-import-fs'))
-conf.set_quoted('SYSTEMD_IMPORT_PATH', join_paths(rootlibexecdir, 'systemd-import'))
-conf.set_quoted('SYSTEMD_KBD_MODEL_MAP', join_paths(pkgdatadir, 'kbd-model-map'))
-conf.set_quoted('SYSTEMD_LANGUAGE_FALLBACK_MAP', join_paths(pkgdatadir, 'language-fallback-map'))
-conf.set_quoted('SYSTEMD_MAKEFS_PATH', join_paths(rootlibexecdir, 'systemd-makefs'))
-conf.set_quoted('SYSTEMD_PULL_PATH', join_paths(rootlibexecdir, 'systemd-pull'))
-conf.set_quoted('SYSTEMD_SHUTDOWN_BINARY_PATH', join_paths(rootlibexecdir, 'systemd-shutdown'))
-conf.set_quoted('SYSTEMD_STDIO_BRIDGE_BINARY_PATH', join_paths(bindir, 'systemd-stdio-bridge'))
-conf.set_quoted('SYSTEMD_TEST_DATA', join_paths(testsdir, 'testdata'))
-conf.set_quoted('SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH', join_paths(rootbindir, 'systemd-tty-ask-password-agent'))
-conf.set_quoted('SYSTEMD_USERWORK_PATH', join_paths(rootlibexecdir, 'systemd-userwork'))
-conf.set_quoted('SYSTEMD_VERITYSETUP_PATH', join_paths(rootlibexecdir, 'systemd-veritysetup'))
-conf.set_quoted('SYSTEM_CONFIG_UNIT_DIR', join_paths(pkgsysconfdir, 'system'))
+conf.set_quoted('SYSTEMD_CGROUPS_AGENT_PATH', rootlibexecdir / 'systemd-cgroups-agent')
+conf.set_quoted('SYSTEMD_CRYPTSETUP_PATH', rootlibexecdir / 'systemd-cryptsetup')
+conf.set_quoted('SYSTEMD_EXPORT_PATH', rootlibexecdir / 'systemd-export')
+conf.set_quoted('SYSTEMD_FSCK_PATH', rootlibexecdir / 'systemd-fsck')
+conf.set_quoted('SYSTEMD_GROWFS_PATH', rootlibexecdir / 'systemd-growfs')
+conf.set_quoted('SYSTEMD_HOMEWORK_PATH', rootlibexecdir / 'systemd-homework')
+conf.set_quoted('SYSTEMD_IMPORT_FS_PATH', rootlibexecdir / 'systemd-import-fs')
+conf.set_quoted('SYSTEMD_IMPORT_PATH', rootlibexecdir / 'systemd-import')
+conf.set_quoted('SYSTEMD_KBD_MODEL_MAP', pkgdatadir / 'kbd-model-map')
+conf.set_quoted('SYSTEMD_LANGUAGE_FALLBACK_MAP', pkgdatadir / 'language-fallback-map')
+conf.set_quoted('SYSTEMD_MAKEFS_PATH', rootlibexecdir / 'systemd-makefs')
+conf.set_quoted('SYSTEMD_PULL_PATH', rootlibexecdir / 'systemd-pull')
+conf.set_quoted('SYSTEMD_SHUTDOWN_BINARY_PATH', rootlibexecdir / 'systemd-shutdown')
+conf.set_quoted('SYSTEMD_STDIO_BRIDGE_BINARY_PATH', bindir / 'systemd-stdio-bridge')
+conf.set_quoted('SYSTEMD_TEST_DATA', testsdir / 'testdata')
+conf.set_quoted('SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH', rootbindir / 'systemd-tty-ask-password-agent')
+conf.set_quoted('SYSTEMD_UPDATE_HELPER_PATH', rootlibexecdir / 'systemd-update-helper')
+conf.set_quoted('SYSTEMD_USERWORK_PATH', rootlibexecdir / 'systemd-userwork')
+conf.set_quoted('SYSTEMD_VERITYSETUP_PATH', rootlibexecdir / 'systemd-veritysetup')
+conf.set_quoted('SYSTEM_CONFIG_UNIT_DIR', pkgsysconfdir / 'system')
conf.set_quoted('SYSTEM_DATA_UNIT_DIR', systemunitdir)
conf.set_quoted('SYSTEM_ENV_GENERATOR_DIR', systemenvgeneratordir)
conf.set_quoted('SYSTEM_GENERATOR_DIR', systemgeneratordir)
conf.set_quoted('UDEVLIBEXECDIR', udevlibexecdir)
conf.set_quoted('UDEV_HWDB_DIR', udevhwdbdir)
conf.set_quoted('UDEV_RULES_DIR', udevrulesdir)
-conf.set_quoted('USER_CONFIG_UNIT_DIR', join_paths(pkgsysconfdir, 'user'))
+conf.set_quoted('UPDATE_HELPER_USER_TIMEOUT', get_option('update-helper-user-timeout'))
+conf.set_quoted('USER_CONFIG_UNIT_DIR', pkgsysconfdir / 'user')
conf.set_quoted('USER_DATA_UNIT_DIR', userunitdir)
conf.set_quoted('USER_ENV_GENERATOR_DIR', userenvgeneratordir)
conf.set_quoted('USER_GENERATOR_DIR', usergeneratordir)
-conf.set_quoted('USER_KEYRING_PATH', join_paths(pkgsysconfdir, 'import-pubring.gpg'))
+conf.set_quoted('USER_KEYRING_PATH', pkgsysconfdir / 'import-pubring.gpg')
conf.set_quoted('USER_PRESET_DIR', userpresetdir)
-conf.set_quoted('VENDOR_KEYRING_PATH', join_paths(rootlibexecdir, 'import-pubring.gpg'))
+conf.set_quoted('VENDOR_KEYRING_PATH', rootlibexecdir / 'import-pubring.gpg')
conf.set('ANSI_OK_COLOR', 'ANSI_' + get_option('ok-color').underscorify().to_upper())
+conf.set10('ENABLE_URLIFY', get_option('urlify'))
conf.set10('ENABLE_FEXECVE', get_option('fexecve'))
conf.set10('MEMORY_ACCOUNTING_DEFAULT', memory_accounting_default)
conf.set('STATUS_UNIT_FORMAT_DEFAULT', 'STATUS_UNIT_FORMAT_' + status_unit_format_default.to_upper())
'-Wno-format-signedness',
'-Wno-missing-field-initializers',
'-Wno-unused-parameter',
- '-Wno-unused-result',
]
possible_common_cc_flags = [
possible_common_cc_flags += '-Wno-maybe-uninitialized'
endif
+# Disable -Wno-unused-result with gcc, see
+# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425.
+if cc.get_id() == 'gcc'
+ possible_common_cc_flags += '-Wno-unused-result'
+endif
+
# --as-needed and --no-undefined are provided by meson by default,
-# run mesonconf to see what is enabled
+# run 'meson configure' to see what is enabled
possible_link_flags = [
'-Wl,-z,relro',
'-Wl,-z,now',
mkdir_p = 'mkdir -p $DESTDIR/@0@'
splash_bmp = files('test/splash.bmp')
-# if -Dxxx-path option is found, use that. Otherwise, check in $PATH,
+# If -Dxxx-path option is found, use that. Otherwise, check in $PATH,
# /usr/sbin, /sbin, and fall back to the default from middle column.
progs = [['quotaon', '/usr/sbin/quotaon' ],
['quotacheck', '/usr/sbin/quotacheck' ],
endif
conf.set('TIME_EPOCH', time_epoch)
+conf.set('CLOCK_VALID_RANGE_USEC_MAX', get_option('clock-valid-range-usec-max'))
+
foreach tuple : [['system-alloc-uid-min', 'SYS_UID_MIN', 1], # Also see login.defs(5).
['system-uid-max', 'SYS_UID_MAX', 999],
['system-alloc-gid-min', 'SYS_GID_MIN', 1],
default_user_path = get_option('user-path')
if default_user_path != ''
conf.set_quoted('DEFAULT_USER_PATH', default_user_path)
- default_user_path_display = default_user_path
-else
- # meson 0.49 fails when ?: is used in .format()
- default_user_path_display = '(same as system services)'
endif
else
clang = find_program('clang', required : bpf_framework_required)
llvm_strip = find_program('llvm-strip', required : bpf_framework_required)
- # Debian installs this in /usr/sbin/ which is not in $PATH
- # FIXME: use the 'dirs' parameter once we bump Meson version to >= 0.53
+
+ # Debian installs this in /usr/sbin/ which is not in $PATH.
+ # We check for 'bpftool' first, honouring $PATH, and in /usr/sbin/ for Debian.
bpftool = find_program('bpftool', '/usr/sbin/bpftool', required : bpf_framework_required)
+
bpf_arches = ['x86_64']
deps_found = libbpf.found() and clang.found() and llvm_strip.found() and bpftool.found()
# Can build BPF program from source code in restricted C
conf.set10('HAVE_MICROHTTPD', have)
want_libcryptsetup = get_option('libcryptsetup')
+want_libcryptsetup_plugins = get_option('libcryptsetup-plugins')
+
+if want_libcryptsetup_plugins == 'true' and want_libcryptsetup == 'false'
+ error('libcryptsetup-plugins can not be requested without libcryptsetup')
+endif
+
if want_libcryptsetup != 'false' and not skip_deps
libcryptsetup = dependency('libcryptsetup',
- version : '>= 2.0.1',
- required : want_libcryptsetup == 'true')
+ version : want_libcryptsetup_plugins == 'true' ? '>= 2.4.0' : '>= 2.0.1',
+ required : want_libcryptsetup == 'true' or want_libcryptsetup_plugins == 'true')
have = libcryptsetup.found()
conf.set10('HAVE_CRYPT_SET_METADATA_SIZE',
endif
conf.set10('HAVE_LIBCRYPTSETUP', have)
+if want_libcryptsetup_plugins != 'false' and not skip_deps
+ have = (cc.has_function('crypt_activate_by_token_pin', dependencies : libcryptsetup) and
+ cc.has_function('crypt_token_external_path', dependencies : libcryptsetup))
+else
+ have = false
+endif
+conf.set10('HAVE_LIBCRYPTSETUP_PLUGINS', have)
+
want_libcurl = get_option('libcurl')
if want_libcurl != 'false' and not skip_deps
libcurl = dependency('libcurl',
subdir('src/shared')
subdir('src/udev')
subdir('src/libudev')
+subdir('src/cryptsetup/cryptsetup-tokens')
libsystemd = shared_library(
'systemd',
c_args : static_libudev_pic ? [] : ['-fno-PIC'],
pic : static_libudev_pic)
+if conf.get('HAVE_LIBCRYPTSETUP_PLUGINS') == 1
+ if conf.get('HAVE_TPM2') == 1
+ cryptsetup_token_systemd_tpm2 = shared_library(
+ 'cryptsetup-token-systemd-tpm2',
+ link_args : ['-shared',
+ '-Wl,--version-script=' + cryptsetup_token_sym_path],
+ dependencies : libshared_deps + [libcryptsetup, versiondep],
+ link_with : [libshared],
+ link_whole : [cryptsetup_token_systemd_tpm2_static],
+ link_depends : cryptsetup_token_sym,
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : libcryptsetup_plugins_dir)
+ endif
+endif
+
############################################################
# systemd-analyze requires 'libcore'
module = tuple[0]
sym = 'src/nss-@0@/nss-@0@.sym'.format(module)
- version_script_arg = join_paths(project_source_root, sym)
+ version_script_arg = project_source_root / sym
sources = ['src/nss-@0@/nss-@0@.c'.format(module)]
if tuple.length() > 2
install_dir : rootlibexecdir)
meson.add_install_script(meson_make_symlink,
- join_paths(rootlibexecdir, 'systemd'),
- join_paths(rootsbindir, 'init'))
+ rootlibexecdir / 'systemd',
+ rootsbindir / 'init')
public_programs += executable(
'systemd-analyze',
install_dir : userenvgeneratordir)
meson.add_install_script(meson_make_symlink,
- join_paths(sysconfdir, 'environment'),
- join_paths(environmentdir, '99-environment.conf'))
+ sysconfdir / 'environment',
+ environmentdir / '99-environment.conf')
endif
if conf.get('ENABLE_HIBERNATE') == 1
install : true)
meson.add_install_script(meson_make_symlink,
- join_paths(bindir, 'resolvectl'),
- join_paths(rootsbindir, 'resolvconf'))
+ bindir / 'resolvectl',
+ rootsbindir / 'resolvconf')
meson.add_install_script(meson_make_symlink,
- join_paths(bindir, 'resolvectl'),
- join_paths(bindir, 'systemd-resolve'))
+ bindir / 'resolvectl',
+ bindir / 'systemd-resolve')
endif
if conf.get('ENABLE_LOGIND') == 1
install_dir : rootbindir)
if conf.get('HAVE_PAM') == 1
- version_script_arg = join_paths(project_source_root, pam_systemd_sym)
+ version_script_arg = project_source_root / pam_systemd_sym
pam_systemd = shared_library(
'pam_systemd',
pam_systemd_c,
install_dir : rootbindir)
if conf.get('HAVE_PAM') == 1
- version_script_arg = join_paths(project_source_root, pam_systemd_home_sym)
+ version_script_arg = project_source_root / pam_systemd_home_sym
pam_systemd = shared_library(
'pam_systemd_home',
pam_systemd_home_c,
foreach alias : (['halt', 'poweroff', 'reboot', 'shutdown'] +
(conf.get('HAVE_SYSV_COMPAT') == 1 ? ['runlevel', 'telinit'] : []))
meson.add_install_script(meson_make_symlink,
- join_paths(rootbindir, 'systemctl'),
- join_paths(rootsbindir, alias))
+ rootbindir / 'systemctl',
+ rootsbindir / alias)
endforeach
meson.add_install_script(meson_make_symlink,
- join_paths(rootbindir, 'udevadm'),
- join_paths(rootlibexecdir, 'systemd-udevd'))
+ rootbindir / 'udevadm',
+ rootlibexecdir / 'systemd-udevd')
if conf.get('ENABLE_BACKLIGHT') == 1
executable(
mkdir_p.format(binfmtdir))
if install_sysconfdir
meson.add_install_script('sh', '-c',
- mkdir_p.format(join_paths(sysconfdir, 'binfmt.d')))
+ mkdir_p.format(sysconfdir / 'binfmt.d'))
endif
endif
install : true)
meson.add_install_script(meson_make_symlink,
- 'systemd-mount', join_paths(bindir, 'systemd-umount'))
+ 'systemd-mount', bindir / 'systemd-umount')
public_programs += executable(
'systemd-run',
mkdir_p.format(modulesloaddir))
if install_sysconfdir
meson.add_install_script('sh', '-c',
- mkdir_p.format(join_paths(sysconfdir, 'modules-load.d')))
+ mkdir_p.format(sysconfdir / 'modules-load.d'))
endif
endif
output : 'systemd-runtest.env',
command : [sh, '-c',
'{ echo SYSTEMD_TEST_DATA=@0@; echo SYSTEMD_CATALOG_DIR=@1@; } >@OUTPUT@'.format(
- join_paths(project_source_root, 'test'),
- join_paths(project_build_root, 'catalog'))],
+ project_source_root / 'test',
+ project_build_root / 'catalog')],
build_by_default : true)
test_cflags = ['-DTEST_CODE=1']
build_by_default : want_tests != 'false',
install_rpath : rootlibexecdir,
install : install_tests,
- install_dir : join_paths(testsdir, type))
+ install_dir : testsdir / type)
if type == 'manual'
message('@0@ is a manual test'.format(name))
if b == name
test('@0@_@1@'.format(b, c),
exe,
- args : [join_paths(project_source_root, p)])
+ args : [project_source_root / p])
endif
endforeach
endif
endforeach
-run_target(
- 'fuzzers',
- depends : fuzzer_exes,
- command : ['true'])
+alias_target('fuzzers', fuzzer_exes)
############################################################
test('github-pages',
jekyll,
args : ['build',
- '--source', join_paths(project_source_root, 'docs'),
- '--destination', join_paths(project_build_root, '_site')])
+ '--source', project_source_root / 'docs',
+ '--destination', project_build_root / '_site'])
endif
############################################################
output : name,
depends : build,
command : [ln, '-fs',
- join_paths(build.full_path(), b),
+ build.full_path() / b,
'@OUTPUT@'],
build_by_default : true)
else
env : ['UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1'],
timeout : 60,
args : [exe.full_path(),
- join_paths(project_source_root, p)])
+ project_source_root / p])
endif
endforeach
endif
depends : [man, libsystemd, libudev],
command : [check_api_docs_sh, libsystemd.full_path(), libudev.full_path()])
-############################################################
-
-if dbus_docs.length() > 0
- custom_target(
- 'update-dbus-docs',
- output : 'update-dbus-docs',
- command : [update_dbus_docs_py,
- '--build-dir=@0@'.format(project_build_root),
- '@INPUT@'],
- input : dbus_docs)
-
- if conf.get('BUILD_MODE_DEVELOPER') == 1
- test('dbus-docs-fresh',
- update_dbus_docs_py,
- args : ['--build-dir=@0@'.format(project_build_root),
- '--test'] + dbus_docs)
- endif
-endif
-
-custom_target(
- 'update-man-rules',
- output : 'update-man-rules',
- command : [sh, '-c',
- 'cd @0@ && '.format(meson.build_root()) +
- 'python3 @0@/tools/update-man-rules.py $(find @0@ -wholename "*/man/*.xml") >t && '.format(project_source_root) +
- 'mv t @0@/man/rules/meson.build'.format(meson.current_source_dir())],
- depends : custom_entities_ent)
+alias_target('update-dbus-docs', update_dbus_docs)
+alias_target('update-man-rules', update_man_rules)
############################################################
-watchdog_opt = service_watchdog == '' ? 'disabled' : service_watchdog
-
-status = [
- '@0@ @1@'.format(meson.project_name(), meson.project_version()),
-
- 'build mode: @0@'.format(get_option('mode')),
- 'split /usr: @0@'.format(split_usr),
- 'split bin-sbin: @0@'.format(split_bin),
- 'prefix directory: @0@'.format(prefixdir),
- 'rootprefix directory: @0@'.format(rootprefixdir),
- 'sysconf directory: @0@'.format(sysconfdir),
- 'include directory: @0@'.format(includedir),
- 'lib directory: @0@'.format(libdir),
- 'rootlib directory: @0@'.format(rootlibdir),
- 'SysV init scripts: @0@'.format(sysvinit_path),
- 'SysV rc?.d directories: @0@'.format(sysvrcnd_path),
- 'PAM modules directory: @0@'.format(pamlibdir),
- 'PAM configuration directory: @0@'.format(pamconfdir),
- 'RPM macros directory: @0@'.format(rpmmacrosdir),
- 'modprobe.d directory: @0@'.format(modprobedir),
- 'D-Bus policy directory: @0@'.format(dbuspolicydir),
- 'D-Bus session directory: @0@'.format(dbussessionservicedir),
- 'D-Bus system directory: @0@'.format(dbussystemservicedir),
- 'bash completions directory: @0@'.format(bashcompletiondir),
- 'zsh completions directory: @0@'.format(zshcompletiondir),
- 'extra start script: @0@'.format(get_option('rc-local')),
- 'debug shell: @0@ @ @1@'.format(get_option('debug-shell'),
- get_option('debug-tty')),
- 'system UIDs: <=@0@ (alloc >=@1@)'.format(conf.get('SYSTEM_UID_MAX'),
- conf.get('SYSTEM_ALLOC_UID_MIN')),
- 'system GIDs: <=@0@ (alloc >=@1@)'.format(conf.get('SYSTEM_GID_MAX'),
- conf.get('SYSTEM_ALLOC_GID_MIN')),
- 'dynamic UIDs: @0@…@1@'.format(dynamic_uid_min, dynamic_uid_max),
- 'container UID bases: @0@…@1@'.format(container_uid_base_min, container_uid_base_max),
- 'static UID/GID allocations: @0@'.format(' '.join(static_ugids)),
- '/dev/kvm access mode: @0@'.format(get_option('dev-kvm-mode')),
- 'render group access mode: @0@'.format(get_option('group-render-mode')),
- 'certificate root directory: @0@'.format(get_option('certificate-root')),
- 'support URL: @0@'.format(support_url),
- 'nobody user name: @0@'.format(nobody_user),
- 'nobody group name: @0@'.format(nobody_group),
- 'fallback hostname: @0@'.format(get_option('fallback-hostname')),
-
- 'default DNSSEC mode: @0@'.format(default_dnssec),
- 'default DNS-over-TLS mode: @0@'.format(default_dns_over_tls),
- 'default mDNS mode: @0@'.format(default_mdns),
- 'default LLMNR mode: @0@'.format(default_llmnr),
- 'default cgroup hierarchy: @0@'.format(default_hierarchy),
- 'default net.naming-scheme setting: @0@'.format(default_net_naming_scheme),
- 'default KillUserProcesses setting: @0@'.format(kill_user_processes),
- 'default locale: @0@'.format(default_locale),
- 'default user $PATH: @0@'.format(default_user_path_display),
- 'systemd service watchdog: @0@'.format(watchdog_opt)]
-
-alt_dns_servers = '\n '.join(dns_servers.split(' '))
-alt_ntp_servers = '\n '.join(ntp_servers.split(' '))
-status += [
- 'default DNS servers: @0@'.format(alt_dns_servers),
- 'default NTP servers: @0@'.format(alt_ntp_servers)]
alt_time_epoch = run_command('date', '-Is', '-u', '-d',
'@@0@'.format(time_epoch)).stdout().strip()
-status += [
- 'time epoch: @0@ (@1@)'.format(time_epoch, alt_time_epoch)]
+
+summary({
+ 'build mode' : get_option('mode'),
+ 'split /usr' : split_usr,
+ 'split bin-sbin' : split_bin,
+ 'prefix directory' : prefixdir,
+ 'rootprefix directory' : rootprefixdir,
+ 'sysconf directory' : sysconfdir,
+ 'include directory' : includedir,
+ 'lib directory' : libdir,
+ 'rootlib directory' : rootlibdir,
+ 'SysV init scripts' : sysvinit_path,
+ 'SysV rc?.d directories' : sysvrcnd_path,
+ 'PAM modules directory' : pamlibdir,
+ 'PAM configuration directory' : pamconfdir,
+ 'libcryptsetup plugins directory' : libcryptsetup_plugins_dir,
+ 'RPM macros directory' : rpmmacrosdir,
+ 'modprobe.d directory' : modprobedir,
+ 'D-Bus policy directory' : dbuspolicydir,
+ 'D-Bus session directory' : dbussessionservicedir,
+ 'D-Bus system directory' : dbussystemservicedir,
+ 'bash completions directory' : bashcompletiondir,
+ 'zsh completions directory' : zshcompletiondir,
+ 'extra start script' : get_option('rc-local'),
+ 'debug shell' : '@0@ @ @1@'.format(get_option('debug-shell'),
+ get_option('debug-tty')),
+ 'system UIDs' : '<=@0@ (alloc >=@1@)'.format(conf.get('SYSTEM_UID_MAX'),
+ conf.get('SYSTEM_ALLOC_UID_MIN')),
+ 'system GIDs' : '<=@0@ (alloc >=@1@)'.format(conf.get('SYSTEM_GID_MAX'),
+ conf.get('SYSTEM_ALLOC_GID_MIN')),
+ 'dynamic UIDs' : '@0@…@1@'.format(dynamic_uid_min, dynamic_uid_max),
+ 'container UID bases' : '@0@…@1@'.format(container_uid_base_min, container_uid_base_max),
+ 'static UID/GID allocations' : ' '.join(static_ugids),
+ '/dev/kvm access mode' : get_option('dev-kvm-mode'),
+ 'render group access mode' : get_option('group-render-mode'),
+ 'certificate root directory' : get_option('certificate-root'),
+ 'support URL' : support_url,
+ 'nobody user name' : nobody_user,
+ 'nobody group name' : nobody_group,
+ 'fallback hostname' : get_option('fallback-hostname'),
+ 'default DNSSEC mode' : default_dnssec,
+ 'default DNS-over-TLS mode' : default_dns_over_tls,
+ 'default mDNS mode' : default_mdns,
+ 'default LLMNR mode' : default_llmnr,
+ 'default DNS servers' : dns_servers.split(' '),
+ 'default NTP servers' : ntp_servers.split(' '),
+ 'default cgroup hierarchy' : default_hierarchy,
+ 'default net.naming-scheme value' : default_net_naming_scheme,
+ 'default KillUserProcesses value' : kill_user_processes,
+ 'default locale' : default_locale,
+ 'default user $PATH' :
+ default_user_path != '' ? default_user_path : '(same as system services)',
+ 'systemd service watchdog' : service_watchdog == '' ? 'disabled' : service_watchdog,
+ 'time epoch' : '@0@ (@1@)'.format(time_epoch, alt_time_epoch)})
# TODO:
# CFLAGS: ${OUR_CFLAGS} ${CFLAGS}
# LDFLAGS: ${OUR_LDFLAGS} ${LDFLAGS}
if conf.get('ENABLE_EFI') == 1
- status += 'efi arch: @0@'.format(efi_arch)
+ summary({'efi arch' : efi_arch},
+ section : 'Extensible Firmware Interface')
if have_gnu_efi
- status += [
- 'EFI machine type: @0@'.format(EFI_MACHINE_TYPE_NAME),
- 'EFI CC @0@'.format(' '.join(efi_cc)),
- 'EFI lds: @0@'.format(efi_lds),
- 'EFI crt0: @0@'.format(efi_crt0),
- 'EFI include directory: @0@'.format(efi_incdir)]
+ summary({
+ 'EFI machine type' : EFI_MACHINE_TYPE_NAME,
+ 'EFI CC' : '@0@'.format(' '.join(efi_cc)),
+ 'EFI lds' : efi_lds,
+ 'EFI crt0' : efi_crt0,
+ 'EFI include directory' : efi_incdir},
+ section : 'Extensible Firmware Interface')
endif
endif
['gnutls'],
['libbpf'],
['libcryptsetup'],
+ ['libcryptsetup-plugins'],
['libcurl'],
['libfdisk'],
['libfido2'],
missing += 'DNS-over-TLS'
endif
-status += [
- '',
- 'enabled features: @0@'.format(', '.join(found)),
- '',
- 'disabled features: @0@'.format(', '.join(missing)),
- '']
-message('\n '.join(status))
+summary({
+ 'enabled' : ', '.join(found),
+ 'disabled' : ', '.join(missing)},
+ section : 'Features')
if rootprefixdir != rootprefix_default
warning('\n' +
description : 'directory for xinitrc files')
option('rpmmacrosdir', type : 'string', value : 'lib/rpm/macros.d',
description : 'directory for rpm macros ["no" disables]')
+option('update-helper-user-timeout', type : 'string', value : '15s',
+ description : 'how long to wait for user manager operations')
option('pamlibdir', type : 'string',
description : 'directory for PAM modules')
option('pamconfdir', type : 'string',
description : 'directory for PAM configuration ["no" disables]')
+option('libcryptsetup-plugins-dir', type : 'string',
+ description : 'directory for libcryptsetup plugins')
option('docdir', type : 'string',
description : 'documentation directory')
option('install-sysconfdir', type : 'combo', choices : ['true', 'no-samples', 'false'], value : 'true',
description : 'use unit name or description in messages by default')
option('time-epoch', type : 'integer', value : '-1',
description : 'time epoch for time clients')
+option('clock-valid-range-usec-max', type : 'integer', value : '473364000000000', # 15 years
+ description : 'maximum value in microseconds for the difference between RTC and epoch, exceeding which is considered an RTC error')
option('system-alloc-uid-min', type : 'integer', value : '-1',
description : 'minimum system UID used when allocating')
description : 'libµhttpd support')
option('libcryptsetup', type : 'combo', choices : ['auto', 'true', 'false'],
description : 'libcryptsetup support')
+option('libcryptsetup-plugins', type : 'combo', choices : ['auto', 'true', 'false'],
+ description : 'libcryptsetup LUKS2 external token handlers support (plugins)')
option('libcurl', type : 'combo', choices : ['auto', 'true', 'false'],
description : 'libcurl support')
option('idn', type : 'boolean',
'highlight-cyan', 'highlight-white'],
value : 'green',
description: 'color of the "OK" status message')
+option('urlify', type : 'boolean', value : 'true',
+ description : 'enable pager Hyperlink ANSI sequence support')
option('fexecve', type : 'boolean', value : 'false',
description : 'use fexecve() to spawn children')
if install_sysconfdir
meson.add_install_script('sh', '-c',
- mkdir_p.format(join_paths(sysconfdir, 'systemd/network')))
+ mkdir_p.format(sysconfdir / 'systemd/network'))
endif
endif
enable systemd-homed.service
enable systemd-userdbd.socket
enable systemd-pstore.service
+enable systemd-boot-update.service
disable console-getty.service
disable debug-shell.service
if bash_completion.found()
bashcompletiondir = bash_completion.get_pkgconfig_variable('completionsdir')
else
- bashcompletiondir = join_paths(datadir, 'bash-completion/completions')
+ bashcompletiondir = datadir / 'bash-completion/completions'
endif
endif
'--version[Show package version]' \
'--wait=[Wait until service stopped again]' \
'--working-directory=[Run with the specified working directory]' \
- '*::command:_command'
+ '(-):command: _command_names -e' \
+ '*::arguments:_normal'
zshcompletiondir = get_option('zshcompletiondir')
if zshcompletiondir == ''
- zshcompletiondir = join_paths(datadir, 'zsh/site-functions')
+ zshcompletiondir = datadir / 'zsh/site-functions'
endif
custom_target(
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
if (optind < argc)
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
if (optind == argc)
assert(a->parameter < _SYSCALL_FILTER_SET_MAX);
const SyscallFilterSet *f = syscall_filter_sets + a->parameter;
- char *d = NULL;
+ _cleanup_free_ char *d = NULL;
uint64_t b;
+ int r;
if (!info->system_call_filter_allow_list && set_isempty(info->system_call_filter)) {
- d = strdup("Service does not filter system calls");
+ r = free_and_strdup(&d, "Service does not filter system calls");
b = 10;
} else {
bool bad;
if (info->system_call_filter_allow_list) {
if (bad) {
- (void) asprintf(&d, "System call allow list defined for service, and %s is included "
- "(e.g. %s is allowed)",
- f->name, offender);
+ r = asprintf(&d, "System call allow list defined for service, and %s is included "
+ "(e.g. %s is allowed)",
+ f->name, offender);
b = 9;
} else {
- (void) asprintf(&d, "System call allow list defined for service, and %s is not included",
- f->name);
+ r = asprintf(&d, "System call allow list defined for service, and %s is not included",
+ f->name);
b = 0;
}
} else {
if (bad) {
- (void) asprintf(&d, "System call deny list defined for service, and %s is not included "
- "(e.g. %s is allowed)",
- f->name, offender);
+ r = asprintf(&d, "System call deny list defined for service, and %s is not included "
+ "(e.g. %s is allowed)",
+ f->name, offender);
b = 10;
} else {
- (void) asprintf(&d, "System call deny list defined for service, and %s is included",
- f->name);
+ r = asprintf(&d, "System call deny list defined for service, and %s is included",
+ f->name);
b = 0;
}
}
}
-
- if (!d)
+ if (r < 0)
return log_oom();
*ret_badness = b;
- *ret_description = d;
+ *ret_description = TAKE_PTR(d);
return 0;
}
}
static int pretty_boot_time(sd_bus *bus, char **_buf) {
- char ts[FORMAT_TIMESPAN_MAX];
BootTimes *t;
static char buf[4096];
size_t size;
size = strpcpyf(&ptr, size, "Startup finished in ");
if (t->firmware_time > 0)
- size = strpcpyf(&ptr, size, "%s (firmware) + ", format_timespan(ts, sizeof(ts), t->firmware_time - t->loader_time, USEC_PER_MSEC));
+ size = strpcpyf(&ptr, size, "%s (firmware) + ", FORMAT_TIMESPAN(t->firmware_time - t->loader_time, USEC_PER_MSEC));
if (t->loader_time > 0)
- size = strpcpyf(&ptr, size, "%s (loader) + ", format_timespan(ts, sizeof(ts), t->loader_time, USEC_PER_MSEC));
+ size = strpcpyf(&ptr, size, "%s (loader) + ", FORMAT_TIMESPAN(t->loader_time, USEC_PER_MSEC));
if (t->kernel_done_time > 0)
- size = strpcpyf(&ptr, size, "%s (kernel) + ", format_timespan(ts, sizeof(ts), t->kernel_done_time, USEC_PER_MSEC));
+ size = strpcpyf(&ptr, size, "%s (kernel) + ", FORMAT_TIMESPAN(t->kernel_done_time, USEC_PER_MSEC));
if (t->initrd_time > 0)
- size = strpcpyf(&ptr, size, "%s (initrd) + ", format_timespan(ts, sizeof(ts), t->userspace_time - t->initrd_time, USEC_PER_MSEC));
+ size = strpcpyf(&ptr, size, "%s (initrd) + ", FORMAT_TIMESPAN(t->userspace_time - t->initrd_time, USEC_PER_MSEC));
- size = strpcpyf(&ptr, size, "%s (userspace) ", format_timespan(ts, sizeof(ts), t->finish_time - t->userspace_time, USEC_PER_MSEC));
+ size = strpcpyf(&ptr, size, "%s (userspace) ", FORMAT_TIMESPAN(t->finish_time - t->userspace_time, USEC_PER_MSEC));
if (t->kernel_done_time > 0)
- strpcpyf(&ptr, size, "= %s ", format_timespan(ts, sizeof(ts), t->firmware_time + t->finish_time, USEC_PER_MSEC));
+ strpcpyf(&ptr, size, "= %s ", FORMAT_TIMESPAN(t->firmware_time + t->finish_time, USEC_PER_MSEC));
if (unit_id && timestamp_is_set(activated_time)) {
usec_t base = t->userspace_time > 0 ? t->userspace_time : t->reverse_offset;
size = strpcpyf(&ptr, size, "\n%s reached after %s in userspace", unit_id,
- format_timespan(ts, sizeof(ts), activated_time - base, USEC_PER_MSEC));
+ FORMAT_TIMESPAN(activated_time - base, USEC_PER_MSEC));
} else if (unit_id && activated_time == 0)
size = strpcpyf(&ptr, size, "\n%s was never reached", unit_id);
else if (unit_id && activated_time == USEC_INFINITY)
}
static int plot_unit_times(UnitTimes *u, double width, int y) {
- char ts[FORMAT_TIMESPAN_MAX];
bool b;
if (!u->name)
b = u->activating * SCALE_X < width / 2;
if (u->time)
svg_text(b, u->activating, y, "%s (%s)",
- u->name, format_timespan(ts, sizeof(ts), u->time, USEC_PER_MSEC));
+ u->name, FORMAT_TIMESPAN(u->time, USEC_PER_MSEC));
else
svg_text(b, u->activating, y, "%s", u->name);
UnitTimes *times,
BootTimes *boot) {
- char ts[FORMAT_TIMESPAN_MAX], ts2[FORMAT_TIMESPAN_MAX];
-
for (unsigned i = level; i != 0; i--)
printf("%s", special_glyph(branches & (1 << (i-1)) ? SPECIAL_GLYPH_TREE_VERTICAL : SPECIAL_GLYPH_TREE_SPACE));
if (times) {
if (times->time > 0)
printf("%s%s @%s +%s%s", ansi_highlight_red(), name,
- format_timespan(ts, sizeof(ts), times->activating - boot->userspace_time, USEC_PER_MSEC),
- format_timespan(ts2, sizeof(ts2), times->time, USEC_PER_MSEC), ansi_normal());
+ FORMAT_TIMESPAN(times->activating - boot->userspace_time, USEC_PER_MSEC),
+ FORMAT_TIMESPAN(times->time, USEC_PER_MSEC), ansi_normal());
else if (times->activated > boot->userspace_time)
- printf("%s @%s", name, format_timespan(ts, sizeof(ts), times->activated - boot->userspace_time, USEC_PER_MSEC));
+ printf("%s @%s", name, FORMAT_TIMESPAN(times->activated - boot->userspace_time, USEC_PER_MSEC));
else
printf("%s", name);
} else
static int list_dependencies(sd_bus *bus, const char *name) {
_cleanup_strv_free_ char **units = NULL;
- char ts[FORMAT_TIMESPAN_MAX];
UnitTimes *times;
int r;
const char *id;
if (times) {
if (times->time)
printf("%s%s +%s%s\n", ansi_highlight_red(), id,
- format_timespan(ts, sizeof(ts), times->time, USEC_PER_MSEC), ansi_normal());
+ FORMAT_TIMESPAN(times->time, USEC_PER_MSEC), ansi_normal());
else if (times->activated > boot->userspace_time)
- printf("%s @%s\n", id, format_timespan(ts, sizeof(ts), times->activated - boot->userspace_time, USEC_PER_MSEC));
+ printf("%s @%s\n", id,
+ FORMAT_TIMESPAN(times->activated - boot->userspace_time, USEC_PER_MSEC));
else
printf("%s\n", id);
}
return -EINVAL;
default:
- assert_not_reached("Unhandled option code.");
+ assert_not_reached();
}
if (arg_scope == UNIT_FILE_GLOBAL &&
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
if (isempty(emoji) || streq(emoji, "auto"))
return log_device_error_errno(device, r, "Failed to write %s: %m", saved);
} else
- assert_not_reached("Unknown verb.");
+ assert_not_reached();
return 0;
}
#define free_and_replace(a, b) \
({ \
- free(a); \
- (a) = (b); \
- (b) = NULL; \
+ typeof(a)* _a = &(a); \
+ typeof(b)* _b = &(b); \
+ free(*_a); \
+ (*_a) = (*_b); \
+ (*_b) = NULL; \
0; \
})
if (streq(arch_map[i].machine, u.machine))
return cached = arch_map[i].arch;
- assert_not_reached("Couldn't identify architecture. You need to patch systemd.");
+ assert_not_reached();
return _ARCHITECTURE_INVALID;
}
n = st.st_size - 4;
if (DEBUG_LOGGING) {
- char ts[FORMAT_TIMESPAN_MAX];
- usec_t end;
-
- end = now(CLOCK_MONOTONIC);
+ usec_t end = now(CLOCK_MONOTONIC);
if (end > begin + EFI_RETRY_DELAY)
log_debug("Detected slow EFI variable read access on %s: %s",
- variable, format_timespan(ts, sizeof(ts), end - begin, 1));
+ variable, FORMAT_TIMESPAN(end - begin, 1));
}
/* Note that efivarfs interestingly doesn't require ftruncate() to update an existing EFI variable
return log_debug_errno(errno, "Failed to stat EFI variable SystemdOptions: %m");
if (stat(EFIVAR_CACHE_PATH(EFI_SYSTEMD_VARIABLE(SystemdOptions)), &b) < 0) {
- if (errno != -ENOENT)
+ if (errno != ENOENT)
log_debug_errno(errno, "Failed to stat "EFIVAR_CACHE_PATH(EFI_SYSTEMD_VARIABLE(SystemdOptions))": %m");
} else if (compare_stat_mtime(&a, &b) > 0)
log_debug("Variable SystemdOptions in evifarfs is newer than in cache.");
#include "escape.h"
#include "hexdecoct.h"
#include "macro.h"
+#include "strv.h"
#include "utf8.h"
int cescape_char(char c, char *buf) {
return r;
}
-int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret) {
- char *r, *t;
+ssize_t cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret) {
+ _cleanup_free_ char *ans = NULL;
+ char *t;
const char *f;
size_t pl;
+ int r;
assert(s);
assert(ret);
pl = strlen_ptr(prefix);
- r = new(char, pl+length+1);
- if (!r)
+ ans = new(char, pl+length+1);
+ if (!ans)
return -ENOMEM;
if (prefix)
- memcpy(r, prefix, pl);
+ memcpy(ans, prefix, pl);
- for (f = s, t = r + pl; f < s + length; f++) {
+ for (f = s, t = ans + pl; f < s + length; f++) {
size_t remaining;
bool eight_bit = false;
char32_t u;
- int k;
remaining = s + length - f;
assert(remaining > 0);
continue;
}
- free(r);
return -EINVAL;
}
- k = cunescape_one(f + 1, remaining - 1, &u, &eight_bit, flags & UNESCAPE_ACCEPT_NUL);
- if (k < 0) {
+ r = cunescape_one(f + 1, remaining - 1, &u, &eight_bit, flags & UNESCAPE_ACCEPT_NUL);
+ if (r < 0) {
if (flags & UNESCAPE_RELAX) {
/* Invalid escape code, let's take it literal then */
*(t++) = '\\';
continue;
}
- free(r);
- return k;
+ return r;
}
- f += k;
+ f += r;
if (eight_bit)
/* One byte? Set directly as specified */
*(t++) = u;
*t = 0;
- *ret = r;
- return t - r;
+ assert(t >= ans); /* Let static analyzers know that the answer is non-negative. */
+ *ret = TAKE_PTR(ans);
+ return t - *ret;
}
char* xescape_full(const char *s, const char *bad, size_t console_width, XEscapeFlags flags) {
return str_realloc(buf);
}
+
+char* quote_command_line(char **argv) {
+ _cleanup_free_ char *result = NULL;
+
+ assert(argv);
+
+ char **a;
+ STRV_FOREACH(a, argv) {
+ _cleanup_free_ char *t = NULL;
+
+ t = shell_maybe_quote(*a, SHELL_ESCAPE_EMPTY);
+ if (!t)
+ return NULL;
+
+ if (!strextend_with_separator(&result, " ", t))
+ return NULL;
+ }
+
+ return TAKE_PTR(result);
+}
char* cescape_length(const char *s, size_t n);
int cescape_char(char c, char *buf);
-int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret);
-static inline int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret) {
+int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit, bool accept_nul);
+
+ssize_t cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret);
+static inline ssize_t cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret) {
return cunescape_length_with_prefix(s, length, NULL, flags, ret);
}
-static inline int cunescape(const char *s, UnescapeFlags flags, char **ret) {
+static inline ssize_t cunescape(const char *s, UnescapeFlags flags, char **ret) {
return cunescape_length(s, strlen(s), flags, ret);
}
-int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit, bool accept_nul);
typedef enum XEscapeFlags {
XESCAPE_8_BIT = 1 << 0,
char* shell_escape(const char *s, const char *bad);
char* shell_maybe_quote(const char *s, ShellEscapeFlags flags);
+char* quote_command_line(char **argv);
#define HW_ADDR_TO_STRING_MAX (3*HW_ADDR_MAX_SIZE)
char* hw_addr_to_string(const struct hw_addr_data *addr, char buffer[HW_ADDR_TO_STRING_MAX]);
-/* Use only as function argument, never stand-alone! */
+/* Note: the lifetime of the compound literal is the immediately surrounding block,
+ * see C11 §6.5.2.5, and
+ * https://stackoverflow.com/questions/34880638/compound-literal-lifetime-and-if-blocks */
#define HW_ADDR_TO_STR(hw_addr) hw_addr_to_string((hw_addr), (char[HW_ADDR_TO_STRING_MAX]){})
#define HW_ADDR_NULL ((const struct hw_addr_data){})
return (int) (m - 1);
}
-int close_all_fds(const int except[], size_t n_except) {
+int close_all_fds_full(int except[], size_t n_except, bool allow_alloc) {
static bool have_close_range = true; /* Assume we live in the future */
_cleanup_closedir_ DIR *d = NULL;
- struct dirent *de;
int r = 0;
assert(n_except == 0 || except);
/* Close everything. Yay! */
if (close_range(3, -1, 0) >= 0)
- return 1;
+ return 0;
- if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
+ if (ERRNO_IS_NOT_SUPPORTED(errno) || ERRNO_IS_PRIVILEGE(errno))
+ have_close_range = false;
+ else
return -errno;
- have_close_range = false;
} else {
- _cleanup_free_ int *sorted_malloc = NULL;
- size_t n_sorted;
- int *sorted;
-
- assert(n_except < SIZE_MAX);
- n_sorted = n_except + 1;
-
- if (n_sorted > 64) /* Use heap for large numbers of fds, stack otherwise */
- sorted = sorted_malloc = new(int, n_sorted);
- else
- sorted = newa(int, n_sorted);
-
- if (sorted) {
- int c = 0;
-
- memcpy(sorted, except, n_except * sizeof(int));
-
- /* Let's add fd 2 to the list of fds, to simplify the loop below, as this
- * allows us to cover the head of the array the same way as the body */
- sorted[n_sorted-1] = 2;
+ typesafe_qsort(except, n_except, cmp_int);
- typesafe_qsort(sorted, n_sorted, cmp_int);
+ for (size_t i = 0; i < n_except; i++) {
+ int start = i == 0 ? 2 : MAX(except[i-1], 2); /* The first three fds shall always remain open */
+ int end = MAX(except[i], 2);
- for (size_t i = 0; i < n_sorted-1; i++) {
- int start, end;
+ assert(end >= start);
- start = MAX(sorted[i], 2); /* The first three fds shall always remain open */
- end = MAX(sorted[i+1], 2);
-
- assert(end >= start);
-
- if (end - start <= 1)
- continue;
-
- /* Close everything between the start and end fds (both of which shall stay open) */
- if (close_range(start + 1, end - 1, 0) < 0) {
- if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
- return -errno;
+ if (end - start <= 1)
+ continue;
+ /* Close everything between the start and end fds (both of which shall stay open) */
+ if (close_range(start + 1, end - 1, 0) < 0) {
+ if (ERRNO_IS_NOT_SUPPORTED(errno) || ERRNO_IS_PRIVILEGE(errno))
have_close_range = false;
- break;
- }
-
- c += end - start - 1;
+ else
+ return -errno;
+ goto opendir_fallback;
}
+ }
- if (have_close_range) {
- /* The loop succeeded. Let's now close everything beyond the end */
+ /* The loop succeeded. Let's now close everything beyond the end */
- if (sorted[n_sorted-1] >= INT_MAX) /* Dont let the addition below overflow */
- return c;
+ if (except[n_except-1] >= INT_MAX) /* Don't let the addition below overflow */
+ return 0;
- if (close_range(sorted[n_sorted-1] + 1, -1, 0) >= 0)
- return c + 1;
+ int start = MAX(except[n_except-1], 2);
- if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
- return -errno;
+ if (close_range(start + 1, -1, 0) >= 0)
+ return 0;
- have_close_range = false;
- }
- }
+ if (ERRNO_IS_NOT_SUPPORTED(errno) || ERRNO_IS_PRIVILEGE(errno))
+ have_close_range = false;
+ else
+ return -errno;
}
-
- /* Fallback on OOM or if close_range() is not supported */
}
- d = opendir("/proc/self/fd");
- if (!d) {
- int fd, max_fd;
+ /* Fallback for when close_range() is not supported */
+ opendir_fallback:
+ d = allow_alloc ? opendir("/proc/self/fd") : NULL;
+ if (d) {
+ struct dirent *de;
- /* When /proc isn't available (for example in chroots) the fallback is brute forcing through
- * the fd table */
+ FOREACH_DIRENT(de, d, return -errno) {
+ int fd = -1, q;
- max_fd = get_max_fd();
- if (max_fd < 0)
- return max_fd;
+ if (safe_atoi(de->d_name, &fd) < 0)
+ /* Let's better ignore this, just in case */
+ continue;
- /* Refuse to do the loop over more too many elements. It's better to fail immediately than to
- * spin the CPU for a long time. */
- if (max_fd > MAX_FD_LOOP_LIMIT)
- return log_debug_errno(SYNTHETIC_ERRNO(EPERM),
- "/proc/self/fd is inaccessible. Refusing to loop over %d potential fds.",
- max_fd);
+ if (fd < 3)
+ continue;
- for (fd = 3; fd >= 0; fd = fd < max_fd ? fd + 1 : -1) {
- int q;
+ if (fd == dirfd(d))
+ continue;
if (fd_in_set(fd, except, n_except))
continue;
q = close_nointr(fd);
- if (q < 0 && q != -EBADF && r >= 0)
+ if (q < 0 && q != -EBADF && r >= 0) /* Valgrind has its own FD and doesn't want to have it closed */
r = q;
}
return r;
}
- FOREACH_DIRENT(de, d, return -errno) {
- int fd = -1, q;
+ /* Fallback for when /proc isn't available (for example in chroots) or when we cannot allocate by
+ * brute-forcing through the file descriptor table. */
- if (safe_atoi(de->d_name, &fd) < 0)
- /* Let's better ignore this, just in case */
- continue;
+ int max_fd = get_max_fd();
+ if (max_fd < 0)
+ return max_fd;
- if (fd < 3)
- continue;
+ /* Refuse to do the loop over more too many elements. It's better to fail immediately than to
+ * spin the CPU for a long time. */
+ if (max_fd > MAX_FD_LOOP_LIMIT)
+ return log_debug_errno(SYNTHETIC_ERRNO(EPERM),
+ "/proc/self/fd is inaccessible. Refusing to loop over %d potential fds.",
+ max_fd);
- if (fd == dirfd(d))
- continue;
+ for (int fd = 3; fd >= 0; fd = fd < max_fd ? fd + 1 : -1) {
+ int q;
if (fd_in_set(fd, except, n_except))
continue;
q = close_nointr(fd);
- if (q < 0 && q != -EBADF && r >= 0) /* Valgrind has its own FD and doesn't want to have it closed */
+ if (q < 0 && q != -EBADF && r >= 0)
r = q;
}
int fd_nonblock(int fd, bool nonblock);
int fd_cloexec(int fd, bool cloexec);
-int close_all_fds(const int except[], size_t n_except);
+int close_all_fds_full(int except[], size_t n_except, bool allow_alloc);
+static inline int close_all_fds(int except[], size_t n_except) {
+ return close_all_fds_full(except, n_except, true);
+}
int same_fd(int a, int b);
#pragma once
#include <dirent.h>
+#include <fcntl.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <sys/stat.h>
-#include <sys/fcntl.h>
#include <sys/types.h>
#include "macro.h"
#define FORMAT_BYTES_MAX 16U
-char *format_bytes_full(char *buf, size_t l, uint64_t t, FormatBytesFlag flag);
+char *format_bytes_full(char *buf, size_t l, uint64_t t, FormatBytesFlag flag) _warn_unused_result_;
+_warn_unused_result_
static inline char *format_bytes(char *buf, size_t l, uint64_t t) {
return format_bytes_full(buf, l, t, FORMAT_BYTES_USE_IEC | FORMAT_BYTES_BELOW_POINT | FORMAT_BYTES_TRAILING_B);
}
-static inline char *format_bytes_cgroup_protection(char *buf, size_t l, uint64_t t) {
- if (t == CGROUP_LIMIT_MAX) {
- (void) snprintf(buf, l, "%s", "infinity");
- return buf;
- }
- return format_bytes(buf, l, t);
-}
+/* Note: the lifetime of the compound literal is the immediately surrounding block,
+ * see C11 §6.5.2.5, and
+ * https://stackoverflow.com/questions/34880638/compound-literal-lifetime-and-if-blocks */
+#define FORMAT_BYTES(t) format_bytes((char[FORMAT_BYTES_MAX]){}, FORMAT_BYTES_MAX, t)
+#define FORMAT_BYTES_FULL(t, flag) format_bytes_full((char[FORMAT_BYTES_MAX]){}, FORMAT_BYTES_MAX, t, flag)
+
+#define FORMAT_BYTES_CGROUP_PROTECTION(t) (t == CGROUP_LIMIT_MAX ? "infinity" : FORMAT_BYTES(t))
if (idx < _IDX_SWAP_END)
return &bucket_at_swap(swap, idx)->p.b;
- assert_not_reached("Invalid index");
+ assert_not_reached();
}
static dib_raw_t* dib_raw_ptr(HashmapBase *h) {
return (void*) e->key;
default:
- assert_not_reached("Unknown hashmap type");
+ assert_not_reached();
}
}
r = set_merge((Set*)copy, (Set*)h);
break;
default:
- assert_not_reached("Unknown hashmap type");
+ assert_not_reached();
}
if (r < 0)
*z = 0;
*out = r;
+ assert(z >= r); /* Let static analyzers know that the answer is non-negative. */
return z - r;
}
k = 0;
break;
default:
- assert_not_reached("Invalid prefixlen mode");
+ assert_not_reached();
}
if (ret_family)
[SPECIAL_GLYPH_DEPRESSED_SMILEY] = ":-[",
[SPECIAL_GLYPH_LOCK_AND_KEY] = "o-,",
[SPECIAL_GLYPH_TOUCH] = "O=", /* Yeah, not very convincing, can you do it better? */
+ [SPECIAL_GLYPH_RECYCLING] = "~",
+ [SPECIAL_GLYPH_DOWNLOAD] = "\\",
+ [SPECIAL_GLYPH_SPARKLES] = "*",
},
/* UTF-8 */
[SPECIAL_GLYPH_LOCK_AND_KEY] = "\360\237\224\220", /* 🔐 (actually called: CLOSED LOCK WITH KEY) */
/* This emoji is a single character cell glyph in Unicode, and two in ASCII */
- [SPECIAL_GLYPH_TOUCH] = "\360\237\221\206", /* 👆 (actually called: BACKHAND INDEX POINTING UP */
+ [SPECIAL_GLYPH_TOUCH] = "\360\237\221\206", /* 👆 (actually called: BACKHAND INDEX POINTING UP) */
+
+ /* These three emojis are single character cell glyphs in Unicode and also in ASCII. */
+ [SPECIAL_GLYPH_RECYCLING] = "\u267B\uFE0F ", /* ♻️ (actually called: UNIVERSAL RECYCLNG SYMBOL) */
+ [SPECIAL_GLYPH_DOWNLOAD] = "\u2935\uFE0F ", /* ⤵️ (actually called: RIGHT ARROW CURVING DOWN) */
+ [SPECIAL_GLYPH_SPARKLES] = "\u2728", /* ✨ */
},
};
SPECIAL_GLYPH_DEPRESSED_SMILEY,
SPECIAL_GLYPH_LOCK_AND_KEY,
SPECIAL_GLYPH_TOUCH,
+ SPECIAL_GLYPH_RECYCLING,
+ SPECIAL_GLYPH_DOWNLOAD,
+ SPECIAL_GLYPH_SPARKLES,
_SPECIAL_GLYPH_MAX,
_SPECIAL_GLYPH_INVALID = -EINVAL,
} SpecialGlyph;
static inline const char *special_glyph_check_mark(bool b) {
return b ? special_glyph(SPECIAL_GLYPH_CHECK_MARK) : special_glyph(SPECIAL_GLYPH_CROSS_MARK);
}
+
+static inline const char *special_glyph_check_mark_space(bool b) {
+ return b ? special_glyph(SPECIAL_GLYPH_CHECK_MARK) : " ";
+}
}
_noreturn_ void log_assert_failed_unreachable(
- const char *text,
const char *file,
int line,
const char *func) {
- log_assert(LOG_CRIT, text, file, line, func,
- "Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
+ log_assert(LOG_CRIT, "Code should not be reached", file, line, func,
+ "%s at %s:%u, function %s(). Aborting. 💥");
abort();
}
const char *func);
_noreturn_ void log_assert_failed_unreachable(
- const char *text,
const char *file,
int line,
const char *func);
#define _weakref_(x) __attribute__((__weakref__(#x)))
#define _alignas_(x) __attribute__((__aligned__(__alignof(x))))
#define _alignptr_ __attribute__((__aligned__(sizeof(void*))))
+#define _warn_unused_result_ __attribute__((__warn_unused_result__))
#if __GNUC__ >= 7
#define _fallthrough_ __attribute__((__fallthrough__))
#else
* Contrary to strlen(), this is a constant expression.
* @x: a string literal.
*/
-#define STRLEN(x) (sizeof(""x"") - 1)
+#define STRLEN(x) (sizeof(""x"") - 1U)
/*
* container_of - cast a member of a structure out to the containing structure
#define assert(expr) assert_message_se(expr, #expr)
#endif
-#define assert_not_reached(t) \
- log_assert_failed_unreachable(t, PROJECT_FILE, __LINE__, __PRETTY_FUNCTION__)
+#define assert_not_reached() \
+ log_assert_failed_unreachable(PROJECT_FILE, __LINE__, __PRETTY_FUNCTION__)
#define assert_return(expr, r) \
do { \
* negative '-' prefix (hence works correctly on signed
* types). Includes space for the trailing NUL. */
#define DECIMAL_STR_MAX(type) \
- (2+(sizeof(type) <= 1 ? 3 : \
- sizeof(type) <= 2 ? 5 : \
- sizeof(type) <= 4 ? 10 : \
- sizeof(type) <= 8 ? 20 : sizeof(int[-2*(sizeof(type) > 8)])))
+ (2U+(sizeof(type) <= 1 ? 3U : \
+ sizeof(type) <= 2 ? 5U : \
+ sizeof(type) <= 4 ? 10U : \
+ sizeof(type) <= 8 ? 20U : sizeof(int[-2*(sizeof(type) > 8)])))
#define DECIMAL_STR_WIDTH(x) \
({ \
typeof(x) _x_ = (x); \
- unsigned ans = 1; \
+ size_t ans = 1; \
while ((_x_ /= 10) != 0) \
ans++; \
ans; \
#include <errno.h>
#include <inttypes.h>
-#include <linux/oom.h>
#include <net/if.h>
#include <stdio.h>
#include <stdlib.h>
if (r < 0)
return r;
- if (v < OOM_SCORE_ADJ_MIN || v > OOM_SCORE_ADJ_MAX)
+ if (!oom_score_adjust_is_valid(v))
return -ERANGE;
*ret = v;
return 0;
default:
- assert_not_reached("Hmm, unexpected scope value.");
+ assert_not_reached();
}
if (!a || !b)
return -EOPNOTSUPP;
default:
- assert_not_reached("Hmm, unexpected scope value.");
+ assert_not_reached();
}
*persistent = TAKE_PTR(a);
break;
default:
- assert_not_reached("Hmm, unexpected scope?");
+ assert_not_reached();
}
if (!add)
break;
default:
- assert_not_reached("Hmm, unexpected scope.");
+ assert_not_reached();
}
if (!add)
return cached > 0;
}
-_noreturn_ void freeze(void) {
-
- log_close();
-
- /* Make sure nobody waits for us on a socket anymore */
- (void) close_all_fds(NULL, 0);
-
- sync();
-
- /* Let's not freeze right away, but keep reaping zombies. */
- for (;;) {
- int r;
- siginfo_t si = {};
-
- r = waitid(P_ALL, 0, &si, WEXITED);
- if (r < 0 && errno != EINTR)
- break;
- }
-
- /* waitid() failed with an unexpected error, things are really borked. Freeze now! */
- for (;;)
- pause();
-}
-
bool oom_score_adjust_is_valid(int oa) {
return oa >= OOM_SCORE_ADJ_MIN && oa <= OOM_SCORE_ADJ_MAX;
}
int safe_fork_full(
const char *name,
- const int except_fds[],
+ int except_fds[],
size_t n_except_fds,
ForkFlags flags,
pid_t *ret_pid) {
int namespace_fork(
const char *outer_name,
const char *inner_name,
- const int except_fds[],
+ int except_fds[],
size_t n_except_fds,
ForkFlags flags,
int pidns_fd,
* process. This ensures that we are fully a member of the destination namespace, with pidns an all, so that
* /proc/self/fd works correctly. */
- r = safe_fork_full(outer_name, except_fds, n_except_fds, (flags|FORK_DEATHSIG) & ~(FORK_REOPEN_LOG|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE), ret_pid);
+ r = safe_fork_full(outer_name, except_fds, n_except_fds,
+ (flags|FORK_DEATHSIG) & ~(FORK_REOPEN_LOG|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE), ret_pid);
if (r < 0)
return r;
if (r == 0) {
return 1;
}
-int fork_agent(const char *name, const int except[], size_t n_except, pid_t *ret_pid, const char *path, ...) {
- bool stdout_is_tty, stderr_is_tty;
- size_t n, i;
- va_list ap;
- char **l;
- int r;
-
- assert(path);
-
- /* Spawns a temporary TTY agent, making sure it goes away when we go away */
-
- r = safe_fork_full(name,
- except,
- n_except,
- FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG,
- ret_pid);
- if (r < 0)
- return r;
- if (r > 0)
- return 0;
-
- /* In the child: */
-
- stdout_is_tty = isatty(STDOUT_FILENO);
- stderr_is_tty = isatty(STDERR_FILENO);
-
- if (!stdout_is_tty || !stderr_is_tty) {
- int fd;
-
- /* Detach from stdout/stderr. and reopen
- * /dev/tty for them. This is important to
- * ensure that when systemctl is started via
- * popen() or a similar call that expects to
- * read EOF we actually do generate EOF and
- * not delay this indefinitely by because we
- * keep an unused copy of stdin around. */
- fd = open("/dev/tty", O_WRONLY);
- if (fd < 0) {
- log_error_errno(errno, "Failed to open /dev/tty: %m");
- _exit(EXIT_FAILURE);
- }
-
- if (!stdout_is_tty && dup2(fd, STDOUT_FILENO) < 0) {
- log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
- _exit(EXIT_FAILURE);
- }
-
- if (!stderr_is_tty && dup2(fd, STDERR_FILENO) < 0) {
- log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
- _exit(EXIT_FAILURE);
- }
-
- safe_close_above_stdio(fd);
- }
-
- (void) rlimit_nofile_safe();
-
- /* Count arguments */
- va_start(ap, path);
- for (n = 0; va_arg(ap, char*); n++)
- ;
- va_end(ap);
-
- /* Allocate strv */
- l = newa(char*, n + 1);
-
- /* Fill in arguments */
- va_start(ap, path);
- for (i = 0; i <= n; i++)
- l[i] = va_arg(ap, char*);
- va_end(ap);
-
- execv(path, l);
- _exit(EXIT_FAILURE);
-}
-
int set_oom_score_adjust(int value) {
char t[DECIMAL_STR_MAX(int)];
- sprintf(t, "%i", value);
+ xsprintf(t, "%i", value);
return write_string_file("/proc/self/oom_score_adj", t,
WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_DISABLE_BUFFER);
bool is_main_thread(void);
-_noreturn_ void freeze(void);
-
bool oom_score_adjust_is_valid(int oa);
#ifndef PERSONALITY_INVALID
FORK_NEW_USERNS = 1 << 13, /* Run child in its own user namespace */
} ForkFlags;
-int safe_fork_full(const char *name, const int except_fds[], size_t n_except_fds, ForkFlags flags, pid_t *ret_pid);
+int safe_fork_full(const char *name, int except_fds[], size_t n_except_fds, ForkFlags flags, pid_t *ret_pid);
static inline int safe_fork(const char *name, ForkFlags flags, pid_t *ret_pid) {
return safe_fork_full(name, NULL, 0, flags, ret_pid);
}
-int namespace_fork(const char *outer_name, const char *inner_name, const int except_fds[], size_t n_except_fds, ForkFlags flags, int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd, pid_t *ret_pid);
-
-int fork_agent(const char *name, const int except[], size_t n_except, pid_t *pid, const char *path, ...) _sentinel_;
+int namespace_fork(const char *outer_name, const char *inner_name, int except_fds[], size_t n_except_fds, ForkFlags flags, int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd, pid_t *ret_pid);
int set_oom_score_adjust(int value);
}
int rlimit_format(const struct rlimit *rl, char **ret) {
- char *s = NULL;
+ _cleanup_free_ char *s = NULL;
+ int r;
assert(rl);
assert(ret);
if (rl->rlim_cur >= RLIM_INFINITY && rl->rlim_max >= RLIM_INFINITY)
- s = strdup("infinity");
+ r = free_and_strdup(&s, "infinity");
else if (rl->rlim_cur >= RLIM_INFINITY)
- (void) asprintf(&s, "infinity:" RLIM_FMT, rl->rlim_max);
+ r = asprintf(&s, "infinity:" RLIM_FMT, rl->rlim_max);
else if (rl->rlim_max >= RLIM_INFINITY)
- (void) asprintf(&s, RLIM_FMT ":infinity", rl->rlim_cur);
+ r = asprintf(&s, RLIM_FMT ":infinity", rl->rlim_cur);
else if (rl->rlim_cur == rl->rlim_max)
- (void) asprintf(&s, RLIM_FMT, rl->rlim_cur);
+ r = asprintf(&s, RLIM_FMT, rl->rlim_cur);
else
- (void) asprintf(&s, RLIM_FMT ":" RLIM_FMT, rl->rlim_cur, rl->rlim_max);
-
- if (!s)
+ r = asprintf(&s, RLIM_FMT ":" RLIM_FMT, rl->rlim_cur, rl->rlim_max);
+ if (r < 0)
return -ENOMEM;
- *ret = s;
+ *ret = TAKE_PTR(s);
return 0;
}
if (sigemptyset(&ss) < 0)
return -errno;
- /* Add first signal (if the signal is zero, we'll silently skip it, to make it easiert to build
+ /* Add first signal (if the signal is zero, we'll silently skip it, to make it easier to build
* parameter lists where some element are sometimes off, similar to how sigset_add_many_ap() handles
* this.) */
if (sig > 0 && sigaddset(&ss, sig) < 0)
_len = sizeof(struct sockaddr_vm); \
break; \
default: \
- assert_not_reached("invalid socket family"); \
+ assert_not_reached(); \
} \
_len; \
})
(void) va_arg(ap, long double); \
break; \
default: \
- assert_not_reached("Unknown format string argument."); \
+ assert_not_reached(); \
} \
} \
} while (false)
#define strv_free_and_replace(a, b) \
({ \
- strv_free(a); \
- (a) = (b); \
- (b) = NULL; \
+ char ***_a = &(a); \
+ char ***_b = &(b); \
+ strv_free(*_a); \
+ (*_a) = (*_b); \
+ (*_b) = NULL; \
0; \
})
/* Let's see if we should shows this in dot notation */
if (t < USEC_PER_MINUTE && b > 0) {
- usec_t cc;
- signed char j;
+ signed char j = 0;
- j = 0;
- for (cc = table[i].usec; cc > 1; cc /= 10)
+ for (usec_t cc = table[i].usec; cc > 1; cc /= 10)
j++;
- for (cc = accuracy; cc > 1; cc /= 10) {
+ for (usec_t cc = accuracy; cc > 1; cc /= 10) {
b /= 10;
j--;
}
continue;
char *tz;
- if (*type == 'Z' || *type == 'z')
+ if (IN_SET(*type, 'Z', 'z'))
/* Zone lines have timezone in field 1. */
tz = f1;
- else if (*type == 'L' || *type == 'l')
+ else if (IN_SET(*type, 'L', 'l'))
/* Link lines have timezone in field 2. */
tz = f2;
else
usec_t timespec_load(const struct timespec *ts) _pure_;
nsec_t timespec_load_nsec(const struct timespec *ts) _pure_;
-struct timespec *timespec_store(struct timespec *ts, usec_t u);
-struct timespec *timespec_store_nsec(struct timespec *ts, nsec_t n);
+struct timespec* timespec_store(struct timespec *ts, usec_t u);
+struct timespec* timespec_store_nsec(struct timespec *ts, nsec_t n);
usec_t timeval_load(const struct timeval *tv) _pure_;
-struct timeval *timeval_store(struct timeval *tv, usec_t u);
+struct timeval* timeval_store(struct timeval *tv, usec_t u);
-char *format_timestamp_style(char *buf, size_t l, usec_t t, TimestampStyle style);
-char *format_timestamp_relative(char *buf, size_t l, usec_t t);
-char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy);
+char* format_timestamp_style(char *buf, size_t l, usec_t t, TimestampStyle style) _warn_unused_result_;
+char* format_timestamp_relative(char *buf, size_t l, usec_t t) _warn_unused_result_;
+char* format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) _warn_unused_result_;
-static inline char *format_timestamp(char *buf, size_t l, usec_t t) {
+_warn_unused_result_
+static inline char* format_timestamp(char *buf, size_t l, usec_t t) {
return format_timestamp_style(buf, l, t, TIMESTAMP_PRETTY);
}
+/* Note: the lifetime of the compound literal is the immediately surrounding block,
+ * see C11 §6.5.2.5, and
+ * https://stackoverflow.com/questions/34880638/compound-literal-lifetime-and-if-blocks */
+#define FORMAT_TIMESTAMP(t) format_timestamp((char[FORMAT_TIMESTAMP_MAX]){}, FORMAT_TIMESTAMP_MAX, t)
+#define FORMAT_TIMESTAMP_RELATIVE(t) \
+ format_timestamp_relative((char[FORMAT_TIMESTAMP_RELATIVE_MAX]){}, FORMAT_TIMESTAMP_RELATIVE_MAX, t)
+#define FORMAT_TIMESPAN(t, accuracy) format_timespan((char[FORMAT_TIMESPAN_MAX]){}, FORMAT_TIMESPAN_MAX, t, accuracy)
+#define FORMAT_TIMESTAMP_STYLE(t, style) \
+ format_timestamp_style((char[FORMAT_TIMESTAMP_MAX]){}, FORMAT_TIMESTAMP_MAX, t, style)
+
int parse_timestamp(const char *t, usec_t *usec);
int parse_sec(const char *t, usec_t *usec);
bool in_utc_timezone(void);
static inline usec_t usec_add(usec_t a, usec_t b) {
-
- /* Adds two time values, and makes sure USEC_INFINITY as input results as USEC_INFINITY in output, and doesn't
- * overflow. */
+ /* Adds two time values, and makes sure USEC_INFINITY as input results as USEC_INFINITY in output,
+ * and doesn't overflow. */
if (a > USEC_INFINITY - b) /* overflow check */
return USEC_INFINITY;
}
static inline usec_t usec_sub_unsigned(usec_t timestamp, usec_t delta) {
-
if (timestamp == USEC_INFINITY) /* Make sure infinity doesn't degrade */
return USEC_INFINITY;
if (timestamp < delta)
}
#if SIZEOF_TIME_T == 8
-/* The last second we can format is 31. Dec 9999, 1s before midnight, because otherwise we'd enter 5 digit year
- * territory. However, since we want to stay away from this in all timezones we take one day off. */
-#define USEC_TIMESTAMP_FORMATTABLE_MAX ((usec_t) 253402214399000000)
+ /* The last second we can format is 31. Dec 9999, 1s before midnight, because otherwise we'd enter 5 digit
+ * year territory. However, since we want to stay away from this in all timezones we take one day off. */
+# define USEC_TIMESTAMP_FORMATTABLE_MAX ((usec_t) 253402214399000000)
#elif SIZEOF_TIME_T == 4
/* With a 32bit time_t we can't go beyond 2038... */
-#define USEC_TIMESTAMP_FORMATTABLE_MAX ((usec_t) 2147483647000000)
+# define USEC_TIMESTAMP_FORMATTABLE_MAX ((usec_t) 2147483647000000)
#else
-#error "Yuck, time_t is neither 4 nor 8 bytes wide?"
+# error "Yuck, time_t is neither 4 nor 8 bytes wide?"
#endif
int time_change_fd(void);
}
int unit_name_path_escape(const char *f, char **ret) {
- char *p, *s;
+ _cleanup_free_ char *p = NULL;
+ char *s;
assert(f);
assert(ret);
- p = strdupa(f);
+ p = strdup(f);
if (!p)
return -ENOMEM;
if (!path_is_normalized(p))
return -EINVAL;
- /* Truncate trailing slashes */
+ /* Truncate trailing slashes and skip leading slashes */
delete_trailing_chars(p, "/");
-
- /* Truncate leading slashes */
- p = skip_leading_chars(p, "/");
-
- s = unit_name_escape(p);
+ s = unit_name_escape(skip_leading_chars(p, "/"));
}
if (!s)
return -ENOMEM;
if (strlen(s) >= UNIT_NAME_MAX) /* Return a slightly more descriptive error for this specific condition */
return -ENAMETOOLONG;
- /* Refuse this if this got too long or for some other reason didn't result in a valid name */
+ /* Refuse if this for some other reason didn't result in a valid name */
if (!unit_name_is_valid(s, UNIT_NAME_PLAIN))
return -EINVAL;
if (strlen(s) >= UNIT_NAME_MAX) /* Return a slightly more descriptive error for this specific condition */
return -ENAMETOOLONG;
- /* Refuse this if this got too long or for some other reason didn't result in a valid name */
+ /* Refuse if this for some other reason didn't result in a valid name */
if (!unit_name_is_valid(s, UNIT_NAME_INSTANCE))
return -EINVAL;
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
if ((arg_unregister || arg_cat_config) && argc > optind)
return -EINVAL;
default:
- assert_not_reached("Unknown option");
+ assert_not_reached();
}
return 1;
return -EINVAL;
default:
- assert_not_reached("Unknown option");
+ assert_not_reached();
}
return 1;
static int acquire_esp(
bool unprivileged_mode,
+ bool graceful,
uint32_t *ret_part,
uint64_t *ret_pstart,
uint64_t *ret_psize,
* this). */
r = find_esp_and_warn(arg_esp_path, unprivileged_mode, &np, ret_part, ret_pstart, ret_psize, ret_uuid);
- if (r == -ENOKEY)
+ if (r == -ENOKEY) {
+ if (graceful)
+ return log_info_errno(r, "Couldn't find EFI system partition, skipping.");
+
return log_error_errno(r,
"Couldn't find EFI system partition. It is recommended to mount it to /boot or /efi.\n"
"Alternatively, use --esp-path= to specify path to mount point.");
+ }
if (r < 0)
return r;
if (r < 0)
return r;
if (r == 0)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ return log_notice_errno(SYNTHETIC_ERRNO(EREMOTE),
"Source file \"%s\" does not carry version information!",
from);
if (r < 0)
return r;
if (r == 0 || compare_product(a, b) != 0)
- return log_notice_errno(SYNTHETIC_ERRNO(EEXIST),
+ return log_notice_errno(SYNTHETIC_ERRNO(EREMOTE),
"Skipping \"%s\", since it's owned by another boot loader.",
to);
- if (compare_version(a, b) < 0)
- return log_warning_errno(SYNTHETIC_ERRNO(ESTALE), "Skipping \"%s\", since a newer boot loader version exists already.", to);
+ r = compare_version(a, b);
+ if (r < 0)
+ return log_warning_errno(SYNTHETIC_ERRNO(ESTALE), "Skipping \"%s\", since newer boot loader version in place already.", to);
+ else if (r == 0)
+ return log_info_errno(SYNTHETIC_ERRNO(ESTALE), "Skipping \"%s\", since same boot loader version in place already.", to);
return 0;
}
continue;
k = copy_one_file(esp_path, de->d_name, force);
+ /* Don't propagate an error code if no update necessary, installed version already equal or
+ * newer version, or other boot loader in place. */
+ if (arg_graceful && IN_SET(k, -ESTALE, -EREMOTE))
+ continue;
if (k < 0 && r == 0)
r = k;
}
return -EINVAL;
default:
- assert_not_reached("Unknown option");
+ assert_not_reached();
}
return 1;
sd_id128_t esp_uuid = SD_ID128_NULL, xbootldr_uuid = SD_ID128_NULL;
int r, k;
- r = acquire_esp(geteuid() != 0, NULL, NULL, NULL, &esp_uuid);
+ r = acquire_esp(/* unprivileged_mode= */ geteuid() != 0, /* graceful= */ false, NULL, NULL, NULL, &esp_uuid);
if (arg_print_esp_path) {
if (r == -EACCES) /* If we couldn't acquire the ESP path, log about access errors (which is the only
* error the find_esp_and_warn() won't log on its own) */
puts(arg_esp_path);
}
- r = acquire_xbootldr(geteuid() != 0, &xbootldr_uuid);
+ r = acquire_xbootldr(/* unprivileged_mode= */ geteuid() != 0, &xbootldr_uuid);
if (arg_print_dollar_boot_path) {
if (r == -EACCES)
return log_error_errno(r, "Failed to determine XBOOTLDR location: %m");
sd_id128_t bootloader_esp_uuid;
bool have_bootloader_esp_uuid = efi_loader_get_device_part_uuid(&bootloader_esp_uuid) >= 0;
- print_yes_no_line(false, have_bootloader_esp_uuid, "Boot loader sets ESP partition information");
+ print_yes_no_line(false, have_bootloader_esp_uuid, "Boot loader sets ESP information");
if (have_bootloader_esp_uuid && !sd_id128_equal(esp_uuid, bootloader_esp_uuid))
printf("WARNING: The boot loader reports a different ESP UUID than detected!\n");
* off logging about access errors and turn off potentially privileged device probing. Here we're interested in
* the latter but not the former, hence request the mode, and log about EACCES. */
- r = acquire_esp(geteuid() != 0, NULL, NULL, NULL, NULL);
+ r = acquire_esp(/* unprivileged_mode= */ geteuid() != 0, /* graceful= */ false, NULL, NULL, NULL, NULL);
if (r == -EACCES) /* We really need the ESP path for this call, hence also log about access errors */
return log_error_errno(r, "Failed to determine ESP: %m");
if (r < 0)
return r;
- r = acquire_xbootldr(geteuid() != 0, NULL);
+ r = acquire_xbootldr(/* unprivileged_mode= */ geteuid() != 0, NULL);
if (r == -EACCES)
return log_error_errno(r, "Failed to determine XBOOTLDR partition: %m");
if (r < 0)
sd_id128_t uuid = SD_ID128_NULL;
uint64_t pstart = 0, psize = 0;
uint32_t part = 0;
- bool install;
+ bool install, graceful;
int r;
- r = acquire_esp(false, &part, &pstart, &psize, &uuid);
+ install = streq(argv[0], "install");
+ graceful = !install && arg_graceful; /* support graceful mode for updates */
+
+ r = acquire_esp(/* unprivileged_mode= */ false, graceful, &part, &pstart, &psize, &uuid);
+ if (graceful && r == -ENOKEY)
+ return 0; /* If --graceful is specified and we can't find an ESP, handle this cleanly */
if (r < 0)
return r;
- r = acquire_xbootldr(false, NULL);
+ r = acquire_xbootldr(/* unprivileged_mode= */ false, NULL);
if (r < 0)
return r;
settle_make_machine_id_directory();
- install = streq(argv[0], "install");
-
RUN_WITH_UMASK(0002) {
if (install) {
/* Don't create any of these directories when we are just updating. When we update
sd_id128_t uuid = SD_ID128_NULL;
int r, q;
- r = acquire_esp(false, NULL, NULL, NULL, &uuid);
+ r = acquire_esp(/* unprivileged_mode= */ false, /* graceful= */ false, NULL, NULL, NULL, &uuid);
if (r < 0)
return r;
- r = acquire_xbootldr(false, NULL);
+ r = acquire_xbootldr(/* unprivileged_mode= */ false, NULL);
if (r < 0)
return r;
_cleanup_free_ char *p = NULL;
int r;
- r = acquire_esp(false, NULL, NULL, NULL, NULL);
+ r = acquire_esp(/* privileged_mode= */ false, /* graceful= */ false, NULL, NULL, NULL, NULL);
if (r < 0)
return r;
efi_libdir = get_option('efi-libdir')
if efi_libdir == ''
# New location first introduced with gnu-efi 3.0.11
- efi_libdir = join_paths('/usr/lib/gnuefi', EFI_MACHINE_TYPE_NAME)
+ efi_libdir = '/usr/lib/gnuefi' / EFI_MACHINE_TYPE_NAME
cmd = run_command(test, '-e', efi_libdir)
if cmd.returncode() != 0
# Fall back to the old approach
cmd = run_command(efi_cc + ['-print-multi-os-directory'])
if cmd.returncode() == 0
- path = join_paths('/usr/lib', cmd.stdout().strip())
+ path = '/usr/lib' / cmd.stdout().strip()
cmd = run_command(env, 'realpath', '-e', path)
if cmd.returncode() == 0
efi_libdir = cmd.stdout().strip()
['sbat-distro-url', 'BUG_REPORT_URL']]
foreach sbatvar : sbatvars
value = get_option(sbatvar[0])
- if value == '' or value == 'auto'
+ if (value == '' and not meson.is_cross_build()) or value == 'auto'
cmd = 'if [ -e /etc/os-release ]; then . /etc/os-release; else . /usr/lib/os-release; fi; echo $@0@'.format(sbatvar[1])
value = run_command(sh, '-c', cmd).stdout().strip()
message('@0@ (from @1@): @2@'.format(sbatvar[0], sbatvar[1], value))
efi_location_map = [
# New locations first introduced with gnu-efi 3.0.11
- [join_paths(efi_libdir, 'efi.lds'),
- join_paths(efi_libdir, 'crt0.o')],
+ [efi_libdir / 'efi.lds',
+ efi_libdir / 'crt0.o'],
# Older locations...
- [join_paths(efi_libdir, 'gnuefi', 'elf_@0@_efi.lds'.format(gnu_efi_path_arch)),
- join_paths(efi_libdir, 'gnuefi', 'crt0-efi-@0@.o'.format(gnu_efi_path_arch))],
- [join_paths(efi_libdir, 'elf_@0@_efi.lds'.format(gnu_efi_path_arch)),
- join_paths(efi_libdir, 'crt0-efi-@0@.o'.format(gnu_efi_path_arch))]]
+ [efi_libdir / 'gnuefi' / 'elf_@0@_efi.lds'.format(gnu_efi_path_arch),
+ efi_libdir / 'gnuefi' / 'crt0-efi-@0@.o'.format(gnu_efi_path_arch)],
+ [efi_libdir / 'elf_@0@_efi.lds'.format(gnu_efi_path_arch),
+ efi_libdir / 'crt0-efi-@0@.o'.format(gnu_efi_path_arch)]]
efi_lds = ''
foreach location : efi_location_map
if efi_lds == ''
'-nostdlib',
'-std=gnu99',
'-isystem', efi_incdir,
- '-isystem', join_paths(efi_incdir, gnu_efi_path_arch),
+ '-isystem', efi_incdir / gnu_efi_path_arch,
'-I', fundamental_path,
'-DSD_BOOT',
'-include', efi_config_h,
break;
default:
- assert_not_reached("Bad state");
+ assert_not_reached();
}
}
}
break;
default:
- assert_not_reached("Hmm, unknown transport type.");
+ assert_not_reached();
}
}
if (r < 0)
break;
default:
- assert_not_reached("Unknown basic type.");
+ assert_not_reached();
}
needs_space = true;
break;
default:
- assert_not_reached("Unexpected element type");
+ assert_not_reached();
}
*ret = TAKE_PTR(v);
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
return 1;
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
if (arg_machine && arg_show_unit != SHOW_UNIT_NONE)
return format_timespan(buf, l, t, accuracy);
}
+#define BUFSIZE1 CONST_MAX(FORMAT_TIMESPAN_MAX, DECIMAL_STR_MAX(usec_t))
+#define MAYBE_FORMAT_TIMESPAN(t, accuracy) \
+ maybe_format_timespan((char[BUFSIZE1]){}, BUFSIZE1, t, accuracy)
+
static const char *maybe_format_bytes(char *buf, size_t l, bool is_valid, uint64_t t) {
if (!is_valid)
return "-";
return format_bytes(buf, l, t);
}
+#define BUFSIZE2 CONST_MAX(FORMAT_BYTES_MAX, DECIMAL_STR_MAX(uint64_t))
+#define MAYBE_FORMAT_BYTES(is_valid, t) \
+ maybe_format_bytes((char[BUFSIZE2]){}, BUFSIZE2, is_valid, t)
+
static bool is_root_cgroup(const char *path) {
/* Returns true if the specified path belongs to the root cgroup. The root cgroup is special on cgroup v2 as it
Group *g;
Group **array;
signed path_columns;
- unsigned rows, n = 0, j, maxtcpu = 0, maxtpath = 3; /* 3 for ellipsize() to work properly */
- char buffer[MAX4(21U, FORMAT_BYTES_MAX, FORMAT_TIMESPAN_MAX, DECIMAL_STR_MAX(usec_t))];
+ unsigned rows, n = 0, maxtcpu = 0, maxtpath = 3; /* 3 for ellipsize() to work properly */
assert(a);
typesafe_qsort(array, n, group_compare);
/* Find the longest names in one run */
- for (j = 0; j < n; j++) {
- unsigned cputlen, pathtlen;
-
- maybe_format_timespan(buffer, sizeof(buffer), (usec_t) (array[j]->cpu_usage / NSEC_PER_USEC), 0);
- cputlen = strlen(buffer);
- maxtcpu = MAX(maxtcpu, cputlen);
-
- pathtlen = strlen(array[j]->path);
- maxtpath = MAX(maxtpath, pathtlen);
+ for (unsigned j = 0; j < n; j++) {
+ maxtcpu = MAX(maxtcpu,
+ strlen(MAYBE_FORMAT_TIMESPAN((usec_t) (array[j]->cpu_usage / NSEC_PER_USEC), 0)));
+ maxtpath = MAX(maxtpath,
+ strlen(array[j]->path));
}
- if (arg_cpu_type == CPU_PERCENT)
- xsprintf(buffer, "%6s", "%CPU");
- else
- xsprintf(buffer, "%*s", maxtcpu, "CPU Time");
-
rows = lines();
if (rows <= 10)
rows = 10;
if (on_tty()) {
const char *on, *off;
+ unsigned cpu_len = arg_cpu_type == CPU_PERCENT ? 6 : maxtcpu;
- path_columns = columns() - 36 - strlen(buffer);
+ path_columns = columns() - 36 - cpu_len;
if (path_columns < 10)
path_columns = 10;
on = ansi_highlight_underline();
off = ansi_underline();
- printf("%s%s%-*s%s %s%7s%s %s%s%s %s%8s%s %s%8s%s %s%8s%s%s\n",
+ printf("%s%s%-*s%s %s%7s%s %s%*s%s %s%8s%s %s%8s%s %s%8s%s%s\n",
ansi_underline(),
arg_order == ORDER_PATH ? on : "", path_columns, "Control Group",
arg_order == ORDER_PATH ? off : "",
- arg_order == ORDER_TASKS ? on : "", arg_count == COUNT_PIDS ? "Tasks" : arg_count == COUNT_USERSPACE_PROCESSES ? "Procs" : "Proc+",
+ arg_order == ORDER_TASKS ? on : "",
+ arg_count == COUNT_PIDS ? "Tasks" : arg_count == COUNT_USERSPACE_PROCESSES ? "Procs" : "Proc+",
arg_order == ORDER_TASKS ? off : "",
- arg_order == ORDER_CPU ? on : "", buffer,
+ arg_order == ORDER_CPU ? on : "",
+ cpu_len,
+ arg_cpu_type == CPU_PERCENT ? "%CPU" : "CPU Time",
arg_order == ORDER_CPU ? off : "",
arg_order == ORDER_MEMORY ? on : "", "Memory",
arg_order == ORDER_MEMORY ? off : "",
} else
path_columns = maxtpath;
- for (j = 0; j < n; j++) {
+ for (unsigned j = 0; j < n; j++) {
_cleanup_free_ char *ellipsized = NULL;
const char *path;
else
fputs(" -", stdout);
} else
- printf(" %*s", maxtcpu, maybe_format_timespan(buffer, sizeof(buffer), (usec_t) (g->cpu_usage / NSEC_PER_USEC), 0));
+ printf(" %*s", maxtcpu, MAYBE_FORMAT_TIMESPAN((usec_t) (g->cpu_usage / NSEC_PER_USEC), 0));
- printf(" %8s", maybe_format_bytes(buffer, sizeof(buffer), g->memory_valid, g->memory));
- printf(" %8s", maybe_format_bytes(buffer, sizeof(buffer), g->io_valid, g->io_input_bps));
- printf(" %8s", maybe_format_bytes(buffer, sizeof(buffer), g->io_valid, g->io_output_bps));
+ printf(" %8s", MAYBE_FORMAT_BYTES(g->memory_valid, g->memory));
+ printf(" %8s", MAYBE_FORMAT_BYTES(g->io_valid, g->io_input_bps));
+ printf(" %8s", MAYBE_FORMAT_BYTES(g->io_valid, g->io_output_bps));
putchar('\n');
}
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
if (optind == argc - 1)
while (!quit) {
usec_t t;
char key;
- char h[FORMAT_TIMESPAN_MAX];
t = now(CLOCK_MONOTONIC);
case '+':
arg_delay = usec_add(arg_delay, arg_delay < USEC_PER_SEC ? USEC_PER_MSEC * 250 : USEC_PER_SEC);
- fprintf(stdout, "\nIncreased delay to %s.", format_timespan(h, sizeof(h), arg_delay, 0));
+ fprintf(stdout, "\nIncreased delay to %s.", FORMAT_TIMESPAN(arg_delay, 0));
fflush(stdout);
sleep(1);
break;
else
arg_delay = usec_sub_unsigned(arg_delay, arg_delay < USEC_PER_MSEC * 1250 ? USEC_PER_MSEC * 250 : USEC_PER_SEC);
- fprintf(stdout, "\nDecreased delay to %s.", format_timespan(h, sizeof(h), arg_delay, 0));
+ fprintf(stdout, "\nDecreased delay to %s.", FORMAT_TIMESPAN(arg_delay, 0));
fflush(stdout);
sleep(1);
break;
}
static void automount_dump(Unit *u, FILE *f, const char *prefix) {
- char time_string[FORMAT_TIMESPAN_MAX];
Automount *a = AUTOMOUNT(u);
assert(a);
prefix, automount_result_to_string(a->result),
prefix, a->where,
prefix, a->directory_mode,
- prefix, format_timespan(time_string, FORMAT_TIMESPAN_MAX, a->timeout_idle_usec, USEC_PER_SEC));
+ prefix, FORMAT_TIMESPAN(a->timeout_idle_usec, USEC_PER_SEC));
}
static void automount_enter_dead(Automount *a, AutomountResult f) {
}
static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = {
- [AUTOMOUNT_SUCCESS] = "success",
- [AUTOMOUNT_FAILURE_RESOURCES] = "resources",
- [AUTOMOUNT_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
+ [AUTOMOUNT_SUCCESS] = "success",
+ [AUTOMOUNT_FAILURE_RESOURCES] = "resources",
+ [AUTOMOUNT_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
[AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT] = "mount-start-limit-hit",
- [AUTOMOUNT_FAILURE_UNMOUNTED] = "unmounted",
+ [AUTOMOUNT_FAILURE_UNMOUNTED] = "unmounted",
};
DEFINE_STRING_TABLE_LOOKUP(automount_result, AutomountResult);
CGroupSocketBindItem *bi;
IPAddressAccessItem *iaai;
char **path;
- char q[FORMAT_TIMESPAN_MAX];
- char v[FORMAT_TIMESPAN_MAX];
char cda[FORMAT_CGROUP_DIFF_MAX];
char cdb[FORMAT_CGROUP_DIFF_MAX];
prefix, c->startup_cpu_weight,
prefix, c->cpu_shares,
prefix, c->startup_cpu_shares,
- prefix, format_timespan(q, sizeof(q), c->cpu_quota_per_sec_usec, 1),
- prefix, format_timespan(v, sizeof(v), c->cpu_quota_period_usec, 1),
+ prefix, FORMAT_TIMESPAN(c->cpu_quota_per_sec_usec, 1),
+ prefix, FORMAT_TIMESPAN(c->cpu_quota_period_usec, 1),
prefix, strempty(cpuset_cpus),
prefix, strempty(cpuset_mems),
prefix, c->io_weight,
"%sIODeviceLatencyTargetSec: %s %s\n",
prefix,
l->path,
- format_timespan(q, sizeof(q), l->target_usec, 1));
-
- LIST_FOREACH(device_limits, il, c->io_device_limits) {
- char buf[FORMAT_BYTES_MAX];
+ FORMAT_TIMESPAN(l->target_usec, 1));
+ LIST_FOREACH(device_limits, il, c->io_device_limits)
for (CGroupIOLimitType type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++)
if (il->limits[type] != cgroup_io_limit_defaults[type])
fprintf(f,
prefix,
cgroup_io_limit_type_to_string(type),
il->path,
- format_bytes(buf, sizeof(buf), il->limits[type]));
- }
+ FORMAT_BYTES(il->limits[type]));
LIST_FOREACH(device_weights, w, c->blockio_device_weights)
fprintf(f,
w->weight);
LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
- char buf[FORMAT_BYTES_MAX];
-
if (b->rbps != CGROUP_LIMIT_MAX)
fprintf(f,
"%sBlockIOReadBandwidth: %s %s\n",
prefix,
b->path,
- format_bytes(buf, sizeof(buf), b->rbps));
+ FORMAT_BYTES(b->rbps));
if (b->wbps != CGROUP_LIMIT_MAX)
fprintf(f,
"%sBlockIOWriteBandwidth: %s %s\n",
prefix,
b->path,
- format_bytes(buf, sizeof(buf), b->wbps));
+ FORMAT_BYTES(b->wbps));
}
LIST_FOREACH(items, iaai, c->ip_address_allow) {
new_period = cgroup_cpu_adjust_period(period, quota, USEC_PER_MSEC, USEC_PER_SEC);
if (new_period != period) {
- char v[FORMAT_TIMESPAN_MAX];
log_unit_full(u, u->warned_clamping_cpu_quota_period ? LOG_DEBUG : LOG_WARNING,
"Clamping CPU interval for cpu.max: period is now %s",
- format_timespan(v, sizeof(v), new_period, 1));
+ FORMAT_TIMESPAN(new_period, 1));
u->warned_clamping_cpu_quota_period = true;
}
unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
if (c->cpu_quota_period_usec == USEC_INFINITY)
unit_write_setting(u, flags, "CPUQuotaPeriodSec", "CPUQuotaPeriodSec=");
- else {
- char v[FORMAT_TIMESPAN_MAX];
+ else
unit_write_settingf(u, flags, "CPUQuotaPeriodSec",
"CPUQuotaPeriodSec=%s",
- format_timespan(v, sizeof(v), c->cpu_quota_period_usec, 1));
- }
+ FORMAT_TIMESPAN(c->cpu_quota_period_usec, 1));
}
return 1;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
_cleanup_free_ char *buf = NULL;
_cleanup_fclose_ FILE *f = NULL;
- char ts[FORMAT_TIMESPAN_MAX];
CGroupIODeviceLatency *a;
size_t size = 0;
fputs("IODeviceLatencyTargetSec=\n", f);
LIST_FOREACH(device_latencies, a, c->io_device_latencies)
fprintf(f, "IODeviceLatencyTargetSec=%s %s\n",
- a->path, format_timespan(ts, sizeof(ts), a->target_usec, 1));
+ a->path, FORMAT_TIMESPAN(a->target_usec, 1));
r = fflush_and_check(f);
if (r < 0)
available = (uint64_t) svfs.f_bfree * (uint64_t) svfs.f_bsize;
- if (available < RELOAD_DISK_SPACE_MIN) {
- char fb_available[FORMAT_BYTES_MAX], fb_need[FORMAT_BYTES_MAX];
+ if (available < RELOAD_DISK_SPACE_MIN)
return sd_bus_error_setf(error,
BUS_ERROR_DISK_FULL,
"%s, not enough space available on /run/systemd. "
"Currently, %s are free, but a safety buffer of %s is enforced.",
message,
- format_bytes(fb_available, sizeof(fb_available), available),
- format_bytes(fb_need, sizeof(fb_need), RELOAD_DISK_SPACE_MIN));
- }
+ FORMAT_BYTES(available),
+ FORMAT_BYTES(RELOAD_DISK_SPACE_MIN));
return 0;
}
available = (uint64_t) svfs.f_bfree * (uint64_t) svfs.f_bsize;
- if (available < RELOAD_DISK_SPACE_MIN) {
- char fb_available[FORMAT_BYTES_MAX], fb_need[FORMAT_BYTES_MAX];
+ if (available < RELOAD_DISK_SPACE_MIN)
log_warning("Dangerously low amount of free space on /run/systemd, root switching might fail.\n"
"Currently, %s are free, but %s are suggested. Proceeding anyway.",
- format_bytes(fb_available, sizeof(fb_available), available),
- format_bytes(fb_need, sizeof(fb_need), RELOAD_DISK_SPACE_MIN));
- }
+ FORMAT_BYTES(available),
+ FORMAT_BYTES(RELOAD_DISK_SPACE_MIN));
r = mac_selinux_access_check(message, "reboot", error);
if (r < 0)
break;
default:
- assert_not_reached("Unknown socket type");
+ assert_not_reached();
}
r = sd_bus_message_append(reply, "(ss)", socket_port_type_to_string(p), a);
sd_bus_error *error) {
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
- char ts[FORMAT_TIMESPAN_MAX];
TimerValue *v;
unit_write_settingf(UNIT(t), flags|UNIT_ESCAPE_SPECIFIERS, name,
"%s=%s",
timer_base_to_string(base),
- format_timespan(ts, sizeof ts, usec, USEC_PER_MSEC));
+ FORMAT_TIMESPAN(usec, USEC_PER_MSEC));
v = new(TimerValue, 1);
if (!v)
return r;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
- char *n, ts[FORMAT_TIMESPAN_MAX];
-
if (fix_0)
*p = v != 0 ? v: USEC_INFINITY;
else
*p = v;
- n = strndupa(name, strlen(name) - 4);
- unit_write_settingf(u, flags, name, "%sSec=%s", n,
- format_timespan(ts, sizeof(ts), v, USEC_PER_MSEC));
+ char *n = strndupa(name, strlen(name) - 4);
+ unit_write_settingf(u, flags, name, "%sSec=%s", n, FORMAT_TIMESPAN(v, USEC_PER_MSEC));
}
return 1;
break;
default:
- assert_not_reached("unknown phase");
+ assert_not_reached();
}
/* Make sure whatever we picked here actually is in the right range */
break;
default:
- assert_not_reached("Unknown emergency action");
+ assert_not_reached();
}
}
#include "env-file.h"
#include "env-util.h"
#include "errno-list.h"
+#include "escape.h"
#include "execute.h"
#include "exit-status.h"
#include "fd-util.h"
}
default:
- assert_not_reached("Unknown input type");
+ assert_not_reached();
}
}
}
default:
- assert_not_reached("Unknown error type");
+ assert_not_reached();
}
}
r = CONFIRM_EXECUTE;
break;
default:
- assert_not_reached("Unhandled choice");
+ assert_not_reached();
}
break;
}
return 0;
}
-static char *exec_command_line(char **argv);
-
static int exec_parameters_get_cgroup_path(const ExecParameters *params, char **ret) {
bool using_subcgroup;
char *p;
const char *vc = params->confirm_spawn;
_cleanup_free_ char *cmdline = NULL;
- cmdline = exec_command_line(command->argv);
+ cmdline = quote_command_line(command->argv);
if (!cmdline) {
*exit_status = EXIT_MEMORY;
return log_oom();
if (DEBUG_LOGGING) {
_cleanup_free_ char *line = NULL;
- line = exec_command_line(final_argv);
- if (line)
- log_unit_struct(unit, LOG_DEBUG,
- "EXECUTABLE=%s", executable,
- LOG_UNIT_MESSAGE(unit, "Executing: %s", line),
- LOG_UNIT_INVOCATION_ID(unit));
+ line = quote_command_line(final_argv);
+ if (!line) {
+ *exit_status = EXIT_MEMORY;
+ return log_oom();
+ }
+
+ log_unit_struct(unit, LOG_DEBUG,
+ "EXECUTABLE=%s", executable,
+ LOG_UNIT_MESSAGE(unit, "Executing: %s", line));
}
if (exec_fd >= 0) {
if (r < 0)
return log_unit_error_errno(unit, r, "Failed to load environment files: %m");
- line = exec_command_line(command->argv);
+ line = quote_command_line(command->argv);
if (!line)
return log_oom();
}
void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
- char **e, **d, buf_clean[FORMAT_TIMESPAN_MAX];
+ char **e, **d;
int r;
assert(c);
fprintf(f, "%s%s: %s\n", prefix, exec_directory_type_to_string(dt), *d);
}
- fprintf(f,
- "%sTimeoutCleanSec: %s\n",
- prefix, format_timespan(buf_clean, sizeof(buf_clean), c->timeout_clean_usec, USEC_PER_SEC));
+ fprintf(f, "%sTimeoutCleanSec: %s\n", prefix, FORMAT_TIMESPAN(c->timeout_clean_usec, USEC_PER_SEC));
if (c->nice_set)
- fprintf(f,
- "%sNice: %i\n",
- prefix, c->nice);
+ fprintf(f, "%sNice: %i\n", prefix, c->nice);
if (c->oom_score_adjust_set)
- fprintf(f,
- "%sOOMScoreAdjust: %i\n",
- prefix, c->oom_score_adjust);
+ fprintf(f, "%sOOMScoreAdjust: %i\n", prefix, c->oom_score_adjust);
if (c->coredump_filter_set)
- fprintf(f,
- "%sCoredumpFilter: 0x%"PRIx64"\n",
- prefix, c->coredump_filter);
+ fprintf(f, "%sCoredumpFilter: 0x%"PRIx64"\n", prefix, c->coredump_filter);
for (unsigned i = 0; i < RLIM_NLIMITS; i++)
if (c->rlimit[i]) {
fprintf(f, "%sLogLevelMax: %s\n", prefix, strna(t));
}
- if (c->log_ratelimit_interval_usec > 0) {
- char buf_timespan[FORMAT_TIMESPAN_MAX];
-
+ if (c->log_ratelimit_interval_usec > 0)
fprintf(f,
"%sLogRateLimitIntervalSec: %s\n",
- prefix, format_timespan(buf_timespan, sizeof(buf_timespan), c->log_ratelimit_interval_usec, USEC_PER_SEC));
- }
+ prefix, FORMAT_TIMESPAN(c->log_ratelimit_interval_usec, USEC_PER_SEC));
if (c->log_ratelimit_burst > 0)
fprintf(f, "%sLogRateLimitBurst: %u\n", prefix, c->log_ratelimit_burst);
}
void exec_status_dump(const ExecStatus *s, FILE *f, const char *prefix) {
- char buf[FORMAT_TIMESTAMP_MAX];
-
assert(s);
assert(f);
if (dual_timestamp_is_set(&s->start_timestamp))
fprintf(f,
"%sStart Timestamp: %s\n",
- prefix, format_timestamp(buf, sizeof(buf), s->start_timestamp.realtime));
+ prefix, FORMAT_TIMESTAMP(s->start_timestamp.realtime));
if (dual_timestamp_is_set(&s->exit_timestamp))
fprintf(f,
"%sExit Timestamp: %s\n"
"%sExit Code: %s\n"
"%sExit Status: %i\n",
- prefix, format_timestamp(buf, sizeof(buf), s->exit_timestamp.realtime),
+ prefix, FORMAT_TIMESTAMP(s->exit_timestamp.realtime),
prefix, sigchld_code_to_string(s->code),
prefix, s->status);
}
-static char *exec_command_line(char **argv) {
- size_t k;
- char *n, *p, **a;
- bool first = true;
-
- assert(argv);
-
- k = 1;
- STRV_FOREACH(a, argv)
- k += strlen(*a)+3;
-
- n = new(char, k);
- if (!n)
- return NULL;
-
- p = n;
- STRV_FOREACH(a, argv) {
-
- if (!first)
- *(p++) = ' ';
- else
- first = false;
-
- if (strpbrk(*a, WHITESPACE)) {
- *(p++) = '\'';
- p = stpcpy(p, *a);
- *(p++) = '\'';
- } else
- p = stpcpy(p, *a);
-
- }
-
- *p = 0;
-
- /* FIXME: this doesn't really handle arguments that have
- * spaces and ticks in them */
-
- return n;
-}
-
static void exec_command_dump(ExecCommand *c, FILE *f, const char *prefix) {
_cleanup_free_ char *cmd = NULL;
const char *prefix2;
prefix = strempty(prefix);
prefix2 = strjoina(prefix, "\t");
- cmd = exec_command_line(c->argv);
+ cmd = quote_command_line(c->argv);
fprintf(f,
"%sCommand Line: %s\n",
prefix, cmd ? cmd : strerror_safe(ENOMEM));
return true;
default:
- assert_not_reached("Invalid job type");
+ assert_not_reached();
}
}
break;
default:
- assert_not_reached("Invalid job type");
+ assert_not_reached();
}
/* Log if the job still exists and the start/stop/reload function actually did something. Note that this means
break;
default:
- assert_not_reached("Unknown job type");
+ assert_not_reached();
}
if (j) {
DEFINE_STRING_TABLE_LOOKUP(job_state, JobState);
static const char* const job_type_table[_JOB_TYPE_MAX] = {
- [JOB_START] = "start",
- [JOB_VERIFY_ACTIVE] = "verify-active",
- [JOB_STOP] = "stop",
- [JOB_RELOAD] = "reload",
+ [JOB_START] = "start",
+ [JOB_VERIFY_ACTIVE] = "verify-active",
+ [JOB_STOP] = "stop",
+ [JOB_RELOAD] = "reload",
[JOB_RELOAD_OR_START] = "reload-or-start",
- [JOB_RESTART] = "restart",
- [JOB_TRY_RESTART] = "try-restart",
- [JOB_TRY_RELOAD] = "try-reload",
- [JOB_NOP] = "nop",
+ [JOB_RESTART] = "restart",
+ [JOB_TRY_RESTART] = "try-restart",
+ [JOB_TRY_RELOAD] = "try-reload",
+ [JOB_NOP] = "nop",
};
DEFINE_STRING_TABLE_LOOKUP(job_type, JobType);
static const char* const job_mode_table[_JOB_MODE_MAX] = {
- [JOB_FAIL] = "fail",
- [JOB_REPLACE] = "replace",
+ [JOB_FAIL] = "fail",
+ [JOB_REPLACE] = "replace",
[JOB_REPLACE_IRREVERSIBLY] = "replace-irreversibly",
- [JOB_ISOLATE] = "isolate",
- [JOB_FLUSH] = "flush",
- [JOB_IGNORE_DEPENDENCIES] = "ignore-dependencies",
- [JOB_IGNORE_REQUIREMENTS] = "ignore-requirements",
- [JOB_TRIGGERING] = "triggering",
+ [JOB_ISOLATE] = "isolate",
+ [JOB_FLUSH] = "flush",
+ [JOB_IGNORE_DEPENDENCIES] = "ignore-dependencies",
+ [JOB_IGNORE_REQUIREMENTS] = "ignore-requirements",
+ [JOB_TRIGGERING] = "triggering",
};
DEFINE_STRING_TABLE_LOOKUP(job_mode, JobMode);
static const char* const job_result_table[_JOB_RESULT_MAX] = {
- [JOB_DONE] = "done",
- [JOB_CANCELED] = "canceled",
- [JOB_TIMEOUT] = "timeout",
- [JOB_FAILED] = "failed",
- [JOB_DEPENDENCY] = "dependency",
- [JOB_SKIPPED] = "skipped",
- [JOB_INVALID] = "invalid",
- [JOB_ASSERT] = "assert",
+ [JOB_DONE] = "done",
+ [JOB_CANCELED] = "canceled",
+ [JOB_TIMEOUT] = "timeout",
+ [JOB_FAILED] = "failed",
+ [JOB_DEPENDENCY] = "dependency",
+ [JOB_SKIPPED] = "skipped",
+ [JOB_INVALID] = "invalid",
+ [JOB_ASSERT] = "assert",
[JOB_UNSUPPORTED] = "unsupported",
- [JOB_COLLECTED] = "collected",
- [JOB_ONCE] = "once",
+ [JOB_COLLECTED] = "collected",
+ [JOB_ONCE] = "once",
};
DEFINE_STRING_TABLE_LOOKUP(job_result, JobResult);
_cleanup_free_ char *unescaped = NULL, *resolved = NULL;
ExecContext *c = data;
const Unit *u = userdata;
- size_t sz;
- void *p;
int r;
assert(data);
return 0;
}
- r = cunescape(rvalue, 0, &unescaped);
- if (r < 0) {
- log_syntax(unit, LOG_WARNING, filename, line, r,
+ ssize_t l = cunescape(rvalue, 0, &unescaped);
+ if (l < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, l,
"Failed to decode C escaped text '%s', ignoring: %m", rvalue);
return 0;
}
return 0;
}
- sz = strlen(resolved);
+ size_t sz = strlen(resolved);
if (c->stdin_data_size + sz + 1 < c->stdin_data_size || /* check for overflow */
c->stdin_data_size + sz + 1 > EXEC_STDIN_DATA_MAX) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
return 0;
}
- p = realloc(c->stdin_data, c->stdin_data_size + sz + 1);
+ void *p = realloc(c->stdin_data, c->stdin_data_size + sz + 1);
if (!p)
return log_oom();
return 0;
}
} else {
- char *unescaped = NULL;
- int l;
+ char *unescaped;
+ ssize_t l;
/* We support escape codes here, so that users can insert trailing \n if they like */
l = cunescape(p, UNESCAPE_ACCEPT_NUL, &unescaped);
#include "machine-id-setup.h"
#include "manager.h"
#include "manager-dump.h"
+#include "manager-serialize.h"
#include "mkdir.h"
#include "mount-setup.h"
#include "os-util.h"
#include "switch-root.h"
#include "sysctl-util.h"
#include "terminal-util.h"
+#include "time-util.h"
#include "umask-util.h"
#include "user-util.h"
#include "util.h"
pid = raw_getpid();
(void) kill(pid, sig); /* raise() would kill the parent */
- assert_not_reached("We shouldn't be here...");
+ assert_not_reached();
_exit(EXIT_EXCEPTION);
} else {
siginfo_t status;
return 0;
default:
- assert_not_reached("Unhandled option code.");
+ assert_not_reached();
}
if (optind < argc && getpid_cached() != 1)
static void bump_file_max_and_nr_open(void) {
- /* Let's bump fs.file-max and fs.nr_open to their respective maximums. On current kernels large numbers of file
- * descriptors are no longer a performance problem and their memory is properly tracked by memcg, thus counting
- * them and limiting them in another two layers of limits is unnecessary and just complicates things. This
- * function hence turns off 2 of the 4 levels of limits on file descriptors, and makes RLIMIT_NOLIMIT (soft +
- * hard) the only ones that really matter. */
+ /* Let's bump fs.file-max and fs.nr_open to their respective maximums. On current kernels large
+ * numbers of file descriptors are no longer a performance problem and their memory is properly
+ * tracked by memcg, thus counting them and limiting them in another two layers of limits is
+ * unnecessary and just complicates things. This function hence turns off 2 of the 4 levels of limits
+ * on file descriptors, and makes RLIMIT_NOLIMIT (soft + hard) the only ones that really matter. */
#if BUMP_PROC_SYS_FS_FILE_MAX || BUMP_PROC_SYS_FS_NR_OPEN
int r;
#if BUMP_PROC_SYS_FS_NR_OPEN
int v = INT_MAX;
- /* Arg! The kernel enforces maximum and minimum values on the fs.nr_open, but we don't really know what they
- * are. The expression by which the maximum is determined is dependent on the architecture, and is something we
- * don't really want to copy to userspace, as it is dependent on implementation details of the kernel. Since
- * the kernel doesn't expose the maximum value to us, we can only try and hope. Hence, let's start with
- * INT_MAX, and then keep halving the value until we find one that works. Ugly? Yes, absolutely, but kernel
- * APIs are kernel APIs, so what do can we do... 🤯 */
+ /* Argh! The kernel enforces maximum and minimum values on the fs.nr_open, but we don't really know
+ * what they are. The expression by which the maximum is determined is dependent on the architecture,
+ * and is something we don't really want to copy to userspace, as it is dependent on implementation
+ * details of the kernel. Since the kernel doesn't expose the maximum value to us, we can only try
+ * and hope. Hence, let's start with INT_MAX, and then keep halving the value until we find one that
+ * works. Ugly? Yes, absolutely, but kernel APIs are kernel APIs, so what do can we do... 🤯 */
for (;;) {
int k;
uint64_t mm;
int r;
- /* BPF_MAP_TYPE_LPM_TRIE bpf maps are charged against RLIMIT_MEMLOCK, even if we have CAP_IPC_LOCK which should
- * normally disable such checks. We need them to implement IPAddressAllow= and IPAddressDeny=, hence let's bump
- * the value high enough for our user. */
+ /* BPF_MAP_TYPE_LPM_TRIE bpf maps are charged against RLIMIT_MEMLOCK, even if we have CAP_IPC_LOCK
+ * which should normally disable such checks. We need them to implement IPAddressAllow= and
+ * IPAddressDeny=, hence let's bump the value high enough for our user. */
/* Using MAX() on resource limits only is safe if RLIM_INFINITY is > 0. POSIX declares that rlim_t
* must be unsigned, hence this is a given, but let's make this clear here. */
assert_cc(RLIM_INFINITY > 0);
- mm = physical_memory_scale(1, 8); /* Let's scale how much we allow to be locked by the amount of physical
- * RAM. We allow an eighth to be locked by us, just to pick a value. */
+ mm = physical_memory_scale(1, 8); /* Let's scale how much we allow to be locked by the amount of
+ * physical RAM. We allow an eighth to be locked by us, just to
+ * pick a value. */
new_rlimit = (struct rlimit) {
.rlim_cur = MAX3(HIGH_RLIMIT_MEMLOCK, saved_rlimit->rlim_cur, mm),
unsigned long v;
int r;
- /* Let's bump the net.unix.max_dgram_qlen sysctl. The kernel default of 16 is simply too low. We set the value
- * really really early during boot, so that it is actually applied to all our sockets, including the
- * $NOTIFY_SOCKET one. */
+ /* Let's bump the net.unix.max_dgram_qlen sysctl. The kernel default of 16 is simply too low. We set
+ * the value really really early during boot, so that it is actually applied to all our sockets,
+ * including the $NOTIFY_SOCKET one. */
r = read_one_line_file("/proc/sys/net/unix/max_dgram_qlen", &qlen);
if (r < 0)
- return log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r, "Failed to read AF_UNIX datagram queue length, ignoring: %m");
+ return log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to read AF_UNIX datagram queue length, ignoring: %m");
r = safe_atolu(qlen, &v);
if (r < 0)
if (v >= DEFAULT_UNIX_MAX_DGRAM_QLEN)
return 0;
- r = write_string_filef("/proc/sys/net/unix/max_dgram_qlen", WRITE_STRING_FILE_DISABLE_BUFFER, "%lu", DEFAULT_UNIX_MAX_DGRAM_QLEN);
+ r = write_string_filef("/proc/sys/net/unix/max_dgram_qlen", WRITE_STRING_FILE_DISABLE_BUFFER,
+ "%lu", DEFAULT_UNIX_MAX_DGRAM_QLEN);
if (r < 0)
return log_full_errno(IN_SET(r, -EROFS, -EPERM, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to bump AF_UNIX datagram queue length, ignoring: %m");
if (detect_container() > 0)
return 0;
- /* When started as PID1, the kernel uses /dev/console for our stdios and uses TERM=linux whatever the backend
- * device used by the console. We try to make a better guess here since some consoles might not have support
- * for color mode for example.
+ /* When started as PID1, the kernel uses /dev/console for our stdios and uses TERM=linux whatever the
+ * backend device used by the console. We try to make a better guess here since some consoles might
+ * not have support for color mode for example.
*
* However if TERM was configured through the kernel command line then leave it alone. */
r = proc_cmdline_get_key("TERM", 0, &term);
if (clock_is_localtime(NULL) > 0) {
int min;
- /*
- * The very first call of settimeofday() also does a time warp in the kernel.
+ /* The very first call of settimeofday() also does a time warp in the kernel.
*
- * In the rtc-in-local time mode, we set the kernel's timezone, and rely on external tools to take care
- * of maintaining the RTC and do all adjustments. This matches the behavior of Windows, which leaves
- * the RTC alone if the registry tells that the RTC runs in UTC.
+ * In the rtc-in-local time mode, we set the kernel's timezone, and rely on external tools to
+ * take care of maintaining the RTC and do all adjustments. This matches the behavior of
+ * Windows, which leaves the RTC alone if the registry tells that the RTC runs in UTC.
*/
r = clock_set_timezone(&min);
if (r < 0)
/*
* Do a dummy very first call to seal the kernel's time warp magic.
*
- * Do not call this from inside the initrd. The initrd might not carry /etc/adjtime with LOCAL, but the
- * real system could be set up that way. In such case, we need to delay the time-warp or the sealing
- * until we reach the real system.
+ * Do not call this from inside the initrd. The initrd might not carry /etc/adjtime with
+ * LOCAL, but the real system could be set up that way. In such case, we need to delay the
+ * time-warp or the sealing until we reach the real system.
*
- * Do no set the kernel's timezone. The concept of local time cannot be supported reliably, the time
- * will jump or be incorrect at every daylight saving time change. All kernel local time concepts will
- * be treated as UTC that way.
+ * Do no set the kernel's timezone. The concept of local time cannot be supported reliably,
+ * the time will jump or be incorrect at every daylight saving time change. All kernel local
+ * time concepts will be treated as UTC that way.
*/
(void) clock_reset_timewarp();
- r = clock_apply_epoch();
- if (r < 0)
- log_error_errno(r, "Current system time is before build time, but cannot correct: %m");
- else if (r > 0)
+ ClockChangeDirection change_dir;
+ r = clock_apply_epoch(&change_dir);
+ if (r > 0 && change_dir == CLOCK_CHANGE_FORWARD)
log_info("System time before build time, advancing clock.");
+ else if (r > 0 && change_dir == CLOCK_CHANGE_BACKWARD)
+ log_info("System time is further ahead than %s after build time, resetting clock to build time.",
+ FORMAT_TIMESPAN(CLOCK_VALID_RANGE_USEC_MAX, USEC_PER_DAY));
+ else if (r < 0 && change_dir == CLOCK_CHANGE_FORWARD)
+ log_error_errno(r, "Current system time is before build time, but cannot correct: %m");
+ else if (r < 0 && change_dir == CLOCK_CHANGE_BACKWARD)
+ log_error_errno(r, "Current system time is further ahead %s after build time, but cannot correct: %m",
+ FORMAT_TIMESPAN(CLOCK_VALID_RANGE_USEC_MAX, USEC_PER_DAY));
}
static void apply_clock_update(void) {
if (clock_settime(CLOCK_REALTIME, timespec_store(&ts, arg_clock_usec)) < 0)
log_error_errno(errno, "Failed to set system clock to time specified on kernel command line: %m");
- else {
- char buf[FORMAT_TIMESTAMP_MAX];
-
+ else
log_info("Set system clock to %s, as specified on the kernel command line.",
- format_timestamp(buf, sizeof(buf), arg_clock_usec));
- }
+ FORMAT_TIMESTAMP(arg_clock_usec));
}
static void cmdline_take_random_seed(void) {
}
log_notice("Successfully credited entropy passed on kernel command line.\n"
- "Note that the seed provided this way is accessible to unprivileged programs. This functionality should not be used outside of testing environments.");
+ "Note that the seed provided this way is accessible to unprivileged programs. "
+ "This functionality should not be used outside of testing environments.");
}
static void initialize_coredump(bool skip_setup) {
if (getpid_cached() != 1)
return;
- /* Don't limit the core dump size, so that coredump handlers such as systemd-coredump (which honour the limit)
- * will process core dumps for system services by default. */
+ /* Don't limit the core dump size, so that coredump handlers such as systemd-coredump (which honour
+ * the limit) will process core dumps for system services by default. */
if (setrlimit(RLIMIT_CORE, &RLIMIT_MAKE_CONST(RLIM_INFINITY)) < 0)
log_warning_errno(errno, "Failed to set RLIMIT_CORE: %m");
- /* But at the same time, turn off the core_pattern logic by default, so that no
- * coredumps are stored until the systemd-coredump tool is enabled via
- * sysctl. However it can be changed via the kernel command line later so core
- * dumps can still be generated during early startup and in initramfs. */
+ /* But at the same time, turn off the core_pattern logic by default, so that no coredumps are stored
+ * until the systemd-coredump tool is enabled via sysctl. However it can be changed via the kernel
+ * command line later so core dumps can still be generated during early startup and in initramfs. */
if (!skip_setup)
disable_coredumps();
#endif
r = write_string_file("/proc/sys/kernel/core_pattern", arg_early_core_pattern, WRITE_STRING_FILE_DISABLE_BUFFER);
if (r < 0)
- log_warning_errno(r, "Failed to write '%s' to /proc/sys/kernel/core_pattern, ignoring: %m", arg_early_core_pattern);
+ log_warning_errno(r, "Failed to write '%s' to /proc/sys/kernel/core_pattern, ignoring: %m",
+ arg_early_core_pattern);
}
static void update_cpu_affinity(bool skip_setup) {
log_warning_errno(r, "Failed to set NUMA memory policy: %m");
}
+static void filter_args(
+ const char* dst[],
+ size_t *dst_index,
+ char **src,
+ int argc) {
+
+ assert(dst);
+ assert(dst_index);
+
+ /* Copy some filtered arguments into the dst array from src. */
+ for (int i = 1; i < argc; i++) {
+ if (STR_IN_SET(src[i],
+ "--switched-root",
+ "--system",
+ "--user"))
+ continue;
+
+ if (startswith(src[i], "--deserialize="))
+ continue;
+ if (streq(src[i], "--deserialize")) {
+ i++; /* Skip the argument too */
+ continue;
+ }
+
+ /* Skip target unit designators. We already acted upon this information and have queued
+ * appropriate jobs. We don't want to redo all this after reexecution. */
+ if (startswith(src[i], "--unit="))
+ continue;
+ if (streq(src[i], "--unit")) {
+ i++; /* Skip the argument too */
+ continue;
+ }
+
+ if (startswith(src[i],
+ in_initrd() ? "rd.systemd.unit=" : "systemd.unit="))
+ continue;
+
+ if (runlevel_to_target(src[i]))
+ continue;
+
+ /* Seems we have a good old option. Let's pass it over to the new instance. */
+ dst[(*dst_index)++] = src[i];
+ }
+}
+
static void do_reexecute(
int argc,
- char *argv[],
+ char* argv[],
const struct rlimit *saved_rlimit_nofile,
const struct rlimit *saved_rlimit_memlock,
FDSet *fds,
const char *switch_root_init,
const char **ret_error_message) {
- unsigned i, j, args_size;
+ size_t i, args_size;
const char **args;
int r;
+ assert(argc >= 0);
assert(saved_rlimit_nofile);
assert(saved_rlimit_memlock);
assert(ret_error_message);
- /* Close and disarm the watchdog, so that the new instance can reinitialize it, but doesn't get rebooted while
- * we do that */
+ /* Close and disarm the watchdog, so that the new instance can reinitialize it, but doesn't get
+ * rebooted while we do that */
watchdog_close(true);
/* Reset RLIMIT_NOFILE + RLIMIT_MEMLOCK back to the kernel defaults, so that the new systemd can pass
(void) setrlimit(RLIMIT_MEMLOCK, saved_rlimit_memlock);
if (switch_root_dir) {
- /* Kill all remaining processes from the initrd, but don't wait for them, so that we can handle the
- * SIGCHLD for them after deserializing. */
+ /* Kill all remaining processes from the initrd, but don't wait for them, so that we can
+ * handle the SIGCHLD for them after deserializing. */
broadcast_signal(SIGTERM, false, true, arg_default_timeout_stop_usec);
/* And switch root with MS_MOVE, because we remove the old directory afterwards and detach it. */
log_error_errno(r, "Failed to switch root, trying to continue: %m");
}
- args_size = MAX(6, argc+1);
+ args_size = argc + 6;
args = newa(const char*, args_size);
if (!switch_root_init) {
- char sfd[DECIMAL_STR_MAX(int) + 1];
+ char sfd[DECIMAL_STR_MAX(int)];
- /* First try to spawn ourselves with the right path, and with full serialization. We do this only if
- * the user didn't specify an explicit init to spawn. */
+ /* First try to spawn ourselves with the right path, and with full serialization. We do this
+ * only if the user didn't specify an explicit init to spawn. */
assert(arg_serialization);
assert(fds);
xsprintf(sfd, "%i", fileno(arg_serialization));
- i = 0;
- args[i++] = SYSTEMD_BINARY_PATH;
+ i = 1; /* Leave args[0] empty for now. */
+ filter_args(args, &i, argv, argc);
+
if (switch_root_dir)
args[i++] = "--switched-root";
args[i++] = arg_system ? "--system" : "--user";
assert(i <= args_size);
/*
- * We want valgrind to print its memory usage summary before reexecution. Valgrind won't do this is on
- * its own on exec(), but it will do it on exit(). Hence, to ensure we get a summary here, fork() off
- * a child, let it exit() cleanly, so that it prints the summary, and wait() for it in the parent,
- * before proceeding into the exec().
+ * We want valgrind to print its memory usage summary before reexecution. Valgrind won't do
+ * this is on its own on exec(), but it will do it on exit(). Hence, to ensure we get a
+ * summary here, fork() off a child, let it exit() cleanly, so that it prints the summary,
+ * and wait() for it in the parent, before proceeding into the exec().
*/
valgrind_summary_hack();
+ args[0] = SYSTEMD_BINARY_PATH;
(void) execv(args[0], (char* const*) args);
- log_debug_errno(errno, "Failed to execute our own binary, trying fallback: %m");
+ log_debug_errno(errno, "Failed to execute our own binary %s, trying fallback: %m", args[0]);
}
- /* Try the fallback, if there is any, without any serialization. We pass the original argv[] and envp[]. (Well,
- * modulo the ordering changes due to getopt() in argv[], and some cleanups in envp[], but let's hope that
- * doesn't matter.) */
+ /* Try the fallback, if there is any, without any serialization. We pass the original argv[] and
+ * envp[]. (Well, modulo the ordering changes due to getopt() in argv[], and some cleanups in envp[],
+ * but let's hope that doesn't matter.) */
arg_serialization = safe_fclose(arg_serialization);
fds = fdset_free(fds);
/* Reopen the console */
(void) make_console_stdio();
- for (j = 1, i = 1; j < (unsigned) argc; j++)
+ i = 1; /* Leave args[0] empty for now. */
+ for (int j = 1; j <= argc; j++)
args[i++] = argv[j];
- args[i++] = NULL;
assert(i <= args_size);
/* Re-enable any blocked signals, especially important if we switch from initial ramdisk to init=... */
if (switch_root_init) {
args[0] = switch_root_init;
(void) execve(args[0], (char* const*) args, saved_env);
- log_warning_errno(errno, "Failed to execute configured init, trying fallback: %m");
+ log_warning_errno(errno, "Failed to execute configured init %s, trying fallback: %m", args[0]);
}
args[0] = "/sbin/init";
log_info("Reloading.");
- /* First, save any overridden log level/target, then parse the configuration file, which might
- * change the log level to new settings. */
+ /* First, save any overridden log level/target, then parse the configuration file,
+ * which might change the log level to new settings. */
saved_log_level = m->log_level_overridden ? log_get_max_level() : -1;
saved_log_target = m->log_target_overridden ? log_get_target() : _LOG_TARGET_INVALID;
r = manager_reload(m);
if (r < 0)
- /* Reloading failed before the point of no return. Let's continue running as if nothing happened. */
+ /* Reloading failed before the point of no return.
+ * Let's continue running as if nothing happened. */
m->objective = MANAGER_OK;
break;
}
default:
- assert_not_reached("Unknown or unexpected manager objective.");
+ assert_not_reached();
}
}
}
/* Become a session leader if we aren't one yet. */
(void) setsid();
- /* If we are init, we connect stdin/stdout/stderr to /dev/null and make sure we don't have a controlling
- * tty. */
+ /* If we are init, we connect stdin/stdout/stderr to /dev/null and make sure we don't have a
+ * controlling tty. */
(void) release_terminal();
/* Reset the console, but only if this is really init and we are freshly booted */
static bool early_skip_setup_check(int argc, char *argv[]) {
bool found_deserialize = false;
- /* Determine if this is a reexecution or normal bootup. We do the full command line parsing much later, so
- * let's just have a quick peek here. Note that if we have switched root, do all the special setup things
- * anyway, even if in that case we also do deserialization. */
+ /* Determine if this is a reexecution or normal bootup. We do the full command line parsing much
+ * later, so let's just have a quick peek here. Note that if we have switched root, do all the
+ * special setup things anyway, even if in that case we also do deserialization. */
for (int i = 1; i < argc; i++)
if (streq(argv[i], "--switched-root"))
char *switch_root_dir = NULL, *switch_root_init = NULL;
usec_t before_startup, after_startup;
static char systemd[] = "systemd";
- char timespan[FORMAT_TIMESPAN_MAX];
const char *shutdown_verb = NULL, *error_message = NULL;
int r, retval = EXIT_FAILURE;
Manager *m = NULL;
dual_timestamp_get(&userspace_timestamp);
/* Figure out whether we need to do initialize the system, or if we already did that because we are
- * reexecuting */
+ * reexecuting. */
skip_setup = early_skip_setup_check(argc, argv);
- /* If we get started via the /sbin/init symlink then we are called 'init'. After a subsequent reexecution we
- * are then called 'systemd'. That is confusing, hence let's call us systemd right-away. */
+ /* If we get started via the /sbin/init symlink then we are called 'init'. After a subsequent
+ * reexecution we are then called 'systemd'. That is confusing, hence let's call us systemd
+ * right-away. */
program_invocation_short_name = systemd;
(void) prctl(PR_SET_NAME, systemd);
/* Disable the umask logic */
umask(0);
- /* Make sure that at least initially we do not ever log to journald/syslogd, because it might not be
- * activated yet (even though the log socket for it exists). */
+ /* Make sure that at least initially we do not ever log to journald/syslogd, because it might
+ * not be activated yet (even though the log socket for it exists). */
log_set_prohibit_ipc(true);
- /* Always reopen /dev/console when running as PID 1 or one of its pre-execve() children. This is
- * important so that we never end up logging to any foreign stderr, for example if we have to log in a
- * child process right before execve()'ing the actual binary, at a point in time where socket
- * activation stderr/stdout area already set up. */
+ /* Always reopen /dev/console when running as PID 1 or one of its pre-execve() children. This
+ * is important so that we never end up logging to any foreign stderr, for example if we have
+ * to log in a child process right before execve()'ing the actual binary, at a point in time
+ * where socket activation stderr/stdout area already set up. */
log_set_always_reopen_console(true);
if (detect_container() <= 0) {
if (!skip_setup)
initialize_clock();
- /* Set the default for later on, but don't actually open the logs like this for now. Note that
- * if we are transitioning from the initrd there might still be journal fd open, and we
- * shouldn't attempt opening that before we parsed /proc/cmdline which might redirect output
- * elsewhere. */
+ /* Set the default for later on, but don't actually open the logs like this for
+ * now. Note that if we are transitioning from the initrd there might still be
+ * journal fd open, and we shouldn't attempt opening that before we parsed
+ * /proc/cmdline which might redirect output elsewhere. */
log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
} else {
goto finish;
}
- /* Try to figure out if we can use colors with the console. No need to do that for user instances since
- * they never log into the console. */
+ /* Try to figure out if we can use colors with the console. No need to do that for user
+ * instances since they never log into the console. */
log_show_color(colors_enabled());
r = make_null_stdio();
log_full(arg_action == ACTION_TEST ? LOG_INFO : LOG_DEBUG,
"Loaded units and determined initial transaction in %s.",
- format_timespan(timespan, sizeof(timespan), after_startup - before_startup, 100 * USEC_PER_MSEC));
+ FORMAT_TIMESPAN(after_startup - before_startup, 100 * USEC_PER_MSEC));
if (arg_action == ACTION_TEST) {
manager_test_summary(m);
for (ManagerTimestamp q = 0; q < _MANAGER_TIMESTAMP_MAX; q++) {
const dual_timestamp *t = m->timestamps + q;
- char buf[CONST_MAX(FORMAT_TIMESPAN_MAX, FORMAT_TIMESTAMP_MAX)];
if (dual_timestamp_is_set(t))
fprintf(f, "%sTimestamp %s: %s\n",
strempty(prefix),
manager_timestamp_to_string(q),
- timestamp_is_set(t->realtime) ? format_timestamp(buf, sizeof buf, t->realtime) :
- format_timespan(buf, sizeof buf, t->monotonic, 1));
+ timestamp_is_set(t->realtime) ? FORMAT_TIMESTAMP(t->realtime) :
+ FORMAT_TIMESPAN(t->monotonic, 1));
}
manager_dump_units(m, f, prefix);
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "clean-ipc.h"
+#include "dbus.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "format-util.h"
+#include "macro.h"
+#include "manager-serialize.h"
+#include "manager.h"
+#include "parse-util.h"
+#include "serialize.h"
+#include "syslog-util.h"
+#include "unit-serialize.h"
+#include "user-util.h"
+
+int manager_open_serialization(Manager *m, FILE **ret_f) {
+ _cleanup_close_ int fd = -1;
+ FILE *f;
+
+ assert(ret_f);
+
+ fd = open_serialization_fd("systemd-state");
+ if (fd < 0)
+ return fd;
+
+ f = take_fdopen(&fd, "w+");
+ if (!f)
+ return -errno;
+
+ *ret_f = f;
+ return 0;
+}
+
+static bool manager_timestamp_shall_serialize(ManagerTimestamp t) {
+ if (!in_initrd())
+ return true;
+
+ /* The following timestamps only apply to the host system, hence only serialize them there */
+ return !IN_SET(t,
+ MANAGER_TIMESTAMP_USERSPACE, MANAGER_TIMESTAMP_FINISH,
+ MANAGER_TIMESTAMP_SECURITY_START, MANAGER_TIMESTAMP_SECURITY_FINISH,
+ MANAGER_TIMESTAMP_GENERATORS_START, MANAGER_TIMESTAMP_GENERATORS_FINISH,
+ MANAGER_TIMESTAMP_UNITS_LOAD_START, MANAGER_TIMESTAMP_UNITS_LOAD_FINISH);
+}
+
+static void manager_serialize_uid_refs_internal(
+ FILE *f,
+ Hashmap *uid_refs,
+ const char *field_name) {
+
+ void *p, *k;
+
+ assert(f);
+ assert(field_name);
+
+ /* Serialize the UID reference table. Or actually, just the IPC destruction flag of it, as
+ * the actual counter of it is better rebuild after a reload/reexec. */
+
+ HASHMAP_FOREACH_KEY(p, k, uid_refs) {
+ uint32_t c;
+ uid_t uid;
+
+ uid = PTR_TO_UID(k);
+ c = PTR_TO_UINT32(p);
+
+ if (!(c & DESTROY_IPC_FLAG))
+ continue;
+
+ (void) serialize_item_format(f, field_name, UID_FMT, uid);
+ }
+}
+
+static void manager_serialize_uid_refs(Manager *m, FILE *f) {
+ manager_serialize_uid_refs_internal(f, m->uid_refs, "destroy-ipc-uid");
+}
+
+static void manager_serialize_gid_refs(Manager *m, FILE *f) {
+ manager_serialize_uid_refs_internal(f, m->gid_refs, "destroy-ipc-gid");
+}
+
+int manager_serialize(
+ Manager *m,
+ FILE *f,
+ FDSet *fds,
+ bool switching_root) {
+
+ const char *t;
+ Unit *u;
+ int r;
+
+ assert(m);
+ assert(f);
+ assert(fds);
+
+ _cleanup_(manager_reloading_stopp) _unused_ Manager *reloading = manager_reloading_start(m);
+
+ (void) serialize_item_format(f, "current-job-id", "%" PRIu32, m->current_job_id);
+ (void) serialize_item_format(f, "n-installed-jobs", "%u", m->n_installed_jobs);
+ (void) serialize_item_format(f, "n-failed-jobs", "%u", m->n_failed_jobs);
+ (void) serialize_bool(f, "taint-usr", m->taint_usr);
+ (void) serialize_bool(f, "ready-sent", m->ready_sent);
+ (void) serialize_bool(f, "taint-logged", m->taint_logged);
+ (void) serialize_bool(f, "service-watchdogs", m->service_watchdogs);
+
+ /* After switching root, udevd has not been started yet. So, enumeration results should not be emitted. */
+ (void) serialize_bool(f, "honor-device-enumeration", !switching_root);
+
+ if (m->show_status_overridden != _SHOW_STATUS_INVALID)
+ (void) serialize_item(f, "show-status-overridden",
+ show_status_to_string(m->show_status_overridden));
+
+ if (m->log_level_overridden)
+ (void) serialize_item_format(f, "log-level-override", "%i", log_get_max_level());
+ if (m->log_target_overridden)
+ (void) serialize_item(f, "log-target-override", log_target_to_string(log_get_target()));
+
+ (void) serialize_usec(f, "runtime-watchdog-overridden", m->watchdog_overridden[WATCHDOG_RUNTIME]);
+ (void) serialize_usec(f, "reboot-watchdog-overridden", m->watchdog_overridden[WATCHDOG_REBOOT]);
+ (void) serialize_usec(f, "kexec-watchdog-overridden", m->watchdog_overridden[WATCHDOG_KEXEC]);
+
+ for (ManagerTimestamp q = 0; q < _MANAGER_TIMESTAMP_MAX; q++) {
+ _cleanup_free_ char *joined = NULL;
+
+ if (!manager_timestamp_shall_serialize(q))
+ continue;
+
+ joined = strjoin(manager_timestamp_to_string(q), "-timestamp");
+ if (!joined)
+ return log_oom();
+
+ (void) serialize_dual_timestamp(f, joined, m->timestamps + q);
+ }
+
+ if (!switching_root)
+ (void) serialize_strv(f, "env", m->client_environment);
+
+ if (m->notify_fd >= 0) {
+ r = serialize_fd(f, fds, "notify-fd", m->notify_fd);
+ if (r < 0)
+ return r;
+
+ (void) serialize_item(f, "notify-socket", m->notify_socket);
+ }
+
+ if (m->cgroups_agent_fd >= 0) {
+ r = serialize_fd(f, fds, "cgroups-agent-fd", m->cgroups_agent_fd);
+ if (r < 0)
+ return r;
+ }
+
+ if (m->user_lookup_fds[0] >= 0) {
+ int copy0, copy1;
+
+ copy0 = fdset_put_dup(fds, m->user_lookup_fds[0]);
+ if (copy0 < 0)
+ return log_error_errno(copy0, "Failed to add user lookup fd to serialization: %m");
+
+ copy1 = fdset_put_dup(fds, m->user_lookup_fds[1]);
+ if (copy1 < 0)
+ return log_error_errno(copy1, "Failed to add user lookup fd to serialization: %m");
+
+ (void) serialize_item_format(f, "user-lookup", "%i %i", copy0, copy1);
+ }
+
+ bus_track_serialize(m->subscribed, f, "subscribed");
+
+ r = dynamic_user_serialize(m, f, fds);
+ if (r < 0)
+ return r;
+
+ manager_serialize_uid_refs(m, f);
+ manager_serialize_gid_refs(m, f);
+
+ r = exec_runtime_serialize(m, f, fds);
+ if (r < 0)
+ return r;
+
+ (void) fputc('\n', f);
+
+ HASHMAP_FOREACH_KEY(u, t, m->units) {
+ if (u->id != t)
+ continue;
+
+ r = unit_serialize(u, f, fds, switching_root);
+ if (r < 0)
+ return r;
+ }
+
+ r = fflush_and_check(f);
+ if (r < 0)
+ return log_error_errno(r, "Failed to flush serialization: %m");
+
+ r = bus_fdset_add_all(m, fds);
+ if (r < 0)
+ return log_error_errno(r, "Failed to add bus sockets to serialization: %m");
+
+ return 0;
+}
+
+static int manager_deserialize_one_unit(Manager *m, const char *name, FILE *f, FDSet *fds) {
+ Unit *u;
+ int r;
+
+ r = manager_load_unit(m, name, NULL, NULL, &u);
+ if (r < 0) {
+ if (r == -ENOMEM)
+ return r;
+ return log_notice_errno(r, "Failed to load unit \"%s\", skipping deserialization: %m", name);
+ }
+
+ r = unit_deserialize(u, f, fds);
+ if (r < 0) {
+ if (r == -ENOMEM)
+ return r;
+ return log_notice_errno(r, "Failed to deserialize unit \"%s\", skipping: %m", name);
+ }
+
+ return 0;
+}
+
+static int manager_deserialize_units(Manager *m, FILE *f, FDSet *fds) {
+ const char *unit_name;
+ int r;
+
+ for (;;) {
+ _cleanup_free_ char *line = NULL;
+ /* Start marker */
+ r = read_line(f, LONG_LINE_MAX, &line);
+ if (r < 0)
+ return log_error_errno(r, "Failed to read serialization line: %m");
+ if (r == 0)
+ break;
+
+ unit_name = strstrip(line);
+
+ r = manager_deserialize_one_unit(m, unit_name, f, fds);
+ if (r == -ENOMEM)
+ return r;
+ if (r < 0) {
+ r = unit_deserialize_skip(f);
+ if (r < 0)
+ return r;
+ }
+ }
+
+ return 0;
+}
+
+static void manager_deserialize_uid_refs_one_internal(
+ Hashmap** uid_refs,
+ const char *value) {
+
+ uid_t uid;
+ uint32_t c;
+ int r;
+
+ assert(uid_refs);
+ assert(value);
+
+ r = parse_uid(value, &uid);
+ if (r < 0 || uid == 0) {
+ log_debug("Unable to parse UID/GID reference serialization: " UID_FMT, uid);
+ return;
+ }
+
+ if (hashmap_ensure_allocated(uid_refs, &trivial_hash_ops) < 0) {
+ log_oom();
+ return;
+ }
+
+ c = PTR_TO_UINT32(hashmap_get(*uid_refs, UID_TO_PTR(uid)));
+ if (c & DESTROY_IPC_FLAG)
+ return;
+
+ c |= DESTROY_IPC_FLAG;
+
+ r = hashmap_replace(*uid_refs, UID_TO_PTR(uid), UINT32_TO_PTR(c));
+ if (r < 0) {
+ log_debug_errno(r, "Failed to add UID/GID reference entry: %m");
+ return;
+ }
+}
+
+static void manager_deserialize_uid_refs_one(Manager *m, const char *value) {
+ manager_deserialize_uid_refs_one_internal(&m->uid_refs, value);
+}
+
+static void manager_deserialize_gid_refs_one(Manager *m, const char *value) {
+ manager_deserialize_uid_refs_one_internal(&m->gid_refs, value);
+}
+
+int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
+ int r = 0;
+
+ assert(m);
+ assert(f);
+
+ if (DEBUG_LOGGING) {
+ if (fdset_isempty(fds))
+ log_debug("No file descriptors passed");
+ else {
+ int fd;
+
+ FDSET_FOREACH(fd, fds) {
+ _cleanup_free_ char *fn = NULL;
+
+ r = fd_get_path(fd, &fn);
+ if (r < 0)
+ log_debug_errno(r, "Received serialized fd %i → %m", fd);
+ else
+ log_debug("Received serialized fd %i → %s", fd, strna(fn));
+ }
+ }
+ }
+
+ log_debug("Deserializing state...");
+
+ /* If we are not in reload mode yet, enter it now. Not that this is recursive, a caller might already have
+ * increased it to non-zero, which is why we just increase it by one here and down again at the end of this
+ * call. */
+ _cleanup_(manager_reloading_stopp) _unused_ Manager *reloading = manager_reloading_start(m);
+
+ for (;;) {
+ _cleanup_free_ char *line = NULL;
+ const char *val, *l;
+
+ r = read_line(f, LONG_LINE_MAX, &line);
+ if (r < 0)
+ return log_error_errno(r, "Failed to read serialization line: %m");
+ if (r == 0)
+ break;
+
+ l = strstrip(line);
+ if (isempty(l)) /* end marker */
+ break;
+
+ if ((val = startswith(l, "current-job-id="))) {
+ uint32_t id;
+
+ if (safe_atou32(val, &id) < 0)
+ log_notice("Failed to parse current job id value '%s', ignoring.", val);
+ else
+ m->current_job_id = MAX(m->current_job_id, id);
+
+ } else if ((val = startswith(l, "n-installed-jobs="))) {
+ uint32_t n;
+
+ if (safe_atou32(val, &n) < 0)
+ log_notice("Failed to parse installed jobs counter '%s', ignoring.", val);
+ else
+ m->n_installed_jobs += n;
+
+ } else if ((val = startswith(l, "n-failed-jobs="))) {
+ uint32_t n;
+
+ if (safe_atou32(val, &n) < 0)
+ log_notice("Failed to parse failed jobs counter '%s', ignoring.", val);
+ else
+ m->n_failed_jobs += n;
+
+ } else if ((val = startswith(l, "taint-usr="))) {
+ int b;
+
+ b = parse_boolean(val);
+ if (b < 0)
+ log_notice("Failed to parse taint /usr flag '%s', ignoring.", val);
+ else
+ m->taint_usr = m->taint_usr || b;
+
+ } else if ((val = startswith(l, "ready-sent="))) {
+ int b;
+
+ b = parse_boolean(val);
+ if (b < 0)
+ log_notice("Failed to parse ready-sent flag '%s', ignoring.", val);
+ else
+ m->ready_sent = m->ready_sent || b;
+
+ } else if ((val = startswith(l, "taint-logged="))) {
+ int b;
+
+ b = parse_boolean(val);
+ if (b < 0)
+ log_notice("Failed to parse taint-logged flag '%s', ignoring.", val);
+ else
+ m->taint_logged = m->taint_logged || b;
+
+ } else if ((val = startswith(l, "service-watchdogs="))) {
+ int b;
+
+ b = parse_boolean(val);
+ if (b < 0)
+ log_notice("Failed to parse service-watchdogs flag '%s', ignoring.", val);
+ else
+ m->service_watchdogs = b;
+
+ } else if ((val = startswith(l, "honor-device-enumeration="))) {
+ int b;
+
+ b = parse_boolean(val);
+ if (b < 0)
+ log_notice("Failed to parse honor-device-enumeration flag '%s', ignoring.", val);
+ else
+ m->honor_device_enumeration = b;
+
+ } else if ((val = startswith(l, "show-status-overridden="))) {
+ ShowStatus s;
+
+ s = show_status_from_string(val);
+ if (s < 0)
+ log_notice("Failed to parse show-status-overridden flag '%s', ignoring.", val);
+ else
+ manager_override_show_status(m, s, "deserialize");
+
+ } else if ((val = startswith(l, "log-level-override="))) {
+ int level;
+
+ level = log_level_from_string(val);
+ if (level < 0)
+ log_notice("Failed to parse log-level-override value '%s', ignoring.", val);
+ else
+ manager_override_log_level(m, level);
+
+ } else if ((val = startswith(l, "log-target-override="))) {
+ LogTarget target;
+
+ target = log_target_from_string(val);
+ if (target < 0)
+ log_notice("Failed to parse log-target-override value '%s', ignoring.", val);
+ else
+ manager_override_log_target(m, target);
+
+ } else if ((val = startswith(l, "runtime-watchdog-overridden="))) {
+ usec_t t;
+
+ if (deserialize_usec(val, &t) < 0)
+ log_notice("Failed to parse runtime-watchdog-overridden value '%s', ignoring.", val);
+ else
+ manager_override_watchdog(m, WATCHDOG_RUNTIME, t);
+
+ } else if ((val = startswith(l, "reboot-watchdog-overridden="))) {
+ usec_t t;
+
+ if (deserialize_usec(val, &t) < 0)
+ log_notice("Failed to parse reboot-watchdog-overridden value '%s', ignoring.", val);
+ else
+ manager_override_watchdog(m, WATCHDOG_REBOOT, t);
+
+ } else if ((val = startswith(l, "kexec-watchdog-overridden="))) {
+ usec_t t;
+
+ if (deserialize_usec(val, &t) < 0)
+ log_notice("Failed to parse kexec-watchdog-overridden value '%s', ignoring.", val);
+ else
+ manager_override_watchdog(m, WATCHDOG_KEXEC, t);
+
+ } else if (startswith(l, "env=")) {
+ r = deserialize_environment(l + 4, &m->client_environment);
+ if (r < 0)
+ log_notice_errno(r, "Failed to parse environment entry: \"%s\", ignoring: %m", l);
+
+ } else if ((val = startswith(l, "notify-fd="))) {
+ int fd;
+
+ if (safe_atoi(val, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
+ log_notice("Failed to parse notify fd, ignoring: \"%s\"", val);
+ else {
+ m->notify_event_source = sd_event_source_disable_unref(m->notify_event_source);
+ safe_close(m->notify_fd);
+ m->notify_fd = fdset_remove(fds, fd);
+ }
+
+ } else if ((val = startswith(l, "notify-socket="))) {
+ r = free_and_strdup(&m->notify_socket, val);
+ if (r < 0)
+ return r;
+
+ } else if ((val = startswith(l, "cgroups-agent-fd="))) {
+ int fd;
+
+ if (safe_atoi(val, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
+ log_notice("Failed to parse cgroups agent fd, ignoring.: %s", val);
+ else {
+ m->cgroups_agent_event_source = sd_event_source_disable_unref(m->cgroups_agent_event_source);
+ safe_close(m->cgroups_agent_fd);
+ m->cgroups_agent_fd = fdset_remove(fds, fd);
+ }
+
+ } else if ((val = startswith(l, "user-lookup="))) {
+ int fd0, fd1;
+
+ if (sscanf(val, "%i %i", &fd0, &fd1) != 2 || fd0 < 0 || fd1 < 0 || fd0 == fd1 || !fdset_contains(fds, fd0) || !fdset_contains(fds, fd1))
+ log_notice("Failed to parse user lookup fd, ignoring: %s", val);
+ else {
+ m->user_lookup_event_source = sd_event_source_disable_unref(m->user_lookup_event_source);
+ safe_close_pair(m->user_lookup_fds);
+ m->user_lookup_fds[0] = fdset_remove(fds, fd0);
+ m->user_lookup_fds[1] = fdset_remove(fds, fd1);
+ }
+
+ } else if ((val = startswith(l, "dynamic-user=")))
+ dynamic_user_deserialize_one(m, val, fds);
+ else if ((val = startswith(l, "destroy-ipc-uid=")))
+ manager_deserialize_uid_refs_one(m, val);
+ else if ((val = startswith(l, "destroy-ipc-gid=")))
+ manager_deserialize_gid_refs_one(m, val);
+ else if ((val = startswith(l, "exec-runtime=")))
+ (void) exec_runtime_deserialize_one(m, val, fds);
+ else if ((val = startswith(l, "subscribed="))) {
+
+ if (strv_extend(&m->deserialized_subscribed, val) < 0)
+ return -ENOMEM;
+
+ } else {
+ ManagerTimestamp q;
+
+ for (q = 0; q < _MANAGER_TIMESTAMP_MAX; q++) {
+ val = startswith(l, manager_timestamp_to_string(q));
+ if (!val)
+ continue;
+
+ val = startswith(val, "-timestamp=");
+ if (val)
+ break;
+ }
+
+ if (q < _MANAGER_TIMESTAMP_MAX) /* found it */
+ (void) deserialize_dual_timestamp(val, m->timestamps + q);
+ else if (!startswith(l, "kdbus-fd=")) /* ignore kdbus */
+ log_notice("Unknown serialization item '%s', ignoring.", l);
+ }
+ }
+
+ return manager_deserialize_units(m, f, fds);
+}
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <stdbool.h>
+
+#include "manager.h"
+#include "fdset.h"
+
+#define DESTROY_IPC_FLAG (UINT32_C(1) << 31)
+
+int manager_open_serialization(Manager *m, FILE **ret_f);
+int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root);
+int manager_deserialize(Manager *m, FILE *f, FDSet *fds);
#include "macro.h"
#include "manager.h"
#include "manager-dump.h"
+#include "manager-serialize.h"
#include "memory-util.h"
#include "mkdir.h"
#include "parse-util.h"
#include "rlimit-util.h"
#include "rm-rf.h"
#include "selinux-util.h"
-#include "serialize.h"
#include "signal-util.h"
#include "socket-util.h"
#include "special.h"
#include "transaction.h"
#include "umask-util.h"
#include "unit-name.h"
-#include "unit-serialize.h"
#include "user-util.h"
#include "virt.h"
#include "watchdog.h"
static void manager_vacuum(Manager *m);
static usec_t manager_watch_jobs_next_time(Manager *m) {
- return usec_add(now(CLOCK_MONOTONIC),
- show_status_on(m->show_status) ? JOBS_IN_PROGRESS_WAIT_USEC :
- JOBS_IN_PROGRESS_QUIET_WAIT_USEC);
+ usec_t timeout;
+
+ if (MANAGER_IS_USER(m))
+ /* Let the user manager without a timeout show status quickly, so the system manager can make
+ * use of it, if it wants to. */
+ timeout = JOBS_IN_PROGRESS_WAIT_USEC * 2 / 3;
+ else if (show_status_on(m->show_status))
+ /* When status is on, just use the usual timeout. */
+ timeout = JOBS_IN_PROGRESS_WAIT_USEC;
+ else
+ timeout = JOBS_IN_PROGRESS_QUIET_WAIT_USEC;
+
+ return usec_add(now(CLOCK_MONOTONIC), timeout);
}
static void manager_watch_jobs_in_progress(Manager *m) {
}
static void manager_print_jobs_in_progress(Manager *m) {
- _cleanup_free_ char *job_of_n = NULL;
Job *j;
unsigned counter = 0, print_nr;
char cylon[6 + CYLON_BUFFER_EXTRA + 1];
unsigned cylon_pos;
- char time[FORMAT_TIMESPAN_MAX], limit[FORMAT_TIMESPAN_MAX] = "no limit";
uint64_t x;
assert(m);
m->jobs_in_progress_iteration++;
- if (m->n_running_jobs > 1) {
- if (asprintf(&job_of_n, "(%u of %u) ", counter, m->n_running_jobs) < 0)
- job_of_n = NULL;
- }
+ char job_of_n[STRLEN("( of ) ") + DECIMAL_STR_MAX(unsigned)*2] = "";
+ if (m->n_running_jobs > 1)
+ xsprintf(job_of_n, "(%u of %u) ", counter, m->n_running_jobs);
- format_timespan(time, sizeof(time), now(CLOCK_MONOTONIC) - j->begin_usec, 1*USEC_PER_SEC);
- if (job_get_timeout(j, &x) > 0)
- format_timespan(limit, sizeof(limit), x - j->begin_usec, 1*USEC_PER_SEC);
+ bool have_timeout = job_get_timeout(j, &x) > 0;
/* We want to use enough information for the user to identify previous lines talking about the same
* unit, but keep the message as short as possible. So if 'Starting foo.service' or 'Starting
- * foo.service (Description)' were used, 'foo.service' is enough here. On the other hand, if we used
+ * foo.service - Description' were used, 'foo.service' is enough here. On the other hand, if we used
* 'Starting Description' before, then we shall also use 'Description' here. So we pass NULL as the
* second argument to unit_status_string(). */
const char *ident = unit_status_string(j->unit, NULL);
- manager_status_printf(m, STATUS_TYPE_EPHEMERAL, cylon,
- "%sA %s job is running for %s (%s / %s)",
- strempty(job_of_n),
- job_type_to_string(j->type),
- ident,
- time, limit);
+ const char *time = FORMAT_TIMESPAN(now(CLOCK_MONOTONIC) - j->begin_usec, 1*USEC_PER_SEC);
+ const char *limit = have_timeout ? FORMAT_TIMESPAN(x - j->begin_usec, 1*USEC_PER_SEC) : "no limit";
+
+ if (m->status_unit_format == STATUS_UNIT_FORMAT_DESCRIPTION)
+ /* When using 'Description', we effectively don't have enough space to show the nested status
+ * without ellipsization, so let's not even try. */
+ manager_status_printf(m, STATUS_TYPE_EPHEMERAL, cylon,
+ "%sA %s job is running for %s (%s / %s)",
+ job_of_n,
+ job_type_to_string(j->type),
+ ident,
+ time, limit);
+ else {
+ const char *status_text = unit_status_text(j->unit);
+
+ manager_status_printf(m, STATUS_TYPE_EPHEMERAL, cylon,
+ "%sJob %s/%s running (%s / %s)%s%s",
+ job_of_n,
+ ident,
+ job_type_to_string(j->type),
+ time, limit,
+ status_text ? ": " : "",
+ strempty(status_text));
+ }
+
+ sd_notifyf(false,
+ "STATUS=%sUser job %s/%s running (%s / %s)...",
+ job_of_n,
+ ident,
+ job_type_to_string(j->type),
+ time, limit);
+ m->status_ready = false;
}
static int have_ask_password(void) {
SIGRTMIN+22, /* systemd: set log level to LOG_DEBUG */
SIGRTMIN+23, /* systemd: set log level to LOG_INFO */
SIGRTMIN+24, /* systemd: Immediate exit (--user only) */
-
- /* .. one free signal here ... */
+ SIGRTMIN+25, /* systemd: reexecute manager */
/* Apparently Linux on hppa had fewer RT signals until v3.18,
* SIGRTMAX was SIGRTMIN+25, and then SIGRTMIN was lowered,
NULL);
/* Let's order the environment alphabetically, just to make it pretty */
- strv_sort(l);
-
- return l;
+ return strv_sort(l);
}
int manager_default_environment(Manager *m) {
m->honor_device_enumeration = true;
}
-static Manager* manager_reloading_start(Manager *m) {
+Manager* manager_reloading_start(Manager *m) {
m->n_reloading++;
return m;
}
-static void manager_reloading_stopp(Manager **m) {
+void manager_reloading_stopp(Manager **m) {
if (*m) {
assert((*m)->n_reloading > 0);
(*m)->n_reloading--;
return 0;
}
-static void manager_start_target(Manager *m, const char *name, JobMode mode) {
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- int r;
+static void manager_start_special(Manager *m, const char *name, JobMode mode) {
+ Job *job;
+
+ if (manager_add_job_by_name_and_warn(m, JOB_START, name, mode, NULL, &job) < 0)
+ return;
- log_debug("Activating special unit %s", name);
+ const char *s = unit_status_string(job->unit, NULL);
- r = manager_add_job_by_name(m, JOB_START, name, mode, NULL, &error, NULL);
- if (r < 0)
- log_error("Failed to enqueue %s job: %s", name, bus_error_message(&error, r));
+ log_info("Activating special unit %s...", s);
+
+ sd_notifyf(false,
+ "STATUS=Activating special unit %s...", s);
+ m->status_ready = false;
}
static void manager_handle_ctrl_alt_del(Manager *m) {
* unless it was disabled in system.conf */
if (ratelimit_below(&m->ctrl_alt_del_ratelimit) || m->cad_burst_action == EMERGENCY_ACTION_NONE)
- manager_start_target(m, SPECIAL_CTRL_ALT_DEL_TARGET, JOB_REPLACE_IRREVERSIBLY);
+ manager_start_special(m, SPECIAL_CTRL_ALT_DEL_TARGET, JOB_REPLACE_IRREVERSIBLY);
else
emergency_action(m, m->cad_burst_action, EMERGENCY_ACTION_WARN, NULL, -1,
"Ctrl-Alt-Del was pressed more than 7 times within 2s");
if (MANAGER_IS_SYSTEM(m))
manager_handle_ctrl_alt_del(m);
else
- manager_start_target(m, SPECIAL_EXIT_TARGET,
- JOB_REPLACE_IRREVERSIBLY);
+ manager_start_special(m, SPECIAL_EXIT_TARGET, JOB_REPLACE_IRREVERSIBLY);
break;
case SIGWINCH:
/* This is a nop on non-init */
if (MANAGER_IS_SYSTEM(m))
- manager_start_target(m, SPECIAL_KBREQUEST_TARGET, JOB_REPLACE);
+ manager_start_special(m, SPECIAL_KBREQUEST_TARGET, JOB_REPLACE);
break;
case SIGPWR:
/* This is a nop on non-init */
if (MANAGER_IS_SYSTEM(m))
- manager_start_target(m, SPECIAL_SIGPWR_TARGET, JOB_REPLACE);
+ manager_start_special(m, SPECIAL_SIGPWR_TARGET, JOB_REPLACE);
break;
if (MANAGER_IS_SYSTEM(m))
(void) bus_init_system(m);
- } else {
- log_info("Starting D-Bus service...");
- manager_start_target(m, SPECIAL_DBUS_SERVICE, JOB_REPLACE);
- }
+ } else
+ manager_start_special(m, SPECIAL_DBUS_SERVICE, JOB_REPLACE);
break;
if ((int) sfsi.ssi_signo >= SIGRTMIN+0 &&
(int) sfsi.ssi_signo < SIGRTMIN+(int) ELEMENTSOF(target_table)) {
int idx = (int) sfsi.ssi_signo - SIGRTMIN;
- manager_start_target(m, target_table[idx].target,
- target_table[idx].mode);
+ manager_start_special(m, target_table[idx].target, target_table[idx].mode);
break;
}
/* This is a nop on init */
break;
+ case 25:
+ m->objective = MANAGER_REEXECUTE;
+ break;
+
case 26:
case 29: /* compatibility: used to be mapped to LOG_TARGET_SYSLOG_OR_KMSG */
manager_restore_original_log_target(m);
return;
}
- if (asprintf(&message, "U\002%c%s%n", (int) (strlen(u->id) + 1), u->id, &n) < 0) {
- log_oom();
- return;
- }
+ if (asprintf(&message, "U\002%c%s%n", (int) (strlen(u->id) + 1), u->id, &n) < 0)
+ return (void) log_oom();
errno = 0;
if (write(fd, message, n + 1) != n + 1)
log_error_errno(errno, "Failed to write Plymouth message: %m");
}
-int manager_open_serialization(Manager *m, FILE **_f) {
- _cleanup_close_ int fd = -1;
- FILE *f;
-
- assert(_f);
-
- fd = open_serialization_fd("systemd-state");
- if (fd < 0)
- return fd;
-
- f = take_fdopen(&fd, "w+");
- if (!f)
- return -errno;
-
- *_f = f;
- return 0;
-}
-
-static bool manager_timestamp_shall_serialize(ManagerTimestamp t) {
-
- if (!in_initrd())
- return true;
-
- /* The following timestamps only apply to the host system, hence only serialize them there */
- return !IN_SET(t,
- MANAGER_TIMESTAMP_USERSPACE, MANAGER_TIMESTAMP_FINISH,
- MANAGER_TIMESTAMP_SECURITY_START, MANAGER_TIMESTAMP_SECURITY_FINISH,
- MANAGER_TIMESTAMP_GENERATORS_START, MANAGER_TIMESTAMP_GENERATORS_FINISH,
- MANAGER_TIMESTAMP_UNITS_LOAD_START, MANAGER_TIMESTAMP_UNITS_LOAD_FINISH);
-}
-
-#define DESTROY_IPC_FLAG (UINT32_C(1) << 31)
-
-static void manager_serialize_uid_refs_internal(
- FILE *f,
- Hashmap *uid_refs,
- const char *field_name) {
-
- void *p, *k;
-
- assert(f);
- assert(field_name);
-
- /* Serialize the UID reference table. Or actually, just the IPC destruction flag of it, as
- * the actual counter of it is better rebuild after a reload/reexec. */
-
- HASHMAP_FOREACH_KEY(p, k, uid_refs) {
- uint32_t c;
- uid_t uid;
-
- uid = PTR_TO_UID(k);
- c = PTR_TO_UINT32(p);
-
- if (!(c & DESTROY_IPC_FLAG))
- continue;
-
- (void) serialize_item_format(f, field_name, UID_FMT, uid);
- }
-}
-
-static void manager_serialize_uid_refs(Manager *m, FILE *f) {
- manager_serialize_uid_refs_internal(f, m->uid_refs, "destroy-ipc-uid");
-}
-
-static void manager_serialize_gid_refs(Manager *m, FILE *f) {
- manager_serialize_uid_refs_internal(f, m->gid_refs, "destroy-ipc-gid");
-}
-
-int manager_serialize(
- Manager *m,
- FILE *f,
- FDSet *fds,
- bool switching_root) {
-
- const char *t;
- Unit *u;
- int r;
-
- assert(m);
- assert(f);
- assert(fds);
-
- _cleanup_(manager_reloading_stopp) _unused_ Manager *reloading = manager_reloading_start(m);
-
- (void) serialize_item_format(f, "current-job-id", "%" PRIu32, m->current_job_id);
- (void) serialize_item_format(f, "n-installed-jobs", "%u", m->n_installed_jobs);
- (void) serialize_item_format(f, "n-failed-jobs", "%u", m->n_failed_jobs);
- (void) serialize_bool(f, "taint-usr", m->taint_usr);
- (void) serialize_bool(f, "ready-sent", m->ready_sent);
- (void) serialize_bool(f, "taint-logged", m->taint_logged);
- (void) serialize_bool(f, "service-watchdogs", m->service_watchdogs);
-
- /* After switching root, udevd has not been started yet. So, enumeration results should not be emitted. */
- (void) serialize_bool(f, "honor-device-enumeration", !switching_root);
-
- if (m->show_status_overridden != _SHOW_STATUS_INVALID)
- (void) serialize_item(f, "show-status-overridden",
- show_status_to_string(m->show_status_overridden));
-
- if (m->log_level_overridden)
- (void) serialize_item_format(f, "log-level-override", "%i", log_get_max_level());
- if (m->log_target_overridden)
- (void) serialize_item(f, "log-target-override", log_target_to_string(log_get_target()));
-
- (void) serialize_usec(f, "runtime-watchdog-overridden", m->watchdog_overridden[WATCHDOG_RUNTIME]);
- (void) serialize_usec(f, "reboot-watchdog-overridden", m->watchdog_overridden[WATCHDOG_REBOOT]);
- (void) serialize_usec(f, "kexec-watchdog-overridden", m->watchdog_overridden[WATCHDOG_KEXEC]);
-
- for (ManagerTimestamp q = 0; q < _MANAGER_TIMESTAMP_MAX; q++) {
- _cleanup_free_ char *joined = NULL;
-
- if (!manager_timestamp_shall_serialize(q))
- continue;
-
- joined = strjoin(manager_timestamp_to_string(q), "-timestamp");
- if (!joined)
- return log_oom();
-
- (void) serialize_dual_timestamp(f, joined, m->timestamps + q);
- }
-
- if (!switching_root)
- (void) serialize_strv(f, "env", m->client_environment);
-
- if (m->notify_fd >= 0) {
- r = serialize_fd(f, fds, "notify-fd", m->notify_fd);
- if (r < 0)
- return r;
-
- (void) serialize_item(f, "notify-socket", m->notify_socket);
- }
-
- if (m->cgroups_agent_fd >= 0) {
- r = serialize_fd(f, fds, "cgroups-agent-fd", m->cgroups_agent_fd);
- if (r < 0)
- return r;
- }
-
- if (m->user_lookup_fds[0] >= 0) {
- int copy0, copy1;
-
- copy0 = fdset_put_dup(fds, m->user_lookup_fds[0]);
- if (copy0 < 0)
- return log_error_errno(copy0, "Failed to add user lookup fd to serialization: %m");
-
- copy1 = fdset_put_dup(fds, m->user_lookup_fds[1]);
- if (copy1 < 0)
- return log_error_errno(copy1, "Failed to add user lookup fd to serialization: %m");
-
- (void) serialize_item_format(f, "user-lookup", "%i %i", copy0, copy1);
- }
-
- bus_track_serialize(m->subscribed, f, "subscribed");
-
- r = dynamic_user_serialize(m, f, fds);
- if (r < 0)
- return r;
-
- manager_serialize_uid_refs(m, f);
- manager_serialize_gid_refs(m, f);
-
- r = exec_runtime_serialize(m, f, fds);
- if (r < 0)
- return r;
-
- (void) fputc('\n', f);
-
- HASHMAP_FOREACH_KEY(u, t, m->units) {
- if (u->id != t)
- continue;
-
- r = unit_serialize(u, f, fds, switching_root);
- if (r < 0)
- return r;
- }
-
- r = fflush_and_check(f);
- if (r < 0)
- return log_error_errno(r, "Failed to flush serialization: %m");
-
- r = bus_fdset_add_all(m, fds);
- if (r < 0)
- return log_error_errno(r, "Failed to add bus sockets to serialization: %m");
-
- return 0;
-}
-
-static int manager_deserialize_one_unit(Manager *m, const char *name, FILE *f, FDSet *fds) {
- Unit *u;
- int r;
-
- r = manager_load_unit(m, name, NULL, NULL, &u);
- if (r < 0) {
- if (r == -ENOMEM)
- return r;
- return log_notice_errno(r, "Failed to load unit \"%s\", skipping deserialization: %m", name);
- }
-
- r = unit_deserialize(u, f, fds);
- if (r < 0) {
- if (r == -ENOMEM)
- return r;
- return log_notice_errno(r, "Failed to deserialize unit \"%s\", skipping: %m", name);
- }
-
- return 0;
-}
-
-static int manager_deserialize_units(Manager *m, FILE *f, FDSet *fds) {
- const char *unit_name;
- int r;
-
- for (;;) {
- _cleanup_free_ char *line = NULL;
- /* Start marker */
- r = read_line(f, LONG_LINE_MAX, &line);
- if (r < 0)
- return log_error_errno(r, "Failed to read serialization line: %m");
- if (r == 0)
- break;
-
- unit_name = strstrip(line);
-
- r = manager_deserialize_one_unit(m, unit_name, f, fds);
- if (r == -ENOMEM)
- return r;
- if (r < 0) {
- r = unit_deserialize_skip(f);
- if (r < 0)
- return r;
- }
- }
-
- return 0;
-}
-
usec_t manager_get_watchdog(Manager *m, WatchdogType t) {
assert(m);
m->runtime_watchdog_running = true;
}
-static void manager_deserialize_uid_refs_one_internal(
- Hashmap** uid_refs,
- const char *value) {
-
- uid_t uid;
- uint32_t c;
- int r;
-
- assert(uid_refs);
- assert(value);
-
- r = parse_uid(value, &uid);
- if (r < 0 || uid == 0) {
- log_debug("Unable to parse UID/GID reference serialization: " UID_FMT, uid);
- return;
- }
-
- if (hashmap_ensure_allocated(uid_refs, &trivial_hash_ops) < 0) {
- log_oom();
- return;
- }
-
- c = PTR_TO_UINT32(hashmap_get(*uid_refs, UID_TO_PTR(uid)));
- if (c & DESTROY_IPC_FLAG)
- return;
-
- c |= DESTROY_IPC_FLAG;
-
- r = hashmap_replace(*uid_refs, UID_TO_PTR(uid), UINT32_TO_PTR(c));
- if (r < 0) {
- log_debug_errno(r, "Failed to add UID/GID reference entry: %m");
- return;
- }
-}
-
-static void manager_deserialize_uid_refs_one(Manager *m, const char *value) {
- manager_deserialize_uid_refs_one_internal(&m->uid_refs, value);
-}
-
-static void manager_deserialize_gid_refs_one(Manager *m, const char *value) {
- manager_deserialize_uid_refs_one_internal(&m->gid_refs, value);
-}
-
-int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
- int r = 0;
-
- assert(m);
- assert(f);
-
- if (DEBUG_LOGGING) {
- if (fdset_isempty(fds))
- log_debug("No file descriptors passed");
- else {
- int fd;
-
- FDSET_FOREACH(fd, fds) {
- _cleanup_free_ char *fn = NULL;
-
- r = fd_get_path(fd, &fn);
- if (r < 0)
- log_debug_errno(r, "Received serialized fd %i → %m", fd);
- else
- log_debug("Received serialized fd %i → %s", fd, strna(fn));
- }
- }
- }
-
- log_debug("Deserializing state...");
-
- /* If we are not in reload mode yet, enter it now. Not that this is recursive, a caller might already have
- * increased it to non-zero, which is why we just increase it by one here and down again at the end of this
- * call. */
- _cleanup_(manager_reloading_stopp) _unused_ Manager *reloading = manager_reloading_start(m);
-
- for (;;) {
- _cleanup_free_ char *line = NULL;
- const char *val, *l;
-
- r = read_line(f, LONG_LINE_MAX, &line);
- if (r < 0)
- return log_error_errno(r, "Failed to read serialization line: %m");
- if (r == 0)
- break;
-
- l = strstrip(line);
- if (isempty(l)) /* end marker */
- break;
-
- if ((val = startswith(l, "current-job-id="))) {
- uint32_t id;
-
- if (safe_atou32(val, &id) < 0)
- log_notice("Failed to parse current job id value '%s', ignoring.", val);
- else
- m->current_job_id = MAX(m->current_job_id, id);
-
- } else if ((val = startswith(l, "n-installed-jobs="))) {
- uint32_t n;
-
- if (safe_atou32(val, &n) < 0)
- log_notice("Failed to parse installed jobs counter '%s', ignoring.", val);
- else
- m->n_installed_jobs += n;
-
- } else if ((val = startswith(l, "n-failed-jobs="))) {
- uint32_t n;
-
- if (safe_atou32(val, &n) < 0)
- log_notice("Failed to parse failed jobs counter '%s', ignoring.", val);
- else
- m->n_failed_jobs += n;
-
- } else if ((val = startswith(l, "taint-usr="))) {
- int b;
-
- b = parse_boolean(val);
- if (b < 0)
- log_notice("Failed to parse taint /usr flag '%s', ignoring.", val);
- else
- m->taint_usr = m->taint_usr || b;
-
- } else if ((val = startswith(l, "ready-sent="))) {
- int b;
-
- b = parse_boolean(val);
- if (b < 0)
- log_notice("Failed to parse ready-sent flag '%s', ignoring.", val);
- else
- m->ready_sent = m->ready_sent || b;
-
- } else if ((val = startswith(l, "taint-logged="))) {
- int b;
-
- b = parse_boolean(val);
- if (b < 0)
- log_notice("Failed to parse taint-logged flag '%s', ignoring.", val);
- else
- m->taint_logged = m->taint_logged || b;
-
- } else if ((val = startswith(l, "service-watchdogs="))) {
- int b;
-
- b = parse_boolean(val);
- if (b < 0)
- log_notice("Failed to parse service-watchdogs flag '%s', ignoring.", val);
- else
- m->service_watchdogs = b;
-
- } else if ((val = startswith(l, "honor-device-enumeration="))) {
- int b;
-
- b = parse_boolean(val);
- if (b < 0)
- log_notice("Failed to parse honor-device-enumeration flag '%s', ignoring.", val);
- else
- m->honor_device_enumeration = b;
-
- } else if ((val = startswith(l, "show-status-overridden="))) {
- ShowStatus s;
-
- s = show_status_from_string(val);
- if (s < 0)
- log_notice("Failed to parse show-status-overridden flag '%s', ignoring.", val);
- else
- manager_override_show_status(m, s, "deserialize");
-
- } else if ((val = startswith(l, "log-level-override="))) {
- int level;
-
- level = log_level_from_string(val);
- if (level < 0)
- log_notice("Failed to parse log-level-override value '%s', ignoring.", val);
- else
- manager_override_log_level(m, level);
-
- } else if ((val = startswith(l, "log-target-override="))) {
- LogTarget target;
-
- target = log_target_from_string(val);
- if (target < 0)
- log_notice("Failed to parse log-target-override value '%s', ignoring.", val);
- else
- manager_override_log_target(m, target);
-
- } else if ((val = startswith(l, "runtime-watchdog-overridden="))) {
- usec_t t;
-
- if (deserialize_usec(val, &t) < 0)
- log_notice("Failed to parse runtime-watchdog-overridden value '%s', ignoring.", val);
- else
- manager_override_watchdog(m, WATCHDOG_RUNTIME, t);
-
- } else if ((val = startswith(l, "reboot-watchdog-overridden="))) {
- usec_t t;
-
- if (deserialize_usec(val, &t) < 0)
- log_notice("Failed to parse reboot-watchdog-overridden value '%s', ignoring.", val);
- else
- manager_override_watchdog(m, WATCHDOG_REBOOT, t);
-
- } else if ((val = startswith(l, "kexec-watchdog-overridden="))) {
- usec_t t;
-
- if (deserialize_usec(val, &t) < 0)
- log_notice("Failed to parse kexec-watchdog-overridden value '%s', ignoring.", val);
- else
- manager_override_watchdog(m, WATCHDOG_KEXEC, t);
-
- } else if (startswith(l, "env=")) {
- r = deserialize_environment(l + 4, &m->client_environment);
- if (r < 0)
- log_notice_errno(r, "Failed to parse environment entry: \"%s\", ignoring: %m", l);
-
- } else if ((val = startswith(l, "notify-fd="))) {
- int fd;
-
- if (safe_atoi(val, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_notice("Failed to parse notify fd, ignoring: \"%s\"", val);
- else {
- m->notify_event_source = sd_event_source_disable_unref(m->notify_event_source);
- safe_close(m->notify_fd);
- m->notify_fd = fdset_remove(fds, fd);
- }
-
- } else if ((val = startswith(l, "notify-socket="))) {
- r = free_and_strdup(&m->notify_socket, val);
- if (r < 0)
- return r;
-
- } else if ((val = startswith(l, "cgroups-agent-fd="))) {
- int fd;
-
- if (safe_atoi(val, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_notice("Failed to parse cgroups agent fd, ignoring.: %s", val);
- else {
- m->cgroups_agent_event_source = sd_event_source_disable_unref(m->cgroups_agent_event_source);
- safe_close(m->cgroups_agent_fd);
- m->cgroups_agent_fd = fdset_remove(fds, fd);
- }
-
- } else if ((val = startswith(l, "user-lookup="))) {
- int fd0, fd1;
-
- if (sscanf(val, "%i %i", &fd0, &fd1) != 2 || fd0 < 0 || fd1 < 0 || fd0 == fd1 || !fdset_contains(fds, fd0) || !fdset_contains(fds, fd1))
- log_notice("Failed to parse user lookup fd, ignoring: %s", val);
- else {
- m->user_lookup_event_source = sd_event_source_disable_unref(m->user_lookup_event_source);
- safe_close_pair(m->user_lookup_fds);
- m->user_lookup_fds[0] = fdset_remove(fds, fd0);
- m->user_lookup_fds[1] = fdset_remove(fds, fd1);
- }
-
- } else if ((val = startswith(l, "dynamic-user=")))
- dynamic_user_deserialize_one(m, val, fds);
- else if ((val = startswith(l, "destroy-ipc-uid=")))
- manager_deserialize_uid_refs_one(m, val);
- else if ((val = startswith(l, "destroy-ipc-gid=")))
- manager_deserialize_gid_refs_one(m, val);
- else if ((val = startswith(l, "exec-runtime=")))
- (void) exec_runtime_deserialize_one(m, val, fds);
- else if ((val = startswith(l, "subscribed="))) {
-
- if (strv_extend(&m->deserialized_subscribed, val) < 0)
- return -ENOMEM;
-
- } else {
- ManagerTimestamp q;
-
- for (q = 0; q < _MANAGER_TIMESTAMP_MAX; q++) {
- val = startswith(l, manager_timestamp_to_string(q));
- if (!val)
- continue;
-
- val = startswith(val, "-timestamp=");
- if (val)
- break;
- }
-
- if (q < _MANAGER_TIMESTAMP_MAX) /* found it */
- (void) deserialize_dual_timestamp(val, m->timestamps + q);
- else if (!startswith(l, "kdbus-fd=")) /* ignore kdbus */
- log_notice("Unknown serialization item '%s', ignoring.", l);
- }
- }
-
- return manager_deserialize_units(m, f, fds);
-}
-
int manager_reload(Manager *m) {
_cleanup_(manager_reloading_stopp) Manager *reloading = NULL;
_cleanup_fdset_free_ FDSet *fds = NULL;
}
static void manager_notify_finished(Manager *m) {
- char userspace[FORMAT_TIMESPAN_MAX], initrd[FORMAT_TIMESPAN_MAX], kernel[FORMAT_TIMESPAN_MAX], sum[FORMAT_TIMESPAN_MAX];
usec_t firmware_usec, loader_usec, kernel_usec, initrd_usec, userspace_usec, total_usec;
if (MANAGER_IS_TEST_RUN(m))
return;
if (MANAGER_IS_SYSTEM(m) && detect_container() <= 0) {
- char ts[FORMAT_TIMESPAN_MAX];
char buf[FORMAT_TIMESPAN_MAX + STRLEN(" (firmware) + ") + FORMAT_TIMESPAN_MAX + STRLEN(" (loader) + ")]
= {};
char *p = buf;
total_usec = m->timestamps[MANAGER_TIMESTAMP_FIRMWARE].monotonic + m->timestamps[MANAGER_TIMESTAMP_FINISH].monotonic;
if (firmware_usec > 0)
- size = strpcpyf(&p, size, "%s (firmware) + ", format_timespan(ts, sizeof(ts), firmware_usec, USEC_PER_MSEC));
+ size = strpcpyf(&p, size, "%s (firmware) + ", FORMAT_TIMESPAN(firmware_usec, USEC_PER_MSEC));
if (loader_usec > 0)
- size = strpcpyf(&p, size, "%s (loader) + ", format_timespan(ts, sizeof(ts), loader_usec, USEC_PER_MSEC));
+ size = strpcpyf(&p, size, "%s (loader) + ", FORMAT_TIMESPAN(loader_usec, USEC_PER_MSEC));
if (dual_timestamp_is_set(&m->timestamps[MANAGER_TIMESTAMP_INITRD])) {
"USERSPACE_USEC="USEC_FMT, userspace_usec,
LOG_MESSAGE("Startup finished in %s%s (kernel) + %s (initrd) + %s (userspace) = %s.",
buf,
- format_timespan(kernel, sizeof(kernel), kernel_usec, USEC_PER_MSEC),
- format_timespan(initrd, sizeof(initrd), initrd_usec, USEC_PER_MSEC),
- format_timespan(userspace, sizeof(userspace), userspace_usec, USEC_PER_MSEC),
- format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC)));
+ FORMAT_TIMESPAN(kernel_usec, USEC_PER_MSEC),
+ FORMAT_TIMESPAN(initrd_usec, USEC_PER_MSEC),
+ FORMAT_TIMESPAN(userspace_usec, USEC_PER_MSEC),
+ FORMAT_TIMESPAN(total_usec, USEC_PER_MSEC)));
} else {
/* The initrd-less case on bare-metal */
"USERSPACE_USEC="USEC_FMT, userspace_usec,
LOG_MESSAGE("Startup finished in %s%s (kernel) + %s (userspace) = %s.",
buf,
- format_timespan(kernel, sizeof(kernel), kernel_usec, USEC_PER_MSEC),
- format_timespan(userspace, sizeof(userspace), userspace_usec, USEC_PER_MSEC),
- format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC)));
+ FORMAT_TIMESPAN(kernel_usec, USEC_PER_MSEC),
+ FORMAT_TIMESPAN(userspace_usec, USEC_PER_MSEC),
+ FORMAT_TIMESPAN(total_usec, USEC_PER_MSEC)));
}
} else {
/* The container and --user case */
"MESSAGE_ID=" SD_MESSAGE_USER_STARTUP_FINISHED_STR,
"USERSPACE_USEC="USEC_FMT, userspace_usec,
LOG_MESSAGE("Startup finished in %s.",
- format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC)));
+ FORMAT_TIMESPAN(total_usec, USEC_PER_MSEC)));
}
bus_manager_send_finished(m, firmware_usec, loader_usec, kernel_usec, initrd_usec, userspace_usec, total_usec);
- sd_notifyf(false,
- m->ready_sent ? "STATUS=Startup finished in %s."
- : "READY=1\n"
- "STATUS=Startup finished in %s.",
- format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC));
- m->ready_sent = true;
-
log_taint_string(m);
}
-static void manager_send_ready(Manager *m) {
+static void user_manager_send_ready(Manager *m) {
assert(m);
/* We send READY=1 on reaching basic.target only when running in --user mode. */
if (!MANAGER_IS_USER(m) || m->ready_sent)
return;
- m->ready_sent = true;
-
sd_notifyf(false,
"READY=1\n"
"STATUS=Reached " SPECIAL_BASIC_TARGET ".");
+ m->ready_sent = true;
+ m->status_ready = false;
+}
+
+static void manager_send_ready(Manager *m) {
+ if (m->ready_sent && m->status_ready)
+ /* Skip the notification if nothing changed. */
+ return;
+
+ sd_notifyf(false,
+ "%sSTATUS=Ready.",
+ m->ready_sent ? "READY=1\n" : "");
+ m->ready_sent = m->status_ready = true;
}
static void manager_check_basic_target(Manager *m) {
return;
/* For user managers, send out READY=1 as soon as we reach basic.target */
- manager_send_ready(m);
+ user_manager_send_ready(m);
/* Log the taint string as soon as we reach basic.target */
log_taint_string(m);
if (hashmap_buckets(m->jobs) > hashmap_size(m->units) / 10)
m->jobs = hashmap_free(m->jobs);
+ manager_send_ready(m);
+
+ if (MANAGER_IS_FINISHED(m))
+ return;
+
manager_flip_auto_status(m, false, "boot finished");
/* Notify Type=idle units that we are done now */
/* This is no longer the first boot */
manager_set_first_boot(m, false);
- if (MANAGER_IS_FINISHED(m))
- return;
-
dual_timestamp_get(m->timestamps + MANAGER_TIMESTAMP_FINISH);
manager_notify_finished(m);
static const char *const manager_state_table[_MANAGER_STATE_MAX] = {
[MANAGER_INITIALIZING] = "initializing",
- [MANAGER_STARTING] = "starting",
- [MANAGER_RUNNING] = "running",
- [MANAGER_DEGRADED] = "degraded",
- [MANAGER_MAINTENANCE] = "maintenance",
- [MANAGER_STOPPING] = "stopping",
+ [MANAGER_STARTING] = "starting",
+ [MANAGER_RUNNING] = "running",
+ [MANAGER_DEGRADED] = "degraded",
+ [MANAGER_MAINTENANCE] = "maintenance",
+ [MANAGER_STOPPING] = "stopping",
};
DEFINE_STRING_TABLE_LOOKUP(manager_state, ManagerState);
static const char *const manager_timestamp_table[_MANAGER_TIMESTAMP_MAX] = {
- [MANAGER_TIMESTAMP_FIRMWARE] = "firmware",
- [MANAGER_TIMESTAMP_LOADER] = "loader",
- [MANAGER_TIMESTAMP_KERNEL] = "kernel",
- [MANAGER_TIMESTAMP_INITRD] = "initrd",
- [MANAGER_TIMESTAMP_USERSPACE] = "userspace",
- [MANAGER_TIMESTAMP_FINISH] = "finish",
- [MANAGER_TIMESTAMP_SECURITY_START] = "security-start",
- [MANAGER_TIMESTAMP_SECURITY_FINISH] = "security-finish",
- [MANAGER_TIMESTAMP_GENERATORS_START] = "generators-start",
- [MANAGER_TIMESTAMP_GENERATORS_FINISH] = "generators-finish",
- [MANAGER_TIMESTAMP_UNITS_LOAD_START] = "units-load-start",
- [MANAGER_TIMESTAMP_UNITS_LOAD_FINISH] = "units-load-finish",
- [MANAGER_TIMESTAMP_INITRD_SECURITY_START] = "initrd-security-start",
- [MANAGER_TIMESTAMP_INITRD_SECURITY_FINISH] = "initrd-security-finish",
- [MANAGER_TIMESTAMP_INITRD_GENERATORS_START] = "initrd-generators-start",
+ [MANAGER_TIMESTAMP_FIRMWARE] = "firmware",
+ [MANAGER_TIMESTAMP_LOADER] = "loader",
+ [MANAGER_TIMESTAMP_KERNEL] = "kernel",
+ [MANAGER_TIMESTAMP_INITRD] = "initrd",
+ [MANAGER_TIMESTAMP_USERSPACE] = "userspace",
+ [MANAGER_TIMESTAMP_FINISH] = "finish",
+ [MANAGER_TIMESTAMP_SECURITY_START] = "security-start",
+ [MANAGER_TIMESTAMP_SECURITY_FINISH] = "security-finish",
+ [MANAGER_TIMESTAMP_GENERATORS_START] = "generators-start",
+ [MANAGER_TIMESTAMP_GENERATORS_FINISH] = "generators-finish",
+ [MANAGER_TIMESTAMP_UNITS_LOAD_START] = "units-load-start",
+ [MANAGER_TIMESTAMP_UNITS_LOAD_FINISH] = "units-load-finish",
+ [MANAGER_TIMESTAMP_INITRD_SECURITY_START] = "initrd-security-start",
+ [MANAGER_TIMESTAMP_INITRD_SECURITY_FINISH] = "initrd-security-finish",
+ [MANAGER_TIMESTAMP_INITRD_GENERATORS_START] = "initrd-generators-start",
[MANAGER_TIMESTAMP_INITRD_GENERATORS_FINISH] = "initrd-generators-finish",
- [MANAGER_TIMESTAMP_INITRD_UNITS_LOAD_START] = "initrd-units-load-start",
+ [MANAGER_TIMESTAMP_INITRD_UNITS_LOAD_START] = "initrd-units-load-start",
[MANAGER_TIMESTAMP_INITRD_UNITS_LOAD_FINISH] = "initrd-units-load-finish",
};
static const char* const oom_policy_table[_OOM_POLICY_MAX] = {
[OOM_CONTINUE] = "continue",
- [OOM_STOP] = "stop",
- [OOM_KILL] = "kill",
+ [OOM_STOP] = "stop",
+ [OOM_KILL] = "kill",
};
DEFINE_STRING_TABLE_LOOKUP(oom_policy, OOMPolicy);
/* Have we already sent out the READY=1 notification? */
bool ready_sent;
+ /* Was the last status sent "STATUS=Ready."? */
+ bool status_ready;
+
/* Have we already printed the taint line if necessary? */
bool taint_logged;
int manager_loop(Manager *m);
-int manager_open_serialization(Manager *m, FILE **_f);
-
-int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root);
-int manager_deserialize(Manager *m, FILE *f, FDSet *fds);
-
int manager_reload(Manager *m);
+Manager* manager_reloading_start(Manager *m);
+void manager_reloading_stopp(Manager **m);
void manager_reset_failed(Manager *m);
locale-setup.h
manager-dump.c
manager-dump.h
+ manager-serialize.c
+ manager-serialize.h
manager.c
manager.h
mount.c
meson.add_install_script('sh', '-c', mkdir_p.format(usergeneratordir))
if install_sysconfdir
- meson.add_install_script('sh', '-c', mkdir_p.format(join_paths(pkgsysconfdir, 'system')))
- meson.add_install_script('sh', '-c', mkdir_p.format(join_paths(pkgsysconfdir, 'user')))
- meson.add_install_script('sh', '-c', mkdir_p.format(join_paths(sysconfdir, 'xdg/systemd')))
+ meson.add_install_script('sh', '-c', mkdir_p.format(pkgsysconfdir / 'system'))
+ meson.add_install_script('sh', '-c', mkdir_p.format(pkgsysconfdir / 'user'))
+ meson.add_install_script('sh', '-c', mkdir_p.format(sysconfdir / 'xdg/systemd'))
endif
############################################################
}
static void mount_dump(Unit *u, FILE *f, const char *prefix) {
- char buf[FORMAT_TIMESPAN_MAX];
Mount *m = MOUNT(u);
MountParameters *p;
prefix, yes_no(m->lazy_unmount),
prefix, yes_no(m->force_unmount),
prefix, yes_no(m->read_write_only),
- prefix, format_timespan(buf, sizeof(buf), m->timeout_usec, USEC_PER_SEC));
+ prefix, FORMAT_TIMESPAN(m->timeout_usec, USEC_PER_SEC));
if (m->control_pid > 0)
fprintf(f,
return 0;
default:
- assert_not_reached("Unexpected state.");
+ assert_not_reached();
}
}
else if (code == CLD_DUMPED)
f = MOUNT_FAILURE_CORE_DUMP;
else
- assert_not_reached("Unknown code");
+ assert_not_reached();
if (IN_SET(m->state, MOUNT_REMOUNTING, MOUNT_REMOUNTING_SIGKILL, MOUNT_REMOUNTING_SIGTERM))
mount_set_reload_result(m, f);
break;
default:
- assert_not_reached("Uh, control process died at wrong time.");
+ assert_not_reached();
}
/* Notify clients about changed exit status */
break;
default:
- assert_not_reached("Timeout at wrong time.");
+ assert_not_reached();
}
return 0;
}
static const char* const mount_exec_command_table[_MOUNT_EXEC_COMMAND_MAX] = {
- [MOUNT_EXEC_MOUNT] = "ExecMount",
+ [MOUNT_EXEC_MOUNT] = "ExecMount",
[MOUNT_EXEC_UNMOUNT] = "ExecUnmount",
[MOUNT_EXEC_REMOUNT] = "ExecRemount",
};
DEFINE_STRING_TABLE_LOOKUP(mount_exec_command, MountExecCommand);
static const char* const mount_result_table[_MOUNT_RESULT_MAX] = {
- [MOUNT_SUCCESS] = "success",
- [MOUNT_FAILURE_RESOURCES] = "resources",
- [MOUNT_FAILURE_TIMEOUT] = "timeout",
- [MOUNT_FAILURE_EXIT_CODE] = "exit-code",
- [MOUNT_FAILURE_SIGNAL] = "signal",
- [MOUNT_FAILURE_CORE_DUMP] = "core-dump",
+ [MOUNT_SUCCESS] = "success",
+ [MOUNT_FAILURE_RESOURCES] = "resources",
+ [MOUNT_FAILURE_TIMEOUT] = "timeout",
+ [MOUNT_FAILURE_EXIT_CODE] = "exit-code",
+ [MOUNT_FAILURE_SIGNAL] = "signal",
+ [MOUNT_FAILURE_CORE_DUMP] = "core-dump",
[MOUNT_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
- [MOUNT_FAILURE_PROTOCOL] = "protocol",
+ [MOUNT_FAILURE_PROTOCOL] = "protocol",
};
DEFINE_STRING_TABLE_LOOKUP(mount_result, MountResult);
return append_static_mounts(p, protect_home_yes_table, ELEMENTSOF(protect_home_yes_table), ignore_protect);
default:
- assert_not_reached("Unexpected ProtectHome= value");
+ assert_not_reached();
}
}
return append_static_mounts(p, protect_system_full_table, ELEMENTSOF(protect_system_full_table), ignore_protect);
default:
- assert_not_reached("Unexpected ProtectSystem= value");
+ assert_not_reached();
}
}
return mount_overlay(m);
default:
- assert_not_reached("Unknown mode");
+ assert_not_reached();
}
assert(what);
p->result = f;
} else if (streq(key, "path-spec")) {
- int previous_exists, skip = 0, r;
+ int previous_exists, skip = 0;
_cleanup_free_ char *type_str = NULL;
if (sscanf(value, "%ms %i %n", &type_str, &previous_exists, &skip) < 2)
log_unit_debug(u, "Failed to parse path-spec value: %s", value);
else {
_cleanup_free_ char *unescaped = NULL;
+ ssize_t l;
PathType type;
PathSpec *s;
return 0;
}
- r = cunescape(value+skip, 0, &unescaped);
- if (r < 0) {
- log_unit_warning_errno(u, r, "Failed to unescape serialize path: %m");
+ l = cunescape(value+skip, 0, &unescaped);
+ if (l < 0) {
+ log_unit_warning_errno(u, l, "Failed to unescape serialize path: %m");
return 0;
}
}
static const char* const path_type_table[_PATH_TYPE_MAX] = {
- [PATH_EXISTS] = "PathExists",
- [PATH_EXISTS_GLOB] = "PathExistsGlob",
+ [PATH_EXISTS] = "PathExists",
+ [PATH_EXISTS_GLOB] = "PathExistsGlob",
[PATH_DIRECTORY_NOT_EMPTY] = "DirectoryNotEmpty",
- [PATH_CHANGED] = "PathChanged",
- [PATH_MODIFIED] = "PathModified",
+ [PATH_CHANGED] = "PathChanged",
+ [PATH_MODIFIED] = "PathModified",
};
DEFINE_STRING_TABLE_LOOKUP(path_type, PathType);
static const char* const path_result_table[_PATH_RESULT_MAX] = {
- [PATH_SUCCESS] = "success",
- [PATH_FAILURE_RESOURCES] = "resources",
- [PATH_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
+ [PATH_SUCCESS] = "success",
+ [PATH_FAILURE_RESOURCES] = "resources",
+ [PATH_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
[PATH_FAILURE_UNIT_START_LIMIT_HIT] = "unit-start-limit-hit",
};
static void scope_dump(Unit *u, FILE *f, const char *prefix) {
Scope *s = SCOPE(u);
- char buf_runtime[FORMAT_TIMESPAN_MAX];
assert(s);
assert(f);
"%sRuntimeMaxSec: %s\n",
prefix, scope_state_to_string(s->state),
prefix, scope_result_to_string(s->result),
- prefix, format_timespan(buf_runtime, sizeof(buf_runtime), s->runtime_max_usec, USEC_PER_SEC));
+ prefix, FORMAT_TIMESPAN(s->runtime_max_usec, USEC_PER_SEC));
cgroup_context_dump(UNIT(s), f, prefix);
kill_context_dump(&s->kill_context, f, prefix);
break;
default:
- assert_not_reached("Timeout at wrong time.");
+ assert_not_reached();
}
return 0;
}
static const char* const scope_result_table[_SCOPE_RESULT_MAX] = {
- [SCOPE_SUCCESS] = "success",
+ [SCOPE_SUCCESS] = "success",
[SCOPE_FAILURE_RESOURCES] = "resources",
- [SCOPE_FAILURE_TIMEOUT] = "timeout",
+ [SCOPE_FAILURE_TIMEOUT] = "timeout",
};
DEFINE_STRING_TABLE_LOOKUP(scope_result, ScopeResult);
r = selinux_init_load_policy(&enforce);
if (r == 0) {
_cleanup_(mac_selinux_freep) char *label = NULL;
- char timespan[FORMAT_TIMESPAN_MAX];
mac_selinux_retest();
after_load = now(CLOCK_MONOTONIC);
log_info("Successfully loaded SELinux policy in %s.",
- format_timespan(timespan, sizeof(timespan), after_load - before_load, 0));
+ FORMAT_TIMESPAN(after_load - before_load, 0));
*loaded_policy = true;
}
static void service_dump(Unit *u, FILE *f, const char *prefix) {
- char buf_restart[FORMAT_TIMESPAN_MAX], buf_start[FORMAT_TIMESPAN_MAX], buf_stop[FORMAT_TIMESPAN_MAX],
- buf_runtime[FORMAT_TIMESPAN_MAX], buf_watchdog[FORMAT_TIMESPAN_MAX], buf_abort[FORMAT_TIMESPAN_MAX];
ServiceExecCommand c;
Service *s = SERVICE(u);
const char *prefix2;
"%sTimeoutStopSec: %s\n"
"%sTimeoutStartFailureMode: %s\n"
"%sTimeoutStopFailureMode: %s\n",
- prefix, format_timespan(buf_restart, sizeof(buf_restart), s->restart_usec, USEC_PER_SEC),
- prefix, format_timespan(buf_start, sizeof(buf_start), s->timeout_start_usec, USEC_PER_SEC),
- prefix, format_timespan(buf_stop, sizeof(buf_stop), s->timeout_stop_usec, USEC_PER_SEC),
+ prefix, FORMAT_TIMESPAN(s->restart_usec, USEC_PER_SEC),
+ prefix, FORMAT_TIMESPAN(s->timeout_start_usec, USEC_PER_SEC),
+ prefix, FORMAT_TIMESPAN(s->timeout_stop_usec, USEC_PER_SEC),
prefix, service_timeout_failure_mode_to_string(s->timeout_start_failure_mode),
prefix, service_timeout_failure_mode_to_string(s->timeout_stop_failure_mode));
if (s->timeout_abort_set)
fprintf(f,
"%sTimeoutAbortSec: %s\n",
- prefix, format_timespan(buf_abort, sizeof(buf_abort), s->timeout_abort_usec, USEC_PER_SEC));
+ prefix, FORMAT_TIMESPAN(s->timeout_abort_usec, USEC_PER_SEC));
fprintf(f,
"%sRuntimeMaxSec: %s\n"
"%sWatchdogSec: %s\n",
- prefix, format_timespan(buf_runtime, sizeof(buf_runtime), s->runtime_max_usec, USEC_PER_SEC),
- prefix, format_timespan(buf_watchdog, sizeof(buf_watchdog), s->watchdog_usec, USEC_PER_SEC));
+ prefix, FORMAT_TIMESPAN(s->runtime_max_usec, USEC_PER_SEC),
+ prefix, FORMAT_TIMESPAN(s->watchdog_usec, USEC_PER_SEC));
kill_context_dump(&s->kill_context, f, prefix);
exec_context_dump(&s->exec_context, f, prefix);
return IN_SET(s->result, SERVICE_FAILURE_SIGNAL, SERVICE_FAILURE_CORE_DUMP);
default:
- assert_not_reached("unknown restart setting");
+ assert_not_reached();
}
}
service_set_main_pid(s, pid);
service_set_state(s, SERVICE_START);
} else
- assert_not_reached("Unknown service type");
+ assert_not_reached();
return;
return -ENOMEM;
break;
default:
- assert_not_reached("Logic error in exec command deserialization");
+ assert_not_reached();
}
}
log_unit_error_errno(u, r, "Unable to deserialize current bus owner %s: %m", value);
} else if (streq(key, "status-text")) {
char *t;
+ ssize_t l;
- r = cunescape(value, 0, &t);
- if (r < 0)
- log_unit_debug_errno(u, r, "Failed to unescape status text '%s': %m", value);
+ l = cunescape(value, 0, &t);
+ if (l < 0)
+ log_unit_debug_errno(u, l, "Failed to unescape status text '%s': %m", value);
else
free_and_replace(s->status_text, t);
else if (code == CLD_DUMPED)
f = SERVICE_FAILURE_CORE_DUMP;
else
- assert_not_reached("Unknown code");
+ assert_not_reached();
if (s->main_pid == pid) {
/* Clean up the exec_fd event source. We want to do this here, not later in
break;
default:
- assert_not_reached("Uh, main process died at wrong time.");
+ assert_not_reached();
}
}
break;
default:
- assert_not_reached("Uh, control process died at wrong time.");
+ assert_not_reached();
}
}
} else /* Neither control nor main PID? If so, don't notify about anything */
break;
default:
- assert_not_reached("unknown timeout mode");
+ assert_not_reached();
}
break;
break;
default:
- assert_not_reached("unknown timeout mode");
+ assert_not_reached();
}
break;
break;
default:
- assert_not_reached("unknown timeout mode");
+ assert_not_reached();
}
break;
break;
case SERVICE_AUTO_RESTART:
- if (s->restart_usec > 0) {
- char buf_restart[FORMAT_TIMESPAN_MAX];
+ if (s->restart_usec > 0)
log_unit_debug(UNIT(s),
"Service RestartSec=%s expired, scheduling restart.",
- format_timespan(buf_restart, sizeof buf_restart, s->restart_usec, USEC_PER_SEC));
- } else
+ FORMAT_TIMESPAN(s->restart_usec, USEC_PER_SEC));
+ else
log_unit_debug(UNIT(s),
"Service has no hold-off time (RestartSec=0), scheduling restart.");
break;
default:
- assert_not_reached("Timeout at wrong time.");
+ assert_not_reached();
}
return 0;
static int service_dispatch_watchdog(sd_event_source *source, usec_t usec, void *userdata) {
Service *s = SERVICE(userdata);
- char t[FORMAT_TIMESPAN_MAX];
usec_t watchdog_usec;
assert(s);
if (UNIT(s)->manager->service_watchdogs) {
log_unit_error(UNIT(s), "Watchdog timeout (limit %s)!",
- format_timespan(t, sizeof(t), watchdog_usec, 1));
+ FORMAT_TIMESPAN(watchdog_usec, 1));
service_enter_signal(s, SERVICE_STOP_WATCHDOG, SERVICE_FAILURE_WATCHDOG);
} else
log_unit_warning(UNIT(s), "Watchdog disabled! Ignoring watchdog timeout (limit %s)!",
- format_timespan(t, sizeof(t), watchdog_usec, 1));
+ FORMAT_TIMESPAN(watchdog_usec, 1));
return 0;
}
return s->main_exec_status.status;
}
+static const char* service_status_text(Unit *u) {
+ Service *s = SERVICE(u);
+
+ assert(s);
+
+ return s->status_text;
+}
+
static int service_clean(Unit *u, ExecCleanMask mask) {
_cleanup_strv_free_ char **l = NULL;
Service *s = SERVICE(u);
}
static const char* const service_restart_table[_SERVICE_RESTART_MAX] = {
- [SERVICE_RESTART_NO] = "no",
- [SERVICE_RESTART_ON_SUCCESS] = "on-success",
- [SERVICE_RESTART_ON_FAILURE] = "on-failure",
+ [SERVICE_RESTART_NO] = "no",
+ [SERVICE_RESTART_ON_SUCCESS] = "on-success",
+ [SERVICE_RESTART_ON_FAILURE] = "on-failure",
[SERVICE_RESTART_ON_ABNORMAL] = "on-abnormal",
[SERVICE_RESTART_ON_WATCHDOG] = "on-watchdog",
- [SERVICE_RESTART_ON_ABORT] = "on-abort",
- [SERVICE_RESTART_ALWAYS] = "always",
+ [SERVICE_RESTART_ON_ABORT] = "on-abort",
+ [SERVICE_RESTART_ALWAYS] = "always",
};
DEFINE_STRING_TABLE_LOOKUP(service_restart, ServiceRestart);
static const char* const service_type_table[_SERVICE_TYPE_MAX] = {
- [SERVICE_SIMPLE] = "simple",
+ [SERVICE_SIMPLE] = "simple",
[SERVICE_FORKING] = "forking",
[SERVICE_ONESHOT] = "oneshot",
- [SERVICE_DBUS] = "dbus",
- [SERVICE_NOTIFY] = "notify",
- [SERVICE_IDLE] = "idle",
- [SERVICE_EXEC] = "exec",
+ [SERVICE_DBUS] = "dbus",
+ [SERVICE_NOTIFY] = "notify",
+ [SERVICE_IDLE] = "idle",
+ [SERVICE_EXEC] = "exec",
};
DEFINE_STRING_TABLE_LOOKUP(service_type, ServiceType);
static const char* const service_exec_command_table[_SERVICE_EXEC_COMMAND_MAX] = {
- [SERVICE_EXEC_CONDITION] = "ExecCondition",
- [SERVICE_EXEC_START_PRE] = "ExecStartPre",
- [SERVICE_EXEC_START] = "ExecStart",
+ [SERVICE_EXEC_CONDITION] = "ExecCondition",
+ [SERVICE_EXEC_START_PRE] = "ExecStartPre",
+ [SERVICE_EXEC_START] = "ExecStart",
[SERVICE_EXEC_START_POST] = "ExecStartPost",
- [SERVICE_EXEC_RELOAD] = "ExecReload",
- [SERVICE_EXEC_STOP] = "ExecStop",
- [SERVICE_EXEC_STOP_POST] = "ExecStopPost",
+ [SERVICE_EXEC_RELOAD] = "ExecReload",
+ [SERVICE_EXEC_STOP] = "ExecStop",
+ [SERVICE_EXEC_STOP_POST] = "ExecStopPost",
};
DEFINE_STRING_TABLE_LOOKUP(service_exec_command, ServiceExecCommand);
static const char* const service_exec_ex_command_table[_SERVICE_EXEC_COMMAND_MAX] = {
- [SERVICE_EXEC_CONDITION] = "ExecConditionEx",
- [SERVICE_EXEC_START_PRE] = "ExecStartPreEx",
- [SERVICE_EXEC_START] = "ExecStartEx",
+ [SERVICE_EXEC_CONDITION] = "ExecConditionEx",
+ [SERVICE_EXEC_START_PRE] = "ExecStartPreEx",
+ [SERVICE_EXEC_START] = "ExecStartEx",
[SERVICE_EXEC_START_POST] = "ExecStartPostEx",
- [SERVICE_EXEC_RELOAD] = "ExecReloadEx",
- [SERVICE_EXEC_STOP] = "ExecStopEx",
- [SERVICE_EXEC_STOP_POST] = "ExecStopPostEx",
+ [SERVICE_EXEC_RELOAD] = "ExecReloadEx",
+ [SERVICE_EXEC_STOP] = "ExecStopEx",
+ [SERVICE_EXEC_STOP_POST] = "ExecStopPostEx",
};
DEFINE_STRING_TABLE_LOOKUP(service_exec_ex_command, ServiceExecCommand);
static const char* const notify_state_table[_NOTIFY_STATE_MAX] = {
- [NOTIFY_UNKNOWN] = "unknown",
- [NOTIFY_READY] = "ready",
+ [NOTIFY_UNKNOWN] = "unknown",
+ [NOTIFY_READY] = "ready",
[NOTIFY_RELOADING] = "reloading",
- [NOTIFY_STOPPING] = "stopping",
+ [NOTIFY_STOPPING] = "stopping",
};
DEFINE_STRING_TABLE_LOOKUP(notify_state, NotifyState);
static const char* const service_result_table[_SERVICE_RESULT_MAX] = {
- [SERVICE_SUCCESS] = "success",
- [SERVICE_FAILURE_RESOURCES] = "resources",
- [SERVICE_FAILURE_PROTOCOL] = "protocol",
- [SERVICE_FAILURE_TIMEOUT] = "timeout",
- [SERVICE_FAILURE_EXIT_CODE] = "exit-code",
- [SERVICE_FAILURE_SIGNAL] = "signal",
- [SERVICE_FAILURE_CORE_DUMP] = "core-dump",
- [SERVICE_FAILURE_WATCHDOG] = "watchdog",
+ [SERVICE_SUCCESS] = "success",
+ [SERVICE_FAILURE_RESOURCES] = "resources",
+ [SERVICE_FAILURE_PROTOCOL] = "protocol",
+ [SERVICE_FAILURE_TIMEOUT] = "timeout",
+ [SERVICE_FAILURE_EXIT_CODE] = "exit-code",
+ [SERVICE_FAILURE_SIGNAL] = "signal",
+ [SERVICE_FAILURE_CORE_DUMP] = "core-dump",
+ [SERVICE_FAILURE_WATCHDOG] = "watchdog",
[SERVICE_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
- [SERVICE_FAILURE_OOM_KILL] = "oom-kill",
- [SERVICE_SKIP_CONDITION] = "exec-condition",
+ [SERVICE_FAILURE_OOM_KILL] = "oom-kill",
+ [SERVICE_SKIP_CONDITION] = "exec-condition",
};
DEFINE_STRING_TABLE_LOOKUP(service_result, ServiceResult);
static const char* const service_timeout_failure_mode_table[_SERVICE_TIMEOUT_FAILURE_MODE_MAX] = {
[SERVICE_TIMEOUT_TERMINATE] = "terminate",
- [SERVICE_TIMEOUT_ABORT] = "abort",
- [SERVICE_TIMEOUT_KILL] = "kill",
+ [SERVICE_TIMEOUT_ABORT] = "abort",
+ [SERVICE_TIMEOUT_KILL] = "kill",
};
DEFINE_STRING_TABLE_LOOKUP(service_timeout_failure_mode, ServiceTimeoutFailureMode);
.get_timeout = service_get_timeout,
.needs_console = service_needs_console,
.exit_status = service_exit_status,
+ .status_text = service_status_text,
.status_message_formats = {
.finished_start_job = {
else if (s->peer.sa.sa_family == AF_VSOCK)
siphash24_compress(&s->peer.vm.svm_cid, sizeof(s->peer.vm.svm_cid), state);
else
- assert_not_reached("Unknown address family.");
+ assert_not_reached();
}
static int peer_address_compare_func(const SocketPeer *x, const SocketPeer *y) {
case AF_VSOCK:
return CMP(x->peer.vm.svm_cid, y->peer.vm.svm_cid);
}
- assert_not_reached("Black sheep in the family!");
+ assert_not_reached();
}
DEFINE_PRIVATE_HASH_OPS(peer_address_hash_ops, SocketPeer, peer_address_hash_func, peer_address_compare_func);
else if (type == SOCK_SEQPACKET)
return "ListenSequentialPacket";
- assert_not_reached("Unknown socket type");
+ assert_not_reached();
return NULL;
}
static void socket_dump(Unit *u, FILE *f, const char *prefix) {
- char time_string[FORMAT_TIMESPAN_MAX];
- SocketExecCommand c;
Socket *s = SOCKET(u);
SocketPort *p;
const char *prefix2, *str;
if (s->keep_alive_time > 0)
fprintf(f,
"%sKeepAliveTimeSec: %s\n",
- prefix, format_timespan(time_string, FORMAT_TIMESPAN_MAX, s->keep_alive_time, USEC_PER_SEC));
+ prefix, FORMAT_TIMESPAN(s->keep_alive_time, USEC_PER_SEC));
if (s->keep_alive_interval > 0)
fprintf(f,
"%sKeepAliveIntervalSec: %s\n",
- prefix, format_timespan(time_string, FORMAT_TIMESPAN_MAX, s->keep_alive_interval, USEC_PER_SEC));
+ prefix, FORMAT_TIMESPAN(s->keep_alive_interval, USEC_PER_SEC));
if (s->keep_alive_cnt > 0)
fprintf(f,
if (s->defer_accept > 0)
fprintf(f,
"%sDeferAcceptSec: %s\n",
- prefix, format_timespan(time_string, FORMAT_TIMESPAN_MAX, s->defer_accept, USEC_PER_SEC));
+ prefix, FORMAT_TIMESPAN(s->defer_accept, USEC_PER_SEC));
LIST_FOREACH(port, p, s->ports) {
fprintf(f,
"%sTriggerLimitIntervalSec: %s\n"
"%sTriggerLimitBurst: %u\n",
- prefix, format_timespan(time_string, FORMAT_TIMESPAN_MAX, s->trigger_limit.interval, USEC_PER_SEC),
+ prefix, FORMAT_TIMESPAN(s->trigger_limit.interval, USEC_PER_SEC),
prefix, s->trigger_limit.burst);
str = ip_protocol_to_name(s->socket_protocol);
fprintf(f,
"%sTimeoutSec: %s\n",
- prefix, format_timespan(time_string, FORMAT_TIMESPAN_MAX, s->timeout_usec, USEC_PER_SEC));
+ prefix, FORMAT_TIMESPAN(s->timeout_usec, USEC_PER_SEC));
exec_context_dump(&s->exec_context, f, prefix);
kill_context_dump(&s->kill_context, f, prefix);
- for (c = 0; c < _SOCKET_EXEC_COMMAND_MAX; c++) {
+ for (SocketExecCommand c = 0; c < _SOCKET_EXEC_COMMAND_MAX; c++) {
if (!s->exec_command[c])
continue;
break;
default:
- assert_not_reached("Unhandled socket type.");
+ assert_not_reached();
}
*instance = r;
break;
}
default:
- assert_not_reached("Unknown port type");
+ assert_not_reached();
}
}
else if (code == CLD_DUMPED)
f = SOCKET_FAILURE_CORE_DUMP;
else
- assert_not_reached("Unknown sigchld code");
+ assert_not_reached();
if (s->control_command) {
exec_status_exit(&s->control_command->exec_status, &s->exec_context, pid, code, status);
break;
default:
- assert_not_reached("Uh, control process died at wrong time.");
+ assert_not_reached();
}
}
break;
default:
- assert_not_reached("Timeout at wrong time.");
+ assert_not_reached();
}
return 0;
return -ENOMEM;
LIST_FOREACH(port, p, s->ports) {
- size_t i;
-
if (p->fd >= 0)
rfds[k++] = p->fd;
- for (i = 0; i < p->n_auxiliary_fds; ++i)
+ for (size_t i = 0; i < p->n_auxiliary_fds; ++i)
rfds[k++] = p->auxiliary_fds[i];
}
}
static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = {
- [SOCKET_EXEC_START_PRE] = "ExecStartPre",
+ [SOCKET_EXEC_START_PRE] = "ExecStartPre",
[SOCKET_EXEC_START_CHOWN] = "ExecStartChown",
- [SOCKET_EXEC_START_POST] = "ExecStartPost",
- [SOCKET_EXEC_STOP_PRE] = "ExecStopPre",
- [SOCKET_EXEC_STOP_POST] = "ExecStopPost"
+ [SOCKET_EXEC_START_POST] = "ExecStartPost",
+ [SOCKET_EXEC_STOP_PRE] = "ExecStopPre",
+ [SOCKET_EXEC_STOP_POST] = "ExecStopPost"
};
DEFINE_STRING_TABLE_LOOKUP(socket_exec_command, SocketExecCommand);
static const char* const socket_result_table[_SOCKET_RESULT_MAX] = {
- [SOCKET_SUCCESS] = "success",
- [SOCKET_FAILURE_RESOURCES] = "resources",
- [SOCKET_FAILURE_TIMEOUT] = "timeout",
- [SOCKET_FAILURE_EXIT_CODE] = "exit-code",
- [SOCKET_FAILURE_SIGNAL] = "signal",
- [SOCKET_FAILURE_CORE_DUMP] = "core-dump",
- [SOCKET_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
- [SOCKET_FAILURE_TRIGGER_LIMIT_HIT] = "trigger-limit-hit",
+ [SOCKET_SUCCESS] = "success",
+ [SOCKET_FAILURE_RESOURCES] = "resources",
+ [SOCKET_FAILURE_TIMEOUT] = "timeout",
+ [SOCKET_FAILURE_EXIT_CODE] = "exit-code",
+ [SOCKET_FAILURE_SIGNAL] = "signal",
+ [SOCKET_FAILURE_CORE_DUMP] = "core-dump",
+ [SOCKET_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
+ [SOCKET_FAILURE_TRIGGER_LIMIT_HIT] = "trigger-limit-hit",
[SOCKET_FAILURE_SERVICE_START_LIMIT_HIT] = "service-start-limit-hit"
};
static const char* const socket_timestamping_table[_SOCKET_TIMESTAMPING_MAX] = {
[SOCKET_TIMESTAMPING_OFF] = "off",
- [SOCKET_TIMESTAMPING_US] = "us",
- [SOCKET_TIMESTAMPING_NS] = "ns",
+ [SOCKET_TIMESTAMPING_US] = "us",
+ [SOCKET_TIMESTAMPING_NS] = "ns",
};
DEFINE_STRING_TABLE_LOOKUP(socket_timestamping, SocketTimestamping);
}
static void swap_dump(Unit *u, FILE *f, const char *prefix) {
- char buf[FORMAT_TIMESPAN_MAX];
Swap *s = SWAP(u);
SwapParameters *p;
fprintf(f,
"%sTimeoutSec: %s\n",
- prefix, format_timespan(buf, sizeof(buf), s->timeout_usec, USEC_PER_SEC));
+ prefix, FORMAT_TIMESPAN(s->timeout_usec, USEC_PER_SEC));
if (s->control_pid > 0)
fprintf(f,
return 0;
default:
- assert_not_reached("Unexpected state.");
+ assert_not_reached();
}
}
else if (code == CLD_DUMPED)
f = SWAP_FAILURE_CORE_DUMP;
else
- assert_not_reached("Unknown code");
+ assert_not_reached();
if (s->result == SWAP_SUCCESS)
s->result = f;
break;
default:
- assert_not_reached("Uh, control process died at wrong time.");
+ assert_not_reached();
}
/* Notify clients about changed exit status */
break;
default:
- assert_not_reached("Timeout at wrong time.");
+ assert_not_reached();
}
return 0;
continue;
}
- if (cunescape(dev, UNESCAPE_RELAX, &d) < 0)
- return log_oom();
+ ssize_t l = cunescape(dev, UNESCAPE_RELAX, &d);
+ if (l < 0)
+ return log_error_errno(l, "Failed to unescape device path: %m");
device_found_node(m, d, DEVICE_FOUND_SWAP, DEVICE_FOUND_SWAP);
}
static const char* const swap_exec_command_table[_SWAP_EXEC_COMMAND_MAX] = {
- [SWAP_EXEC_ACTIVATE] = "ExecActivate",
+ [SWAP_EXEC_ACTIVATE] = "ExecActivate",
[SWAP_EXEC_DEACTIVATE] = "ExecDeactivate",
};
DEFINE_STRING_TABLE_LOOKUP(swap_exec_command, SwapExecCommand);
static const char* const swap_result_table[_SWAP_RESULT_MAX] = {
- [SWAP_SUCCESS] = "success",
- [SWAP_FAILURE_RESOURCES] = "resources",
- [SWAP_FAILURE_TIMEOUT] = "timeout",
- [SWAP_FAILURE_EXIT_CODE] = "exit-code",
- [SWAP_FAILURE_SIGNAL] = "signal",
- [SWAP_FAILURE_CORE_DUMP] = "core-dump",
+ [SWAP_SUCCESS] = "success",
+ [SWAP_FAILURE_RESOURCES] = "resources",
+ [SWAP_FAILURE_TIMEOUT] = "timeout",
+ [SWAP_FAILURE_EXIT_CODE] = "exit-code",
+ [SWAP_FAILURE_SIGNAL] = "signal",
+ [SWAP_FAILURE_CORE_DUMP] = "core-dump",
[SWAP_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
};
}
static void timer_dump(Unit *u, FILE *f, const char *prefix) {
- char buf[FORMAT_TIMESPAN_MAX];
Timer *t = TIMER(u);
Unit *trigger;
TimerValue *v;
prefix, trigger ? trigger->id : "n/a",
prefix, yes_no(t->persistent),
prefix, yes_no(t->wake_system),
- prefix, format_timespan(buf, sizeof(buf), t->accuracy_usec, 1),
+ prefix, FORMAT_TIMESPAN(t->accuracy_usec, 1),
prefix, yes_no(t->remain_after_elapse),
prefix, yes_no(t->fixed_random_delay),
prefix, yes_no(t->on_clock_change),
prefix,
timer_base_to_string(v->base),
strna(p));
- } else {
- char timespan1[FORMAT_TIMESPAN_MAX];
-
+ } else
fprintf(f,
"%s%s: %s\n",
prefix,
timer_base_to_string(v->base),
- format_timespan(timespan1, sizeof(timespan1), v->value, 0));
- }
+ FORMAT_TIMESPAN(v->value, 0));
}
static void timer_set_state(Timer *t, TimerState state) {
}
static void add_random(Timer *t, usec_t *v) {
- char s[FORMAT_TIMESPAN_MAX];
usec_t add;
assert(t);
else
*v += add;
- log_unit_debug(UNIT(t), "Adding %s random time.", format_timespan(s, sizeof(s), add, 0));
+ log_unit_debug(UNIT(t), "Adding %s random time.", FORMAT_TIMESPAN(add, 0));
}
static void timer_enter_waiting(Timer *t, bool time_change) {
break;
default:
- assert_not_reached("Unknown timer base");
+ assert_not_reached();
}
v->next_elapse = usec_add(usec_shift_clock(base, CLOCK_MONOTONIC, TIMER_MONOTONIC_CLOCK(t)), v->value);
}
if (found_monotonic) {
- char buf[FORMAT_TIMESPAN_MAX];
usec_t left;
add_random(t, &t->next_elapse_monotonic_or_boottime);
left = usec_sub_unsigned(t->next_elapse_monotonic_or_boottime, triple_timestamp_by_clock(&ts, TIMER_MONOTONIC_CLOCK(t)));
- log_unit_debug(UNIT(t), "Monotonic timer elapses in %s.", format_timespan(buf, sizeof(buf), left, 0));
+ log_unit_debug(UNIT(t), "Monotonic timer elapses in %s.", FORMAT_TIMESPAN(left, 0));
if (t->monotonic_event_source) {
r = sd_event_source_set_time(t->monotonic_event_source, t->next_elapse_monotonic_or_boottime);
}
if (found_realtime) {
- char buf[FORMAT_TIMESTAMP_MAX];
-
add_random(t, &t->next_elapse_realtime);
- log_unit_debug(UNIT(t), "Realtime timer elapses at %s.", format_timestamp(buf, sizeof(buf), t->next_elapse_realtime));
+ log_unit_debug(UNIT(t), "Realtime timer elapses at %s.", FORMAT_TIMESTAMP(t->next_elapse_realtime));
if (t->realtime_event_source) {
r = sd_event_source_set_time(t->realtime_event_source, t->next_elapse_realtime);
ft = timespec_load(&st.st_mtim);
if (ft < now(CLOCK_REALTIME))
t->last_trigger.realtime = ft;
- else {
- char z[FORMAT_TIMESTAMP_MAX];
-
+ else
log_unit_warning(u, "Not using persistent file timestamp %s as it is in the future.",
- format_timestamp(z, sizeof(z), ft));
- }
+ FORMAT_TIMESTAMP(ft));
} else if (errno == ENOENT)
/* The timer has never run before, make sure a stamp file exists. */
break;
default:
- assert_not_reached("Unknown timer state");
+ assert_not_reached();
}
}
}
static const char* const timer_base_table[_TIMER_BASE_MAX] = {
- [TIMER_ACTIVE] = "OnActiveSec",
- [TIMER_BOOT] = "OnBootSec",
- [TIMER_STARTUP] = "OnStartupSec",
- [TIMER_UNIT_ACTIVE] = "OnUnitActiveSec",
+ [TIMER_ACTIVE] = "OnActiveSec",
+ [TIMER_BOOT] = "OnBootSec",
+ [TIMER_STARTUP] = "OnStartupSec",
+ [TIMER_UNIT_ACTIVE] = "OnUnitActiveSec",
[TIMER_UNIT_INACTIVE] = "OnUnitInactiveSec",
- [TIMER_CALENDAR] = "OnCalendar"
+ [TIMER_CALENDAR] = "OnCalendar"
};
DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase);
static const char* const timer_result_table[_TIMER_RESULT_MAX] = {
- [TIMER_SUCCESS] = "success",
- [TIMER_FAILURE_RESOURCES] = "resources",
+ [TIMER_SUCCESS] = "success",
+ [TIMER_FAILURE_RESOURCES] = "resources",
[TIMER_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
};
void unit_dump(Unit *u, FILE *f, const char *prefix) {
char *t, **j;
const char *prefix2;
- char timestamp[5][FORMAT_TIMESTAMP_MAX], timespan[FORMAT_TIMESPAN_MAX];
Unit *following;
_cleanup_set_free_ Set *following_set = NULL;
CGroupMask m;
prefix, strna(u->instance),
prefix, unit_load_state_to_string(u->load_state),
prefix, unit_active_state_to_string(unit_active_state(u)),
- prefix, strna(format_timestamp(timestamp[0], sizeof(timestamp[0]), u->state_change_timestamp.realtime)),
- prefix, strna(format_timestamp(timestamp[1], sizeof(timestamp[1]), u->inactive_exit_timestamp.realtime)),
- prefix, strna(format_timestamp(timestamp[2], sizeof(timestamp[2]), u->active_enter_timestamp.realtime)),
- prefix, strna(format_timestamp(timestamp[3], sizeof(timestamp[3]), u->active_exit_timestamp.realtime)),
- prefix, strna(format_timestamp(timestamp[4], sizeof(timestamp[4]), u->inactive_enter_timestamp.realtime)),
+ prefix, strna(FORMAT_TIMESTAMP(u->state_change_timestamp.realtime)),
+ prefix, strna(FORMAT_TIMESTAMP(u->inactive_exit_timestamp.realtime)),
+ prefix, strna(FORMAT_TIMESTAMP(u->active_enter_timestamp.realtime)),
+ prefix, strna(FORMAT_TIMESTAMP(u->active_exit_timestamp.realtime)),
+ prefix, strna(FORMAT_TIMESTAMP(u->inactive_enter_timestamp.realtime)),
prefix, yes_no(unit_may_gc(u)),
prefix, yes_no(unit_need_daemon_reload(u)),
prefix, yes_no(u->transient),
fprintf(f, "%s\tSuccess Action Exit Status: %i\n", prefix, u->success_action_exit_status);
if (u->job_timeout != USEC_INFINITY)
- fprintf(f, "%s\tJob Timeout: %s\n", prefix, format_timespan(timespan, sizeof(timespan), u->job_timeout, 0));
+ fprintf(f, "%s\tJob Timeout: %s\n", prefix, FORMAT_TIMESPAN(u->job_timeout, 0));
if (u->job_timeout_action != EMERGENCY_ACTION_NONE)
fprintf(f, "%s\tJob Timeout Action: %s\n", prefix, emergency_action_to_string(u->job_timeout_action));
fprintf(f,
"%s\tCondition Timestamp: %s\n"
"%s\tCondition Result: %s\n",
- prefix, strna(format_timestamp(timestamp[0], sizeof(timestamp[0]), u->condition_timestamp.realtime)),
+ prefix, strna(FORMAT_TIMESTAMP(u->condition_timestamp.realtime)),
prefix, yes_no(u->condition_result));
if (dual_timestamp_is_set(&u->assert_timestamp))
fprintf(f,
"%s\tAssert Timestamp: %s\n"
"%s\tAssert Result: %s\n",
- prefix, strna(format_timestamp(timestamp[0], sizeof(timestamp[0]), u->assert_timestamp.realtime)),
+ prefix, strna(FORMAT_TIMESTAMP(u->assert_timestamp.realtime)),
prefix, yes_no(u->assert_result));
for (UnitDependency d = 0; d < _UNIT_DEPENDENCY_MAX; d++) {
break;
default:
- assert_not_reached("Unknown garbage collection mode");
+ assert_not_reached();
}
if (u->cgroup_path) {
(void) unit_get_cpu_usage(u, &nsec);
if (nsec != NSEC_INFINITY) {
- char buf[FORMAT_TIMESPAN_MAX] = "";
-
/* Format the CPU time for inclusion in the structured log message */
if (asprintf(&t, "CPU_USAGE_NSEC=%" PRIu64, nsec) < 0) {
r = log_oom();
iovec[n_iovec++] = IOVEC_MAKE_STRING(t);
/* Format the CPU time for inclusion in the human language message string */
- format_timespan(buf, sizeof(buf), nsec / NSEC_PER_USEC, USEC_PER_MSEC);
- t = strjoin("consumed ", buf, " CPU time");
+ t = strjoin("consumed ", FORMAT_TIMESPAN(nsec / NSEC_PER_USEC, USEC_PER_MSEC), " CPU time");
if (!t) {
r = log_oom();
goto finish;
}
for (CGroupIOAccountingMetric k = 0; k < _CGROUP_IO_ACCOUNTING_METRIC_MAX; k++) {
- char buf[FORMAT_BYTES_MAX] = "";
uint64_t value = UINT64_MAX;
assert(io_fields[k]);
* for the bytes counters (and not for the operations counters) */
if (k == CGROUP_IO_READ_BYTES) {
assert(!rr);
- rr = strjoin("read ", format_bytes(buf, sizeof(buf), value), " from disk");
+ rr = strjoin("read ", strna(FORMAT_BYTES(value)), " from disk");
if (!rr) {
r = log_oom();
goto finish;
}
} else if (k == CGROUP_IO_WRITE_BYTES) {
assert(!wr);
- wr = strjoin("written ", format_bytes(buf, sizeof(buf), value), " to disk");
+ wr = strjoin("written ", strna(FORMAT_BYTES(value)), " to disk");
if (!wr) {
r = log_oom();
goto finish;
}
for (CGroupIPAccountingMetric m = 0; m < _CGROUP_IP_ACCOUNTING_METRIC_MAX; m++) {
- char buf[FORMAT_BYTES_MAX] = "";
uint64_t value = UINT64_MAX;
assert(ip_fields[m]);
* bytes counters (and not for the packets counters) */
if (m == CGROUP_IP_INGRESS_BYTES) {
assert(!igress);
- igress = strjoin("received ", format_bytes(buf, sizeof(buf), value), " IP traffic");
+ igress = strjoin("received ", strna(FORMAT_BYTES(value)), " IP traffic");
if (!igress) {
r = log_oom();
goto finish;
}
} else if (m == CGROUP_IP_EGRESS_BYTES) {
assert(!egress);
- egress = strjoin("sent ", format_bytes(buf, sizeof(buf), value), " IP traffic");
+ egress = strjoin("sent ", strna(FORMAT_BYTES(value)), " IP traffic");
if (!egress) {
r = log_oom();
goto finish;
break;
default:
- assert_not_reached("Job type unknown");
+ assert_not_reached();
}
return unexpected;
return unit_can_reload(u) && unit_can_start(u);
default:
- assert_not_reached("Invalid job type");
+ assert_not_reached();
}
}
return c->watchdog_signal;
default:
- assert_not_reached("KillOperation unknown");
+ assert_not_reached();
}
}
* exit code of the "main" process of the service or similar. */
int (*exit_status)(Unit *u);
+ /* Return a copy of the status string pointer. */
+ const char* (*status_text)(Unit *u);
+
/* Like the enumerate() callback further down, but only enumerates the perpetual units, i.e. all units that
* unconditionally exist and are always active. The main reason to keep both enumeration functions separate is
* philosophical: the state of perpetual units should be put in place by coldplug(), while the state of those
(UNIT_VTABLE(u)->is_extrinsic && UNIT_VTABLE(u)->is_extrinsic(u));
}
+static inline const char* unit_status_text(Unit *u) {
+ if (u && UNIT_VTABLE(u)->status_text)
+ return UNIT_VTABLE(u)->status_text(u);
+ return NULL;
+}
+
void unit_add_to_load_queue(Unit *u);
void unit_add_to_dbus_queue(Unit *u);
void unit_add_to_cleanup_queue(Unit *u);
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
if (arg_since != USEC_INFINITY && arg_until != USEC_INFINITY &&
usec_t u;
r = safe_atou64(timestamp, &u);
- if (r >= 0) {
- char absolute[FORMAT_TIMESTAMP_MAX], relative[FORMAT_TIMESPAN_MAX];
+ if (r >= 0)
+ fprintf(file, " Timestamp: %s (%s)\n",
+ FORMAT_TIMESTAMP(u), FORMAT_TIMESTAMP_RELATIVE(u));
- fprintf(file,
- " Timestamp: %s (%s)\n",
- format_timestamp(absolute, sizeof(absolute), u),
- format_timestamp_relative(relative, sizeof(relative), u));
-
- } else
+ else
fprintf(file, " Timestamp: %s\n", timestamp);
}
if (filename) {
const char *state = NULL, *color = NULL;
uint64_t size = UINT64_MAX;
- char buf[FORMAT_BYTES_MAX];
analyze_coredump_file(filename, &state, &color, &size);
ansi_normal());
if (size != UINT64_MAX)
- fprintf(file,
- " Disk Size: %s\n",
- format_bytes(buf, sizeof(buf), size));
+ fprintf(file, " Disk Size: %s\n", FORMAT_BYTES(size));
+
} else if (coredump)
fprintf(file, " Storage: journal\n");
else
program_header->p_offset,
program_header->p_filesz,
ELF_T_NHDR);
+ if (!data)
+ continue;
while (note_offset < data->d_size &&
(note_offset = gelf_getnote(data, note_offset, ¬e_header, &name_offset, &desc_offset)) > 0) {
switch (arg_transcode) {
case TRANSCODE_BASE64: {
- char *buf = NULL;
+ char *buf;
ssize_t l;
l = base64mem_full(input, input_size, 79, &buf);
return r;
default:
- assert_not_reached("Unexpected transcoding mode");
+ assert_not_reached();
}
}
assert(argc == 3);
- input_path = (isempty(argv[1]) || streq(argv[1], "-")) ? NULL : argv[1];
+ input_path = empty_or_dash(argv[1]) ? NULL : argv[1];
if (input_path)
r = read_full_file_full(AT_FDCWD, input_path, UINT64_MAX, CREDENTIAL_SIZE_MAX, READ_FULL_FILE_SECURE|READ_FULL_FILE_FAIL_WHEN_LARGER, NULL, &plaintext, &plaintext_size);
if (r < 0)
return log_error_errno(r, "Failed to read plaintext: %m");
- output_path = (isempty(argv[2]) || streq(argv[2], "-")) ? NULL : argv[2];
+ output_path = empty_or_dash(argv[2]) ? NULL : argv[2];
if (arg_name_any)
name = NULL;
assert(IN_SET(argc, 2, 3));
- input_path = (isempty(argv[1]) || streq(argv[1], "-")) ? NULL : argv[1];
+ input_path = empty_or_dash(argv[1]) ? NULL : argv[1];
if (input_path)
r = read_full_file_full(AT_FDCWD, argv[1], UINT64_MAX, CREDENTIAL_ENCRYPTED_SIZE_MAX, READ_FULL_FILE_UNBASE64|READ_FULL_FILE_FAIL_WHEN_LARGER, NULL, &input, &input_size);
arg_with_key = CRED_AES256_GCM_BY_TPM2_HMAC;
break;
- case ARG_TPM2_DEVICE: {
- _cleanup_free_ char *device = NULL;
-
+ case ARG_TPM2_DEVICE:
if (streq(optarg, "list"))
return tpm2_list_devices();
- if (!streq(optarg, "auto")) {
- device = strdup(optarg);
- if (!device)
- return log_oom();
- }
-
- arg_tpm2_device = TAKE_PTR(device);
+ arg_tpm2_device = streq(optarg, "auto") ? NULL : optarg;
break;
- }
-
- case ARG_TPM2_PCRS: {
- uint32_t mask;
+ case ARG_TPM2_PCRS:
if (isempty(optarg)) {
arg_tpm2_pcr_mask = 0;
break;
}
+ uint32_t mask;
r = tpm2_parse_pcrs(optarg, &mask);
if (r < 0)
return r;
arg_tpm2_pcr_mask |= mask;
break;
- }
case ARG_NAME:
if (isempty(optarg)) {
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
}
_cleanup_(erase_and_freep) char *base64_encoded = NULL;
size_t secret_size, secret2_size, blob_size, hash_size;
_cleanup_free_ void *blob = NULL, *hash = NULL;
+ uint16_t pcr_bank;
const char *node;
int r, keyslot;
assert_se(node = crypt_get_device_name(cd));
- r = tpm2_seal(device, pcr_mask, &secret, &secret_size, &blob, &blob_size, &hash, &hash_size);
+ r = tpm2_seal(device, pcr_mask, &secret, &secret_size, &blob, &blob_size, &hash, &hash_size, &pcr_bank);
if (r < 0)
return r;
/* Quick verification that everything is in order, we are not in a hurry after all. */
log_debug("Unsealing for verification...");
- r = tpm2_unseal(device, pcr_mask, blob, blob_size, hash, hash_size, &secret2, &secret2_size);
+ r = tpm2_unseal(device, pcr_mask, pcr_bank, blob, blob_size, hash, hash_size, &secret2, &secret2_size);
if (r < 0)
return r;
if (keyslot < 0)
return log_error_errno(keyslot, "Failed to add new TPM2 key to %s: %m", node);
- r = tpm2_make_luks2_json(keyslot, pcr_mask, blob, blob_size, hash, hash_size, &v);
+ r = tpm2_make_luks2_json(keyslot, pcr_mask, pcr_bank, blob, blob_size, hash, hash_size, &v);
if (r < 0)
return log_error_errno(r, "Failed to prepare TPM2 JSON token object: %m");
break;
default:
- assert_not_reached("Unexpected wipe scope");
+ assert_not_reached();
}
/* Then add all slots that match a token type */
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
}
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <errno.h>
+#include <libcryptsetup.h>
+
+#include "cryptsetup-token.h"
+#include "cryptsetup-token-util.h"
+#include "hexdecoct.h"
+#include "luks2-tpm2.h"
+#include "memory-util.h"
+#include "tpm2-util.h"
+#include "version.h"
+
+#define TOKEN_NAME "systemd-tpm2"
+#define TOKEN_VERSION_MAJOR "1"
+#define TOKEN_VERSION_MINOR "0"
+
+/* for libcryptsetup debug purpose */
+_public_ const char *cryptsetup_token_version(void) {
+
+ return TOKEN_VERSION_MAJOR "." TOKEN_VERSION_MINOR " systemd-v" STRINGIFY(PROJECT_VERSION) " (" GIT_VERSION ")";
+}
+
+static int log_debug_open_error(struct crypt_device *cd, int r) {
+ if (r == -EAGAIN) {
+ crypt_log_debug(cd, "TPM2 device not found.");
+ return r;
+ } else if (r == -ENXIO) {
+ crypt_log_debug(cd, "No matching TPM2 token data found.");
+ return r;
+ }
+
+ return crypt_log_debug_errno(cd, r, TOKEN_NAME " open failed: %m.");
+}
+
+/*
+ * This function is called from within following libcryptsetup calls
+ * provided conditions further below are met:
+ *
+ * crypt_activate_by_token(), crypt_activate_by_token_type(type == 'systemd-tpm2'):
+ *
+ * - token is assigned to at least one luks2 keyslot eligible to activate LUKS2 device
+ * (alternatively: name is set to null, flags contains CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY
+ * and token is assigned to at least single keyslot).
+ *
+ * - if plugin defines validate funtion (see cryptsetup_token_validate below) it must have
+ * passed the check (aka return 0)
+ */
+_public_ int cryptsetup_token_open(
+ struct crypt_device *cd, /* is always LUKS2 context */
+ int token /* is always >= 0 */,
+ char **password, /* freed by cryptsetup_token_buffer_free */
+ size_t *password_len,
+ void *usrptr /* plugin defined parameter passed to crypt_activate_by_token*() API */) {
+
+ int r;
+ const char *json;
+ size_t blob_size, policy_hash_size, decrypted_key_size;
+ uint32_t pcr_mask;
+ uint16_t pcr_bank;
+ systemd_tpm2_plugin_params params = {
+ .search_pcr_mask = UINT32_MAX
+ };
+ _cleanup_free_ void *blob = NULL, *policy_hash = NULL;
+ _cleanup_free_ char *base64_blob = NULL, *hex_policy_hash = NULL;
+ _cleanup_(erase_and_freep) void *decrypted_key = NULL;
+ _cleanup_(erase_and_freep) char *base64_encoded = NULL;
+
+ assert(password);
+ assert(password_len);
+ assert(token >= 0);
+
+ /* This must not fail at this moment (internal error) */
+ r = crypt_token_json_get(cd, token, &json);
+ assert(token == r);
+ assert(json);
+
+ if (usrptr)
+ params = *(systemd_tpm2_plugin_params *)usrptr;
+
+ r = parse_luks2_tpm2_data(json, params.search_pcr_mask, &pcr_mask, &pcr_bank, &base64_blob, &hex_policy_hash);
+ if (r < 0)
+ return log_debug_open_error(cd, r);
+
+ /* should not happen since cryptsetup_token_validate have passed */
+ r = unbase64mem(base64_blob, SIZE_MAX, &blob, &blob_size);
+ if (r < 0)
+ return log_debug_open_error(cd, r);
+
+ /* should not happen since cryptsetup_token_validate have passed */
+ r = unhexmem(hex_policy_hash, SIZE_MAX, &policy_hash, &policy_hash_size);
+ if (r < 0)
+ return log_debug_open_error(cd, r);
+
+ r = acquire_luks2_key(
+ pcr_mask,
+ pcr_bank,
+ params.device,
+ blob,
+ blob_size,
+ policy_hash,
+ policy_hash_size,
+ &decrypted_key,
+ &decrypted_key_size);
+ if (r < 0)
+ return log_debug_open_error(cd, r);
+
+ /* Before using this key as passphrase we base64 encode it, for compat with homed */
+ r = base64mem(decrypted_key, decrypted_key_size, &base64_encoded);
+ if (r < 0)
+ return log_debug_open_error(cd, r);
+
+ /* free'd automaticaly by libcryptsetup */
+ *password_len = strlen(base64_encoded);
+ *password = TAKE_PTR(base64_encoded);
+
+ return 0;
+}
+
+/*
+ * libcryptsetup callback for memory deallocation of 'password' parameter passed in
+ * any crypt_token_open_* plugin function
+ */
+_public_ void cryptsetup_token_buffer_free(void *buffer, size_t buffer_len) {
+ erase_and_free(buffer);
+}
+
+/*
+ * prints systemd-tpm2 token content in crypt_dump().
+ * 'type' and 'keyslots' fields are printed by libcryptsetup
+ */
+_public_ void cryptsetup_token_dump(
+ struct crypt_device *cd /* is always LUKS2 context */,
+ const char *json /* validated 'systemd-tpm2' token if cryptsetup_token_validate is defined */) {
+
+ int r;
+ uint32_t i, pcr_mask;
+ uint16_t pcr_bank;
+ size_t decoded_blob_size;
+ _cleanup_free_ char *base64_blob = NULL, *hex_policy_hash = NULL,
+ *pcrs_str = NULL, *blob_str = NULL, *policy_hash_str = NULL;
+ _cleanup_free_ void *decoded_blob = NULL;
+
+ assert(json);
+
+ r = parse_luks2_tpm2_data(json, UINT32_MAX, &pcr_mask, &pcr_bank, &base64_blob, &hex_policy_hash);
+ if (r < 0)
+ return (void) crypt_log_debug_errno(cd, r, "Failed to parse " TOKEN_NAME " metadata: %m.");
+
+ for (i = 0; i < TPM2_PCRS_MAX; i++) {
+ if ((pcr_mask & (UINT32_C(1) << i)) &&
+ ((r = strextendf_with_separator(&pcrs_str, ", ", "%" PRIu32, i)) < 0))
+ return (void) crypt_log_debug_errno(cd, r, "Can not dump " TOKEN_NAME " content: %m");
+ }
+
+ r = unbase64mem(base64_blob, SIZE_MAX, &decoded_blob, &decoded_blob_size);
+ if (r < 0)
+ return (void) crypt_log_debug_errno(cd, r, "Can not dump " TOKEN_NAME " content: %m");
+
+ r = crypt_dump_buffer_to_hex_string(decoded_blob, decoded_blob_size, &blob_str);
+ if (r < 0)
+ return (void) crypt_log_debug_errno(cd, r, "Can not dump " TOKEN_NAME " content: %m");
+
+ r = crypt_dump_hex_string(hex_policy_hash, &policy_hash_str);
+ if (r < 0)
+ return (void) crypt_log_debug_errno(cd, r, "Can not dump " TOKEN_NAME " content: %m");
+
+ crypt_log(cd, "\ttpm2-pcrs: %s\n", strna(pcrs_str));
+ crypt_log(cd, "\ttpm2-bank: %s\n", strna(tpm2_pcr_bank_to_string(pcr_bank)));
+ crypt_log(cd, "\ttmp2-blob: %s\n", blob_str);
+ crypt_log(cd, "\ttmp2-policy-hash:" CRYPT_DUMP_LINE_SEP "%s\n", policy_hash_str);
+}
+
+/*
+ * Note:
+ * If plugin is available in library path, it's called in before following libcryptsetup calls:
+ *
+ * crypt_token_json_set, crypt_dump, any crypt_activate_by_token_* flavour
+ */
+_public_ int cryptsetup_token_validate(
+ struct crypt_device *cd, /* is always LUKS2 context */
+ const char *json /* contains valid 'type' and 'keyslots' fields. 'type' is 'systemd-tpm2' */) {
+
+ int r;
+ JsonVariant *w, *e;
+ _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
+
+ assert(json);
+
+ r = json_parse(json, 0, &v, NULL, NULL);
+ if (r < 0)
+ return crypt_log_debug_errno(cd, r, "Could not parse " TOKEN_NAME " json object: %m");
+
+ w = json_variant_by_key(v, "tpm2-pcrs");
+ if (!w || !json_variant_is_array(w)) {
+ crypt_log_debug(cd, "TPM2 token data lacks 'tpm2-pcrs' field.");
+ return 1;
+ }
+
+ JSON_VARIANT_ARRAY_FOREACH(e, w) {
+ uintmax_t u;
+
+ if (!json_variant_is_number(e)) {
+ crypt_log_debug(cd, "TPM2 PCR is not a number.");
+ return 1;
+ }
+
+ u = json_variant_unsigned(e);
+ if (u >= TPM2_PCRS_MAX) {
+ crypt_log_debug(cd, "TPM2 PCR number out of range.");
+ return 1;
+ }
+ }
+
+ w = json_variant_by_key(v, "tpm2-blob");
+ if (!w || !json_variant_is_string(w)) {
+ crypt_log_debug(cd, "TPM2 token data lacks 'tpm2-blob' field.");
+ return 1;
+ }
+
+ r = unbase64mem(json_variant_string(w), SIZE_MAX, NULL, NULL);
+ if (r < 0)
+ return crypt_log_debug_errno(cd, r, "Invalid base64 data in 'tpm2-blob' field: %m");
+
+ w = json_variant_by_key(v, "tpm2-policy-hash");
+ if (!w || !json_variant_is_string(w)) {
+ crypt_log_debug(cd, "TPM2 token data lacks 'tpm2-policy-hash' field.");
+ return 1;
+ }
+
+ r = unhexmem(json_variant_string(w), SIZE_MAX, NULL, NULL);
+ if (r < 0)
+ return crypt_log_debug_errno(cd, r, "Invalid base64 data in 'tpm2-policy-hash' field: %m");
+
+ return 0;
+}
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "cryptsetup-token-util.h"
+#include "string-util.h"
+
+int crypt_dump_buffer_to_hex_string(
+ const char *buf,
+ size_t buf_size,
+ char **ret_dump_str) {
+
+ int r;
+ _cleanup_free_ char *dump_str = NULL;
+
+ assert(buf || !buf_size);
+ assert(ret_dump_str);
+
+ for (size_t i = 0; i < buf_size; i++) {
+ /* crypt_dump() breaks line after every
+ * 16th couple of chars in dumped hexstring */
+ r = strextendf_with_separator(
+ &dump_str,
+ (i && !(i % 16)) ? CRYPT_DUMP_LINE_SEP : " ",
+ "%02hhx", buf[i]);
+ if (r < 0)
+ return r;
+ }
+
+ *ret_dump_str = TAKE_PTR(dump_str);
+
+ return 0;
+}
+
+int crypt_dump_hex_string(const char *hex_str, char **ret_dump_str) {
+
+ int r;
+ size_t len;
+ _cleanup_free_ char *dump_str = NULL;
+
+ assert(hex_str);
+ assert(ret_dump_str);
+
+ len = strlen(hex_str) >> 1;
+
+ for (size_t i = 0; i < len; i++) {
+ /* crypt_dump() breaks line after every
+ * 16th couple of chars in dumped hexstring */
+ r = strextendf_with_separator(
+ &dump_str,
+ (i && !(i % 16)) ? CRYPT_DUMP_LINE_SEP : " ",
+ "%.2s", hex_str + (i<<1));
+ if (r < 0)
+ return r;
+ }
+
+ *ret_dump_str = TAKE_PTR(dump_str);
+
+ return 0;
+}
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#pragma once
+
+#include <stddef.h>
+
+/* crypt_dump() internal indentation magic */
+#define CRYPT_DUMP_LINE_SEP "\n\t "
+
+#define crypt_log_debug(cd, ...) crypt_logf(cd, CRYPT_LOG_DEBUG, __VA_ARGS__)
+#define crypt_log_error(cd, ...) crypt_logf(cd, CRYPT_LOG_ERROR, __VA_ARGS__)
+#define crypt_log(cd, ...) crypt_logf(cd, CRYPT_LOG_NORMAL, __VA_ARGS__)
+
+#define crypt_log_debug_errno(cd, e, ...) ({ \
+ int _e = abs(e), _s = errno; \
+ errno = _e; \
+ crypt_logf(cd, CRYPT_LOG_DEBUG, __VA_ARGS__); \
+ errno = _s; \
+ -_e; \
+})
+
+int crypt_dump_buffer_to_hex_string(
+ const char *buf,
+ size_t buf_size,
+ char **ret_dump_str);
+
+int crypt_dump_hex_string(const char *hex_str, char **ret_dump_str);
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+/* for more information see libcryptsetup.h crypt-tokens section */
+
+const char *cryptsetup_token_version(void);
+
+int cryptsetup_token_open(struct crypt_device *cd, int token,
+ char **password, size_t *password_len, void *usrptr);
+
+void cryptsetup_token_dump(struct crypt_device *cd, const char *json);
+
+int cryptsetup_token_validate(struct crypt_device *cd, const char *json);
+
+void cryptsetup_token_buffer_free(void *buffer, size_t buffer_len);
--- /dev/null
+/***
+ SPDX-License-Identifier: LGPL-2.1-or-later
+
+ 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.
+***/
+
+CRYPTSETUP_TOKEN_1.0 {
+global:
+ cryptsetup_token_open;
+ cryptsetup_token_buffer_free;
+ cryptsetup_token_validate;
+ cryptsetup_token_dump;
+ cryptsetup_token_version;
+local: *;
+};
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "alloc-util.h"
+#include "hexdecoct.h"
+#include "json.h"
+#include "luks2-tpm2.h"
+#include "parse-util.h"
+#include "random-util.h"
+#include "tpm2-util.h"
+
+int acquire_luks2_key(
+ uint32_t pcr_mask,
+ uint16_t pcr_bank,
+ const char *device,
+ const void *key_data,
+ size_t key_data_size,
+ const void *policy_hash,
+ size_t policy_hash_size,
+ void **ret_decrypted_key,
+ size_t *ret_decrypted_key_size) {
+
+ _cleanup_free_ char *auto_device = NULL;
+ int r;
+
+ assert(ret_decrypted_key);
+ assert(ret_decrypted_key_size);
+
+ if (!device) {
+ r = tpm2_find_device_auto(LOG_DEBUG, &auto_device);
+ if (r == -ENODEV)
+ return -EAGAIN; /* Tell the caller to wait for a TPM2 device to show up */
+ if (r < 0)
+ return r;
+
+ device = auto_device;
+ }
+
+ return tpm2_unseal(
+ device,
+ pcr_mask, pcr_bank,
+ key_data, key_data_size,
+ policy_hash, policy_hash_size,
+ ret_decrypted_key, ret_decrypted_key_size);
+}
+
+/* this function expects valid "systemd-tpm2" in json */
+int parse_luks2_tpm2_data(
+ const char *json,
+ uint32_t search_pcr_mask,
+ uint32_t *ret_pcr_mask,
+ uint16_t *ret_pcr_bank,
+ char **ret_base64_blob,
+ char **ret_hex_policy_hash) {
+
+ int r;
+ JsonVariant *w, *e;
+ uint32_t pcr_mask = 0;
+ uint16_t pcr_bank = UINT16_MAX;
+ _cleanup_free_ char *base64_blob = NULL, *hex_policy_hash = NULL;
+ _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
+
+ assert(json);
+ assert(ret_pcr_mask);
+ assert(ret_pcr_bank);
+ assert(ret_base64_blob);
+ assert(ret_hex_policy_hash);
+
+ r = json_parse(json, 0, &v, NULL, NULL);
+ if (r < 0)
+ return -EINVAL;
+
+ w = json_variant_by_key(v, "tpm2-pcrs");
+ if (!w || !json_variant_is_array(w))
+ return -EINVAL;
+
+ JSON_VARIANT_ARRAY_FOREACH(e, w) {
+ uintmax_t u;
+
+ if (!json_variant_is_number(e))
+ return -EINVAL;
+
+ u = json_variant_unsigned(e);
+ if (u >= TPM2_PCRS_MAX)
+ return -EINVAL;
+
+ pcr_mask |= UINT32_C(1) << u;
+ }
+
+ if (search_pcr_mask != UINT32_MAX &&
+ search_pcr_mask != pcr_mask)
+ return -ENXIO;
+
+ w = json_variant_by_key(v, "tpm2-pcr-bank");
+ if (w) {
+ /* The PCR bank field is optional */
+
+ if (!json_variant_is_string(w))
+ return -EINVAL;
+
+ r = tpm2_pcr_bank_from_string(json_variant_string(w));
+ if (r < 0)
+ return r;
+
+ pcr_bank = r;
+ }
+
+ w = json_variant_by_key(v, "tpm2-blob");
+ if (!w || !json_variant_is_string(w))
+ return -EINVAL;
+
+ base64_blob = strdup(json_variant_string(w));
+ if (!base64_blob)
+ return -ENOMEM;
+
+ w = json_variant_by_key(v, "tpm2-policy-hash");
+ if (!w || !json_variant_is_string(w))
+ return -EINVAL;
+
+ hex_policy_hash = strdup(json_variant_string(w));
+ if (!hex_policy_hash)
+ return -ENOMEM;
+
+ *ret_pcr_mask = pcr_mask;
+ *ret_pcr_bank = pcr_bank;
+ *ret_base64_blob = TAKE_PTR(base64_blob);
+ *ret_hex_policy_hash = TAKE_PTR(hex_policy_hash);
+
+ return 0;
+}
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#pragma once
+
+struct crypt_device;
+
+int acquire_luks2_key(
+ uint32_t pcr_mask,
+ uint16_t pcr_bank,
+ const char *device,
+ const void *key_data,
+ size_t key_data_size,
+ const void *policy_hash,
+ size_t policy_hash_size,
+ void **ret_decrypted_key,
+ size_t *ret_decrypted_key_size);
+
+int parse_luks2_tpm2_data(
+ const char *json,
+ uint32_t search_pcr_mask,
+ uint32_t *ret_pcr_mask,
+ uint16_t *ret_pcr_bank,
+ char **ret_base64_blob,
+ char **ret_hex_policy_hash);
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+if conf.get('HAVE_LIBCRYPTSETUP_PLUGINS') == 1
+
+cryptsetup_token_c_args = ['-fvisibility=hidden']
+
+cryptsetup_token_sym = files('cryptsetup-token.sym')
+cryptsetup_token_sym_path = meson.current_source_dir() / 'cryptsetup-token.sym'
+
+if conf.get('HAVE_TPM2') == 1
+ cryptsetup_token_systemd_tpm2_sources = files('''
+ cryptsetup-token-systemd-tpm2.c
+ cryptsetup-token.h
+ cryptsetup-token-util.h
+ cryptsetup-token-util.c
+ luks2-tpm2.c
+ luks2-tpm2.h
+ '''.split())
+
+ cryptsetup_token_systemd_tpm2_static = static_library(
+ 'cryptsetup-token-systemd-tpm2_static',
+ cryptsetup_token_systemd_tpm2_sources,
+ include_directories : includes,
+ dependencies : libshared_deps + [libcryptsetup, versiondep],
+ c_args : cryptsetup_token_c_args)
+endif
+
+endif
const char *volume_name,
const char *device,
uint32_t pcr_mask,
+ uint16_t pcr_bank,
const char *key_file,
size_t key_file_size,
uint64_t key_file_offset,
blob = loaded_blob;
}
- return tpm2_unseal(device, pcr_mask, blob, blob_size, policy_hash, policy_hash_size, ret_decrypted_key, ret_decrypted_key_size);
+ return tpm2_unseal(device, pcr_mask, pcr_bank, blob, blob_size, policy_hash, policy_hash_size, ret_decrypted_key, ret_decrypted_key_size);
}
int find_tpm2_auto_data(
uint32_t search_pcr_mask,
int start_token,
uint32_t *ret_pcr_mask,
+ uint16_t *ret_pcr_bank,
void **ret_blob,
size_t *ret_blob_size,
void **ret_policy_hash,
size_t blob_size = 0, policy_hash_size = 0;
int r, keyslot = -1, token = -1;
uint32_t pcr_mask = 0;
+ uint16_t pcr_bank = UINT16_MAX; /* default: pick automatically */
assert(cd);
search_pcr_mask != pcr_mask) /* PCR mask doesn't match what is configured, ignore this entry */
continue;
+ /* The bank field is optional, since it was added in systemd 250 only. Before the bank was hardcoded to SHA256 */
+ assert(pcr_bank == UINT16_MAX);
+ w = json_variant_by_key(v, "tpm2-pcr-bank");
+ if (w) {
+ /* The PCR bank field is optional */
+
+ if (!json_variant_is_string(w))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "TPM2 PCR bank is not a string.");
+
+ r = tpm2_pcr_bank_from_string(json_variant_string(w));
+ if (r < 0)
+ return log_error_errno(r, "TPM2 PCR bank invalid or not supported: %s", json_variant_string(w));
+
+ pcr_bank = r;
+ }
+
assert(!blob);
w = json_variant_by_key(v, "tpm2-blob");
if (!w || !json_variant_is_string(w))
*ret_policy_hash_size = policy_hash_size;
*ret_keyslot = keyslot;
*ret_token = token;
+ *ret_pcr_bank = pcr_bank;
return 0;
}
const char *volume_name,
const char *device,
uint32_t pcr_mask,
+ uint16_t pcr_bank,
const char *key_file,
size_t key_file_size,
uint64_t key_file_offset,
uint32_t search_pcr_mask,
int start_token,
uint32_t *ret_pcr_mask,
+ uint16_t *ret_pcr_bank,
void **ret_blob,
size_t *ret_blob_size,
void **ret_policy_hash,
const char *volume_name,
const char *device,
uint32_t pcr_mask,
+ uint16_t pcr_bank,
const char *key_file,
size_t key_file_size,
uint64_t key_file_offset,
uint32_t search_pcr_mask,
int start_token,
uint32_t *ret_pcr_mask,
+ uint16_t *ret_pcr_bank,
void **ret_blob,
size_t *ret_blob_size,
void **ret_policy_hash,
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
const char *i, *name;
struct stat st;
- int r;
assert(path);
if (sd_device_get_property_value(device, "ID_PART_ENTRY_NAME", &name) >= 0) {
_cleanup_free_ char *unescaped = NULL;
+ ssize_t l;
/* ID_PART_ENTRY_NAME uses \x style escaping, using libblkid's blkid_encode_string(). Let's
* reverse this here to make the string more human friendly in case people embed spaces or
* other weird stuff. */
- r = cunescape(name, UNESCAPE_RELAX, &unescaped);
- if (r < 0) {
- log_debug_errno(r, "Failed to unescape ID_PART_ENTRY_NAME, skipping device: %m");
+ l = cunescape(name, UNESCAPE_RELAX, &unescaped);
+ if (l < 0) {
+ log_debug_errno(l, "Failed to unescape ID_PART_ENTRY_NAME, skipping device: %m");
return NULL;
}
return 0;
}
+static int attach_luks2_by_tpm2(
+ struct crypt_device *cd,
+ const char *name,
+ uint32_t flags) {
+
+#if HAVE_LIBCRYPTSETUP_PLUGINS
+ int r;
+
+ systemd_tpm2_plugin_params params = {
+ .search_pcr_mask = arg_tpm2_pcr_mask,
+ .device = arg_tpm2_device
+ };
+
+ if (crypt_token_external_path() == NULL)
+ return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+ "Libcryptsetup has external plugins support disabled.");
+
+ r = crypt_activate_by_token_pin(cd, name, "systemd-tpm2", CRYPT_ANY_TOKEN, NULL, 0, ¶ms, flags);
+ if (r > 0) /* returns unlocked keyslot id on success */
+ r = 0;
+
+ return r;
+#else
+ return -EOPNOTSUPP;
+#endif
+}
+
static int attach_luks_or_plain_or_bitlk_by_tpm2(
struct crypt_device *cd,
const char *name,
name,
arg_tpm2_device,
arg_tpm2_pcr_mask == UINT32_MAX ? TPM2_PCR_MASK_DEFAULT : arg_tpm2_pcr_mask,
+ UINT16_MAX,
key_file, arg_keyfile_size, arg_keyfile_offset,
key_data, key_data_size,
NULL, 0, /* we don't know the policy hash */
if (r != -EAGAIN) /* EAGAIN means: no tpm2 chip found */
return r;
} else {
+ r = attach_luks2_by_tpm2(cd, name, flags);
+ /* EAGAIN means: no tpm2 chip found
+ * EOPNOTSUPP means: no libcryptsetup plugins support */
+ if (r == -ENXIO)
+ return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
+ "No TPM2 metadata matching the current system state found in LUKS2 header, falling back to traditional unlocking.");
+ if (r == -ENOENT)
+ return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
+ "No TPM2 metadata enrolled in LUKS2 header or TPM2 support not available, falling back to traditional unlocking.");
+ if (!IN_SET(r, -EOPNOTSUPP, -EAGAIN))
+ return r;
+ }
+
+ if (r == -EOPNOTSUPP) {
_cleanup_free_ void *blob = NULL, *policy_hash = NULL;
size_t blob_size, policy_hash_size;
bool found_some = false;
for (;;) {
uint32_t pcr_mask;
+ uint16_t pcr_bank;
r = find_tpm2_auto_data(
cd,
arg_tpm2_pcr_mask, /* if != UINT32_MAX we'll only look for tokens with this PCR mask */
token, /* search for the token with this index, or any later index than this */
&pcr_mask,
+ &pcr_bank,
&blob, &blob_size,
&policy_hash, &policy_hash_size,
&keyslot,
name,
arg_tpm2_device,
pcr_mask,
+ pcr_bank,
NULL, 0, 0, /* no key file */
blob, blob_size,
policy_hash, policy_hash_size,
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
return 1;
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
if (optind < argc)
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
}
break;
default:
- assert_not_reached("Unknown action.");
+ assert_not_reached();
}
return 1;
if (ioctl(d->fd, BLKGETSIZE64, &size) < 0)
log_debug_errno(errno, "Failed to query size of loopback device: %m");
- else if (arg_json_format_flags & JSON_FORMAT_OFF) {
- char s[FORMAT_BYTES_MAX];
- printf(" Size: %s\n", format_bytes(s, sizeof(s), size));
- }
+ else if (arg_json_format_flags & JSON_FORMAT_OFF)
+ printf(" Size: %s\n", FORMAT_BYTES(size));
if (arg_json_format_flags & JSON_FORMAT_OFF)
putc('\n', stdout);
break;
default:
- assert_not_reached("Unknown action.");
+ assert_not_reached();
}
return r;
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
if (optind >= argc)
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
/* We check if the specified locale strings are valid down here, so that we can take --root= into
const char *variable) {
_cleanup_free_ char *timeout = NULL;
- char timespan[FORMAT_TIMESPAN_MAX];
usec_t u;
int r;
return 0;
}
- fprintf(f, "%s=%s\n", variable, format_timespan(timespan, sizeof(timespan), u, 0));
+ fprintf(f, "%s=%s\n", variable, FORMAT_TIMESPAN(u, 0));
return 0;
}
UNIQ_T(A, aq) > UNIQ_T(B, bq) ? UNIQ_T(A, aq) : UNIQ_T(B, bq); \
})
-/* evaluates to (void) if _A or _B are not constant or of different types */
+#define IS_UNSIGNED_INTEGER_TYPE(type) \
+ (__builtin_types_compatible_p(typeof(type), unsigned char) || \
+ __builtin_types_compatible_p(typeof(type), unsigned short) || \
+ __builtin_types_compatible_p(typeof(type), unsigned) || \
+ __builtin_types_compatible_p(typeof(type), unsigned long) || \
+ __builtin_types_compatible_p(typeof(type), unsigned long long))
+
+#define IS_SIGNED_INTEGER_TYPE(type) \
+ (__builtin_types_compatible_p(typeof(type), signed char) || \
+ __builtin_types_compatible_p(typeof(type), signed short) || \
+ __builtin_types_compatible_p(typeof(type), signed) || \
+ __builtin_types_compatible_p(typeof(type), signed long) || \
+ __builtin_types_compatible_p(typeof(type), signed long long))
+
+/* Evaluates to (void) if _A or _B are not constant or of different types (being integers of different sizes
+ * is also OK as long as the signedness matches) */
#define CONST_MAX(_A, _B) \
(__builtin_choose_expr( \
__builtin_constant_p(_A) && \
__builtin_constant_p(_B) && \
- __builtin_types_compatible_p(typeof(_A), typeof(_B)), \
+ (__builtin_types_compatible_p(typeof(_A), typeof(_B)) || \
+ (IS_UNSIGNED_INTEGER_TYPE(_A) && IS_UNSIGNED_INTEGER_TYPE(_B)) || \
+ (IS_SIGNED_INTEGER_TYPE(_A) && IS_SIGNED_INTEGER_TYPE(_B))), \
((_A) > (_B)) ? (_A) : (_B), \
VOID_0))
# for sd-boot
fundamental_source_paths = []
-foreach s : sources
- fundamental_source_paths += join_paths(meson.current_source_dir(), s)
+foreach source : sources
+ fundamental_source_paths += meson.current_source_dir() / source
endforeach
# for libbasic
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
}
break;
default:
- assert_not_reached("Unexpected state after worker exited");
+ assert_not_reached();
}
return 0;
}
if (ret == 0) {
- char buf[FORMAT_TIMESPAN_MAX];
usec_t t, n;
n = now(CLOCK_REALTIME);
t = user_record_ratelimit_next_try(h->record);
if (t != USEC_INFINITY && t > n)
- return sd_bus_error_setf(error, BUS_ERROR_AUTHENTICATION_LIMIT_HIT, "Too many login attempts, please try again in %s!",
- format_timespan(buf, sizeof(buf), t - n, USEC_PER_SEC));
+ return sd_bus_error_setf(error, BUS_ERROR_AUTHENTICATION_LIMIT_HIT,
+ "Too many login attempts, please try again in %s!",
+ FORMAT_TIMESPAN(t - n, USEC_PER_SEC));
return sd_bus_error_set(error, BUS_ERROR_AUTHENTICATION_LIMIT_HIT, "Too many login attempts, please try again later.");
}
break;
default:
- assert_not_reached("unknown phase");
+ assert_not_reached();
}
other = hashmap_get(m->homes_by_uid, UID_TO_PTR(candidate));
break;
default:
- assert_not_reached("unexpected storage");
+ assert_not_reached();
}
temporary = TAKE_PTR(d); /* Needs to be destroyed now */
}
int run_fitrim(int root_fd) {
- char buf[FORMAT_BYTES_MAX];
struct fstrim_range range = {
.len = UINT64_MAX,
};
return log_warning_errno(errno, "Failed to invoke FITRIM, ignoring: %m");
}
- log_info("Discarded unused %s.",
- format_bytes(buf, sizeof(buf), range.len));
+ log_info("Discarded unused %s.", FORMAT_BYTES(range.len));
return 1;
}
}
int run_fallocate(int backing_fd, const struct stat *st) {
- char buf[FORMAT_BYTES_MAX];
struct stat stbuf;
assert(backing_fd >= 0);
}
log_info("Allocated additional %s.",
- format_bytes(buf, sizeof(buf), (DIV_ROUND_UP(st->st_size, 512) - st->st_blocks) * 512));
+ FORMAT_BYTES((DIV_ROUND_UP(st->st_size, 512) - st->st_blocks) * 512));
return 1;
}
}
static void print_size_summary(uint64_t host_size, uint64_t encrypted_size, struct statfs *sfs) {
- char buffer1[FORMAT_BYTES_MAX], buffer2[FORMAT_BYTES_MAX], buffer3[FORMAT_BYTES_MAX], buffer4[FORMAT_BYTES_MAX];
-
assert(sfs);
log_info("Image size is %s, file system size is %s, file system payload size is %s, file system free is %s.",
- format_bytes(buffer1, sizeof(buffer1), host_size),
- format_bytes(buffer2, sizeof(buffer2), encrypted_size),
- format_bytes(buffer3, sizeof(buffer3), (uint64_t) sfs->f_blocks * (uint64_t) sfs->f_frsize),
- format_bytes(buffer4, sizeof(buffer4), (uint64_t) sfs->f_bfree * (uint64_t) sfs->f_frsize));
+ FORMAT_BYTES(host_size),
+ FORMAT_BYTES(encrypted_size),
+ FORMAT_BYTES((uint64_t) sfs->f_blocks * (uint64_t) sfs->f_frsize),
+ FORMAT_BYTES((uint64_t) sfs->f_bfree * (uint64_t) sfs->f_frsize));
}
int home_activate_luks(
}
static int calculate_disk_size(UserRecord *h, const char *parent_dir, uint64_t *ret) {
- char buf[FORMAT_BYTES_MAX];
struct statfs sfs;
uint64_t m;
log_info("Sizing home to %u%% of available disk space, which is %s.",
USER_DISK_SIZE_DEFAULT_PERCENT,
- format_bytes(buf, sizeof(buf), *ret));
+ FORMAT_BYTES(*ret));
} else {
*ret = DISK_SIZE_ROUND_DOWN((uint64_t) ((double) m * (double) h->disk_size_relative / (double) UINT32_MAX));
log_info("Sizing home to %" PRIu64 ".%01" PRIu64 "%% of available disk space, which is %s.",
(h->disk_size_relative * 100) / UINT32_MAX,
((h->disk_size_relative * 1000) / UINT32_MAX) % 10,
- format_bytes(buf, sizeof(buf), *ret));
+ FORMAT_BYTES(*ret));
}
if (*ret < USER_DISK_SIZE_MIN)
HomeSetup *setup,
UserRecord **ret_home) {
- char buffer1[FORMAT_BYTES_MAX], buffer2[FORMAT_BYTES_MAX], buffer3[FORMAT_BYTES_MAX],
- buffer4[FORMAT_BYTES_MAX], buffer5[FORMAT_BYTES_MAX], buffer6[FORMAT_BYTES_MAX];
uint64_t old_image_size, new_image_size, old_fs_size, new_fs_size, crypto_offset, new_partition_size;
_cleanup_(user_record_unrefp) UserRecord *header_home = NULL, *embedded_home = NULL, *new_home = NULL;
_cleanup_(fdisk_unref_tablep) struct fdisk_table *table = NULL;
return log_error_errno(SYNTHETIC_ERRNO(ETXTBSY), "File systems of this type can only be resized offline, but is currently online.");
log_info("Ready to resize image size %s → %s, partition size %s → %s, file system size %s → %s.",
- format_bytes(buffer1, sizeof(buffer1), old_image_size),
- format_bytes(buffer2, sizeof(buffer2), new_image_size),
- format_bytes(buffer3, sizeof(buffer3), setup->partition_size),
- format_bytes(buffer4, sizeof(buffer4), new_partition_size),
- format_bytes(buffer5, sizeof(buffer5), old_fs_size),
- format_bytes(buffer6, sizeof(buffer6), new_fs_size));
+ FORMAT_BYTES(old_image_size),
+ FORMAT_BYTES(new_image_size),
+ FORMAT_BYTES(setup->partition_size),
+ FORMAT_BYTES(new_partition_size),
+ FORMAT_BYTES(old_fs_size),
+ FORMAT_BYTES(new_fs_size));
r = prepare_resize_partition(
image_fd,
break;
default:
- assert_not_reached("unexpected type");
+ assert_not_reached();
}
/* Note that the returned object might either be a reference to an updated version of the existing
break;
default:
- assert_not_reached("unknown storage type");
+ assert_not_reached();
}
if (hd) {
}
default:
- assert_not_reached("unexpected storage type");
+ assert_not_reached();
}
return has_mount; /* return true if the home record is already active */
usec_t n = now(CLOCK_REALTIME);
if (t > n) {
- char buf[FORMAT_TIMESPAN_MAX];
(void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Too many logins, try again in %s.",
- format_timespan(buf, sizeof(buf), t - n, USEC_PER_SEC));
+ FORMAT_TIMESPAN(t - n, USEC_PER_SEC));
return PAM_MAXTRIES;
}
return -ENOTDIR;
default:
- assert_not_reached("Unexpected record type");
+ assert_not_reached();
}
}
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
return 1;
return -EINVAL;
default:
- assert_not_reached("Unknown option");
+ assert_not_reached();
}
return 1;
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
return 1;
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
return 1;
#endif
default:
- assert_not_reached("Unknown compression");
+ assert_not_reached();
}
return 1;
if (p->size == 0)
log_info("Copying tree, currently at '%s'...", p->path);
- else {
- char buffer[FORMAT_BYTES_MAX];
-
- log_info("Copying tree, currently at '%s' (@%s)...", p->path, format_bytes(buffer, sizeof(buffer), p->size));
- }
+ else
+ log_info("Copying tree, currently at '%s' (@%s)...", p->path, FORMAT_BYTES(p->size));
}
static int progress_path(const char *path, const struct stat *st, void *userdata) {
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
return 1;
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
return 1;
break;
default:
- assert_not_reached("Unexpected transfer type");
+ assert_not_reached();
}
switch (t->type) {
const char *suffix,
char ***etags) {
- _cleanup_free_ char *escaped_url = NULL;
- _cleanup_closedir_ DIR *d = NULL;
- _cleanup_strv_free_ char **l = NULL;
- struct dirent *de;
int r;
assert(url);
if (!image_root)
image_root = "/var/lib/machines";
- escaped_url = xescape(url, FILENAME_ESCAPE);
+ _cleanup_free_ char *escaped_url = xescape(url, FILENAME_ESCAPE);
if (!escaped_url)
return -ENOMEM;
- d = opendir(image_root);
+ _cleanup_closedir_ DIR *d = opendir(image_root);
if (!d) {
if (errno == ENOENT) {
*etags = NULL;
return -errno;
}
+ _cleanup_strv_free_ char **ans = NULL;
+ struct dirent *de;
+
FOREACH_DIRENT_ALL(de, d, return -errno) {
_cleanup_free_ char *u = NULL;
const char *a, *b;
if (a >= b)
continue;
- r = cunescape_length(a, b - a, 0, &u);
- if (r < 0)
- return r;
+ ssize_t l = cunescape_length(a, b - a, 0, &u);
+ if (l < 0) {
+ assert(l >= INT8_MIN);
+ return l;
+ }
if (!http_etag_is_valid(u))
continue;
- r = strv_consume(&l, TAKE_PTR(u));
+ r = strv_consume(&ans, TAKE_PTR(u));
if (r < 0)
return r;
}
- *etags = TAKE_PTR(l);
+ *etags = TAKE_PTR(ans);
return 0;
}
goto fail;
default:
- assert_not_reached("Impossible state.");
+ assert_not_reached();
}
return sz;
(void) safe_atou64(length, &j->content_length);
if (j->content_length != UINT64_MAX) {
- char bytes[FORMAT_BYTES_MAX];
-
if (j->content_length > j->compressed_max) {
- log_error("Content too large.");
- r = -EFBIG;
+ r = log_error_errno(SYNTHETIC_ERRNO(EFBIG), "Content too large.");
goto fail;
}
- log_info("Downloading %s for %s.", format_bytes(bytes, sizeof(bytes), j->content_length), j->url);
+ log_info("Downloading %s for %s.", FORMAT_BYTES(j->content_length), j->url);
}
return sz;
if (n > j->last_status_usec + USEC_PER_SEC &&
percent != j->progress_percent &&
dlnow < dltotal) {
- char buf[FORMAT_TIMESPAN_MAX];
if (n - j->start_usec > USEC_PER_SEC && dlnow > 0) {
- char y[FORMAT_BYTES_MAX];
usec_t left, done;
done = n - j->start_usec;
log_info("Got %u%% of %s. %s left at %s/s.",
percent,
j->url,
- format_timespan(buf, sizeof(buf), left, USEC_PER_SEC),
- format_bytes(y, sizeof(y), (uint64_t) ((double) dlnow / ((double) done / (double) USEC_PER_SEC))));
+ FORMAT_TIMESPAN(left, USEC_PER_SEC),
+ FORMAT_BYTES((uint64_t) ((double) dlnow / ((double) done / (double) USEC_PER_SEC))));
} else
log_info("Got %u%% of %s.", percent, j->url);
break;
default:
- assert_not_reached("Unknown progress state");
+ assert_not_reached();
}
sd_notifyf(false, "X_IMPORT_PROGRESS=%u", percent);
break;
default:
- assert_not_reached("Unknown progress state");
+ assert_not_reached();
}
sd_notifyf(false, "X_IMPORT_PROGRESS=%u", percent);
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
return 1;
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
if (optind < argc)
return -EINVAL;
default:
- assert_not_reached("Unknown option code.");
+ assert_not_reached();
}
if (optind < argc)
}
default:
- assert_not_reached("what?");
+ assert_not_reached();
}
r = journal_file_open_reliably(filename,
break;
default:
- assert_not_reached("what split mode?");
+ assert_not_reached();
}
w = hashmap_get(s->writers, key);
else if (split_mode == JOURNAL_WRITE_SPLIT_HOST)
s->output = REMOTE_JOURNAL_PATH;
else
- assert_not_reached("bad split mode");
+ assert_not_reached();
r = sd_event_default(&s->events);
if (r < 0)
return pos;
default:
- assert_not_reached("WTF?");
+ assert_not_reached();
}
}
- assert_not_reached("WTF?");
+ assert_not_reached();
}
static void check_update_watchdog(Uploader *u) {
argv[optind - 1]);
default:
- assert_not_reached("Unhandled option code.");
+ assert_not_reached();
}
if (!arg_url)
DATA={data}
"""
-m = 0x198603b12d7
-realtime_ts = 1404101101501873
-monotonic_ts = 1753961140951
-source_realtime_ts = 1404101101483516
priority = 3
facility = 6
data = '{:0{}}'.format(counter, OPTIONS.data_size)
counter += 1
- entry = template.format(m=m,
- realtime_ts=realtime_ts,
- monotonic_ts=monotonic_ts,
- source_realtime_ts=source_realtime_ts,
+ entry = template.format(m=0x198603b12d7 + i,
+ realtime_ts=1404101101501873 + i,
+ monotonic_ts=1753961140951 + i,
+ source_realtime_ts=1404101101483516 + i,
priority=priority,
facility=facility,
message=message,
data=data)
- m += 1
- realtime_ts += 1
- monotonic_ts += 1
- source_realtime_ts += 1
bytes += len(entry)
if conf.get('ENABLE_REMOTE') == 1 and conf.get('HAVE_MICROHTTPD') == 1
install_data('browse.html',
- install_dir : join_paths(pkgdatadir, 'gatewayd'))
+ install_dir : pkgdatadir / 'gatewayd')
if get_option('create-log-dirs')
meson.add_install_script('sh', '-c',
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
return 1;
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
if (arg_follow && !arg_no_tail && !arg_since && arg_lines == ARG_LINES_DEFAULT)
if (hn)
hostname_cleanup(hn);
- char tsb[FORMAT_TIMESPAN_MAX];
fprintf(stderr,
"\nNew keys have been generated for host %s%s" SD_ID128_FORMAT_STR ".\n"
"\n"
SD_ID128_FORMAT_VAL(machine),
ansi_highlight(), ansi_normal(),
p,
- format_timespan(tsb, sizeof(tsb), arg_interval, 0),
+ FORMAT_TIMESPAN(arg_interval, 0),
ansi_highlight(), ansi_normal(),
ansi_highlight_red());
fflush(stderr);
else if (k < 0)
r = log_warning_errno(k, "FAIL: %s (%m)", f->path);
else {
- char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
+ char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX];
log_info("PASS: %s", f->path);
if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
log_info("=> Validated from %s to %s, final %s entries not sealed.",
format_timestamp_maybe_utc(a, sizeof(a), first),
format_timestamp_maybe_utc(b, sizeof(b), validated),
- format_timespan(c, sizeof(c), last > validated ? last - validated : 0, 0));
+ FORMAT_TIMESPAN(last > validated ? last - validated : 0, 0));
} else if (last > 0)
log_info("=> No sealing yet, %s of entries not sealed.",
- format_timespan(c, sizeof(c), last - first, 0));
+ FORMAT_TIMESPAN(last - first, 0));
else
log_info("=> No sealing yet, no entries in file.");
}
break;
default:
- assert_not_reached("Unknown action");
+ assert_not_reached();
}
if (arg_directory)
case ACTION_FLUSH:
case ACTION_SYNC:
case ACTION_ROTATE:
- assert_not_reached("Unexpected action.");
+ assert_not_reached();
case ACTION_PRINT_HEADER:
journal_print_header(j);
case ACTION_DISK_USAGE: {
uint64_t bytes = 0;
- char sbytes[FORMAT_BYTES_MAX];
r = sd_journal_get_usage(j, &bytes);
if (r < 0)
goto finish;
printf("Archived and active journals take up %s in the file system.\n",
- format_bytes(sbytes, sizeof(sbytes), bytes));
+ FORMAT_BYTES(bytes));
goto finish;
}
break;
default:
- assert_not_reached("Unknown action");
+ assert_not_reached();
}
if (arg_boot_offset != 0 &&
}
void server_space_usage_message(Server *s, JournalStorage *storage) {
- char fb1[FORMAT_BYTES_MAX], fb2[FORMAT_BYTES_MAX], fb3[FORMAT_BYTES_MAX],
- fb4[FORMAT_BYTES_MAX], fb5[FORMAT_BYTES_MAX], fb6[FORMAT_BYTES_MAX];
- JournalMetrics *metrics;
-
assert(s);
if (!storage)
if (cache_space_refresh(s, storage) < 0)
return;
- metrics = &storage->metrics;
- format_bytes(fb1, sizeof(fb1), storage->space.vfs_used);
- format_bytes(fb2, sizeof(fb2), metrics->max_use);
- format_bytes(fb3, sizeof(fb3), metrics->keep_free);
- format_bytes(fb4, sizeof(fb4), storage->space.vfs_available);
- format_bytes(fb5, sizeof(fb5), storage->space.limit);
- format_bytes(fb6, sizeof(fb6), storage->space.available);
+ const JournalMetrics *metrics = &storage->metrics;
server_driver_message(s, 0,
"MESSAGE_ID=" SD_MESSAGE_JOURNAL_USAGE_STR,
LOG_MESSAGE("%s (%s) is %s, max %s, %s free.",
- storage->name, storage->path, fb1, fb5, fb6),
+ storage->name, storage->path,
+ FORMAT_BYTES(storage->space.vfs_used),
+ FORMAT_BYTES(storage->space.limit),
+ FORMAT_BYTES(storage->space.available)),
"JOURNAL_NAME=%s", storage->name,
"JOURNAL_PATH=%s", storage->path,
"CURRENT_USE=%"PRIu64, storage->space.vfs_used,
- "CURRENT_USE_PRETTY=%s", fb1,
+ "CURRENT_USE_PRETTY=%s", FORMAT_BYTES(storage->space.vfs_used),
"MAX_USE=%"PRIu64, metrics->max_use,
- "MAX_USE_PRETTY=%s", fb2,
+ "MAX_USE_PRETTY=%s", FORMAT_BYTES(metrics->max_use),
"DISK_KEEP_FREE=%"PRIu64, metrics->keep_free,
- "DISK_KEEP_FREE_PRETTY=%s", fb3,
+ "DISK_KEEP_FREE_PRETTY=%s", FORMAT_BYTES(metrics->keep_free),
"DISK_AVAILABLE=%"PRIu64, storage->space.vfs_available,
- "DISK_AVAILABLE_PRETTY=%s", fb4,
+ "DISK_AVAILABLE_PRETTY=%s", FORMAT_BYTES(storage->space.vfs_available),
"LIMIT=%"PRIu64, storage->space.limit,
- "LIMIT_PRETTY=%s", fb5,
+ "LIMIT_PRETTY=%s", FORMAT_BYTES(storage->space.limit),
"AVAILABLE=%"PRIu64, storage->space.available,
- "AVAILABLE_PRETTY=%s", fb6,
+ "AVAILABLE_PRETTY=%s", FORMAT_BYTES(storage->space.available),
NULL);
}
}
int server_flush_to_var(Server *s, bool require_flag_file) {
- char ts[FORMAT_TIMESPAN_MAX];
sd_journal *j = NULL;
const char *fn;
unsigned n = 0;
server_driver_message(s, 0, NULL,
LOG_MESSAGE("Time spent on flushing to %s is %s for %u entries.",
s->system_storage.path,
- format_timespan(ts, sizeof(ts), usec_sub_unsigned(now(CLOCK_MONOTONIC), start), 0),
+ FORMAT_TIMESPAN(usec_sub_unsigned(now(CLOCK_MONOTONIC), start), 0),
n),
NULL);
return stdout_stream_log(s, orig, line_break);
}
- assert_not_reached("Unknown stream state");
+ assert_not_reached();
}
static int stdout_stream_found(
if install_sysconfdir
meson.add_install_script('sh', '-c',
- mkdir_p.format(join_paths(sysconfdir, 'kernel/install.d')))
+ mkdir_p.format(sysconfdir / 'kernel/install.d'))
endif
endif
int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast) {
assert_return(client, -EINVAL);
- client->request_broadcast = !!broadcast;
+ client->request_broadcast = broadcast;
return 0;
}
goto error;
default:
- assert_not_reached("Unhandled choice");
+ assert_not_reached();
}
r = event_reset_time(client->event, &client->timeout_resend,
static int client_set_lease_timeouts(sd_dhcp_client *client) {
usec_t time_now;
- char time_string[FORMAT_TIMESPAN_MAX];
int r;
assert(client);
return 0;
log_dhcp_client(client, "lease expires in %s",
- format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->expire_time - time_now, USEC_PER_SEC));
+ FORMAT_TIMESPAN(client->expire_time - time_now, USEC_PER_SEC));
/* arm T2 timeout */
r = event_reset_time(client->event, &client->timeout_t2,
return 0;
log_dhcp_client(client, "T2 expires in %s",
- format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->t2_time - time_now, USEC_PER_SEC));
+ FORMAT_TIMESPAN(client->t2_time - time_now, USEC_PER_SEC));
/* arm T1 timeout */
r = event_reset_time(client->event, &client->timeout_t1,
if (client->t1_time > time_now)
log_dhcp_client(client, "T1 expires in %s",
- format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->t1_time - time_now, USEC_PER_SEC));
+ FORMAT_TIMESPAN(client->t1_time - time_now, USEC_PER_SEC));
return 0;
}
static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, int len) {
DHCP_CLIENT_DONT_DESTROY(client);
- char time_string[FORMAT_TIMESPAN_MAX];
int r, notify_event;
assert(client);
if (r < 0)
goto error;
- log_dhcp_client(client, "REBOOT in %s", format_timespan(time_string, FORMAT_TIMESPAN_MAX,
- client->start_delay, USEC_PER_SEC));
+ log_dhcp_client(client, "REBOOT in %s", FORMAT_TIMESPAN(client->start_delay, USEC_PER_SEC));
client->start_delay = CLAMP(client->start_delay * 2,
RESTART_AFTER_NAK_MIN_USEC, RESTART_AFTER_NAK_MAX_USEC);
r = -EINVAL;
goto error;
default:
- assert_not_reached("invalid state");
+ assert_not_reached();
}
error:
usec_t time_now, init_retransmit_time = 0, max_retransmit_time = 0;
usec_t max_retransmit_duration = 0;
uint8_t max_retransmit_count = 0;
- char time_string[FORMAT_TIMESPAN_MAX];
assert(s);
assert(client);
}
log_dhcp6_client(client, "Next retransmission in %s",
- format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->retransmit_time, USEC_PER_SEC));
+ FORMAT_TIMESPAN(client->retransmit_time, USEC_PER_SEC));
r = event_reset_time(client->event, &client->timeout_resend,
clock_boottime_or_monotonic(),
static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
int r;
usec_t timeout, time_now;
- char time_string[FORMAT_TIMESPAN_MAX];
uint32_t lifetime_t1, lifetime_t2;
assert_return(client, -EINVAL);
timeout = client_timeout_compute_random(lifetime_t1 * USEC_PER_SEC);
- log_dhcp6_client(client, "T1 expires in %s",
- format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
+ log_dhcp6_client(client, "T1 expires in %s", FORMAT_TIMESPAN(timeout, USEC_PER_SEC));
r = event_reset_time(client->event, &client->timeout_t1,
clock_boottime_or_monotonic(),
timeout = client_timeout_compute_random(lifetime_t2 * USEC_PER_SEC);
- log_dhcp6_client(client, "T2 expires in %s",
- format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
+ log_dhcp6_client(client, "T2 expires in %s", FORMAT_TIMESPAN(timeout, USEC_PER_SEC));
r = event_reset_time(client->event, &client->timeout_t2,
clock_boottime_or_monotonic(),
ipv4acd_set_state(acd, IPV4ACD_STATE_WAITING_PROBE, true);
if (acd->n_conflict >= MAX_CONFLICTS) {
- char ts[FORMAT_TIMESPAN_MAX];
-
log_ipv4acd(acd, "Max conflicts reached, delaying by %s",
- format_timespan(ts, sizeof(ts), RATE_LIMIT_INTERVAL_USEC, 0));
+ FORMAT_TIMESPAN(RATE_LIMIT_INTERVAL_USEC, 0));
r = ipv4acd_set_next_wakeup(acd, RATE_LIMIT_INTERVAL_USEC, PROBE_WAIT_USEC);
} else
r = ipv4acd_set_next_wakeup(acd, 0, PROBE_WAIT_USEC);
break;
default:
- assert_not_reached("Invalid state.");
+ assert_not_reached();
}
return 0;
break;
default:
- assert_not_reached("Invalid state.");
+ assert_not_reached();
}
return 0;
break;
default:
- assert_not_reached("Invalid IPv4ACD event.");
+ assert_not_reached();
}
return;
}
static int ndisc_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
- char time_string[FORMAT_TIMESPAN_MAX];
sd_ndisc *nd = userdata;
usec_t time_now;
int r;
}
log_ndisc(nd, "Sent Router Solicitation, next solicitation in %s",
- format_timespan(time_string, FORMAT_TIMESPAN_MAX,
- nd->retransmit_time, USEC_PER_SEC));
+ FORMAT_TIMESPAN(nd->retransmit_time, USEC_PER_SEC));
return 0;
usec_t min_timeout = SD_RADV_DEFAULT_MIN_TIMEOUT_USEC;
usec_t max_timeout = SD_RADV_DEFAULT_MAX_TIMEOUT_USEC;
usec_t time_now, timeout;
- char time_string[FORMAT_TIMESPAN_MAX];
assert(s);
assert(ra);
}
timeout = radv_compute_timeout(min_timeout, max_timeout);
-
- log_radv(ra, "Next Router Advertisement in %s",
- format_timespan(time_string, FORMAT_TIMESPAN_MAX,
- timeout, USEC_PER_SEC));
+ log_radv(ra, "Next Router Advertisement in %s", FORMAT_TIMESPAN(timeout, USEC_PER_SEC));
r = event_reset_time(ra->event, &ra->timeout_event_source,
clock_boottime_or_monotonic(),
sd_radv_prefix *cur;
int r;
_cleanup_free_ char *addr_p = NULL;
- char time_string_preferred[FORMAT_TIMESPAN_MAX];
- char time_string_valid[FORMAT_TIMESPAN_MAX];
usec_t time_now, valid, preferred, valid_until, preferred_until;
assert_return(ra, -EINVAL);
log_radv(ra, "Updated prefix %s preferred %s valid %s",
strna(addr_p),
- format_timespan(time_string_preferred, FORMAT_TIMESPAN_MAX,
- preferred, USEC_PER_SEC),
- format_timespan(time_string_valid, FORMAT_TIMESPAN_MAX,
- valid, USEC_PER_SEC));
+ FORMAT_TIMESPAN(preferred, USEC_PER_SEC),
+ FORMAT_TIMESPAN(valid, USEC_PER_SEC));
return 0;
}
}
_public_ int sd_radv_add_route_prefix(sd_radv *ra, sd_radv_route_prefix *p, int dynamic) {
- char time_string_valid[FORMAT_TIMESPAN_MAX];
usec_t time_now, valid, valid_until;
_cleanup_free_ char *pretty = NULL;
sd_radv_route_prefix *cur;
log_radv(ra, "Updated route prefix %s valid %s",
strna(pretty),
- format_timespan(time_string_valid, FORMAT_TIMESPAN_MAX, valid, USEC_PER_SEC));
+ FORMAT_TIMESPAN(valid, USEC_PER_SEC));
return 0;
}
log_error("the client was stopped");
break;
default:
- assert_not_reached("invalid ACD event");
+ assert_not_reached();
}
}
static sd_event_source *test_hangcheck;
static int test_dhcp_hangcheck(sd_event_source *s, uint64_t usec, void *userdata) {
- assert_not_reached("Test case should have completed in 2 seconds");
+ assert_not_reached();
return 0;
}
return 0;
}
-static int test_hangcheck(sd_event_source *s, uint64_t usec, void *userdata) {
- assert_not_reached("Test case should have completed in 2 seconds");
-
- return 0;
+static int test_check_completed_in_2_seconds(sd_event_source *s, uint64_t usec, void *userdata) {
+ assert_not_reached();
}
static void test_client_solicit_cb(sd_dhcp6_client *client, int event,
break;
case SD_DHCP6_OPTION_IA_NA:
- assert_not_reached("IA TA option must not be present");
-
- break;
-
case SD_DHCP6_OPTION_SERVERID:
- assert_not_reached("Server ID option must not be present");
-
- break;
+ assert_not_reached();
case SD_DHCP6_OPTION_ELAPSED_TIME:
assert_se(!found_elapsed_time);
assert_se(sd_event_add_time_relative(e, &hangcheck, clock_boottime_or_monotonic(),
2 * USEC_PER_SEC, 0,
- test_hangcheck, NULL) >= 0);
+ test_check_completed_in_2_seconds, NULL) >= 0);
assert_se(sd_dhcp6_client_set_local_address(client, &address) >= 0);
log_error("the client was stopped with address %s", strna(address));
break;
default:
- assert_not_reached("invalid LL event");
+ assert_not_reached();
}
}
static void router_dump(sd_ndisc_router *rt) {
struct in6_addr addr;
- char buf[FORMAT_TIMESTAMP_MAX];
uint8_t hop_limit;
uint64_t t, flags;
uint32_t mtu;
assert_se(sd_ndisc_router_get_address(rt, &addr) == -ENODATA);
assert_se(sd_ndisc_router_get_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
- log_info("Timestamp: %s", format_timestamp(buf, sizeof(buf), t));
+ log_info("Timestamp: %s", FORMAT_TIMESTAMP(t));
assert_se(sd_ndisc_router_get_timestamp(rt, CLOCK_MONOTONIC, &t) >= 0);
log_info("Monotonic: %" PRIu64, t);
static usec_t last = 0;
sd_ndisc *nd = test_timeout_nd;
usec_t min, max;
- char time_string_min[FORMAT_TIMESPAN_MAX];
- char time_string_nd[FORMAT_TIMESPAN_MAX];
- char time_string_max[FORMAT_TIMESPAN_MAX];
assert_se(nd);
assert_se(nd->event);
NDISC_MAX_ROUTER_SOLICITATION_INTERVAL / 10;
}
- format_timespan(time_string_min, FORMAT_TIMESPAN_MAX,
- min, USEC_PER_MSEC);
- format_timespan(time_string_nd, FORMAT_TIMESPAN_MAX,
- nd->retransmit_time, USEC_PER_MSEC);
- format_timespan(time_string_max, FORMAT_TIMESPAN_MAX,
- max, USEC_PER_MSEC);
-
log_info("backoff timeout interval %2d %s%s <= %s <= %s",
count,
- (last * 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL)? "(max) ": "",
- time_string_min, time_string_nd, time_string_max);
+ last * 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL ? "(max) ": "",
+ FORMAT_TIMESPAN(min, USEC_PER_MSEC),
+ FORMAT_TIMESPAN(nd->retransmit_time, USEC_PER_MSEC),
+ FORMAT_TIMESPAN(max, USEC_PER_MSEC));
assert_se(min <= nd->retransmit_time);
assert_se(max >= nd->retransmit_time);
c_args : libsystemd_c_args)
libsystemd_sym = files('libsystemd.sym')
-libsystemd_sym_path = join_paths(meson.current_source_dir(), 'libsystemd.sym')
+libsystemd_sym_path = meson.current_source_dir() / 'libsystemd.sym'
static_libsystemd = get_option('static-libsystemd')
static_libsystemd_pic = static_libsystemd == 'true' or static_libsystemd == 'pic'
r = namespace_open(b->nspid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
if (r < 0)
- return r;
+ return log_debug_errno(r, "Failed to open namespace of PID "PID_FMT": %m", b->nspid);
b->input_fd = socket(b->sockaddr.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (b->input_fd < 0)
- return -errno;
+ return log_debug_errno(errno, "Failed to create a socket: %m");
b->input_fd = fd_move_above_stdio(b->input_fd);
bus_socket_setup(b);
if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, pair) < 0)
- return -errno;
+ return log_debug_errno(errno, "Failed to create a socket pair: %m");
r = namespace_fork("(sd-buscntrns)", "(sd-buscntr)", NULL, 0, FORK_RESET_SIGNALS|FORK_DEATHSIG,
pidnsfd, mntnsfd, -1, usernsfd, rootfd, &child);
if (r < 0)
- return r;
+ return log_debug_errno(r, "Failed to create namespace for (sd-buscntr): %m");
if (r == 0) {
pair[0] = safe_close(pair[0]);
n = read(pair[0], &error_buf, sizeof(error_buf));
if (n < 0)
- return -errno;
+ return log_debug_errno(errno, "Failed to read error status from (sd-buscntr): %m");
if (n > 0) {
if (n != sizeof(error_buf))
- return -EIO;
+ return log_debug_errno(SYNTHETIC_ERRNO(EIO),
+ "Read error status of unexpected length %zd from (sd-buscntr): %m", n);
if (error_buf < 0)
- return -EIO;
+ return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
+ "Got unexpected error status from (sd-buscntr): %m");
if (error_buf == EINPROGRESS)
return 1;
if (error_buf > 0)
- return -error_buf;
+ return log_debug_errno(error_buf, "Got error from (sd-buscntr): %m");
}
return bus_socket_start_auth(b);
f = stdout;
if (flags & SD_BUS_MESSAGE_DUMP_WITH_HEADER) {
- char buf[FORMAT_TIMESTAMP_MAX];
- const char *p;
usec_t ts = m->realtime;
if (ts == 0)
ts = now(CLOCK_REALTIME);
- p = format_timestamp_style(buf, sizeof(buf), ts, TIMESTAMP_US_UTC);
-
fprintf(f,
"%s%s%s Type=%s%s%s Endian=%c Flags=%u Version=%u",
m->header->type == SD_BUS_MESSAGE_METHOD_ERROR ? ansi_highlight_red() :
if (m->reply_cookie != 0)
fprintf(f, " ReplyCookie=%" PRIu64, m->reply_cookie);
- fprintf(f, " Timestamp=\"%s\"", strna(p));
-
- fputs("\n", f);
+ fprintf(f, " Timestamp=\"%s\"\n", strna(FORMAT_TIMESTAMP_STYLE(ts, TIMESTAMP_US_UTC)));
if (m->sender)
fprintf(f, " Sender=%s%s%s", ansi_highlight(), m->sender, ansi_normal());
break;
default:
- assert_not_reached("Unknown basic type.");
+ assert_not_reached();
}
}
fprintf(f, "%sFSGID=%s"GID_FMT"%s", prefix, color, c->fsgid, suffix);
if (c->mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
- unsigned i;
-
fprintf(f, "%sSupplementaryGIDs=%s", prefix, color);
- for (i = 0; i < c->n_supplementary_gids; i++)
+ for (unsigned i = 0; i < c->n_supplementary_gids; i++)
fprintf(f, "%s" GID_FMT, i > 0 ? " " : "", c->supplementary_gids[i]);
fprintf(f, "%s", suffix);
}
return -ENOMEM;
}
- /* If we hit OOM on formatting the pretty message, we ignore
- * this, since we at least managed to write the error name */
- if (format)
- (void) vasprintf((char**) &e->message, format, ap);
+ if (format) {
+ _cleanup_free_ char *mesg = NULL;
+
+ /* If we hit OOM on formatting the pretty message, we ignore
+ * this, since we at least managed to write the error name */
+
+ if (vasprintf(&mesg, format, ap) >= 0)
+ e->message = TAKE_PTR(mesg);
+ }
e->_need_free = 1;
}
return -EINVAL;
default:
- assert_not_reached("Unknown signature type");
+ assert_not_reached();
}
p += n;
}
default:
- assert_not_reached("Unknown signature type");
+ assert_not_reached();
}
if (a < 0)
}
default:
- assert_not_reached("Unknown signature type");
+ assert_not_reached();
}
p += n;
else if (sz == 8)
return le64toh(x.u64);
- assert_not_reached("unknown word width");
+ assert_not_reached();
}
void bus_gvariant_write_word_le(void *p, size_t sz, size_t value) {
else if (sz == 8)
x.u64 = htole64((uint64_t) value);
else
- assert_not_reached("unknown word width");
+ assert_not_reached();
memcpy(p, &x, sz);
}
return false;
default:
- assert_not_reached("Invalid node type");
+ assert_not_reached();
}
}
return streq(node->value.str, value_str);
default:
- assert_not_reached("Invalid node type");
+ assert_not_reached();
}
}
break;
default:
- assert_not_reached("Unknown match type.");
+ assert_not_reached();
}
if (BUS_MATCH_CAN_HASH(node->type)) {
else if (IN_SET(c->enclosing, SD_BUS_TYPE_STRUCT, SD_BUS_TYPE_DICT_ENTRY))
r = bus_message_close_struct(m, c, true);
else
- assert_not_reached("Unknown container type");
+ assert_not_reached();
free(c->signature);
free(c->offsets);
} else if (c->enclosing == SD_BUS_TYPE_VARIANT)
goto end;
else
- assert_not_reached("Unknown container type");
+ assert_not_reached();
return 0;
}
default:
- assert_not_reached("unexpected type");
+ assert_not_reached();
}
}
}
default:
- assert_not_reached("Unknown basic type...");
+ assert_not_reached();
}
}
}
break;
default:
- assert_not_reached("Wut? Unknown slot type?");
+ assert_not_reached();
}
bus = slot->bus;
#include "bus-internal.h"
#include "bus-message.h"
#include "bus-socket.h"
+#include "escape.h"
#include "fd-util.h"
#include "format-util.h"
#include "fs-util.h"
assert(b->exec_path);
assert(b->busexec_pid == 0);
- log_debug("sd-bus: starting bus%s%s with %s...",
- b->description ? " " : "", strempty(b->description), b->exec_path);
+ if (DEBUG_LOGGING) {
+ _cleanup_free_ char *line = NULL;
+
+ if (b->exec_argv)
+ line = quote_command_line(b->exec_argv);
+
+ log_debug("sd-bus: starting bus%s%s with %s%s",
+ b->description ? " " : "", strempty(b->description),
+ line ?: b->exec_path,
+ b->exec_argv && !line ? "…" : "");
+ }
r = socketpair(AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0, s);
if (r < 0)
if (b->exec_argv)
execvp(b->exec_path, b->exec_argv);
- else {
- const char *argv[] = { b->exec_path, NULL };
- execvp(b->exec_path, (char**) argv);
- }
+ else
+ execvp(b->exec_path, STRV_MAKE(b->exec_path));
_exit(EXIT_FAILURE);
}
#include "parse-util.h"
#include "path-util.h"
#include "process-util.h"
+#include "stdio-util.h"
#include "string-util.h"
#include "strv.h"
#include "user-util.h"
if (!user)
return -ENOMEM;
- if (!isempty(user) && !valid_user_group_name(user, VALID_USER_RELAX))
+ if (!isempty(user) && !valid_user_group_name(user, VALID_USER_RELAX | VALID_USER_ALLOW_NUMERIC))
return false;
h++;
/* Otherwise, if we are root, then we can also allow the ".host" syntax, as that's the user this
* would connect to. */
- if (geteuid() == 0 && STR_IN_SET(user_and_machine, ".host", "root@.host"))
+ uid_t uid = geteuid();
+
+ if (uid == 0 && STR_IN_SET(user_and_machine, ".host", "root@.host", "0@.host"))
return true;
- /* Otherwise, we have to figure our user name, and compare things with that. */
- un = getusername_malloc();
- if (!un)
- return -ENOMEM;
+ /* Otherwise, we have to figure out our user id and name, and compare things with that. */
+ char buf[DECIMAL_STR_MAX(uid_t)];
+ xsprintf(buf, UID_FMT, uid);
+
+ f = startswith(user_and_machine, buf);
+ if (!f) {
+ un = getusername_malloc();
+ if (!un)
+ return -ENOMEM;
- f = startswith(user_and_machine, un);
- if (!f)
- return false;
+ f = startswith(user_and_machine, un);
+ if (!f)
+ return false;
+ }
return STR_IN_SET(f, "@", "@.host");
}
break;
default:
- assert_not_reached("Unknown state");
+ assert_not_reached();
}
return flags;
return 0;
default:
- assert_not_reached("Unknown or unexpected stat");
+ assert_not_reached();
}
}
else
exit(EXIT_FAILURE);
- assert_not_reached("exit() didn't exit?");
+ assert_not_reached();
}
static int process_closing_reply_callback(sd_bus *bus, struct reply_callback *c) {
return process_closing(bus, ret);
default:
- assert_not_reached("Unknown state");
+ assert_not_reached();
}
if (ERRNO_IS_DISCONNECT(r)) {
return;
} else if (!sd_bus_message_is_signal(m, NULL, NULL))
- assert_not_reached("Unknown method");
+ assert_not_reached();
}
}
OBJECT_PATH_FOREACH_PREFIX(prefix, "/") {
log_info("<%s>", prefix);
- assert_not_reached("???");
+ assert_not_reached();
}
r = 0;
break;
default:
- assert_not_reached("Invalid state when parsing uevent file");
+ assert_not_reached();
}
if (major) {
}
default:
- assert_not_reached("Wut? I shouldn't exist.");
+ assert_not_reached();
}
if (s->pending)
break;
default:
- assert_not_reached("Wut? I shouldn't exist.");
+ assert_not_reached();
}
/* Always reshuffle time prioq, as the ratelimited flag may be changed. */
break;
default:
- assert_not_reached("Wut? I shouldn't exist.");
+ assert_not_reached();
}
s->enabled = enabled;
case SOURCE_WATCHDOG:
case _SOURCE_EVENT_SOURCE_TYPE_MAX:
case _SOURCE_EVENT_SOURCE_TYPE_INVALID:
- assert_not_reached("Wut? I shouldn't exist.");
+ assert_not_reached();
}
s->dispatching = false;
break;
default:
- assert_not_reached("Unexpected event source type");
+ assert_not_reached();
}
break;
break;
default:
- assert_not_reached("Invalid wake-up pointer");
+ assert_not_reached();
}
}
if (r < 0)
#include "sd-event.h"
#include "alloc-util.h"
+#include "exec-util.h"
#include "fd-util.h"
#include "fs-util.h"
#include "log.h"
else
assert_se(sd_event_source_set_enabled(s, SD_EVENT_OFF) >= 0);
} else
- assert_not_reached("Yuck!");
+ assert_not_reached();
return 1;
}
got_c = true;
}
} else
- assert_not_reached("Huh?");
+ assert_not_reached();
return 2;
}
log_info("inotify-handler <%s>: delete of %s", description, ev->name);
assert_se(streq(ev->name, "sub"));
} else
- assert_not_reached("unexpected inotify event");
+ assert_not_reached();
maybe_exit(s, c);
return 1;
} else if (ev->mask & IN_IGNORED) {
log_info("delete-self-handler: ignore");
} else
- assert_not_reached("unexpected inotify event (delete-self)");
+ assert_not_reached();
maybe_exit(s, c);
return 1;
log_error("File corrupt");
}
-static const char* format_timestamp_safe(char *buf, size_t l, usec_t t) {
- const char *x;
-
- x = format_timestamp(buf, l, t);
- if (x)
- return x;
- return " --- ";
-}
+/* Note: the lifetime of the compound literal is the immediately surrounding block. */
+#define FORMAT_TIMESTAMP_SAFE(t) (FORMAT_TIMESTAMP(t) ?: " --- ")
void journal_file_print_header(JournalFile *f) {
char a[SD_ID128_STRING_MAX], b[SD_ID128_STRING_MAX], c[SD_ID128_STRING_MAX], d[SD_ID128_STRING_MAX];
- char x[FORMAT_TIMESTAMP_MAX], y[FORMAT_TIMESTAMP_MAX], z[FORMAT_TIMESTAMP_MAX];
struct stat st;
- char bytes[FORMAT_BYTES_MAX];
assert(f);
assert(f->header);
yes_no(journal_file_rotate_suggested(f, 0)),
le64toh(f->header->head_entry_seqnum), le64toh(f->header->head_entry_seqnum),
le64toh(f->header->tail_entry_seqnum), le64toh(f->header->tail_entry_seqnum),
- format_timestamp_safe(x, sizeof(x), le64toh(f->header->head_entry_realtime)), le64toh(f->header->head_entry_realtime),
- format_timestamp_safe(y, sizeof(y), le64toh(f->header->tail_entry_realtime)), le64toh(f->header->tail_entry_realtime),
- format_timespan(z, sizeof(z), le64toh(f->header->tail_entry_monotonic), USEC_PER_MSEC), le64toh(f->header->tail_entry_monotonic),
+ FORMAT_TIMESTAMP_SAFE(le64toh(f->header->head_entry_realtime)), le64toh(f->header->head_entry_realtime),
+ FORMAT_TIMESTAMP_SAFE(le64toh(f->header->tail_entry_realtime)), le64toh(f->header->tail_entry_realtime),
+ FORMAT_TIMESPAN(le64toh(f->header->tail_entry_monotonic), USEC_PER_MSEC), le64toh(f->header->tail_entry_monotonic),
le64toh(f->header->n_objects),
le64toh(f->header->n_entries));
f->header->data_hash_chain_depth);
if (fstat(f->fd, &st) >= 0)
- printf("Disk usage: %s\n", format_bytes(bytes, sizeof(bytes), (uint64_t) st.st_blocks * 512ULL));
+ printf("Disk usage: %s\n", FORMAT_BYTES((uint64_t) st.st_blocks * 512ULL));
}
static int journal_file_warn_btrfs(JournalFile *f) {
if (DEBUG_LOGGING) {
static int last_seal = -1, last_compress = -1, last_keyed_hash = -1;
static uint64_t last_bytes = UINT64_MAX;
- char bytes[FORMAT_BYTES_MAX];
if (last_seal != f->seal ||
last_keyed_hash != f->keyed_hash ||
log_debug("Journal effective settings seal=%s keyed_hash=%s compress=%s compress_threshold_bytes=%s",
yes_no(f->seal), yes_no(f->keyed_hash), yes_no(JOURNAL_FILE_COMPRESS(f)),
- format_bytes(bytes, sizeof bytes, f->compress_threshold_bytes));
+ FORMAT_BYTES(f->compress_threshold_bytes));
last_seal = f->seal;
last_keyed_hash = f->keyed_hash;
last_compress = JOURNAL_FILE_COMPRESS(f);
}
void journal_default_metrics(JournalMetrics *m, int fd) {
- char a[FORMAT_BYTES_MAX], b[FORMAT_BYTES_MAX], c[FORMAT_BYTES_MAX], d[FORMAT_BYTES_MAX], e[FORMAT_BYTES_MAX];
struct statvfs ss;
uint64_t fs_size = 0;
m->n_max_files = DEFAULT_N_MAX_FILES;
log_debug("Fixed min_use=%s max_use=%s max_size=%s min_size=%s keep_free=%s n_max_files=%" PRIu64,
- format_bytes(a, sizeof(a), m->min_use),
- format_bytes(b, sizeof(b), m->max_use),
- format_bytes(c, sizeof(c), m->max_size),
- format_bytes(d, sizeof(d), m->min_size),
- format_bytes(e, sizeof(e), m->keep_free),
+ FORMAT_BYTES(m->min_use),
+ FORMAT_BYTES(m->max_use),
+ FORMAT_BYTES(m->max_size),
+ FORMAT_BYTES(m->min_size),
+ FORMAT_BYTES(m->keep_free),
m->n_max_files);
}
_cleanup_closedir_ DIR *d = NULL;
struct vacuum_info *list = NULL;
usec_t retention_limit = 0;
- char sbytes[FORMAT_BYTES_MAX];
struct dirent *de;
int r;
return -errno;
FOREACH_DIRENT_ALL(de, d, r = -errno; goto finish) {
-
unsigned long long seqnum = 0, realtime;
_cleanup_free_ char *p = NULL;
sd_id128_t seqnum_id;
if (r >= 0) {
log_full(verbose ? LOG_INFO : LOG_DEBUG,
- "Deleted empty archived journal %s/%s (%s).", directory, p, format_bytes(sbytes, sizeof(sbytes), size));
+ "Deleted empty archived journal %s/%s (%s).", directory, p, FORMAT_BYTES(size));
freed += size;
} else if (r != -ENOENT)
r = unlinkat_deallocate(dirfd(d), list[i].filename, 0);
if (r >= 0) {
- log_full(verbose ? LOG_INFO : LOG_DEBUG, "Deleted archived journal %s/%s (%s).", directory, list[i].filename, format_bytes(sbytes, sizeof(sbytes), list[i].usage));
+ log_full(verbose ? LOG_INFO : LOG_DEBUG, "Deleted archived journal %s/%s (%s).",
+ directory, list[i].filename, FORMAT_BYTES(list[i].usage));
freed += list[i].usage;
if (list[i].usage < sum)
free(list[i].filename);
free(list);
- log_full(verbose ? LOG_INFO : LOG_DEBUG, "Vacuuming done, freed %s of archived journals from %s.", format_bytes(sbytes, sizeof(sbytes), freed), directory);
+ log_full(verbose ? LOG_INFO : LOG_DEBUG, "Vacuuming done, freed %s of archived journals from %s.",
+ FORMAT_BYTES(freed), directory);
return r;
}
return true;
}
- assert_not_reached("\"=\" not found");
+ assert_not_reached();
}
static Match *match_new(Match *p, MatchType t) {
random_bytes(buf + 8*step, step);
memzero(buf + 9*step, step);
} else
- assert_not_reached("here");
+ assert_not_reached();
return buf;
}
JournalFile *f;
const char *verification_key = argv[1];
usec_t from = 0, to = 0, total = 0;
- char a[FORMAT_TIMESTAMP_MAX];
- char b[FORMAT_TIMESTAMP_MAX];
- char c[FORMAT_TIMESPAN_MAX];
struct stat st;
uint64_t p;
if (verification_key && JOURNAL_HEADER_SEALED(f->header))
log_info("=> Validated from %s to %s, %s missing",
- format_timestamp(a, sizeof(a), from),
- format_timestamp(b, sizeof(b), to),
- format_timespan(c, sizeof(c), total > to ? total - to : 0, 0));
+ FORMAT_TIMESTAMP(from),
+ FORMAT_TIMESTAMP(to),
+ FORMAT_TIMESPAN(total > to ? total - to : 0, 0));
(void) journal_file_close(f);
_public_ int sd_session_get_desktop(const char *session, char **desktop) {
_cleanup_free_ char *escaped = NULL;
- char *t;
int r;
+ ssize_t l;
assert_return(desktop, -EINVAL);
if (r < 0)
return r;
- r = cunescape(escaped, 0, &t);
- if (r < 0)
- return r;
-
- *desktop = t;
+ l = cunescape(escaped, 0, desktop);
+ if (l < 0)
+ return l;
return 0;
}
_public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
if (m)
- close_nointr(MONITOR_TO_FD(m));
+ (void) close_nointr(MONITOR_TO_FD(m));
return NULL;
}
break;
}
default:
- assert_not_reached("sd-netlink: invalid type system union type");
+ assert_not_reached();
}
} else
return -EINVAL;
break;
default:
- assert_not_reached("Wut? Unknown slot type?");
+ assert_not_reached();
}
slot->type = _NETLINK_SLOT_INVALID;
assert_return(IN_SET(nh_family, AF_UNSPEC, AF_INET, AF_INET6), -EINVAL);
break;
default:
- assert_not_reached("Invalid message type.");
+ assert_not_reached();
}
assert_return(ret, -EINVAL);
_public_ sd_network_monitor* sd_network_monitor_unref(sd_network_monitor *m) {
if (m)
- close_nointr(MONITOR_TO_FD(m));
+ (void) close_nointr(MONITOR_TO_FD(m));
return NULL;
}
return -ECONNRESET;
default:
- assert_not_reached("Unknown request");
+ assert_not_reached();
}
return 0;
break;
default:
- assert_not_reached("Cannot complete unknown query type");
+ assert_not_reached();
}
resolve->current = NULL;
}
if (r < 0) {
log_error_errno(r, "sd_resolve_wait(): %m");
- assert_not_reached("sd_resolve_wait() failed");
+ assert_not_reached();
}
}
Description: Library to access udev device information
Version: {{PROJECT_VERSION}}
Libs: -L${libdir} -ludev
+Libs.private: -lrt -pthread
Cflags: -I${includedir}
libudev_includes = [includes, include_directories('.')]
libudev_sym = files('libudev.sym')
-libudev_sym_path = join_paths(meson.current_source_dir(), 'libudev.sym')
+libudev_sym_path = meson.current_source_dir() / 'libudev.sym'
install_headers('libudev.h')
-libudev_h_path = join_paths(meson.current_source_dir(), 'libudev.h')
+libudev_h_path = meson.current_source_dir() / 'libudev.h'
libudev_basic = static_library(
'udev-basic',
return -EINVAL;
default:
- assert_not_reached("Unhandled option code.");
+ assert_not_reached();
}
return 1;
}
}
- assert_not_reached("should not be here");
+ assert_not_reached();
}
int x11_convert_to_vconsole(Context *c) {
else if (streq(argv[0], "list-x11-keymap-options"))
look_for = OPTIONS;
else
- assert_not_reached("Wrong parameter");
+ assert_not_reached();
for (;;) {
_cleanup_free_ char *line = NULL;
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
return 1;
# If you know a way that allows the same variables to be used
# in sources list and concatenated to a string for test_env,
# let me know.
-kbd_model_map = join_paths(meson.current_source_dir(), 'kbd-model-map')
-language_fallback_map = join_paths(meson.current_source_dir(), 'language-fallback-map')
+kbd_model_map = meson.current_source_dir() / 'kbd-model-map'
+language_fallback_map = meson.current_source_dir() / 'language-fallback-map'
if conf.get('ENABLE_LOCALED') == 1
install_data('kbd-model-map',
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
if (arg_action == ACTION_INHIBIT && optind == argc)
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
- char since1[FORMAT_TIMESTAMP_RELATIVE_MAX];
- char since2[FORMAT_TIMESTAMP_MAX];
- const char *s1, *s2;
SessionStatusInfo i = {};
int r;
else
printf("%"PRIu32"\n", i.uid);
- s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
- s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
-
- if (s1)
- printf("\t Since: %s; %s\n", s2, s1);
- else if (s2)
- printf("\t Since: %s\n", s2);
+ if (i.timestamp.realtime > 0 && i.timestamp.realtime < USEC_INFINITY)
+ printf("\t Since: %s; %s\n",
+ FORMAT_TIMESTAMP(i.timestamp.realtime),
+ FORMAT_TIMESTAMP_RELATIVE(i.timestamp.realtime));
if (i.leader > 0) {
_cleanup_free_ char *t = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
- char since1[FORMAT_TIMESTAMP_RELATIVE_MAX];
- char since2[FORMAT_TIMESTAMP_MAX];
- const char *s1, *s2;
_cleanup_(user_status_info_clear) UserStatusInfo i = {};
int r;
else
printf("%"PRIu32"\n", i.uid);
- s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
- s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
-
- if (s1)
- printf("\t Since: %s; %s\n", s2, s1);
- else if (s2)
- printf("\t Since: %s\n", s2);
+ if (i.timestamp.realtime > 0 && i.timestamp.realtime < USEC_INFINITY)
+ printf("\t Since: %s; %s\n",
+ FORMAT_TIMESTAMP(i.timestamp.realtime),
+ FORMAT_TIMESTAMP_RELATIVE(i.timestamp.realtime));
if (!isempty(i.state))
printf("\t State: %s\n", i.state);
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
return 1;
}
} else if (ev.type == EV_KEY && ev.value == 0) {
- if (ev.code == KEY_RESTART) {
- if (b->manager->reboot_key_long_press_event_source) {
+
+ switch (ev.code) {
+
+ case KEY_POWER:
+ case KEY_POWER2:
+ if (b->manager->power_key_long_press_event_source) {
/* Long press event timer is still pending and key release
event happened. This means that key press duration was
insufficient to trigger a long press event
*/
+ log_struct(LOG_INFO,
+ LOG_MESSAGE("Power key pressed short."),
+ "MESSAGE_ID=" SD_MESSAGE_POWER_KEY_STR);
+
+ b->manager->power_key_long_press_event_source = sd_event_source_unref(b->manager->power_key_long_press_event_source);
+
+ manager_handle_action(b->manager, INHIBIT_HANDLE_POWER_KEY, b->manager->handle_power_key, b->manager->power_key_ignore_inhibited, true);
+ }
+ break;
+
+ case KEY_RESTART:
+ if (b->manager->reboot_key_long_press_event_source) {
log_struct(LOG_INFO,
LOG_MESSAGE("Reboot key pressed short."),
"MESSAGE_ID=" SD_MESSAGE_REBOOT_KEY_STR);
manager_handle_action(b->manager, INHIBIT_HANDLE_REBOOT_KEY, b->manager->handle_reboot_key, b->manager->reboot_key_ignore_inhibited, true);
}
+ break;
+
+ case KEY_SLEEP:
+ if (b->manager->suspend_key_long_press_event_source) {
+ log_struct(LOG_INFO,
+ LOG_MESSAGE("Suspend key pressed short."),
+ "MESSAGE_ID=" SD_MESSAGE_SUSPEND_KEY_STR);
+
+ b->manager->suspend_key_long_press_event_source = sd_event_source_unref(b->manager->suspend_key_long_press_event_source);
+
+ manager_handle_action(b->manager, INHIBIT_HANDLE_SUSPEND_KEY, b->manager->handle_suspend_key, b->manager->suspend_key_ignore_inhibited, true);
+ }
+ break;
+ case KEY_SUSPEND:
+ if (b->manager->hibernate_key_long_press_event_source) {
+ log_struct(LOG_INFO,
+ LOG_MESSAGE("Hibernate key pressed short."),
+ "MESSAGE_ID=" SD_MESSAGE_HIBERNATE_KEY_STR);
+
+ b->manager->hibernate_key_long_press_event_source = sd_event_source_unref(b->manager->hibernate_key_long_press_event_source);
+
+ manager_handle_action(b->manager, INHIBIT_HANDLE_HIBERNATE_KEY, b->manager->handle_hibernate_key, b->manager->hibernate_key_ignore_inhibited, true);
+ }
+ break;
}
} else if (ev.type == EV_SW && ev.value > 0) {
assert(message);
assert(w >= 0);
assert(w <= _INHIBIT_WHAT_MAX);
+ assert(action);
+ assert(action_multiple_sessions);
+ assert(action_ignore_inhibit);
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
if (r < 0)
blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL);
interactive = flags & SD_LOGIND_INTERACTIVE;
- if (multiple_sessions && action_multiple_sessions) {
+ if (multiple_sessions) {
r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_multiple_sessions, NULL, interactive, UID_INVALID, &m->polkit_registry, error);
if (r < 0)
return r;
return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED,
"Access denied to root due to active block inhibitor");
- if (action_ignore_inhibit) {
- r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_ignore_inhibit, NULL, interactive, UID_INVALID, &m->polkit_registry, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
- }
+ r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_ignore_inhibit, NULL, interactive, UID_INVALID, &m->polkit_registry, error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
}
- if (!multiple_sessions && !blocked && action) {
+ if (!multiple_sessions && !blocked) {
r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action, NULL, interactive, UID_INVALID, &m->polkit_registry, error);
if (r < 0)
return r;
else if (streq(m->scheduled_shutdown_type, "halt"))
target = SPECIAL_HALT_TARGET;
else
- assert_not_reached("unexpected shutdown type");
+ assert_not_reached();
/* Don't allow multiple jobs being executed at the same time */
if (m->action_what > 0) {
}
int inhibitor_load(Inhibitor *i) {
-
- _cleanup_free_ char
- *what = NULL,
- *uid = NULL,
- *pid = NULL,
- *who = NULL,
- *why = NULL,
- *mode = NULL;
-
+ _cleanup_free_ char *what = NULL, *uid = NULL, *pid = NULL, *who = NULL, *why = NULL, *mode = NULL;
InhibitWhat w;
InhibitMode mm;
char *cc;
+ ssize_t l;
int r;
r = parse_env_file(NULL, i->state_file,
}
if (who) {
- r = cunescape(who, 0, &cc);
- if (r < 0)
- return log_oom();
+ l = cunescape(who, 0, &cc);
+ if (l < 0)
+ return log_debug_errno(l, "Failed to unescape \"who\" of inhibitor: %m");
free_and_replace(i->who, cc);
}
if (why) {
- r = cunescape(why, 0, &cc);
- if (r < 0)
- return log_oom();
+ l = cunescape(why, 0, &cc);
+ if (l < 0)
+ return log_debug_errno(l, "Failed to unescape \"why\" of inhibitor: %m");
free_and_replace(i->why, cc);
}
* that so fail at all times and let caller retry in inactive state. */
r = sd_drmsetmaster(fd);
if (r < 0) {
- close_nointr(fd);
+ (void) close_nointr(fd);
return r;
}
} else
if (r < 0)
log_warning_errno(r, "Failed to enqueue user stop event source, ignoring: %m");
- if (DEBUG_LOGGING) {
- char s[FORMAT_TIMESPAN_MAX];
-
+ if (DEBUG_LOGGING)
log_debug("Last session of user '%s' logged out, terminating user context in %s.",
u->user_record->user_name,
- format_timespan(s, sizeof(s), user_stop_delay, USEC_PER_MSEC));
- }
+ FORMAT_TIMESPAN(user_stop_delay, USEC_PER_MSEC));
}
static const char* const user_state_table[_USER_STATE_MAX] = {
}
static int warn_wall(Manager *m, usec_t n) {
- char date[FORMAT_TIMESTAMP_MAX] = {};
_cleanup_free_ char *l = NULL, *username = NULL;
usec_t left;
int r;
isempty(m->wall_message) ? "" : "\n",
m->scheduled_shutdown_type,
left ? "at " : "NOW",
- left ? format_timestamp(date, sizeof(date), m->scheduled_shutdown_timeout) : "");
+ left ? FORMAT_TIMESTAMP(m->scheduled_shutdown_timeout) : "");
if (r < 0) {
log_oom();
return 0;
* "systemd-user" we simply set XDG_RUNTIME_DIR and
* leave. */
- (void) pam_get_item(handle, PAM_SERVICE, (const void**) &service);
+ r = pam_get_item(handle, PAM_SERVICE, (const void**) &service);
+ if (!IN_SET(r, PAM_BAD_ITEM, PAM_SUCCESS)) {
+ pam_syslog(handle, LOG_ERR, "Failed to get PAM service: %s", pam_strerror(handle, r));
+ return r;
+ }
if (streq_ptr(service, "systemd-user")) {
char rt[STRLEN("/run/user/") + DECIMAL_STR_MAX(uid_t)];
/* Otherwise, we ask logind to create a session for us */
- (void) pam_get_item(handle, PAM_XDISPLAY, (const void**) &display);
- (void) pam_get_item(handle, PAM_TTY, (const void**) &tty);
- (void) pam_get_item(handle, PAM_RUSER, (const void**) &remote_user);
- (void) pam_get_item(handle, PAM_RHOST, (const void**) &remote_host);
+ r = pam_get_item(handle, PAM_XDISPLAY, (const void**) &display);
+ if (!IN_SET(r, PAM_BAD_ITEM, PAM_SUCCESS)) {
+ pam_syslog(handle, LOG_ERR, "Failed to get PAM XDISPLAY: %s", pam_strerror(handle, r));
+ return r;
+ }
+ r = pam_get_item(handle, PAM_TTY, (const void**) &tty);
+ if (!IN_SET(r, PAM_BAD_ITEM, PAM_SUCCESS)) {
+ pam_syslog(handle, LOG_ERR, "Failed to get PAM TTY: %s", pam_strerror(handle, r));
+ return r;
+ }
+ r = pam_get_item(handle, PAM_RUSER, (const void**) &remote_user);
+ if (!IN_SET(r, PAM_BAD_ITEM, PAM_SUCCESS)) {
+ pam_syslog(handle, LOG_ERR, "Failed to get PAM RUSER: %s", pam_strerror(handle, r));
+ return r;
+ }
+ r = pam_get_item(handle, PAM_RHOST, (const void**) &remote_host);
+ if (!IN_SET(r, PAM_BAD_ITEM, PAM_SUCCESS)) {
+ pam_syslog(handle, LOG_ERR, "Failed to get PAM RHOST: %s", pam_strerror(handle, r));
+ return r;
+ }
seat = getenv_harder(handle, "XDG_SEAT", NULL);
cvtnr = getenv_harder(handle, "XDG_VTNR", NULL);
remote = !isempty(remote_host) && !is_localhost(remote_host);
- (void) pam_get_data(handle, "systemd.memory_max", (const void **)&memory_max);
- (void) pam_get_data(handle, "systemd.tasks_max", (const void **)&tasks_max);
- (void) pam_get_data(handle, "systemd.cpu_weight", (const void **)&cpu_weight);
- (void) pam_get_data(handle, "systemd.io_weight", (const void **)&io_weight);
- (void) pam_get_data(handle, "systemd.runtime_max_sec", (const void **)&runtime_max_sec);
+ r = pam_get_data(handle, "systemd.memory_max", (const void **)&memory_max);
+ if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) {
+ pam_syslog(handle, LOG_ERR, "Failed to get PAM systemd.memory_max data: %s", pam_strerror(handle, r));
+ return r;
+ }
+ r = pam_get_data(handle, "systemd.tasks_max", (const void **)&tasks_max);
+ if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) {
+ pam_syslog(handle, LOG_ERR, "Failed to get PAM systemd.tasks_max data: %s", pam_strerror(handle, r));
+ return r;
+ }
+ r = pam_get_data(handle, "systemd.cpu_weight", (const void **)&cpu_weight);
+ if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) {
+ pam_syslog(handle, LOG_ERR, "Failed to get PAM systemd.cpu_weight data: %s", pam_strerror(handle, r));
+ return r;
+ }
+ r = pam_get_data(handle, "systemd.io_weight", (const void **)&io_weight);
+ if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) {
+ pam_syslog(handle, LOG_ERR, "Failed to get PAM systemd.io_weight data: %s", pam_strerror(handle, r));
+ return r;
+ }
+ r = pam_get_data(handle, "systemd.runtime_max_sec", (const void **)&runtime_max_sec);
+ if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) {
+ pam_syslog(handle, LOG_ERR, "Failed to get PAM systemd.runtime_max_sec data: %s", pam_strerror(handle, r));
+ return r;
+ }
/* Talk to logind over the message bus */
/* Only release session if it wasn't pre-existing when we
* tried to create it */
- (void) pam_get_data(handle, "systemd.existing", &existing);
+ r = pam_get_data(handle, "systemd.existing", &existing);
+ if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) {
+ pam_syslog(handle, LOG_ERR, "Failed to get PAM systemd.existing data: %s", pam_strerror(handle, r));
+ return r;
+ }
id = pam_getenv(handle, "XDG_SESSION_ID");
if (id && !existing) {
return do_mount(argv[2]);
if (streq(argv[1], "stop"))
return do_umount(argv[2]);
- assert_not_reached("Unknown verb!");
+ assert_not_reached();
}
DEFINE_MAIN_FUNCTION(run);
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
if (optind < argc)
}
static void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) {
- char since1[FORMAT_TIMESTAMP_RELATIVE_MAX];
- char since2[FORMAT_TIMESTAMP_MAX];
- _cleanup_free_ char *addresses = NULL;
- const char *s1, *s2;
+ _cleanup_free_ char *addresses = NULL, *s1 = NULL, *s2 = NULL;
int ifi = -1;
assert(bus);
else
putchar('\n');
- s1 = format_timestamp_relative(since1, sizeof(since1), i->timestamp.realtime);
- s2 = format_timestamp(since2, sizeof(since2), i->timestamp.realtime);
+ s1 = strdup(strempty(FORMAT_TIMESTAMP_RELATIVE(i->timestamp.realtime)));
+ s2 = strdup(strempty(FORMAT_TIMESTAMP(i->timestamp.realtime)));
- if (s1)
- printf("\t Since: %s; %s\n", s2, s1);
- else if (s2)
+ if (!isempty(s1))
+ printf("\t Since: %s; %s\n", strna(s2), s1);
+ else if (!isempty(s2))
printf("\t Since: %s\n", s2);
if (i->leader > 0) {
} ImageStatusInfo;
static void print_image_status_info(sd_bus *bus, ImageStatusInfo *i) {
- char ts_relative[FORMAT_TIMESTAMP_RELATIVE_MAX];
- char ts_absolute[FORMAT_TIMESTAMP_MAX];
- char bs[FORMAT_BYTES_MAX];
- char bs_exclusive[FORMAT_BYTES_MAX];
- const char *s1, *s2, *s3, *s4;
-
assert(bus);
assert(i);
i->read_only ? "read-only" : "writable",
i->read_only ? ansi_normal() : "");
- s1 = format_timestamp_relative(ts_relative, sizeof(ts_relative), i->crtime);
- s2 = format_timestamp(ts_absolute, sizeof(ts_absolute), i->crtime);
- if (s1 && s2)
- printf("\t Created: %s; %s\n", s2, s1);
- else if (s2)
- printf("\t Created: %s\n", s2);
-
- s1 = format_timestamp_relative(ts_relative, sizeof(ts_relative), i->mtime);
- s2 = format_timestamp(ts_absolute, sizeof(ts_absolute), i->mtime);
- if (s1 && s2)
- printf("\tModified: %s; %s\n", s2, s1);
- else if (s2)
- printf("\tModified: %s\n", s2);
-
- s3 = format_bytes(bs, sizeof(bs), i->usage);
- s4 = i->usage_exclusive != i->usage ? format_bytes(bs_exclusive, sizeof(bs_exclusive), i->usage_exclusive) : NULL;
- if (s3 && s4)
- printf("\t Usage: %s (exclusive: %s)\n", s3, s4);
- else if (s3)
- printf("\t Usage: %s\n", s3);
-
- s3 = format_bytes(bs, sizeof(bs), i->limit);
- s4 = i->limit_exclusive != i->limit ? format_bytes(bs_exclusive, sizeof(bs_exclusive), i->limit_exclusive) : NULL;
- if (s3 && s4)
- printf("\t Limit: %s (exclusive: %s)\n", s3, s4);
- else if (s3)
- printf("\t Limit: %s\n", s3);
+ if (i->crtime > 0 && i->crtime < USEC_INFINITY)
+ printf("\t Created: %s; %s\n",
+ FORMAT_TIMESTAMP(i->crtime), FORMAT_TIMESTAMP_RELATIVE(i->crtime));
+
+ if (i->mtime > 0 && i->mtime < USEC_INFINITY)
+ printf("\tModified: %s; %s\n",
+ FORMAT_TIMESTAMP(i->mtime), FORMAT_TIMESTAMP_RELATIVE(i->mtime));
+
+ if (i->usage != UINT64_MAX) {
+ if (i->usage_exclusive != i->usage && i->usage_exclusive != UINT64_MAX)
+ printf("\t Usage: %s (exclusive: %s)\n",
+ FORMAT_BYTES(i->usage), FORMAT_BYTES(i->usage_exclusive));
+ else
+ printf("\t Usage: %s\n", FORMAT_BYTES(i->usage));
+ }
+
+ if (i->limit != UINT64_MAX) {
+ if (i->limit_exclusive != i->limit && i->limit_exclusive != UINT64_MAX)
+ printf("\t Limit: %s (exclusive: %s)\n",
+ FORMAT_BYTES(i->limit), FORMAT_BYTES(i->limit_exclusive));
+ else
+ printf("\t Limit: %s\n", FORMAT_BYTES(i->limit));
+ }
}
static int show_image_info(sd_bus *bus, const char *path, bool *new_line) {
} PoolStatusInfo;
static void print_pool_status_info(sd_bus *bus, PoolStatusInfo *i) {
- char bs[FORMAT_BYTES_MAX], *s;
-
if (i->path)
printf("\t Path: %s\n", i->path);
- s = format_bytes(bs, sizeof(bs), i->usage);
- if (s)
- printf("\t Usage: %s\n", s);
+ if (i->usage != UINT64_MAX)
+ printf("\t Usage: %s\n", FORMAT_BYTES(i->usage));
- s = format_bytes(bs, sizeof(bs), i->limit);
- if (s)
- printf("\t Limit: %s\n", s);
+ if (i->limit != UINT64_MAX)
+ printf("\t Limit: %s\n", FORMAT_BYTES(i->limit));
}
static int show_pool_info(sd_bus *bus) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
uint64_t usage, total = 0;
- char fb[FORMAT_BYTES_MAX];
sd_bus *bus = userdata;
const char *name;
unsigned c = 0;
total = UINT64_MAX;
} else {
log_info("Removed image '%s'. Freed exclusive disk space: %s",
- name, format_bytes(fb, sizeof(fb), usage));
+ name, FORMAT_BYTES(usage));
if (total != UINT64_MAX)
total += usage;
}
log_info("Removed %u images in total.", c);
else
log_info("Removed %u images in total. Total freed exclusive disk space: %s.",
- c, format_bytes(fb, sizeof(fb), total));
+ c, FORMAT_BYTES(total));
return 0;
}
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
}
desc = mfree(desc);
*ret_gid = converted_gid;
- *ret_description = desc;
+ *ret_description = TAKE_PTR(desc);
return 0;
}
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
return 1;
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
if (arg_user && arg_transport != BUS_TRANSPORT_LOCAL)
break;
default:
- assert_not_reached("Unexpected action.");
+ assert_not_reached();
}
return r;
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
return 1;
]
tests += [
+ [['src/network/test-networkd-address.c'],
+ [libnetworkd_core,
+ libsystemd_network],
+ [],
+ network_includes],
+
[['src/network/test-networkd-conf.c'],
[libnetworkd_core,
libsystemd_network],
encap_type = FOU_ENCAP_GUE;
break;
default:
- assert_not_reached("invalid encap type");
+ assert_not_reached();
}
r = sd_netlink_message_append_u8(m, FOU_ATTR_TYPE, encap_type);
filename);
break;
default:
- assert_not_reached("Invalid fou encap type");
+ assert_not_reached();
}
if (t->peer_family == AF_UNSPEC && t->peer_port > 0)
return r;
break;
default:
- assert_not_reached("Cannot join independent netdev");
+ assert_not_reached();
}
return 0;
t = GRETAP(netdev);
break;
default:
- assert_not_reached("invalid netdev kind");
+ assert_not_reached();
}
assert(t);
t = ERSPAN(netdev);
break;
default:
- assert_not_reached("Invalid tunnel kind");
+ assert_not_reached();
}
assert(t);
t = SIT(n);
break;
default:
- assert_not_reached("invalid netdev kind");
+ assert_not_reached();
}
assert(t);
t = GRETAP(n);
break;
default:
- assert_not_reached("invalid netdev kind");
+ assert_not_reached();
}
assert(t);
}
if (info->has_bitrates) {
- char tx[FORMAT_BYTES_MAX], rx[FORMAT_BYTES_MAX];
-
r = table_add_many(table,
TABLE_EMPTY,
TABLE_STRING, "Bit Rate (Tx/Rx):");
if (r < 0)
return table_log_add_error(r);
r = table_add_cell_stringf(table, NULL, "%sbps/%sbps",
- format_bytes_full(tx, sizeof tx, info->tx_bitrate, 0),
- format_bytes_full(rx, sizeof rx, info->rx_bitrate, 0));
+ FORMAT_BYTES_FULL(info->tx_bitrate, 0),
+ FORMAT_BYTES_FULL(info->rx_bitrate, 0));
if (r < 0)
return table_log_add_error(r);
}
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
}
#include "parse-util.h"
#include "string-util.h"
#include "strv.h"
+#include "strxcpyx.h"
#define ADDRESSES_PER_LINK_MAX 2048U
#define STATIC_ADDRESSES_PER_NETWORK_MAX 1024U
set_remove(address->link->dhcp6_pd_addresses, address);
set_remove(address->link->dhcp6_pd_addresses_old, address);
SET_FOREACH(n, address->link->ndisc_addresses)
- if (n->address == address)
+ if (address_equal(n->address, address))
free(set_remove(address->link->ndisc_addresses, n));
if (address->family == AF_INET6 &&
return false;
}
+const char* format_lifetime(char *buf, size_t l, uint32_t lifetime) {
+ assert(buf);
+ assert(l > 4);
+
+ if (lifetime == CACHE_INFO_INFINITY_LIFE_TIME)
+ return "forever";
+
+ sprintf(buf, "for ");
+ /* format_timespan() never fails */
+ assert_se(format_timespan(buf + 4, l - 4, lifetime * USEC_PER_SEC, USEC_PER_SEC));
+ return buf;
+}
+
static void log_address_debug(const Address *address, const char *str, const Link *link) {
_cleanup_free_ char *addr = NULL, *peer = NULL, *flags_str = NULL;
- char valid_buf[FORMAT_TIMESPAN_MAX], preferred_buf[FORMAT_TIMESPAN_MAX];
- const char *valid_str = NULL, *preferred_str = NULL;
- bool has_peer;
assert(address);
assert(str);
return;
(void) in_addr_to_string(address->family, &address->in_addr, &addr);
- has_peer = in_addr_is_set(address->family, &address->in_addr_peer);
- if (has_peer)
+ if (in_addr_is_set(address->family, &address->in_addr_peer))
(void) in_addr_to_string(address->family, &address->in_addr_peer, &peer);
- if (address->cinfo.ifa_valid != CACHE_INFO_INFINITY_LIFE_TIME)
- valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX,
- address->cinfo.ifa_valid * USEC_PER_SEC,
- USEC_PER_SEC);
-
- if (address->cinfo.ifa_prefered != CACHE_INFO_INFINITY_LIFE_TIME)
- preferred_str = format_timespan(preferred_buf, FORMAT_TIMESPAN_MAX,
- address->cinfo.ifa_prefered * USEC_PER_SEC,
- USEC_PER_SEC);
-
(void) address_flags_to_string_alloc(address->flags, address->family, &flags_str);
- log_link_debug(link, "%s address: %s%s%s/%u (valid %s%s, preferred %s%s), flags: %s",
- str, strnull(addr), has_peer ? " peer " : "",
- has_peer ? strnull(peer) : "", address->prefixlen,
- valid_str ? "for " : "forever", strempty(valid_str),
- preferred_str ? "for " : "forever", strempty(preferred_str),
+ log_link_debug(link, "%s address: %s%s%s/%u (valid %s, preferred %s), flags: %s",
+ str, strnull(addr), peer ? " peer " : "", strempty(peer), address->prefixlen,
+ FORMAT_LIFETIME(address->cinfo.ifa_valid),
+ FORMAT_LIFETIME(address->cinfo.ifa_prefered),
strna(flags_str));
}
if (r <= 0)
return r;
- r = address_get(link, req->address, &a);
- if (r < 0)
- return r;
-
- r = address_configure(a, link, req->netlink_handler);
+ r = address_configure(req->address, link, req->netlink_handler);
if (r < 0)
return r;
/* To prevent a double decrement on failure in after_configure(). */
req->message_counter = NULL;
+ r = address_get(link, req->address, &a);
+ if (r < 0)
+ return r;
+
if (req->after_configure) {
r = req->after_configure(req, a);
if (r < 0)
break;
default:
- assert_not_reached("Received unsupported address family");
+ assert_not_reached();
}
r = sd_netlink_message_read_cache_info(message, IFA_CACHEINFO, &tmp->cinfo);
break;
default:
- assert_not_reached("Received invalid RTNL message type");
+ assert_not_reached();
}
return 1;
address_ready_callback_t callback;
} Address;
+const char* format_lifetime(char *buf, size_t l, uint32_t lifetime) _warn_unused_result_;
+/* Note: the lifetime of the compound literal is the immediately surrounding block,
+ * see C11 §6.5.2.5, and
+ * https://stackoverflow.com/questions/34880638/compound-literal-lifetime-and-if-blocks */
+#define FORMAT_LIFETIME(lifetime) \
+ format_lifetime((char[FORMAT_TIMESPAN_MAX+STRLEN("for ")]){}, FORMAT_TIMESPAN_MAX+STRLEN("for "), lifetime)
+
int address_new(Address **ret);
-Address *address_free(Address *address);
+Address* address_free(Address *address);
int address_get(Link *link, const Address *in, Address **ret);
int address_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, const char *error_msg);
int address_remove(const Address *address, Link *link);
break;
default:
- assert_not_reached("Invalid address family");
+ assert_not_reached();
}
/* create new RTM message */
}
if (link->network->can_restart_us > 0) {
- char time_string[FORMAT_TIMESPAN_MAX];
uint64_t restart_ms;
if (link->network->can_restart_us == USEC_INFINITY)
else
restart_ms = DIV_ROUND_UP(link->network->can_restart_us, USEC_PER_MSEC);
- format_timespan(time_string, FORMAT_TIMESPAN_MAX, restart_ms * 1000, MSEC_PER_SEC);
-
if (restart_ms > UINT32_MAX)
- return log_link_debug_errno(link, SYNTHETIC_ERRNO(ERANGE), "restart timeout (%s) too big.", time_string);
+ return log_link_debug_errno(link, SYNTHETIC_ERRNO(ERANGE), "restart timeout (%s) too big.",
+ FORMAT_TIMESPAN(restart_ms * 1000, MSEC_PER_SEC));
- log_link_debug(link, "Setting restart = %s", time_string);
+ log_link_debug(link, "Setting restart = %s", FORMAT_TIMESPAN(restart_ms * 1000, MSEC_PER_SEC));
r = sd_netlink_message_append_u32(m, IFLA_CAN_RESTART_MS, restart_ms);
if (r < 0)
return r;
if (m->use_speed_meter && m->speed_meter_interval_usec < SPEED_METER_MINIMUM_TIME_INTERVAL) {
- char buf[FORMAT_TIMESPAN_MAX];
-
log_warning("SpeedMeterIntervalSec= is too small, using %s.",
- format_timespan(buf, sizeof buf, SPEED_METER_MINIMUM_TIME_INTERVAL, USEC_PER_SEC));
+ FORMAT_TIMESPAN(SPEED_METER_MINIMUM_TIME_INTERVAL, USEC_PER_SEC));
m->speed_meter_interval_usec = SPEED_METER_MINIMUM_TIME_INTERVAL;
}
break;
default:
- assert_not_reached("Unexpected server type");
+ assert_not_reached();
}
if (use_dhcp_lease_data && link->dhcp_lease) {
#include <linux/if.h>
#include <linux/if_arp.h>
-#include "escape.h"
#include "alloc-util.h"
#include "dhcp-client-internal.h"
#include "hostname-setup.h"
#include "string-table.h"
#include "strv.h"
#include "sysctl-util.h"
-#include "web-util.h"
static int dhcp4_request_address_and_routes(Link *link, bool announce);
static int dhcp4_remove_all(Link *link);
assert(link->dhcp_lease);
assert(ret_default_gw);
- if (!link->network->dhcp_use_routes)
- return 0;
-
n = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes);
if (IN_SET(n, 0, -ENODATA)) {
log_link_debug(link, "DHCP: No static routes received from DHCP server.");
if (classless_route && static_route)
log_link_debug(link, "Classless static routes received from DHCP server: ignoring static-route option");
+ if (!link->network->dhcp_use_routes) {
+ if (!classless_route)
+ return 0;
+
+ /* Even if UseRoutes=no, try to find default gateway to make semi-static routes and
+ * routes to DNS or NTP servers can be configured in later steps. */
+ for (int i = 0; i < n; i++) {
+ struct in_addr dst;
+ uint8_t prefixlen;
+
+ if (sd_dhcp_route_get_option(static_routes[i]) != SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE)
+ continue;
+
+ r = sd_dhcp_route_get_destination(static_routes[i], &dst);
+ if (r < 0)
+ return r;
+
+ if (in4_addr_is_set(&dst))
+ continue;
+
+ r = sd_dhcp_route_get_destination_prefix_length(static_routes[i], &prefixlen);
+ if (r < 0)
+ return r;
+
+ if (prefixlen != 0)
+ continue;
+
+ r = sd_dhcp_route_get_gateway(static_routes[i], ret_default_gw);
+ if (r < 0)
+ return r;
+
+ break;
+ }
+
+ /* Do not return 1 here, to ensure the router option can override the default gateway
+ * that was found. */
+ return 0;
+ }
+
for (int i = 0; i < n; i++) {
_cleanup_(route_freep) Route *route = NULL;
struct in_addr gw;
return classless_route;
}
-static int dhcp4_request_gateway(Link *link, struct in_addr *ret_gw) {
+static int dhcp4_request_gateway(Link *link, struct in_addr *gw) {
_cleanup_(route_freep) Route *route = NULL;
const struct in_addr *router;
struct in_addr address;
- Route *rt;
int r;
assert(link);
assert(link->dhcp_lease);
- assert(ret_gw);
-
- if (!link->network->dhcp_use_gateway)
- return 0;
+ assert(gw);
r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
if (r < 0)
return 0;
}
+ if (!link->network->dhcp_use_gateway) {
+ /* When no classless static route is provided, even if UseGateway=no, use the gateway
+ * address to configure semi-static routes or routes to DNS or NTP servers. Note, if
+ * neither UseRoutes= nor UseGateway= is disabled, use the default gateway in classless
+ * static routes if provided (in that case, in4_addr_is_null(gw) below is true). */
+ if (in4_addr_is_null(gw))
+ *gw = router[0];
+ return 0;
+ }
+
/* The dhcp netmask may mask out the gateway. First, add an explicit route for the gateway host
* so that we can route no matter the netmask or existing kernel route tables. */
r = dhcp4_request_route_to_gateway(link, &router[0]);
if (r < 0)
return r;
+ /* When no classless static route is provided, or UseRoutes=no, then use the router address to
+ * configure semi-static routes and routes to DNS or NTP servers in later steps. */
+ *gw = router[0];
+ return 0;
+}
+
+static int dhcp4_request_semi_static_routes(Link *link, const struct in_addr *gw) {
+ Route *rt;
+ int r;
+
+ assert(link);
+ assert(link->dhcp_lease);
+ assert(link->network);
+ assert(gw);
+
+ if (in4_addr_is_null(gw))
+ return 0;
+
HASHMAP_FOREACH(rt, link->network->routes_by_section) {
+ _cleanup_(route_freep) Route *route = NULL;
+
if (!rt->gateway_from_dhcp_or_ra)
continue;
if (rt->gw_family != AF_INET)
continue;
+ r = dhcp4_request_route_to_gateway(link, gw);
+ if (r < 0)
+ return r;
+
r = route_dup(rt, &route);
if (r < 0)
return r;
- route->gw.in = router[0];
+ route->gw.in = *gw;
if (!route->protocol_set)
route->protocol = RTPROT_DHCP;
if (!route->priority_set)
return r;
}
- *ret_gw = router[0];
return 0;
}
return log_link_error_errno(link, r, "DHCP error: Could not request gateway: %m");
}
+ r = dhcp4_request_semi_static_routes(link, &gw);
+ if (r < 0)
+ return log_link_error_errno(link, r, "DHCP error: Could not request routes with Gateway=_dhcp4 setting: %m");
+
r = dhcp4_request_routes_to_dns(link, &gw);
if (r < 0)
return log_link_error_errno(link, r, "DHCP error: Could not request routes to DNS servers: %m");
break;
}
default:
- assert_not_reached("Unknown client identifier type.");
+ assert_not_reached();
}
return 0;
return 0;
}
-int config_parse_dhcp_mud_url(
- const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- _cleanup_free_ char *unescaped = NULL;
- Network *network = data;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- if (isempty(rvalue)) {
- network->dhcp_mudurl = mfree(network->dhcp_mudurl);
- return 0;
- }
-
- r = cunescape(rvalue, 0, &unescaped);
- if (r < 0) {
- log_syntax(unit, LOG_WARNING, filename, line, r,
- "Failed to Failed to unescape MUD URL, ignoring: %s", rvalue);
- return 0;
- }
-
- if (!http_url_is_valid(unescaped) || strlen(unescaped) > 255) {
- log_syntax(unit, LOG_WARNING, filename, line, 0,
- "Failed to parse MUD URL '%s', ignoring: %m", rvalue);
-
- return 0;
- }
-
- return free_and_strdup_warn(&network->dhcp_mudurl, unescaped);
-}
-
int config_parse_dhcp_fallback_lease_lifetime(const char *unit,
const char *filename,
unsigned line,
#include "sd-dhcp6-client.h"
-#include "escape.h"
#include "hashmap.h"
#include "hostname-setup.h"
#include "hostname-util.h"
#include "string-table.h"
#include "string-util.h"
#include "radv-internal.h"
-#include "web-util.h"
bool link_dhcp6_with_address_enabled(Link *link) {
if (!link_dhcp6_enabled(link))
}
static void log_dhcp6_pd_address(Link *link, const Address *address) {
- char valid_buf[FORMAT_TIMESPAN_MAX], preferred_buf[FORMAT_TIMESPAN_MAX];
- const char *valid_str = NULL, *preferred_str = NULL;
_cleanup_free_ char *buffer = NULL;
int log_level;
return;
(void) in6_addr_prefix_to_string(&address->in_addr.in6, address->prefixlen, &buffer);
- if (address->cinfo.ifa_valid != CACHE_INFO_INFINITY_LIFE_TIME)
- valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX,
- address->cinfo.ifa_valid * USEC_PER_SEC,
- USEC_PER_SEC);
- if (address->cinfo.ifa_prefered != CACHE_INFO_INFINITY_LIFE_TIME)
- preferred_str = format_timespan(preferred_buf, FORMAT_TIMESPAN_MAX,
- address->cinfo.ifa_prefered * USEC_PER_SEC,
- USEC_PER_SEC);
-
- log_link_full(link, log_level, "DHCPv6-PD address %s (valid %s%s, preferred %s%s)",
+
+ log_link_full(link, log_level, "DHCPv6-PD address %s (valid %s, preferred %s)",
strna(buffer),
- valid_str ? "for " : "forever", strempty(valid_str),
- preferred_str ? "for " : "forever", strempty(preferred_str));
+ FORMAT_LIFETIME(address->cinfo.ifa_valid),
+ FORMAT_LIFETIME(address->cinfo.ifa_prefered));
}
static int dhcp6_pd_after_address_configure(Request *req, void *object) {
}
static void log_dhcp6_address(Link *link, const Address *address, char **ret) {
- char valid_buf[FORMAT_TIMESPAN_MAX], preferred_buf[FORMAT_TIMESPAN_MAX];
- const char *valid_str = NULL, *preferred_str = NULL;
_cleanup_free_ char *buffer = NULL;
bool by_ndisc = false;
Address *existing;
assert(address->family == AF_INET6);
(void) in6_addr_prefix_to_string(&address->in_addr.in6, address->prefixlen, &buffer);
- if (address->cinfo.ifa_valid != CACHE_INFO_INFINITY_LIFE_TIME)
- valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX,
- address->cinfo.ifa_valid * USEC_PER_SEC,
- USEC_PER_SEC);
- if (address->cinfo.ifa_prefered != CACHE_INFO_INFINITY_LIFE_TIME)
- preferred_str = format_timespan(preferred_buf, FORMAT_TIMESPAN_MAX,
- address->cinfo.ifa_prefered * USEC_PER_SEC,
- USEC_PER_SEC);
r = address_get(link, address, &existing);
if (r < 0) {
break;
}
- log_link_warning(link, "DHCPv6 address %s (valid %s%s, preferred %s%s) conflicts the existing address %s %s.",
+ log_link_warning(link, "DHCPv6 address %s (valid %s, preferred %s) conflicts the existing address %s %s.",
strna(buffer),
- valid_str ? "for " : "forever", strempty(valid_str),
- preferred_str ? "for " : "forever", strempty(preferred_str),
+ FORMAT_LIFETIME(address->cinfo.ifa_valid),
+ FORMAT_LIFETIME(address->cinfo.ifa_prefered),
strna(buffer),
by_ndisc ? "assigned by NDISC. Please try to use or update IPv6Token= setting "
"to change the address generated by NDISC, or disable UseAutonomousPrefix=" : "");
goto finalize;
simple_log:
- log_link_full(link, log_level, "DHCPv6 address %s (valid %s%s, preferred %s%s)",
+ log_link_full(link, log_level, "DHCPv6 address %s (valid %s, preferred %s)",
strna(buffer),
- valid_str ? "for " : "forever", strempty(valid_str),
- preferred_str ? "for " : "forever", strempty(preferred_str));
+ FORMAT_LIFETIME(address->cinfo.ifa_valid),
+ FORMAT_LIFETIME(address->cinfo.ifa_prefered));
finalize:
if (ret)
return 0;
}
-int config_parse_dhcp6_mud_url(
- const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- _cleanup_free_ char *unescaped = NULL;
- Network *network = data;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- if (isempty(rvalue)) {
- network->dhcp6_mudurl = mfree(network->dhcp6_mudurl);
- return 0;
- }
-
- r = cunescape(rvalue, 0, &unescaped);
- if (r < 0) {
- log_syntax(unit, LOG_WARNING, filename, line, r,
- "Failed to Failed to unescape MUD URL, ignoring: %s", rvalue);
- return 0;
- }
-
- if (!http_url_is_valid(unescaped) || strlen(unescaped) > UINT8_MAX) {
- log_syntax(unit, LOG_WARNING, filename, line, 0,
- "Failed to parse MUD URL '%s', ignoring: %m", rvalue);
- return 0;
- }
-
- return free_and_replace(network->dhcp6_mudurl, unescaped);
-}
-
DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp6_client_start_mode, dhcp6_client_start_mode, DHCP6ClientStartMode,
"Failed to parse WithoutRA= setting");
break;
default:
- assert_not_reached("Invalid IPv4ACD event.");
+ assert_not_reached();
}
}
/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#include <net/if.h>
#include <netinet/in.h>
#include <linux/if.h>
#include <linux/if_arp.h>
#include <linux/if_link.h>
+#include <linux/netdevice.h>
#include <sys/socket.h>
#include <unistd.h>
#include "ethtool-util.h"
#include "fd-util.h"
#include "fileio.h"
+#include "format-util.h"
#include "fs-util.h"
#include "ipvlan.h"
#include "missing_network.h"
}
static int link_update_name(Link *link, sd_netlink_message *message) {
+ char ifname_from_index[IF_NAMESIZE + 1];
const char *ifname;
int r;
if (streq(ifname, link->ifname))
return 0;
+ if (!format_ifname(link->ifindex, ifname_from_index))
+ return log_link_debug_errno(link, SYNTHETIC_ERRNO(ENXIO), "Could not get interface name for index %i.", link->ifindex);
+
+ if (!streq(ifname, ifname_from_index)) {
+ log_link_debug(link, "New interface name '%s' received from the kernel does not correspond "
+ "with the name currently configured on the actual interface '%s'. Ignoring.",
+ ifname, ifname_from_index);
+ return 0;
+ }
+
log_link_info(link, "Interface name change detected, renamed to %s.", ifname);
hashmap_remove(link->manager->links_by_name, link->ifname);
if (r < 0)
return log_link_debug_errno(link, r, "Failed to manage link by its new name: %m");
+ if (link->dhcp_client) {
+ r = sd_dhcp_client_set_ifname(link->dhcp_client, link->ifname);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Failed to update interface name in DHCP client: %m");
+ }
+
+ if (link->dhcp6_client) {
+ r = sd_dhcp6_client_set_ifname(link->dhcp6_client, link->ifname);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Failed to update interface name in DHCP6 client: %m");
+ }
+
+ if (link->ndisc) {
+ r = sd_ndisc_set_ifname(link->ndisc, link->ifname);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Failed to update interface name in NDisc: %m");
+ }
+
+ if (link->dhcp_server) {
+ r = sd_dhcp_server_set_ifname(link->dhcp_server, link->ifname);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Failed to update interface name in DHCP server: %m");
+ }
+
+ if (link->radv) {
+ r = sd_radv_set_ifname(link->radv, link->ifname);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Failed to update interface name in Router Advertisement: %m");
+ }
+
+ if (link->lldp) {
+ r = sd_lldp_set_ifname(link->lldp, link->ifname);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Failed to update interface name in LLDP: %m");
+ }
+
+ if (link->ipv4ll) {
+ r = sd_ipv4ll_set_ifname(link->ipv4ll, link->ifname);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Failed to update interface name in IPv4LL client: %m");
+ }
+
+ Address *a;
+ SET_FOREACH(a, link->addresses_ipv4acd) {
+ r = sd_ipv4acd_set_ifname(a->acd, link->ifname);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Failed to update interface name in IPv4ACD client: %m");
+ }
+
return 0;
}
break;
default:
- assert_not_reached("Received link message with invalid RTNL message type.");
+ assert_not_reached();
}
return 1;
#include "alloc-util.h"
#include "env-file.h"
-#include "escape.h"
#include "fd-util.h"
#include "hostname-util.h"
#include "missing_network.h"
#include "string-util.h"
#include "strv.h"
#include "unaligned.h"
-#include "web-util.h"
/* The LLDP spec calls this "txFastInit", see 9.2.5.19 */
#define LLDP_TX_FAST_INIT 4U
link->lldp_emit_event_source = sd_event_source_unref(link->lldp_emit_event_source);
}
-int config_parse_lldp_mud(
- const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- _cleanup_free_ char *unescaped = NULL;
- Network *n = data;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- r = cunescape(rvalue, 0, &unescaped);
- if (r < 0) {
- log_syntax(unit, LOG_WARNING, filename, line, r,
- "Failed to Failed to unescape LLDP MUD URL, ignoring: %s", rvalue);
- return 0;
- }
-
- if (!http_url_is_valid(unescaped) || strlen(unescaped) > 255) {
- log_syntax(unit, LOG_WARNING, filename, line, 0,
- "Failed to parse LLDP MUD URL '%s', ignoring: %m", rvalue);
-
- return 0;
- }
-
- return free_and_replace(n->lldp_mud, unescaped);
-}
-
static const char * const lldp_emit_table[_LLDP_EMIT_MAX] = {
[LLDP_EMIT_NO] = "no",
[LLDP_EMIT_NEAREST_BRIDGE] = "nearest-bridge",
}
break;
default:
- assert_not_reached("Unknown NDisc event");
+ assert_not_reached();
}
}
break;
default:
- assert_not_reached("Received invalid RTNL message type");
+ assert_not_reached();
}
return 1;
DHCPv4.Hostname, config_parse_hostname, 0, offsetof(Network, dhcp_hostname)
DHCPv4.RequestBroadcast, config_parse_tristate, 0, offsetof(Network, dhcp_broadcast)
DHCPv4.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier)
-DHCPv4.MUDURL, config_parse_dhcp_mud_url, 0, 0
+DHCPv4.MUDURL, config_parse_mud_url, 0, offsetof(Network, dhcp_mudurl)
DHCPv4.MaxAttempts, config_parse_dhcp_max_attempts, 0, 0
DHCPv4.UserClass, config_parse_dhcp_user_or_vendor_class, AF_INET, offsetof(Network, dhcp_user_class)
DHCPv4.IAID, config_parse_iaid, AF_INET, 0
DHCPv6.UseDomains, config_parse_dhcp_use_domains, 0, 0
DHCPv6.UseNTP, config_parse_dhcp_use_ntp, 0, 0
DHCPv6.RapidCommit, config_parse_bool, 0, offsetof(Network, dhcp6_rapid_commit)
-DHCPv6.MUDURL, config_parse_dhcp6_mud_url, 0, 0
+DHCPv6.MUDURL, config_parse_mud_url, 0, offsetof(Network, dhcp6_mudurl)
DHCPv6.RequestOptions, config_parse_dhcp_request_options, AF_INET6, 0
DHCPv6.UserClass, config_parse_dhcp_user_or_vendor_class, AF_INET6, offsetof(Network, dhcp6_user_class)
DHCPv6.VendorClass, config_parse_dhcp_user_or_vendor_class, AF_INET6, offsetof(Network, dhcp6_vendor_class)
IPv6Prefix.RouteMetric, config_parse_prefix_metric, 0, 0
IPv6RoutePrefix.Route, config_parse_route_prefix, 0, 0
IPv6RoutePrefix.LifetimeSec, config_parse_route_prefix_lifetime, 0, 0
-LLDP.MUDURL, config_parse_lldp_mud, 0, 0
+LLDP.MUDURL, config_parse_mud_url, 0, offsetof(Network, lldp_mud)
CAN.BitRate, config_parse_can_bitrate, 0, offsetof(Network, can_bitrate)
CAN.SamplePoint, config_parse_permille, 0, offsetof(Network, can_sample_point)
CAN.DataBitRate, config_parse_can_bitrate, 0, offsetof(Network, can_data_bitrate)
#include "networkd-route.h"
#include "parse-util.h"
#include "set.h"
+#include "stdio-util.h"
#include "string-util.h"
NextHop *nexthop_free(NextHop *nexthop) {
}
static void log_nexthop_debug(const NextHop *nexthop, uint32_t id, const char *str, const Link *link) {
- _cleanup_free_ char *gw = NULL, *new_id = NULL, *group = NULL;
+ _cleanup_free_ char *gw = NULL, *group = NULL;
struct nexthop_grp *nhg;
assert(nexthop);
if (!DEBUG_LOGGING)
return;
+ char new_id[STRLEN("→") + DECIMAL_STR_MAX(uint32_t)] = "";
if (nexthop->id != id)
- (void) asprintf(&new_id, "→%"PRIu32, id);
+ xsprintf(new_id, "→%"PRIu32, id);
(void) in_addr_to_string(nexthop->family, &nexthop->gw, &gw);
(void) strextendf_with_separator(&group, ",", "%"PRIu32":%"PRIu32, nhg->id, nhg->weight+1);
log_link_debug(link, "%s nexthop: id: %"PRIu32"%s, gw: %s, blackhole: %s, group: %s",
- str, nexthop->id, strempty(new_id), strna(gw), yes_no(nexthop->blackhole), strna(group));
+ str, nexthop->id, new_id, strna(gw), yes_no(nexthop->blackhole), strna(group));
}
static int link_nexthop_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
break;
default:
- assert_not_reached("Received invalid RTNL message type");
+ assert_not_reached();
}
return 1;
n->family = AF_INET6;
break;
default:
- assert_not_reached("Invalid family.");
+ assert_not_reached();
}
TAKE_PTR(n);
case REQUEST_TYPE_UP_DOWN:
break;
default:
- assert_not_reached("invalid request type.");
+ assert_not_reached();
}
}
case REQUEST_TYPE_UP_DOWN:
break;
default:
- assert_not_reached("invalid request type.");
+ assert_not_reached();
}
}
case REQUEST_TYPE_UP_DOWN:
return 0;
default:
- assert_not_reached("invalid request type.");
+ assert_not_reached();
}
}
int manager_get_route_table_to_string(const Manager *m, uint32_t table, char **ret) {
_cleanup_free_ char *str = NULL;
const char *s;
+ int r;
assert(m);
assert(ret);
if (!s)
s = hashmap_get(m->route_table_names_by_number, UINT32_TO_PTR(table));
- if (s) {
+ if (s)
/* Currently, this is only used in debugging logs. To not confuse any bug
* reports, let's include the table number. */
- if (asprintf(&str, "%s(%" PRIu32 ")", s, table) < 0)
- return -ENOMEM;
-
- *ret = TAKE_PTR(str);
- return 0;
- }
-
- if (asprintf(&str, "%" PRIu32, table) < 0)
+ r = asprintf(&str, "%s(%" PRIu32 ")", s, table);
+ else
+ r = asprintf(&str, "%" PRIu32, table);
+ if (r < 0)
return -ENOMEM;
*ret = TAKE_PTR(str);
set_remove(route->link->dhcp6_pd_routes, route);
set_remove(route->link->dhcp6_pd_routes_old, route);
SET_FOREACH(n, route->link->ndisc_routes)
- if (n->route == route)
+ if (route_equal(n->route, route))
free(set_remove(route->link->ndisc_routes, n));
}
route_compare_func,
route_free);
-static bool route_equal(const Route *r1, const Route *r2) {
+bool route_equal(const Route *r1, const Route *r2) {
if (r1 == r2)
return true;
FAMILY_ADDRESS_SIZE(family) * 8) > 0;
}
+static bool prefix_route_address_is_reachable(const Address *a, int family, const union in_addr_union *address) {
+ assert(a);
+ assert(IN_SET(family, AF_INET, AF_INET6));
+ assert(address);
+
+ if (a->family != family)
+ return false;
+ if (FLAGS_SET(a->flags, IFA_F_NOPREFIXROUTE))
+ return false;
+ if (in_addr_is_set(a->family, &a->in_addr_peer))
+ return false;
+
+ return in_addr_prefix_intersect(
+ family,
+ &a->in_addr,
+ a->prefixlen,
+ address,
+ FAMILY_ADDRESS_SIZE(family) * 8) > 0;
+}
+
bool manager_address_is_reachable(Manager *manager, int family, const union in_addr_union *address) {
Link *link;
return true;
}
+ /* If we do not manage foreign routes, then there may exist a prefix route we do not know,
+ * which was created on configuring an address. Hence, also check the addresses. */
+ if (!manager->manage_foreign_routes)
+ HASHMAP_FOREACH(link, manager->links_by_index) {
+ Address *a;
+
+ SET_FOREACH(a, link->addresses)
+ if (prefix_route_address_is_reachable(a, family, address))
+ return true;
+ SET_FOREACH(a, link->addresses_foreign)
+ if (prefix_route_address_is_reachable(a, family, address))
+ return true;
+ }
+
return false;
}
break;
default:
- assert_not_reached("Received route message with invalid RTNL message type");
+ assert_not_reached();
}
return 1;
buffer = &n->src;
prefixlen = &n->src_prefixlen;
} else
- assert_not_reached(lvalue);
+ assert_not_reached();
if (n->family == AF_UNSPEC)
r = in_addr_prefix_from_string_auto(rvalue, &n->family, buffer, prefixlen);
else if (streq(lvalue, "TTLPropagate"))
n->ttl_propagate = r;
else
- assert_not_reached("Invalid lvalue");
+ assert_not_reached();
TAKE_PTR(n);
return 0;
else if (streq(lvalue, "InitialAdvertisedReceiveWindow"))
n->initrwnd = k;
else
- assert_not_reached("Invalid TCP window type.");
+ assert_not_reached();
TAKE_PTR(n);
return 0;
void route_hash_func(const Route *route, struct siphash *state);
int route_compare_func(const Route *a, const Route *b);
+bool route_equal(const Route *r1, const Route *r2);
extern const struct hash_ops route_hash_ops;
int route_new(Route **ret);
break;
default:
- assert_not_reached("Received invalid RTNL message type");
+ assert_not_reached();
}
return 1;
* update routing_policy_rule_is_created_by_kernel() when a new setting which sets the flag is
* added in the future. */
if (rule->l3mdev > 0)
- assert_not_reached("FRA_L3MDEV flag should not be configured.");
+ assert_not_reached();
return 0;
}
return log_link_debug_errno(link, r, "Could not append IFLA_MTU attribute: %m");
break;
default:
- assert_not_reached("Invalid set link operation");
+ assert_not_reached();
}
r = netlink_call_async(link->manager->rtnl, NULL, req, callback,
up = false;
break;
default:
- assert_not_reached("invalid activation policy");
+ assert_not_reached();
}
link->activated = false;
else if (streq(lvalue, "QualityOfService"))
sr_iov->qos = 0;
else
- assert_not_reached("Invalid lvalue");
+ assert_not_reached();
TAKE_PTR(sr_iov);
return 0;
} else if (streq(lvalue, "QualityOfService"))
sr_iov->qos = k;
else
- assert_not_reached("Invalid lvalue");
+ assert_not_reached();
TAKE_PTR(sr_iov);
return 0;
else if (streq(lvalue, "Trust"))
sr_iov->trust = -1;
else
- assert_not_reached("Invalid lvalue");
+ assert_not_reached();
TAKE_PTR(sr_iov);
return 0;
else if (streq(lvalue, "Trust"))
sr_iov->trust = r;
else
- assert_not_reached("Invalid lvalue");
+ assert_not_reached();
TAKE_PTR(sr_iov);
return 0;
#include "condition.h"
#include "conf-parser.h"
+#include "escape.h"
#include "networkd-link.h"
#include "networkd-util.h"
#include "parse-util.h"
#include "string-table.h"
#include "string-util.h"
-#include "util.h"
+#include "web-util.h"
static const char* const address_family_table[_ADDRESS_FAMILY_MAX] = {
[ADDRESS_FAMILY_NO] = "no",
return 0;
}
+int config_parse_mud_url(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ _cleanup_free_ char *unescaped = NULL;
+ char **url = data;
+ ssize_t l;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(url);
+
+ if (isempty(rvalue)) {
+ *url = mfree(*url);
+ return 0;
+ }
+
+ l = cunescape(rvalue, 0, &unescaped);
+ if (l < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, l,
+ "Failed to unescape MUD URL, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ if (l > UINT8_MAX || !http_url_is_valid(unescaped)) {
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "Invalid MUD URL, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ return free_and_replace(*url, unescaped);
+}
+
/* Router lifetime can be set with netlink interface since kernel >= 4.5
* so for the supported kernel we don't need to expire routes in userspace */
int kernel_route_expiration_supported(void) {
CONFIG_PARSER_PROTOTYPE(config_parse_link_local_address_family);
CONFIG_PARSER_PROTOTYPE(config_parse_address_family_with_kernel);
CONFIG_PARSER_PROTOTYPE(config_parse_ip_masquerade);
+CONFIG_PARSER_PROTOTYPE(config_parse_mud_url);
const char *address_family_to_string(AddressFamily b) _const_;
AddressFamily address_family_from_string(const char *s) _pure_;
else if (streq(lvalue, "CEThresholdSec"))
p = &cd->ce_threshold_usec;
else
- assert_not_reached("Invalid lvalue");
+ assert_not_reached();
if (isempty(rvalue)) {
if (streq(lvalue, "CEThresholdSec"))
else if (streq(lvalue, "StrictBands"))
p = &ets->n_strict;
else
- assert_not_reached("Invalid lvalue.");
+ assert_not_reached();
if (isempty(rvalue)) {
*p = 0;
fifo = PFIFO_HEAD_DROP(qdisc);
break;
default:
- assert_not_reached("Invalid QDisc kind.");
+ assert_not_reached();
}
opt.limit = fifo->limit;
fifo = PFIFO_HEAD_DROP(qdisc);
break;
default:
- assert_not_reached("Invalid QDisc kind.");
+ assert_not_reached();
}
if (isempty(rvalue)) {
else if (streq(lvalue, "Flows"))
p = &fqcd->flows;
else
- assert_not_reached("Invalid lvalue.");
+ assert_not_reached();
if (isempty(rvalue)) {
*p = 0;
else if (streq(lvalue, "CEThresholdSec"))
p = &fqcd->ce_threshold_usec;
else
- assert_not_reached("Invalid lvalue.");
+ assert_not_reached();
if (isempty(rvalue)) {
if (streq(lvalue, "CEThresholdSec"))
else if (STR_IN_SET(lvalue, "QuantumBytes", "Quantum"))
p = &fqcd->quantum;
else
- assert_not_reached("Invalid lvalue.");
+ assert_not_reached();
if (isempty(rvalue)) {
if (STR_IN_SET(lvalue, "MemoryLimitBytes", "MemoryLimit"))
else if (streq(lvalue, "OrphanMask"))
p = &fq->orphan_mask;
else
- assert_not_reached("Invalid lvalue");
+ assert_not_reached();
if (isempty(rvalue)) {
*p = 0;
else if (STR_IN_SET(lvalue, "InitialQuantumBytes", "InitialQuantum"))
p = &fq->initial_quantum;
else
- assert_not_reached("Invalid lvalue");
+ assert_not_reached();
if (isempty(rvalue)) {
*p = 0;
else if (streq(lvalue, "DefaultVirtualQueue"))
p = &gred->default_virtual_queue;
else
- assert_not_reached("Invalid lvalue.");
+ assert_not_reached();
if (isempty(rvalue)) {
*p = 0;
else if (streq(lvalue, "CeilBufferBytes"))
htb->ceil_buffer = 0;
else
- assert_not_reached("Invalid lvalue");
+ assert_not_reached();
tclass = NULL;
return 0;
else if (streq(lvalue, "CeilBufferBytes"))
htb->ceil_buffer = v;
else
- assert_not_reached("Invalid lvalue");
+ assert_not_reached();
tclass = NULL;
else if (streq(lvalue, "CeilRate"))
v = &htb->ceil_rate;
else
- assert_not_reached("Invalid lvalue");
+ assert_not_reached();
if (isempty(rvalue)) {
*v = 0;
else if (streq(lvalue, "MPUBytes"))
tbf->mpu = 0;
else
- assert_not_reached("unknown lvalue");
+ assert_not_reached();
TAKE_PTR(qdisc);
return 0;
else if (streq(lvalue, "MTUBytes"))
tbf->mtu = k;
else
- assert_not_reached("unknown lvalue");
+ assert_not_reached();
TAKE_PTR(qdisc);
else if (streq(lvalue, "PeakRate"))
p = &tbf->peak_rate;
else
- assert_not_reached("unknown lvalue");
+ assert_not_reached();
if (isempty(rvalue)) {
*p = 0;
tclass_free(TC_TO_TCLASS(tc));
break;
default:
- assert_not_reached("Invalid traffic control type");
+ assert_not_reached();
}
}
case TC_KIND_TCLASS:
return tclass_configure(link, TC_TO_TCLASS(tc));
default:
- assert_not_reached("Invalid traffic control type");
+ assert_not_reached();
}
}
case TC_KIND_TCLASS:
return tclass_section_verify(TC_TO_TCLASS(tc));
default:
- assert_not_reached("Invalid traffic control type");
+ assert_not_reached();
}
}
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "networkd-address.h"
+#include "tests.h"
+
+static void test_FORMAT_LIFETIME_one(uint32_t lifetime, const char *expected) {
+ const char *t = FORMAT_LIFETIME(lifetime);
+
+ log_debug("%"PRIu32 " → \"%s\" (expected \"%s\")", lifetime, t, expected);
+ assert_se(streq(t, expected));
+}
+
+static void test_FORMAT_LIFETIME(void) {
+ log_info("/* %s */", __func__);
+
+ test_FORMAT_LIFETIME_one(0, "for 0");
+ test_FORMAT_LIFETIME_one(1, "for 1s");
+ test_FORMAT_LIFETIME_one(3 * (USEC_PER_WEEK/USEC_PER_SEC), "for 3w");
+ test_FORMAT_LIFETIME_one(CACHE_INFO_INFINITY_LIFE_TIME, "forever");
+}
+
+int main(int argc, char *argv[]) {
+ test_setup_logging(LOG_INFO);
+
+ test_FORMAT_LIFETIME();
+
+ return 0;
+}
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
return 1;
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
}
/* We want to use the UID also as GID, hence check for it in /etc/group too */
r = check_etc_group_collisions(directory, NULL, (gid_t) *current_uid);
- if (r < 0)
+ if (r <= 0)
return r;
- if (r == 0) /* free! yay! */
- return 0;
}
}
break;
default:
- assert_not_reached("Unknown custom mount type");
+ assert_not_reached();
}
if (r < 0)
state = STATE_REBOOT;
else
- assert_not_reached("Got unexpected signal");
+ assert_not_reached();
r = kill_and_sigcont(pid, SIGTERM);
_cleanup_free_ char *word = NULL, *data = NULL;
const char *p = optarg;
Credential *a;
- size_t i;
- int l;
+ ssize_t l;
r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
if (r == -ENOMEM)
if (!credential_name_valid(word))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Credential name is not valid: %s", word);
- for (i = 0; i < arg_n_credentials; i++)
+ for (size_t i = 0; i < arg_n_credentials; i++)
if (streq(arg_credentials[i].id, word))
return log_error_errno(SYNTHETIC_ERRNO(EEXIST), "Duplicate credential '%s', refusing.", word);
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
if (argc > optind) {
break;
default:
- assert_not_reached("unexpected mode");
+ assert_not_reached();
}
/* Fix permissions of the symlink or file copy we just created */
int r;
assert(n_bind_user_uid == 0 || bind_user_uid);
- assert(offset == 0 || offset == 2); /* used to switch between UID and GID map */
+ assert(IN_SET(offset, 0, 2)); /* used to switch between UID and GID map */
assert(ret);
/* The bind_user_uid[] array is a series of 4 uid_t values, for each --bind-user= entry one
return -EINVAL;
default:
- assert_not_reached("Invalid option passed.");
+ assert_not_reached();
}
return 1;
OomdCGroupContext *t;
SET_FOREACH(t, targets) {
_cleanup_free_ char *selected = NULL;
- char ts[FORMAT_TIMESPAN_MAX];
/* Check if there was reclaim activity in the given interval. The concern is the following case:
* Pressure climbed, a lot of high-frequency pages were reclaimed, and we killed the offending
t->path,
LOAD_INT(t->memory_pressure.avg10), LOAD_FRAC(t->memory_pressure.avg10),
LOAD_INT(t->mem_pressure_limit), LOAD_FRAC(t->mem_pressure_limit),
- format_timespan(ts, sizeof ts,
- m->default_mem_pressure_duration_usec,
- USEC_PER_SEC));
+ FORMAT_TIMESPAN(m->default_mem_pressure_duration_usec, USEC_PER_SEC));
r = update_monitored_cgroup_contexts_candidates(
m->monitored_mem_pressure_cgroup_contexts, &m->monitored_mem_pressure_cgroup_contexts_candidates);
selected, t->path,
LOAD_INT(t->memory_pressure.avg10), LOAD_FRAC(t->memory_pressure.avg10),
LOAD_INT(t->mem_pressure_limit), LOAD_FRAC(t->mem_pressure_limit),
- format_timespan(ts, sizeof ts,
- m->default_mem_pressure_duration_usec,
- USEC_PER_SEC));
+ FORMAT_TIMESPAN(m->default_mem_pressure_duration_usec, USEC_PER_SEC));
return 0;
}
}
int manager_get_dump_string(Manager *m, char **ret) {
_cleanup_free_ char *dump = NULL;
_cleanup_fclose_ FILE *f = NULL;
- char buf[FORMAT_TIMESPAN_MAX];
OomdCGroupContext *c;
size_t size;
char *key;
yes_no(m->dry_run),
PERMYRIAD_AS_PERCENT_FORMAT_VAL(m->swap_used_limit_permyriad),
LOAD_INT(m->default_mem_pressure_limit), LOAD_FRAC(m->default_mem_pressure_limit),
- format_timespan(buf, sizeof(buf), m->default_mem_pressure_duration_usec, USEC_PER_SEC));
+ FORMAT_TIMESPAN(m->default_mem_pressure_duration_usec, USEC_PER_SEC));
oomd_dump_system_context(&m->system_context, f, "\t");
fprintf(f, "Swap Monitored CGroups:\n");
}
void oomd_dump_swap_cgroup_context(const OomdCGroupContext *ctx, FILE *f, const char *prefix) {
- char swap[FORMAT_BYTES_MAX];
-
assert(ctx);
assert(f);
"%sPath: %s\n"
"%s\tSwap Usage: %s\n",
strempty(prefix), ctx->path,
- strempty(prefix), format_bytes(swap, sizeof(swap), ctx->swap_usage));
+ strempty(prefix), FORMAT_BYTES(ctx->swap_usage));
else
fprintf(f,
"%sPath: %s\n"
}
void oomd_dump_memory_pressure_cgroup_context(const OomdCGroupContext *ctx, FILE *f, const char *prefix) {
- char tbuf[FORMAT_TIMESPAN_MAX], mem_use[FORMAT_BYTES_MAX];
- char mem_min[FORMAT_BYTES_MAX], mem_low[FORMAT_BYTES_MAX];
-
assert(ctx);
assert(f);
LOAD_INT(ctx->memory_pressure.avg10), LOAD_FRAC(ctx->memory_pressure.avg10),
LOAD_INT(ctx->memory_pressure.avg60), LOAD_FRAC(ctx->memory_pressure.avg60),
LOAD_INT(ctx->memory_pressure.avg300), LOAD_FRAC(ctx->memory_pressure.avg300),
- format_timespan(tbuf, sizeof(tbuf), ctx->memory_pressure.total, USEC_PER_SEC),
- strempty(prefix), format_bytes(mem_use, sizeof(mem_use), ctx->current_memory_usage));
+ FORMAT_TIMESPAN(ctx->memory_pressure.total, USEC_PER_SEC),
+ strempty(prefix), FORMAT_BYTES(ctx->current_memory_usage));
if (!empty_or_root(ctx->path))
fprintf(f,
"%s\tMemory Low: %s\n"
"%s\tPgscan: %" PRIu64 "\n"
"%s\tLast Pgscan: %" PRIu64 "\n",
- strempty(prefix), format_bytes_cgroup_protection(mem_min, sizeof(mem_min), ctx->memory_min),
- strempty(prefix), format_bytes_cgroup_protection(mem_low, sizeof(mem_low), ctx->memory_low),
+ strempty(prefix), FORMAT_BYTES_CGROUP_PROTECTION(ctx->memory_min),
+ strempty(prefix), FORMAT_BYTES_CGROUP_PROTECTION(ctx->memory_low),
strempty(prefix), ctx->pgscan,
strempty(prefix), ctx->last_pgscan);
}
void oomd_dump_system_context(const OomdSystemContext *ctx, FILE *f, const char *prefix) {
- char mem_used[FORMAT_BYTES_MAX], mem_total[FORMAT_BYTES_MAX];
- char swap_used[FORMAT_BYTES_MAX], swap_total[FORMAT_BYTES_MAX];
-
assert(ctx);
assert(f);
"%sMemory: Used: %s Total: %s\n"
"%sSwap: Used: %s Total: %s\n",
strempty(prefix),
- format_bytes(mem_used, sizeof(mem_used), ctx->mem_used),
- format_bytes(mem_total, sizeof(mem_total), ctx->mem_total),
+ FORMAT_BYTES(ctx->mem_used),
+ FORMAT_BYTES(ctx->mem_total),
strempty(prefix),
- format_bytes(swap_used, sizeof(swap_used), ctx->swap_used),
- format_bytes(swap_total, sizeof(swap_total), ctx->swap_total));
+ FORMAT_BYTES(ctx->swap_used),
+ FORMAT_BYTES(ctx->swap_total));
}
return -EINVAL;
default:
- assert_not_reached("Unknown option code.");
+ assert_not_reached();
}
if (optind < argc)
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
if (optind + 1 != argc)
_cleanup_close_ int mountfd = -1, devfd = -1;
_cleanup_free_ char *devpath = NULL;
uint64_t size, newsize;
- char fb[FORMAT_BYTES_MAX];
dev_t devno;
int r;
if (newsize == size)
log_info("Successfully resized \"%s\" to %s bytes.",
arg_target,
- format_bytes(fb, sizeof fb, newsize));
+ FORMAT_BYTES(newsize));
else
log_info("Successfully resized \"%s\" to %s bytes (%"PRIu64" bytes lost due to blocksize).",
arg_target,
- format_bytes(fb, sizeof fb, newsize),
+ FORMAT_BYTES(newsize),
size - newsize);
return 0;
}
}
static int format_size_change(uint64_t from, uint64_t to, char **ret) {
- char format_buffer1[FORMAT_BYTES_MAX], format_buffer2[FORMAT_BYTES_MAX], *buf;
-
- if (from != UINT64_MAX)
- format_bytes(format_buffer1, sizeof(format_buffer1), from);
- if (to != UINT64_MAX)
- format_bytes(format_buffer2, sizeof(format_buffer2), to);
+ char *t;
if (from != UINT64_MAX) {
if (from == to || to == UINT64_MAX)
- buf = strdup(format_buffer1);
+ t = strdup(FORMAT_BYTES(from));
else
- buf = strjoin(format_buffer1, " ", special_glyph(SPECIAL_GLYPH_ARROW), " ", format_buffer2);
+ t = strjoin(FORMAT_BYTES(from), " ", special_glyph(SPECIAL_GLYPH_ARROW), " ", FORMAT_BYTES(to));
} else if (to != UINT64_MAX)
- buf = strjoin(special_glyph(SPECIAL_GLYPH_ARROW), " ", format_buffer2);
+ t = strjoin(special_glyph(SPECIAL_GLYPH_ARROW), " ", FORMAT_BYTES(to));
else {
*ret = NULL;
return 0;
}
- if (!buf)
+ if (!t)
return log_oom();
- *ret = TAKE_PTR(buf);
+ *ret = t;
return 1;
}
}
if ((arg_json_format_flags & JSON_FORMAT_OFF) && (sum_padding > 0 || sum_size > 0)) {
- char s[FORMAT_BYTES_MAX];
const char *a, *b;
- a = strjoina(special_glyph(SPECIAL_GLYPH_SIGMA), " = ", format_bytes(s, sizeof(s), sum_size));
- b = strjoina(special_glyph(SPECIAL_GLYPH_SIGMA), " = ", format_bytes(s, sizeof(s), sum_padding));
+ a = strjoina(special_glyph(SPECIAL_GLYPH_SIGMA), " = ", FORMAT_BYTES(sum_size));
+ b = strjoina(special_glyph(SPECIAL_GLYPH_SIGMA), " = ", FORMAT_BYTES(sum_padding));
r = table_add_many(
t,
_cleanup_(erase_and_freep) void *secret = NULL;
_cleanup_free_ void *blob = NULL, *hash = NULL;
size_t secret_size, blob_size, hash_size;
+ uint16_t pcr_bank;
int keyslot;
- r = tpm2_seal(arg_tpm2_device, arg_tpm2_pcr_mask, &secret, &secret_size, &blob, &blob_size, &hash, &hash_size);
+ r = tpm2_seal(arg_tpm2_device, arg_tpm2_pcr_mask, &secret, &secret_size, &blob, &blob_size, &hash, &hash_size, &pcr_bank);
if (r < 0)
return log_error_errno(r, "Failed to seal to TPM2: %m");
if (keyslot < 0)
return log_error_errno(keyslot, "Failed to add new TPM2 key to %s: %m", node);
- r = tpm2_make_luks2_json(keyslot, arg_tpm2_pcr_mask, blob, blob_size, hash, hash_size, &v);
+ r = tpm2_make_luks2_json(keyslot, arg_tpm2_pcr_mask, pcr_bank, blob, blob_size, hash, hash_size, &v);
if (r < 0)
return log_error_errno(r, "Failed to prepare TPM2 JSON token object: %m");
_cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
_cleanup_free_ char *encrypted = NULL;
_cleanup_close_ int encrypted_dev_fd = -1;
- char buf[FORMAT_BYTES_MAX];
int target_fd;
if (p->copy_blocks_fd < 0)
target_fd = whole_fd;
}
- log_info("Copying in '%s' (%s) on block level into future partition %" PRIu64 ".", p->copy_blocks_path, format_bytes(buf, sizeof(buf), p->copy_blocks_size), p->partno);
+ log_info("Copying in '%s' (%s) on block level into future partition %" PRIu64 ".",
+ p->copy_blocks_path, FORMAT_BYTES(p->copy_blocks_size), p->partno);
r = copy_bytes_full(p->copy_blocks_fd, target_fd, p->copy_blocks_size, 0, NULL, NULL, NULL, NULL);
if (r < 0)
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
if (argc - optind > 1)
const char *backing_file, /* If the above refers to a loopback device, the backing regular file for that, which we can grow */
LoopDevice *loop_device) {
- char buf1[FORMAT_BYTES_MAX], buf2[FORMAT_BYTES_MAX];
_cleanup_close_ int writable_fd = -1;
uint64_t current_size;
struct stat st;
current_size = st.st_size;
}
- assert_se(format_bytes(buf1, sizeof(buf1), current_size));
- assert_se(format_bytes(buf2, sizeof(buf2), arg_size));
-
if (current_size >= arg_size) {
- log_info("File '%s' already is of requested size or larger, not growing. (%s >= %s)", node, buf1, buf2);
+ log_info("File '%s' already is of requested size or larger, not growing. (%s >= %s)",
+ node, FORMAT_BYTES(current_size), FORMAT_BYTES(arg_size));
return 0;
}
if ((uint64_t) st.st_size != current_size)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Size of backing file '%s' of loopback block device '%s' don't match, refusing.", node, backing_file);
+ "Size of backing file '%s' of loopback block device '%s' don't match, refusing.",
+ node, backing_file);
} else {
assert(S_ISREG(st.st_mode));
assert(!backing_file);
if (fallocate(writable_fd, 0, 0, arg_size) < 0) {
if (!ERRNO_IS_NOT_SUPPORTED(errno))
return log_error_errno(errno, "Failed to grow '%s' from %s to %s by allocation: %m",
- node, buf1, buf2);
+ node, FORMAT_BYTES(current_size), FORMAT_BYTES(arg_size));
/* Fallback to truncation, if fallocate() is not supported. */
log_debug("Backing file system does not support fallocate(), falling back to ftruncate().");
} else {
if (current_size == 0) /* Likely regular file just created by us */
- log_info("Allocated %s for '%s'.", buf2, node);
+ log_info("Allocated %s for '%s'.", FORMAT_BYTES(arg_size), node);
else
- log_info("File '%s' grown from %s to %s by allocation.", node, buf1, buf2);
+ log_info("File '%s' grown from %s to %s by allocation.",
+ node, FORMAT_BYTES(current_size), FORMAT_BYTES(arg_size));
goto done;
}
if (ftruncate(writable_fd, arg_size) < 0)
return log_error_errno(errno, "Failed to grow '%s' from %s to %s by truncation: %m",
- node, buf1, buf2);
+ node, FORMAT_BYTES(current_size), FORMAT_BYTES(arg_size));
if (current_size == 0) /* Likely regular file just created by us */
- log_info("Sized '%s' to %s.", node, buf2);
+ log_info("Sized '%s' to %s.", node, FORMAT_BYTES(arg_size));
else
- log_info("File '%s' grown from %s to %s by truncation.", node, buf1, buf2);
+ log_info("File '%s' grown from %s to %s by truncation.",
+ node, FORMAT_BYTES(current_size), FORMAT_BYTES(arg_size));
done:
r = resize_pt(writable_fd);
static int determine_auto_size(Context *c) {
uint64_t sum = round_up_size(GPT_METADATA_SIZE, 4096);
- char buf[FORMAT_BYTES_MAX];
Partition *p;
assert_se(c);
sum += m;
}
- assert_se(format_bytes(buf, sizeof(buf), sum));
- if (c->total != UINT64_MAX) { /* Image already allocated? Then show its size */
- char buf2[FORMAT_BYTES_MAX];
- assert_se(format_bytes(buf2, sizeof(buf2), c->total));
- log_info("Automatically determined minimal disk image size as %s, current image size is %s.", buf, buf2);
- } else /* If the image is being created right now, then it has no previous size, suppress any comment about it hence */
- log_info("Automatically determined minimal disk image size as %s.", buf);
+ if (c->total != UINT64_MAX)
+ /* Image already allocated? Then show its size. */
+ log_info("Automatically determined minimal disk image size as %s, current image size is %s.",
+ FORMAT_BYTES(sum), FORMAT_BYTES(c->total));
+ else
+ /* If the image is being created right now, then it has no previous size, suppress any comment about it hence. */
+ log_info("Automatically determined minimal disk image size as %s.",
+ FORMAT_BYTES(sum));
arg_size = sum;
return 0;
break; /* Success! */
if (!context_drop_one_priority(context)) {
- char buf[FORMAT_BYTES_MAX];
r = log_error_errno(SYNTHETIC_ERRNO(ENOSPC),
"Can't fit requested partitions into available free space (%s), refusing.",
- format_bytes(buf, sizeof(buf), largest_free_area));
-
+ FORMAT_BYTES(largest_free_area));
determine_auto_size(context);
return r;
}
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
return 1;
install_data('org.freedesktop.portable1.policy',
install_dir : polkitpolicydir)
- install_data('profile/default/service.conf', install_dir : join_paths(profiledir, 'default'))
- install_data('profile/nonetwork/service.conf', install_dir : join_paths(profiledir, 'nonetwork'))
- install_data('profile/strict/service.conf', install_dir : join_paths(profiledir, 'strict'))
- install_data('profile/trusted/service.conf', install_dir : join_paths(profiledir, 'trusted'))
+ install_data('profile/default/service.conf', install_dir : profiledir / 'default')
+ install_data('profile/nonetwork/service.conf', install_dir : profiledir / 'nonetwork')
+ install_data('profile/strict/service.conf', install_dir : profiledir / 'strict')
+ install_data('profile/trusted/service.conf', install_dir : profiledir / 'trusted')
endif
/* In case of a layered attach, we want to remember which image the unit came from */
if (path) {
m->image_path = strdup(path);
- if (!m->image_path) {
- free(m);
- return NULL;
- }
+ if (!m->image_path)
+ return mfree(m);
}
strcpy(m->name, name);
assert(!os_release);
os_release = TAKE_PTR(add);
} else
- assert_not_reached("Unexpected metadata item from child.");
+ assert_not_reached();
}
r = wait_for_terminate_and_check("(sd-dissect)", child, 0);
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
}
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
if (arg_mode == _MODE_INVALID)
}
static void print_source(uint64_t flags, usec_t rtt) {
- char rtt_str[FORMAT_TIMESTAMP_MAX];
-
if (!arg_legend)
return;
flags & SD_RESOLVED_MDNS_IPV4 ? " mDNS/IPv4" : "",
flags & SD_RESOLVED_MDNS_IPV6 ? " mDNS/IPv6" : "");
- assert_se(format_timespan(rtt_str, sizeof(rtt_str), rtt, 100));
-
printf(" in %s.%s\n"
"%s-- Data is authenticated: %s; Data was acquired via local or encrypted transport: %s%s\n",
- rtt_str, ansi_normal(),
+ FORMAT_TIMESPAN(rtt, 100),
+ ansi_normal(),
ansi_grey(),
yes_no(flags & SD_RESOLVED_AUTHENTICATED),
yes_no(flags & SD_RESOLVED_CONFIDENTIAL),
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
if (arg_type == 0 && arg_class != 0)
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
if (arg_type == 0 && arg_class != 0)
return translate("revert", arg_ifname, 0, NULL, bus);
case _MODE_INVALID:
- assert_not_reached("invalid mode");
+ assert_not_reached();
}
return 0;
case DNS_TRANSACTION_VALIDATING:
case DNS_TRANSACTION_SUCCESS:
default:
- assert_not_reached("Impossible state");
+ assert_not_reached();
}
}
break;
default:
- assert_not_reached("Unknown type of Txt config");
+ assert_not_reached();
}
LIST_INSERT_AFTER(items, txt_data->txt, last, i);
continue;
default:
- assert_not_reached("Unexpected DNSSEC validation result");
+ assert_not_reached();
}
}
}
case AF_INET6:
return UDP6_PACKET_HEADER_SIZE;
default:
- assert_not_reached("Unexpected address family");
+ assert_not_reached();
}
}
}
default:
- assert_not_reached("Unknown scope protocol");
+ assert_not_reached();
}
}
break;
default:
- assert_not_reached("Unknown search domain type");
+ assert_not_reached();
}
d->linked = true;
break;
default:
- assert_not_reached("Unknown search domain type");
+ assert_not_reached();
}
}
break;
default:
- assert_not_reached("Unknown server type");
+ assert_not_reached();
}
s->linked = true;
s->manager->n_dns_servers--;
break;
default:
- assert_not_reached("Unknown server type");
+ assert_not_reached();
}
s->linked = false;
break;
default:
- assert_not_reached("Unknown server type");
+ assert_not_reached();
}
}
case DNS_TRANSACTION_PENDING:
case DNS_TRANSACTION_VALIDATING:
default:
- assert_not_reached("Impossible state");
+ assert_not_reached();
}
dns_query_free(q);
break;
default:
- assert_not_reached("Invalid DNS protocol.");
+ assert_not_reached();
}
if (t->received != p) {
break;
default:
- assert_not_reached("Invalid DNS protocol.");
+ assert_not_reached();
}
if (DNS_PACKET_TC(p)) {
break;
default:
- assert_not_reached("Invalid DNS protocol.");
+ assert_not_reached();
}
log_debug("Timeout reached on transaction %" PRIu16 ".", t->id);
return t->scope->resend_timeout;
default:
- assert_not_reached("Invalid DNS protocol.");
+ assert_not_reached();
}
}
accuracy = MDNS_JITTER_RANGE_USEC;
break;
default:
- assert_not_reached("bad protocol");
+ assert_not_reached();
}
assert(!t->timeout_event_source);
break;
default:
- assert_not_reached("Unexpected NSEC result.");
+ assert_not_reached();
}
}
case DNS_TRANSACTION_VALIDATING:
case DNS_TRANSACTION_SUCCESS:
default:
- assert_not_reached("Impossible state");
+ assert_not_reached();
}
}
%systemd_post() \
%{expand:%%{?__systemd_someargs_%#:%%__systemd_someargs_%# systemd_post}} \
-if [ $1 -eq 1 ] && [ -x %{_bindir}/systemctl ]; then \
+if [ $1 -eq 1 ] && [ -x "{{SYSTEMD_UPDATE_HELPER_PATH}}" ]; then \
# Initial installation \
- %{_bindir}/systemctl --no-reload preset %{?*} || : \
+ {{SYSTEMD_UPDATE_HELPER_PATH}} install-system-units %{?*} || : \
fi \
%{nil}
-%systemd_user_post() %{expand:%systemd_post \\--global %%{?*}}
+%systemd_user_post() \
+%{expand:%%{?__systemd_someargs_%#:%%__systemd_someargs_%# systemd_user_post}} \
+if [ $1 -eq 1 ] && [ -x "{{SYSTEMD_UPDATE_HELPER_PATH}}" ]; then \
+ # Initial installation \
+ {{SYSTEMD_UPDATE_HELPER_PATH}} install-user-units %{?*} || : \
+fi \
+%{nil}
%systemd_preun() \
%{expand:%%{?__systemd_someargs_%#:%%__systemd_someargs_%# systemd_preun}} \
-if [ $1 -eq 0 ] && [ -x %{_bindir}/systemctl ]; then \
+if [ $1 -eq 0 ] && [ -x "{{SYSTEMD_UPDATE_HELPER_PATH}}" ]; then \
# Package removal, not upgrade \
- if [ -d /run/systemd/system ]; then \
- %{_bindir}/systemctl --no-reload disable --now %{?*} || : \
- else \
- %{_bindir}/systemctl --no-reload disable %{?*} || : \
- fi \
+ {{SYSTEMD_UPDATE_HELPER_PATH}} remove-system-units %{?*} || : \
fi \
%{nil}
%systemd_user_preun() \
%{expand:%%{?__systemd_someargs_%#:%%__systemd_someargs_%# systemd_user_preun}} \
-if [ $1 -eq 0 ] && [ -x %{_bindir}/systemctl ]; then \
+if [ $1 -eq 0 ] && [ -x "{{SYSTEMD_UPDATE_HELPER_PATH}}" ]; then \
# Package removal, not upgrade \
- %{_bindir}/systemctl --global disable %{?*} || : \
+ {{SYSTEMD_UPDATE_HELPER_PATH}} remove-user-units %{?*} || : \
fi \
%{nil}
%systemd_postun_with_restart() \
%{expand:%%{?__systemd_someargs_%#:%%__systemd_someargs_%# systemd_postun_with_restart}} \
-if [ $1 -ge 1 ] && [ -x %{_bindir}/systemctl ]; then \
+if [ $1 -ge 1 ] && [ -x "{{SYSTEMD_UPDATE_HELPER_PATH}}" ]; then \
# Package upgrade, not uninstall \
- for unit in %{?*}; do \
- %{_bindir}/systemctl set-property $unit Markers=+needs-restart || : \
- done \
+ {{SYSTEMD_UPDATE_HELPER_PATH}} mark-restart-system-units %{?*} || : \
fi \
%{nil}
%systemd_user_postun_with_restart() \
-%{expand:%%{?__systemd_someargs_%#:%%__systemd_someargs_%# systemd_postun_with_restart}} \
+%{expand:%%{?__systemd_someargs_%#:%%__systemd_someargs_%# systemd_user_postun_with_restart}} \
+if [ $1 -ge 1 ] && [ -x "{{SYSTEMD_UPDATE_HELPER_PATH}}" ]; then \
+ # Package upgrade, not uninstall \
+ {{SYSTEMD_UPDATE_HELPER_PATH}} mark-restart-user-units %{?*} || : \
+fi \
%{nil}
%udev_hwdb_update() %{nil}
# Deprecated. Use %tmpfiles_create_package instead
%tmpfiles_create() \
%{expand:%%{?__systemd_someargs_%#:%%__systemd_someargs_%# tmpfiles_create}} \
-[ -x %{_bindir}/systemd-tmpfiles ] && %{_bindir}/systemd-tmpfiles --create %{?*} || : \
+command -v systemd-tmpfiles >/dev/null && systemd-tmpfiles --create %{?*} || : \
%{nil}
# Deprecated. Use %sysusers_create_package instead
%sysusers_create() \
%{expand:%%{?__systemd_someargs_%#:%%__systemd_someargs_%# sysusers_create}} \
-[ -x %{_bindir}/systemd-sysusers ] && %{_bindir}/systemd-sysusers %{?*} || : \
+command -v systemd-sysusers >/dev/null && systemd-sysusers %{?*} || : \
%{nil}
%sysusers_create_inline() \
-[ -x %{_bindir}/systemd-sysusers ] && %{_bindir}/systemd-sysusers - <<SYSTEMD_INLINE_EOF || : \
+command -v systemd-sysusers >/dev/null && systemd-sysusers - <<SYSTEMD_INLINE_EOF || : \
%{?*} \
SYSTEMD_INLINE_EOF\
%{nil}
# SPDX-License-Identifier: LGPL-2.1-or-later
in_files = [
- ['macros.systemd', rpmmacrosdir != 'no'],
- ['triggers.systemd', false],
- ['triggers.systemd.sh', false]]
+ ['macros.systemd', rpmmacrosdir != 'no', rpmmacrosdir],
+
+ # we conditionalize on rpmmacrosdir, but install into rootlibexecdir
+ ['systemd-update-helper', rpmmacrosdir != 'no', rootlibexecdir, 'rwxr-xr-x'],
+
+ ['triggers.systemd', false],
+ ['triggers.systemd.sh', false]]
# The last two don't get installed anywhere, one of them needs to included in
# the rpm spec file definition instead.
command : [meson_render_jinja2, config_h, '@INPUT@'],
capture : true,
install : tuple[1],
- install_dir : rpmmacrosdir,
+ install_dir : tuple.length() > 2 ? tuple[2] : '',
+ install_mode : tuple.length() > 3 ? tuple[3] : false,
build_by_default : true)
endforeach
--- /dev/null
+#!/bin/bash
+set -eu
+set -o pipefail
+
+command="${1:?}"
+shift
+
+command -v systemctl >/dev/null || exit 0
+
+case "$command" in
+ install-system-units)
+ systemctl --no-reload preset "$@"
+ ;;
+
+ install-user-units)
+ systemctl --no-reload preset --global "$@"
+ ;;
+
+ remove-system-units)
+ if [ -d /run/systemd/system ]; then
+ systemctl --no-reload disable --now "$@"
+ else
+ systemctl --no-reload disable "$@"
+ fi
+ ;;
+
+ remove-user-units)
+ systemctl --global disable "$@"
+
+ [ -d /run/systemd/system ] || exit 0
+
+ users=$(systemctl list-units 'user@*' --legend=no | sed -n -r 's/.*user@([0-9]+).service.*/\1/p')
+ for user in $users; do
+ SYSTEMD_BUS_TIMEOUT={{UPDATE_HELPER_USER_TIMEOUT}} \
+ systemctl --user -M "$user@" disable --now "$@" &
+ done
+ wait
+ ;;
+
+ mark-restart-system-units)
+ [ -d /run/systemd/system ] || exit 0
+
+ for unit in "$@"; do
+ systemctl set-property "$unit" Markers=+needs-restart &
+ done
+ wait
+ ;;
+
+ mark-restart-user-units)
+ [ -d /run/systemd/system ] || exit 0
+
+ users=$(systemctl list-units 'user@*' --legend=no | sed -n -r 's/.*user@([0-9]+).service.*/\1/p')
+ for user in $users; do
+ SYSTEMD_BUS_TIMEOUT={{UPDATE_HELPER_USER_TIMEOUT}} \
+ systemctl --user -M "$user@" set-property "$unit" Markers=+needs-restart &
+ done
+ wait
+ ;;
+
+ system-reload-restart|system-reload|system-restart)
+ if [ -n "$*" ]; then
+ echo "Unexpected arguments for '$command': $*"
+ exit 2
+ fi
+
+ [ -d /run/systemd/system ] || exit 0
+
+ if [[ "$command" =~ reload ]]; then
+ systemctl daemon-reload
+ fi
+
+ if [[ "$command" =~ restart ]]; then
+ systemctl reload-or-restart --marked
+ fi
+ ;;
+
+ user-reload-restart|user-reload|user-restart|user-reexec)
+ if [ -n "$*" ]; then
+ echo "Unexpected arguments for '$command': $*"
+ exit 2
+ fi
+
+ [ -d /run/systemd/system ] || exit 0
+
+ users=$(systemctl list-units 'user@*' --legend=no | sed -n -r 's/.*user@([0-9]+).service.*/\1/p')
+
+ if [[ "$command" =~ reexec ]]; then
+ for user in $users; do
+ SYSTEMD_BUS_TIMEOUT={{UPDATE_HELPER_USER_TIMEOUT}} \
+ systemctl --user -M "$user@" daemon-reexec &
+ done
+ wait
+ fi
+
+ if [[ "$command" =~ reload ]]; then
+ for user in $users; do
+ SYSTEMD_BUS_TIMEOUT={{UPDATE_HELPER_USER_TIMEOUT}} \
+ systemctl --user -M "$user@" daemon-reload &
+ done
+ wait
+ fi
+
+ if [[ "$command" =~ restart ]]; then
+ for user in $users; do
+ SYSTEMD_BUS_TIMEOUT={{UPDATE_HELPER_USER_TIMEOUT}} \
+ systemctl --user -M "$user@" reload-or-restart --marked &
+ done
+ wait
+ fi
+ ;;
+
+ *)
+ echo "Unknown verb '$command'"
+ exit 3
+ ;;
+esac
-- upgraded. We care about the case where a package is initially
-- installed, because other cases are covered by the *un scriptlets,
-- so sometimes we will reload needlessly.
-if posix.access("/run/systemd/system") then
- pid = posix.fork()
- if pid == 0 then
- assert(posix.exec("%{_bindir}/systemctl", "daemon-reload"))
- elseif pid > 0 then
- posix.wait(pid)
- end
+pid = posix.fork()
+if pid == 0 then
+ assert(posix.exec("{{SYSTEMD_UPDATE_HELPER_PATH}}", "system-reload-restart"))
+elseif pid > 0 then
+ posix.wait(pid)
+end
- pid = posix.fork()
- if pid == 0 then
- assert(posix.exec("%{_bindir}/systemctl", "reload-or-restart", "--marked"))
- elseif pid > 0 then
- posix.wait(pid)
- end
+%transfiletriggerin -P 900899 -p <lua> -- {{USER_DATA_UNIT_DIR}} /etc/systemd/user
+pid = posix.fork()
+if pid == 0 then
+ assert(posix.exec("{{SYSTEMD_UPDATE_HELPER_PATH}}", "user-reload-restart"))
+elseif pid > 0 then
+ posix.wait(pid)
end
%transfiletriggerpostun -P 1000100 -p <lua> -- {{SYSTEM_DATA_UNIT_DIR}} /etc/systemd/system
-- On upgrade, we need to run daemon-reload after any new unit files
-- have been installed, but before %postun scripts in packages get
-- executed.
-if posix.access("/run/systemd/system") then
- pid = posix.fork()
- if pid == 0 then
- assert(posix.exec("%{_bindir}/systemctl", "daemon-reload"))
- elseif pid > 0 then
- posix.wait(pid)
- end
+pid = posix.fork()
+if pid == 0 then
+ assert(posix.exec("{{SYSTEMD_UPDATE_HELPER_PATH}}", "system-reload"))
+elseif pid > 0 then
+ posix.wait(pid)
+end
+
+%transfiletriggerpostun -P 1000100 -p <lua> -- {{SYSTEM_DATA_UNIT_DIR}} /etc/systemd/system
+-- Execute daemon-reload in user managers.
+pid = posix.fork()
+if pid == 0 then
+ assert(posix.exec("{{SYSTEMD_UPDATE_HELPER_PATH}}", "user-reload"))
+elseif pid > 0 then
+ posix.wait(pid)
end
%transfiletriggerpostun -P 10000 -p <lua> -- {{SYSTEM_DATA_UNIT_DIR}} /etc/systemd/system
--- We restart remaining services that should be restarted here.
-if posix.access("/run/systemd/system") then
- pid = posix.fork()
- if pid == 0 then
- assert(posix.exec("%{_bindir}/systemctl", "reload-or-restart", "--marked"))
- elseif pid > 0 then
- posix.wait(pid)
- end
+-- We restart remaining system services that should be restarted here.
+pid = posix.fork()
+if pid == 0 then
+ assert(posix.exec("{{SYSTEMD_UPDATE_HELPER_PATH}}", "system-restart"))
+elseif pid > 0 then
+ posix.wait(pid)
+end
+
+%transfiletriggerpostun -P 9999 -p <lua> -- {{USER_DATA_UNIT_DIR}} /etc/systemd/user
+-- We restart remaining user services that should be restarted here.
+pid = posix.fork()
+if pid == 0 then
+ assert(posix.exec("{{SYSTEMD_UPDATE_HELPER_PATH}}", "user-restart"))
+elseif pid > 0 then
+ posix.wait(pid)
end
%transfiletriggerin -P 100700 -p <lua> -- {{SYSUSERS_DIR}}
if posix.access("/run/systemd/system") then
pid = posix.fork()
if pid == 0 then
- assert(posix.exec("%{_bindir}/systemd-sysusers"))
+ assert(posix.execp("systemd-sysusers"))
elseif pid > 0 then
posix.wait(pid)
end
if posix.access("/run/systemd/system") then
pid = posix.fork()
if pid == 0 then
- assert(posix.exec("%{_bindir}/systemd-hwdb", "update"))
+ assert(posix.execp("systemd-hwdb", "update"))
elseif pid > 0 then
posix.wait(pid)
end
if posix.access("/run/systemd/system") then
pid = posix.fork()
if pid == 0 then
- assert(posix.exec("%{_bindir}/journalctl", "--update-catalog"))
+ assert(posix.execp("journalctl", "--update-catalog"))
elseif pid > 0 then
posix.wait(pid)
end
if posix.access("/run/systemd/system") then
pid = posix.fork()
if pid == 0 then
- assert(posix.exec("%{_bindir}/systemd-tmpfiles", "--create"))
+ assert(posix.execp("systemd-tmpfiles", "--create"))
elseif pid > 0 then
posix.wait(pid)
end
if posix.access("/run/systemd/system") then
pid = posix.fork()
if pid == 0 then
- assert(posix.exec("%{_bindir}/udevadm", "control", "--reload"))
+ assert(posix.execp("udevadm", "control", "--reload"))
elseif pid > 0 then
posix.wait(pid)
end
# upgraded. We care about the case where a package is initially
# installed, because other cases are covered by the *un scriptlets,
# so sometimes we will reload needlessly.
-if test -d "/run/systemd/system"; then
- %{_bindir}/systemctl daemon-reload || :
- %{_bindir}/systemctl reload-or-restart --marked || :
-fi
+{{SYSTEMD_UPDATE_HELPER_PATH}} system-reload-restart || :
+
+%transfiletriggerin -P 900899 -- {{USER_DATA_UNIT_DIR}} /etc/systemd/user
+{{SYSTEMD_UPDATE_HELPER_PATH}} user-reload-restart || :
%transfiletriggerpostun -P 1000100 -- {{SYSTEM_DATA_UNIT_DIR}} /etc/systemd/system
# On removal, we need to run daemon-reload after any units have been
# On upgrade, we need to run daemon-reload after any new unit files
# have been installed, but before %postun scripts in packages get
# executed.
-if test -d "/run/systemd/system"; then
- %{_bindir}/systemctl daemon-reload || :
-fi
+{{SYSTEMD_UPDATE_HELPER_PATH}} system-reload || :
+
+%transfiletriggerpostun -P 1000099 -- {{USER_DATA_UNIT_DIR}} /etc/systemd/user
+# Execute daemon-reload in user managers.
+{{SYSTEMD_UPDATE_HELPER_PATH}} user-reload || :
%transfiletriggerpostun -P 10000 -- {{SYSTEM_DATA_UNIT_DIR}} /etc/systemd/system
-# We restart remaining services that should be restarted here.
-if test -d "/run/systemd/system"; then
- %{_bindir}/systemctl reload-or-restart --marked || :
-fi
+# We restart remaining system services that should be restarted here.
+{{SYSTEMD_UPDATE_HELPER_PATH}} system-restart || :
+
+%transfiletriggerpostun -P 9999 -- {{USER_DATA_UNIT_DIR}} /etc/systemd/user
+# We restart remaining user services that should be restarted here.
+{{SYSTEMD_UPDATE_HELPER_PATH}} user-restart || :
%transfiletriggerin -P 1000700 -- {{SYSUSERS_DIR}}
# This script will process files installed in {{SYSUSERS_DIR}} to create
# specified users automatically. The priority is set such that it
# will run before the tmpfiles file trigger.
if test -d "/run/systemd/system"; then
- %{_bindir}/systemd-sysusers || :
+ systemd-sysusers || :
fi
%transfiletriggerin -P 1000700 udev -- {{UDEV_HWDB_DIR}}
# This script will automatically invoke hwdb update if files have been
# installed or updated in {{UDEV_HWDB_DIR}}.
if test -d "/run/systemd/system"; then
- %{_bindir}/systemd-hwdb update || :
+ systemd-hwdb update || :
fi
%transfiletriggerin -P 1000700 -- {{SYSTEMD_CATALOG_DIR}}
# This script will automatically invoke journal catalog update if files
# have been installed or updated in {{SYSTEMD_CATALOG_DIR}}.
if test -d "/run/systemd/system"; then
- %{_bindir}/journalctl --update-catalog || :
+ journalctl --update-catalog || :
fi
%transfiletriggerin -P 1000700 -- {{BINFMT_DIR}}
# tmpfiles automatically. The priority is set such that it will run
# after the sysusers file trigger, but before any other triggers.
if test -d "/run/systemd/system"; then
- %{_bindir}/systemd-tmpfiles --create || :
+ systemd-tmpfiles --create || :
fi
%transfiletriggerin -P 1000600 udev -- {{UDEV_RULES_DIR}}
# This script will automatically update udev with new rules if files
# have been installed or updated in {{UDEV_RULES_DIR}}.
if test -e /run/udev/control; then
- %{_bindir}/udevadm control --reload || :
+ udevadm control --reload || :
fi
%transfiletriggerin -P 1000500 -- {{SYSCTL_DIR}}
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
with_trigger = !!arg_path_property || !!arg_socket_property || arg_with_timer;
if (!pty_path)
return log_oom();
} else
- assert_not_reached("Can't allocate tty via ssh");
+ assert_not_reached();
}
/* Optionally, wait for the start job to complete. If we are supposed to read the service's stdin
if (timestamp_is_set(c.inactive_enter_usec) &&
timestamp_is_set(c.inactive_exit_usec) &&
- c.inactive_enter_usec > c.inactive_exit_usec) {
- char ts[FORMAT_TIMESPAN_MAX];
+ c.inactive_enter_usec > c.inactive_exit_usec)
log_info("Service runtime: %s",
- format_timespan(ts, sizeof ts, c.inactive_enter_usec - c.inactive_exit_usec, USEC_PER_MSEC));
- }
+ FORMAT_TIMESPAN(c.inactive_enter_usec - c.inactive_exit_usec, USEC_PER_MSEC));
- if (c.cpu_usage_nsec != NSEC_INFINITY) {
- char ts[FORMAT_TIMESPAN_MAX];
+ if (c.cpu_usage_nsec != NSEC_INFINITY)
log_info("CPU time consumed: %s",
- format_timespan(ts, sizeof ts, DIV_ROUND_UP(c.cpu_usage_nsec, NSEC_PER_USEC), USEC_PER_MSEC));
- }
+ FORMAT_TIMESPAN(DIV_ROUND_UP(c.cpu_usage_nsec, NSEC_PER_USEC), USEC_PER_MSEC));
- if (c.ip_ingress_bytes != UINT64_MAX) {
- char bytes[FORMAT_BYTES_MAX];
- log_info("IP traffic received: %s", format_bytes(bytes, sizeof bytes, c.ip_ingress_bytes));
- }
- if (c.ip_egress_bytes != UINT64_MAX) {
- char bytes[FORMAT_BYTES_MAX];
- log_info("IP traffic sent: %s", format_bytes(bytes, sizeof bytes, c.ip_egress_bytes));
- }
- if (c.io_read_bytes != UINT64_MAX) {
- char bytes[FORMAT_BYTES_MAX];
- log_info("IO bytes read: %s", format_bytes(bytes, sizeof bytes, c.io_read_bytes));
- }
- if (c.io_write_bytes != UINT64_MAX) {
- char bytes[FORMAT_BYTES_MAX];
- log_info("IO bytes written: %s", format_bytes(bytes, sizeof bytes, c.io_write_bytes));
- }
+ if (c.ip_ingress_bytes != UINT64_MAX)
+ log_info("IP traffic received: %s", FORMAT_BYTES(c.ip_ingress_bytes));
+
+ if (c.ip_egress_bytes != UINT64_MAX)
+ log_info("IP traffic sent: %s", FORMAT_BYTES(c.ip_egress_bytes));
+
+ if (c.io_read_bytes != UINT64_MAX)
+ log_info("IO bytes read: %s", FORMAT_BYTES(c.io_read_bytes));
+
+ if (c.io_write_bytes != UINT64_MAX)
+ log_info("IO bytes written: %s", FORMAT_BYTES(c.io_write_bytes));
}
/* Try to propagate the service's return value. But if the service defines
else if (streq(suffix, ".timer"))
r = transient_timer_set_properties(m);
else
- assert_not_reached("Invalid suffix");
+ assert_not_reached();
if (r < 0)
return r;
return *gid_a == *gid_b;
}
default:
- assert_not_reached("Unknown acl tag type");
+ assert_not_reached();
}
}
_cleanup_free_ char *sfd = NULL, *sat = NULL, *unescaped = NULL;
_cleanup_(bpf_program_unrefp) BPFProgram *p = NULL;
_cleanup_close_ int fd = -1;
+ ssize_t l;
int ifd, at, r;
assert(v);
return at;
/* The rest is the path */
- r = cunescape(v, 0, &unescaped);
- if (r < 0)
- return r;
+ l = cunescape(v, 0, &unescaped);
+ if (l < 0)
+ return l;
fd = fdset_remove(fds, ifd);
if (fd < 0)
return -EISDIR;
r = btrfs_subvol_make(new_path);
- if (r == -ENOTTY && (flags & BTRFS_SNAPSHOT_FALLBACK_DIRECTORY)) {
+ if (ERRNO_IS_NOT_SUPPORTED(r) && (flags & BTRFS_SNAPSHOT_FALLBACK_DIRECTORY)) {
/* If the destination doesn't support subvolumes, then use a plain directory, if that's requested. */
if (mkdir(new_path, 0755) < 0)
return -errno;
r = copy_directory_fd_full(
old_fd, new_path,
- COPY_MERGE|COPY_REFLINK|COPY_SAME_MOUNT|COPY_HARDLINKS|(FLAGS_SET(flags, BTRFS_SNAPSHOT_SIGINT) ? COPY_SIGINT : 0),
- progress_path, progress_bytes, userdata);
+ COPY_MERGE_EMPTY|
+ COPY_REFLINK|
+ COPY_SAME_MOUNT|
+ COPY_HARDLINKS|
+ (FLAGS_SET(flags, BTRFS_SNAPSHOT_SIGINT) ? COPY_SIGINT : 0)|
+ (FLAGS_SET(flags, BTRFS_SNAPSHOT_SIGTERM) ? COPY_SIGTERM : 0),
+ progress_path,
+ progress_bytes,
+ userdata);
if (r < 0)
goto fallback_fail;
BTRFS_SNAPSHOT_FALLBACK_DIRECTORY = 1 << 4, /* If the destination doesn't support subvolumes, reflink/copy instead */
BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE = 1 << 5, /* When we can't create a subvolume, use the FS_IMMUTABLE attribute for indicating read-only */
BTRFS_SNAPSHOT_SIGINT = 1 << 6, /* Check for SIGINT regularly, and return EINTR if seen */
+ BTRFS_SNAPSHOT_SIGTERM = 1 << 7, /* Ditto, but for SIGTERM */
} BtrfsSnapshotFlags;
typedef enum BtrfsRemoveFlags {
* should it turn out to not be sufficient */
if (endswith(name, "Timestamp") ||
- STR_IN_SET(name, "NextElapseUSecRealtime", "LastTriggerUSec", "TimeUSec", "RTCTimeUSec")) {
- char timestamp[FORMAT_TIMESTAMP_MAX];
- const char *t;
+ STR_IN_SET(name, "NextElapseUSecRealtime", "LastTriggerUSec", "TimeUSec", "RTCTimeUSec"))
- t = format_timestamp(timestamp, sizeof(timestamp), u);
- bus_print_property_value(name, expected_value, flags, t);
+ bus_print_property_value(name, expected_value, flags, FORMAT_TIMESTAMP(u));
- } else if (strstr(name, "USec")) {
- char timespan[FORMAT_TIMESPAN_MAX];
+ else if (strstr(name, "USec"))
+ bus_print_property_value(name, expected_value, flags, FORMAT_TIMESPAN(u, 0));
- (void) format_timespan(timespan, sizeof(timespan), u, 0);
- bus_print_property_value(name, expected_value, flags, timespan);
-
- } else if (streq(name, "CoredumpFilter"))
+ else if (streq(name, "CoredumpFilter"))
bus_print_property_valuef(name, expected_value, flags, "0x%"PRIx64, u);
else if (streq(name, "RestrictNamespaces")) {
r = sd_bus_message_append_array(m, 'y', decoded, decoded_size);
} else {
_cleanup_free_ char *unescaped = NULL;
- int l;
+ ssize_t l;
l = cunescape(p, UNESCAPE_ACCEPT_NUL, &unescaped);
if (l < 0)
if (streq(field, "StandardInputText")) {
_cleanup_free_ char *unescaped = NULL;
+ ssize_t l;
- r = cunescape(eq, 0, &unescaped);
- if (r < 0)
- return log_error_errno(r, "Failed to unescape text '%s': %m", eq);
+ l = cunescape(eq, 0, &unescaped);
+ if (l < 0)
+ return log_error_errno(l, "Failed to unescape text '%s': %m", eq);
if (!strextend(&unescaped, "\n"))
return log_oom();
- /* Note that we don't expand specifiers here, but that should be OK, as this is a programmatic
- * interface anyway */
+ /* Note that we don't expand specifiers here, but that should be OK, as this is a
+ * programmatic interface anyway */
- return bus_append_byte_array(m, field, unescaped, strlen(unescaped));
+ return bus_append_byte_array(m, field, unescaped, l + 1);
}
if (streq(field, "StandardInputData")) {
break;
default:
- assert_not_reached("Hmm, unknown transport type.");
+ assert_not_reached();
}
if (r < 0)
return r;
break;
default:
- assert_not_reached("Hmm, unknown transport type.");
+ assert_not_reached();
}
return r;
#define EPOCH_FILE "/usr/lib/clock-epoch"
-int clock_apply_epoch(void) {
+int clock_apply_epoch(ClockChangeDirection *ret_attempted_change) {
struct stat st;
struct timespec ts;
- usec_t epoch_usec;
+ usec_t epoch_usec, now_usec;
+
+ /* NB: we update *ret_attempted_change in *all* cases, both
+ * on success and failure, to indicate what we intended to do! */
+
+ assert(ret_attempted_change);
if (stat(EPOCH_FILE, &st) < 0) {
if (errno != ENOENT)
} else
epoch_usec = timespec_load(&st.st_mtim);
- if (now(CLOCK_REALTIME) >= epoch_usec)
+ now_usec = now(CLOCK_REALTIME);
+ if (now_usec < epoch_usec)
+ *ret_attempted_change = CLOCK_CHANGE_FORWARD;
+ else if (now_usec > usec_add(epoch_usec, CLOCK_VALID_RANGE_USEC_MAX))
+ *ret_attempted_change = CLOCK_CHANGE_BACKWARD;
+ else {
+ *ret_attempted_change = CLOCK_CHANGE_NOOP;
return 0;
+ }
if (clock_settime(CLOCK_REALTIME, timespec_store(&ts, epoch_usec)) < 0)
return -errno;
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
+#include <errno.h>
#include <time.h>
+typedef enum ClockChangeDirection {
+ CLOCK_CHANGE_NOOP,
+ CLOCK_CHANGE_FORWARD,
+ CLOCK_CHANGE_BACKWARD,
+ _CLOCK_CHANGE_MAX,
+ _CLOCK_CHANGE_INVALID = -EINVAL,
+} ClockChangeDirection;
+
int clock_is_localtime(const char* adjtime_path);
int clock_set_timezone(int *ret_minutesdelta);
int clock_reset_timewarp(void);
int clock_get_hwclock(struct tm *tm);
int clock_set_hwclock(const struct tm *tm);
-int clock_apply_epoch(void);
+int clock_apply_epoch(ClockChangeDirection *ret_attempted_change);
return k > 0;
default:
- assert_not_reached("unknown order");
+ assert_not_reached();
}
}
return FLAGS_SET(flags, O_NONBLOCK) ? FD_IS_NONBLOCKING_PIPE : FD_IS_BLOCKING_PIPE;
}
+static int look_for_signals(CopyFlags copy_flags) {
+ int r;
+
+ if ((copy_flags & (COPY_SIGINT|COPY_SIGTERM)) == 0)
+ return 0;
+
+ r = pop_pending_signal(copy_flags & COPY_SIGINT ? SIGINT : 0,
+ copy_flags & COPY_SIGTERM ? SIGTERM : 0);
+ if (r < 0)
+ return r;
+ if (r != 0)
+ return log_debug_errno(SYNTHETIC_ERRNO(EINTR),
+ "Got %s, cancelling copy operation.", signal_to_string(r));
+
+ return 0;
+}
+
int copy_bytes_full(
int fdf, int fdt,
uint64_t max_bytes,
if (max_bytes <= 0)
return 1; /* return > 0 if we hit the max_bytes limit */
- if (FLAGS_SET(copy_flags, COPY_SIGINT)) {
- r = pop_pending_signal(SIGINT);
- if (r < 0)
- return r;
- if (r > 0)
- return -EINTR;
- }
+ r = look_for_signals(copy_flags);
+ if (r < 0)
+ return r;
if (max_bytes != UINT64_MAX && m > max_bytes)
m = max_bytes;
return -errno;
r = copy_bytes_full(fdf, fdt, UINT64_MAX, copy_flags, NULL, NULL, progress, userdata);
- if (r < 0) {
- (void) unlinkat(dt, to, 0);
- return r;
- }
+ if (r < 0)
+ goto fail;
if (fchown(fdt,
uid_is_valid(override_uid) ? override_uid : st->st_uid,
(void) futimens(fdt, (struct timespec[]) { st->st_atim, st->st_mtim });
(void) copy_xattr(fdf, fdt);
- q = close(fdt);
- fdt = -1;
+ if (copy_flags & COPY_FSYNC) {
+ if (fsync(fdt) < 0) {
+ r = -errno;
+ goto fail;
+ }
+ }
+ q = close_nointr(TAKE_FD(fdt)); /* even if this fails, the fd is now invalidated */
if (q < 0) {
- r = -errno;
- (void) unlinkat(dt, to, 0);
+ r = q;
+ goto fail;
}
(void) memorize_hardlink(hardlink_context, st, dt, to);
return r;
+
+fail:
+ (void) unlinkat(dt, to, 0);
+ return r;
}
static int fd_copy_fifo(
if (dot_or_dot_dot(de->d_name))
continue;
- if (FLAGS_SET(copy_flags, COPY_SIGINT)) {
- r = pop_pending_signal(SIGINT);
- if (r < 0)
- return r;
- if (r > 0)
- return -EINTR;
- }
+ r = look_for_signals(copy_flags);
+ if (r < 0)
+ return r;
if (fstatat(dirfd(d), de->d_name, &buf, AT_SYMLINK_NOFOLLOW) < 0) {
r = -errno;
else
q = -EOPNOTSUPP;
- if (q == -EINTR) /* Propagate SIGINT up instantly */
+ if (q == -EINTR) /* Propagate SIGINT/SIGTERM up instantly */
return q;
if (q == -EEXIST && (copy_flags & COPY_MERGE))
q = 0;
(void) futimens(fdt, (struct timespec[]) { st->st_atim, st->st_mtim });
}
+ if (copy_flags & COPY_FSYNC_FULL) {
+ if (fsync(fdt) < 0)
+ return -errno;
+ }
+
return r;
}
void *userdata) {
struct stat st;
+ int r;
assert(from);
assert(to);
return -errno;
if (S_ISREG(st.st_mode))
- return fd_copy_regular(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags, NULL, progress_bytes, userdata);
+ r = fd_copy_regular(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags, NULL, progress_bytes, userdata);
else if (S_ISDIR(st.st_mode))
- return fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, COPY_DEPTH_MAX, override_uid, override_gid, copy_flags, NULL, NULL, progress_path, progress_bytes, userdata);
+ r = fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, COPY_DEPTH_MAX, override_uid, override_gid, copy_flags, NULL, NULL, progress_path, progress_bytes, userdata);
else if (S_ISLNK(st.st_mode))
- return fd_copy_symlink(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
+ r = fd_copy_symlink(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
else if (S_ISFIFO(st.st_mode))
- return fd_copy_fifo(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags, NULL);
+ r = fd_copy_fifo(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags, NULL);
else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode) || S_ISSOCK(st.st_mode))
- return fd_copy_node(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags, NULL);
+ r = fd_copy_node(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags, NULL);
else
return -EOPNOTSUPP;
+ if (r < 0)
+ return r;
+
+ if (S_ISDIR(st.st_mode) && (copy_flags & COPY_SYNCFS)) {
+ /* If the top-level inode is a directory run syncfs() now. */
+ r = syncfs_path(fdt, to);
+ if (r < 0)
+ return r;
+ } else if ((copy_flags & (COPY_FSYNC_FULL|COPY_SYNCFS)) != 0) {
+ /* fsync() the parent dir of what we just copied if COPY_FSYNC_FULL is set. Also do this in
+ * case COPY_SYNCFS is set but the top-level inode wasn't actually a directory. We do this so that
+ * COPY_SYNCFS provides reasonable synchronization semantics on any kind of inode: when the
+ * copy operation is done the whole inode — regardless of its type — and all its children
+ * will be synchronized to disk. */
+ r = fsync_parent_at(fdt, to);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+static int sync_dir_by_flags(const char *path, CopyFlags copy_flags) {
+
+ if (copy_flags & COPY_SYNCFS)
+ return syncfs_path(AT_FDCWD, path);
+ if (copy_flags & COPY_FSYNC_FULL)
+ return fsync_parent_at(AT_FDCWD, path);
+
+ return 0;
}
int copy_directory_fd_full(
if (r < 0)
return r;
- return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, COPY_DEPTH_MAX, UID_INVALID, GID_INVALID, copy_flags, NULL, NULL, progress_path, progress_bytes, userdata);
+ r = fd_copy_directory(
+ dirfd, NULL,
+ &st,
+ AT_FDCWD, to,
+ st.st_dev,
+ COPY_DEPTH_MAX,
+ UID_INVALID, GID_INVALID,
+ copy_flags,
+ NULL, NULL,
+ progress_path,
+ progress_bytes,
+ userdata);
+ if (r < 0)
+ return r;
+
+ r = sync_dir_by_flags(to, copy_flags);
+ if (r < 0)
+ return r;
+
+ return 0;
}
int copy_directory_full(
if (r < 0)
return r;
- return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, COPY_DEPTH_MAX, UID_INVALID, GID_INVALID, copy_flags, NULL, NULL, progress_path, progress_bytes, userdata);
+ r = fd_copy_directory(
+ AT_FDCWD, from,
+ &st,
+ AT_FDCWD, to,
+ st.st_dev,
+ COPY_DEPTH_MAX,
+ UID_INVALID, GID_INVALID,
+ copy_flags,
+ NULL, NULL,
+ progress_path,
+ progress_bytes,
+ userdata);
+ if (r < 0)
+ return r;
+
+ r = sync_dir_by_flags(to, copy_flags);
+ if (r < 0)
+ return r;
+
+ return 0;
}
int copy_file_fd_full(
void *userdata) {
_cleanup_close_ int fdf = -1;
+ struct stat st;
int r;
assert(from);
if (fdf < 0)
return -errno;
+ r = fd_verify_regular(fdf);
+ if (r < 0)
+ return r;
+
+ if (fstat(fdt, &st) < 0)
+ return -errno;
+
r = copy_bytes_full(fdf, fdt, UINT64_MAX, copy_flags, NULL, NULL, progress_bytes, userdata);
+ if (r < 0)
+ return r;
- (void) copy_times(fdf, fdt, copy_flags);
- (void) copy_xattr(fdf, fdt);
+ if (S_ISREG(fdt)) {
+ (void) copy_times(fdf, fdt, copy_flags);
+ (void) copy_xattr(fdf, fdt);
+ }
- return r;
+ if (copy_flags & COPY_FSYNC_FULL) {
+ r = fsync_full(fdt);
+ if (r < 0)
+ return r;
+ } else if (copy_flags & COPY_FSYNC) {
+ if (fsync(fdt) < 0)
+ return -errno;
+ }
+
+ return 0;
}
int copy_file_full(
copy_progress_bytes_t progress_bytes,
void *userdata) {
- _cleanup_close_ int fdf = -1;
+ _cleanup_close_ int fdf = -1, fdt = -1;
struct stat st;
- int r, fdt = -1; /* avoid false maybe-uninitialized warning */
+ int r;
assert(from);
assert(to);
if (fdf < 0)
return -errno;
- if (mode == MODE_INVALID)
- if (fstat(fdf, &st) < 0)
- return -errno;
+ if (fstat(fdf, &st) < 0)
+ return -errno;
+
+ r = stat_verify_regular(&st);
+ if (r < 0)
+ return r;
RUN_WITH_UMASK(0000) {
if (copy_flags & COPY_MAC_CREATE) {
return -errno;
}
+ if (!FLAGS_SET(flags, O_EXCL)) { /* if O_EXCL was used we created the thing as regular file, no need to check again */
+ r = fd_verify_regular(fdt);
+ if (r < 0)
+ goto fail;
+ }
+
if (chattr_mask != 0)
(void) chattr_fd(fdt, chattr_flags, chattr_mask & CHATTR_EARLY_FL, NULL);
r = copy_bytes_full(fdf, fdt, UINT64_MAX, copy_flags, NULL, NULL, progress_bytes, userdata);
- if (r < 0) {
- close(fdt);
- (void) unlink(to);
- return r;
- }
+ if (r < 0)
+ goto fail;
(void) copy_times(fdf, fdt, copy_flags);
(void) copy_xattr(fdf, fdt);
if (chattr_mask != 0)
(void) chattr_fd(fdt, chattr_flags, chattr_mask & ~CHATTR_EARLY_FL, NULL);
- if (close(fdt) < 0) {
- unlink_noerrno(to);
- return -errno;
+ if (copy_flags & (COPY_FSYNC|COPY_FSYNC_FULL)) {
+ if (fsync(fdt) < 0) {
+ r = -errno;
+ goto fail;
+ }
+ }
+
+ r = close_nointr(TAKE_FD(fdt)); /* even if this fails, the fd is now invalidated */
+ if (r < 0)
+ goto fail;
+
+ if (copy_flags & COPY_FSYNC_FULL) {
+ r = fsync_parent_at(AT_FDCWD, to);
+ if (r < 0)
+ goto fail;
}
return 0;
+
+fail:
+ /* Only unlink if we definitely are the ones who created the file */
+ if (FLAGS_SET(flags, O_EXCL))
+ (void) unlink(to);
+
+ return r;
}
int copy_file_atomic_full(
if (fchmod(fdt, mode) < 0)
return -errno;
+ if ((copy_flags & (COPY_FSYNC|COPY_FSYNC_FULL))) {
+ /* Sync the file */
+ if (fsync(fdt) < 0)
+ return -errno;
+ }
+
if (copy_flags & COPY_REPLACE) {
if (renameat(AT_FDCWD, t, AT_FDCWD, to) < 0)
return -errno;
return r;
}
+ t = mfree(t);
+
if (chattr_mask != 0)
(void) chattr_fd(fdt, chattr_flags, chattr_mask & ~CHATTR_EARLY_FL, NULL);
- t = mfree(t);
+ r = close_nointr(TAKE_FD(fdt)); /* even if this fails, the fd is now invalidated */
+ if (r < 0)
+ goto fail;
+
+ if (copy_flags & COPY_FSYNC_FULL) {
+ /* Sync the parent directory */
+ r = fsync_parent_at(AT_FDCWD, to);
+ if (r < 0)
+ goto fail;
+ }
+
return 0;
+
+fail:
+ (void) unlink(to);
+ return r;
}
int copy_times(int fdf, int fdt, CopyFlags flags) {
#include <sys/types.h>
typedef enum CopyFlags {
- COPY_REFLINK = 1 << 0, /* Try to reflink */
- COPY_MERGE = 1 << 1, /* Merge existing trees with our new one to copy */
- COPY_REPLACE = 1 << 2, /* Replace an existing file if there's one */
- COPY_SAME_MOUNT = 1 << 3, /* Don't descend recursively into other file systems, across mount point boundaries */
- COPY_MERGE_EMPTY = 1 << 4, /* Merge an existing, empty directory with our new tree to copy */
- COPY_CRTIME = 1 << 5, /* Generate a user.crtime_usec xattr off the source crtime if there is one, on copying */
- COPY_SIGINT = 1 << 6, /* Check for SIGINT regularly and return EINTR if seen (caller needs to block SIGINT) */
- COPY_MAC_CREATE = 1 << 7, /* Create files with the correct MAC label (currently SELinux only) */
- COPY_HARDLINKS = 1 << 8, /* Try to reproduce hard links */
+ COPY_REFLINK = 1 << 0, /* Try to reflink */
+ COPY_MERGE = 1 << 1, /* Merge existing trees with our new one to copy */
+ COPY_REPLACE = 1 << 2, /* Replace an existing file if there's one */
+ COPY_SAME_MOUNT = 1 << 3, /* Don't descend recursively into other file systems, across mount point boundaries */
+ COPY_MERGE_EMPTY = 1 << 4, /* Merge an existing, empty directory with our new tree to copy */
+ COPY_CRTIME = 1 << 5, /* Generate a user.crtime_usec xattr off the source crtime if there is one, on copying */
+ COPY_SIGINT = 1 << 6, /* Check for SIGINT regularly and return EINTR if seen (caller needs to block SIGINT) */
+ COPY_SIGTERM = 1 << 7, /* ditto, but for SIGTERM */
+ COPY_MAC_CREATE = 1 << 8, /* Create files with the correct MAC label (currently SELinux only) */
+ COPY_HARDLINKS = 1 << 9, /* Try to reproduce hard links */
+ COPY_FSYNC = 1 << 10, /* fsync() after we are done */
+ COPY_FSYNC_FULL = 1 << 11, /* fsync_full() after we are done */
+ COPY_SYNCFS = 1 << 12, /* syncfs() the *top-level* dir after we are done */
} CopyFlags;
typedef int (*copy_progress_bytes_t)(uint64_t n_bytes, void *userdata);
if (ret) {
void *copy;
+ assert(sz <= sizeof(f->data)); /* Ensure we don't read past f->data bounds */
+
copy = memdup(f->data, sz);
if (!copy)
return -ENOMEM;
};
struct _packed_ tpm2_credential_header {
- le64_t pcr_mask;
+ le64_t pcr_mask; /* Note that the spec for PC Clients only mandates 24 PCRs, and that's what systems
+ * generally have. But keep the door open for more. */
+ le16_t pcr_bank; /* For now, either TPM2_ALG_SHA256 or TPM2_ALG_SHA1 */
+ le16_t _zero; /* Filler to maintain 32bit alignment */
le32_t blob_size;
le32_t policy_hash_size;
uint8_t policy_hash_and_blob[];
struct encrypted_credential_header *h;
int ksz, bsz, ivsz, tsz, added, r;
uint8_t md[SHA256_DIGEST_LENGTH];
+ uint16_t tpm2_pcr_bank = 0;
const EVP_CIPHER *cc;
#if HAVE_TPM2
bool try_tpm2 = false;
&tpm2_blob,
&tpm2_blob_size,
&tpm2_policy_hash,
- &tpm2_policy_hash_size);
+ &tpm2_policy_hash_size,
+ &tpm2_pcr_bank);
if (r < 0) {
if (!sd_id128_is_null(with_key))
return r;
t = (struct tpm2_credential_header*) ((uint8_t*) output + p);
t->pcr_mask = htole64(tpm2_pcr_mask);
+ t->pcr_bank = htole16(tpm2_pcr_bank);
t->blob_size = htole32(tpm2_blob_size);
t->policy_hash_size = htole32(tpm2_policy_hash_size);
memcpy(t->policy_hash_and_blob, tpm2_blob, tpm2_blob_size);
if (le64toh(t->pcr_mask) >= (UINT64_C(1) << TPM2_PCRS_MAX))
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "TPM2 PCR mask out of range.");
+ if (!tpm2_pcr_bank_supported(le16toh(t->pcr_bank)))
+ return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "TPM2 PCR bank invalid or not supported");
+ if (le16toh(t->_zero) != 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "TPM2 padding space not zero.");
if (le32toh(t->blob_size) > CREDENTIAL_FIELD_SIZE_MAX)
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Unexpected TPM2 blob size.");
if (le32toh(t->policy_hash_size) > CREDENTIAL_FIELD_SIZE_MAX)
r = tpm2_unseal(tpm2_device,
le64toh(t->pcr_mask),
+ le16toh(t->pcr_bank),
t->policy_hash_and_blob,
le32toh(t->blob_size),
t->policy_hash_and_blob + le32toh(t->blob_size),
if (dir) {
FOREACH_DIRENT(dent, dir, return -errno) {
_cleanup_free_ char *unescaped_devname = NULL;
+ ssize_t l;
- if (cunescape(dent->d_name, UNESCAPE_RELAX, &unescaped_devname) < 0)
- return -ENOMEM;
+ l = cunescape(dent->d_name, UNESCAPE_RELAX, &unescaped_devname);
+ if (l < 0)
+ return l;
n = path_join("/dev", unescaped_devname);
if (!n)
DISSECT_IMAGE_GENERIC_ROOT |
DISSECT_IMAGE_REQUIRE_ROOT |
DISSECT_IMAGE_RELAX_VAR_CHECK |
+ DISSECT_IMAGE_READ_ONLY |
DISSECT_IMAGE_USR_NO_ROOT,
&m);
if (r < 0)
left = usec_sub_unsigned(deadline, start);
if (DEBUG_LOGGING) {
- char buf[FORMAT_TIMESPAN_MAX];
const char *sn = NULL;
(void) sd_device_get_sysname(device, &sn);
log_device_debug(device,
- "Waiting for device '%s' to initialize for %s.", strna(sn), format_timespan(buf, sizeof(buf), left, 0));
+ "Waiting for device '%s' to initialize for %s.", strna(sn), FORMAT_TIMESPAN(left, 0));
}
if (left != USEC_INFINITY)
r = device_wait_for_initialization(device, subsystem, local_deadline, ret);
if (r >= 0 && DEBUG_LOGGING) {
- char buf[FORMAT_TIMESPAN_MAX];
const char *sn = NULL;
(void) sd_device_get_sysname(device, &sn);
log_device_debug(device,
"Successfully waited for device '%s' to initialize for %s.",
strna(sn),
- format_timespan(buf, sizeof(buf), usec_sub_unsigned(now(CLOCK_MONOTONIC), start), 0));
+ FORMAT_TIMESPAN(usec_sub_unsigned(now(CLOCK_MONOTONIC), start), 0));
}
if (r != -ETIMEDOUT || last_try)
return r;
- if (DEBUG_LOGGING) {
- char buf[FORMAT_TIMESPAN_MAX];
-
+ if (DEBUG_LOGGING)
log_device_debug(device,
"Device didn't initialize within %s, assuming lost event. Retriggering device.",
- format_timespan(buf, sizeof(buf), usec_sub_unsigned(now(CLOCK_MONOTONIC), start), 0));
- }
+ FORMAT_TIMESPAN(usec_sub_unsigned(now(CLOCK_MONOTONIC), start), 0));
r = sd_device_trigger(device, SD_DEVICE_CHANGE);
if (r < 0)
static int fs_grow(const char *node_path, const char *mount_path) {
_cleanup_close_ int mount_fd = -1, node_fd = -1;
- char fb[FORMAT_BYTES_MAX];
uint64_t size, newsize;
int r;
if (newsize == size)
log_debug("Successfully resized \"%s\" to %s bytes.",
- mount_path,
- format_bytes(fb, sizeof fb, newsize));
+ mount_path, FORMAT_BYTES(newsize));
else {
assert(newsize < size);
log_debug("Successfully resized \"%s\" to %s bytes (%"PRIu64" bytes lost due to blocksize).",
- mount_path,
- format_bytes(fb, sizeof fb, newsize),
- size - newsize);
+ mount_path, FORMAT_BYTES(newsize), size - newsize);
}
return 0;
return 1 << idx;
}
+_noreturn_ void freeze(void) {
+ log_close();
+
+ /* Make sure nobody waits for us on a socket anymore */
+ (void) close_all_fds_full(NULL, 0, false);
+
+ sync();
+
+ /* Let's not freeze right away, but keep reaping zombies. */
+ for (;;) {
+ int r;
+ siginfo_t si = {};
+
+ r = waitid(P_ALL, 0, &si, WEXITED);
+ if (r < 0 && errno != EINTR)
+ break;
+ }
+
+ /* waitid() failed with an unexpected error, things are really borked. Freeze now! */
+ for (;;)
+ pause();
+}
+
int fexecve_or_execve(int executable_fd, const char *executable, char *const argv[], char *const envp[]) {
#if ENABLE_FEXECVE
execveat(executable_fd, "", argv, envp, AT_EMPTY_PATH);
execve(executable, argv, envp);
return -errno;
}
+
+int fork_agent(const char *name, int except[], size_t n_except, pid_t *ret_pid, const char *path, ...) {
+ bool stdout_is_tty, stderr_is_tty;
+ size_t n, i;
+ va_list ap;
+ char **l;
+ int r;
+
+ assert(path);
+
+ /* Spawns a temporary TTY agent, making sure it goes away when we go away */
+
+ r = safe_fork_full(name,
+ except,
+ n_except,
+ FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG,
+ ret_pid);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ return 0;
+
+ /* In the child: */
+
+ stdout_is_tty = isatty(STDOUT_FILENO);
+ stderr_is_tty = isatty(STDERR_FILENO);
+
+ if (!stdout_is_tty || !stderr_is_tty) {
+ int fd;
+
+ /* Detach from stdout/stderr and reopen /dev/tty for them. This is important to ensure that
+ * when systemctl is started via popen() or a similar call that expects to read EOF we
+ * actually do generate EOF and not delay this indefinitely by keeping an unused copy of
+ * stdin around. */
+ fd = open("/dev/tty", O_WRONLY);
+ if (fd < 0) {
+ log_error_errno(errno, "Failed to open /dev/tty: %m");
+ _exit(EXIT_FAILURE);
+ }
+
+ if (!stdout_is_tty && dup2(fd, STDOUT_FILENO) < 0) {
+ log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
+ _exit(EXIT_FAILURE);
+ }
+
+ if (!stderr_is_tty && dup2(fd, STDERR_FILENO) < 0) {
+ log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
+ _exit(EXIT_FAILURE);
+ }
+
+ safe_close_above_stdio(fd);
+ }
+
+ (void) rlimit_nofile_safe();
+
+ /* Count arguments */
+ va_start(ap, path);
+ for (n = 0; va_arg(ap, char*); n++)
+ ;
+ va_end(ap);
+
+ /* Allocate strv */
+ l = newa(char*, n + 1);
+
+ /* Fill in arguments */
+ va_start(ap, path);
+ for (i = 0; i <= n; i++)
+ l[i] = va_arg(ap, char*);
+ va_end(ap);
+
+ execv(path, l);
+ _exit(EXIT_FAILURE);
+}
const char* exec_command_flags_to_string(ExecCommandFlags i);
ExecCommandFlags exec_command_flags_from_string(const char *s);
+_noreturn_ void freeze(void);
+
int fexecve_or_execve(int executable_fd, const char *executable, char *const argv[], char *const envp[]);
+
+int fork_agent(const char *name, int except[], size_t n_except, pid_t *ret_pid, const char *path, ...) _sentinel_;
return sizeof(mode_t);
default:
- assert_not_reached("Uh? Unexpected cell type");
+ assert_not_reached();
}
}
return 0;
default:
- assert_not_reached("Uh? Unexpected data type.");
+ assert_not_reached();
}
r = table_add_cell(t, &last_cell, type, data);
_cleanup_free_ char *p = NULL;
char *ret;
- p = new(char, FORMAT_TIMESTAMP_MAX);
+ p = new(char, d->type == TABLE_TIMESTAMP_RELATIVE ? FORMAT_TIMESTAMP_RELATIVE_MAX : FORMAT_TIMESTAMP_MAX);
if (!p)
return NULL;
else if (d->type == TABLE_TIMESTAMP_UTC)
ret = format_timestamp_style(p, FORMAT_TIMESTAMP_MAX, d->timestamp, TIMESTAMP_UTC);
else
- ret = format_timestamp_relative(p, FORMAT_TIMESTAMP_MAX, d->timestamp);
+ ret = format_timestamp_relative(p, FORMAT_TIMESTAMP_RELATIVE_MAX, d->timestamp);
if (!ret)
return "n/a";
}
case TABLE_MODE: {
- _cleanup_free_ char *p;
+ _cleanup_free_ char *p = NULL;
if (d->mode == MODE_INVALID)
return "n/a";
}
default:
- assert_not_reached("Unexpected type?");
+ assert_not_reached();
}
return d->formatted;
#include "utf8.h"
const GptPartitionType gpt_partition_type_table[] = {
- { GPT_ROOT_X86, "root-x86" },
- { GPT_ROOT_X86_VERITY, "root-x86-verity" },
- { GPT_ROOT_X86_64, "root-x86-64" },
- { GPT_ROOT_X86_64_VERITY, "root-x86-64-verity" },
- { GPT_ROOT_ARM, "root-arm" },
- { GPT_ROOT_ARM_VERITY, "root-arm-verity" },
- { GPT_ROOT_ARM_64, "root-arm64" },
- { GPT_ROOT_ARM_64_VERITY, "root-arm64-verity" },
- { GPT_ROOT_IA64, "root-ia64" },
- { GPT_ROOT_IA64_VERITY, "root-ia64-verity" },
- { GPT_ROOT_RISCV32, "root-riscv32" },
- { GPT_ROOT_RISCV32_VERITY, "root-riscv32-verity" },
- { GPT_ROOT_RISCV64, "root-riscv64" },
- { GPT_ROOT_RISCV64_VERITY, "root-riscv64-verity" },
+ { GPT_ROOT_X86, "root-x86" },
+ { GPT_ROOT_X86_VERITY, "root-x86-verity" },
+ { GPT_ROOT_X86_64, "root-x86-64" },
+ { GPT_ROOT_X86_64_VERITY, "root-x86-64-verity" },
+ { GPT_ROOT_ARM, "root-arm" },
+ { GPT_ROOT_ARM_VERITY, "root-arm-verity" },
+ { GPT_ROOT_ARM_64, "root-arm64" },
+ { GPT_ROOT_ARM_64_VERITY, "root-arm64-verity" },
+ { GPT_ROOT_IA64, "root-ia64" },
+ { GPT_ROOT_IA64_VERITY, "root-ia64-verity" },
+ { GPT_ROOT_LOONGARCH64, "root-loongarch64" },
+ { GPT_ROOT_LOONGARCH64_VERITY, "root-loongarch64-verity" },
+ { GPT_ROOT_RISCV32, "root-riscv32" },
+ { GPT_ROOT_RISCV32_VERITY, "root-riscv32-verity" },
+ { GPT_ROOT_RISCV64, "root-riscv64" },
+ { GPT_ROOT_RISCV64_VERITY, "root-riscv64-verity" },
#ifdef GPT_ROOT_NATIVE
- { GPT_ROOT_NATIVE, "root" },
- { GPT_ROOT_NATIVE_VERITY, "root-verity" },
+ { GPT_ROOT_NATIVE, "root" },
+ { GPT_ROOT_NATIVE_VERITY, "root-verity" },
#endif
#ifdef GPT_ROOT_SECONDARY
- { GPT_ROOT_SECONDARY, "root-secondary" },
- { GPT_ROOT_SECONDARY_VERITY, "root-secondary-verity" },
+ { GPT_ROOT_SECONDARY, "root-secondary" },
+ { GPT_ROOT_SECONDARY_VERITY, "root-secondary-verity" },
#endif
- { GPT_USR_X86, "usr-x86" },
- { GPT_USR_X86_VERITY, "usr-x86-verity" },
- { GPT_USR_X86_64, "usr-x86-64" },
- { GPT_USR_X86_64_VERITY, "usr-x86-64-verity" },
- { GPT_USR_ARM, "usr-arm" },
- { GPT_USR_ARM_VERITY, "usr-arm-verity" },
- { GPT_USR_ARM_64, "usr-arm64" },
- { GPT_USR_ARM_64_VERITY, "usr-arm64-verity" },
- { GPT_USR_IA64, "usr-ia64" },
- { GPT_USR_IA64_VERITY, "usr-ia64-verity" },
- { GPT_USR_RISCV32, "usr-riscv32" },
- { GPT_USR_RISCV32_VERITY, "usr-riscv32-verity" },
- { GPT_USR_RISCV64, "usr-riscv64" },
- { GPT_USR_RISCV64_VERITY, "usr-riscv64-verity" },
+ { GPT_USR_X86, "usr-x86" },
+ { GPT_USR_X86_VERITY, "usr-x86-verity" },
+ { GPT_USR_X86_64, "usr-x86-64" },
+ { GPT_USR_X86_64_VERITY, "usr-x86-64-verity" },
+ { GPT_USR_ARM, "usr-arm" },
+ { GPT_USR_ARM_VERITY, "usr-arm-verity" },
+ { GPT_USR_ARM_64, "usr-arm64" },
+ { GPT_USR_ARM_64_VERITY, "usr-arm64-verity" },
+ { GPT_USR_IA64, "usr-ia64" },
+ { GPT_USR_IA64_VERITY, "usr-ia64-verity" },
+ { GPT_USR_LOONGARCH64, "usr-loongarch64" },
+ { GPT_USR_LOONGARCH64_VERITY, "usr-loongarch64-verity" },
+ { GPT_USR_RISCV32, "usr-riscv32" },
+ { GPT_USR_RISCV32_VERITY, "usr-riscv32-verity" },
+ { GPT_USR_RISCV64, "usr-riscv64" },
+ { GPT_USR_RISCV64_VERITY, "usr-riscv64-verity" },
#ifdef GPT_USR_NATIVE
- { GPT_USR_NATIVE, "usr" },
- { GPT_USR_NATIVE_VERITY, "usr-verity" },
+ { GPT_USR_NATIVE, "usr" },
+ { GPT_USR_NATIVE_VERITY, "usr-verity" },
#endif
#ifdef GPT_USR_SECONDARY
- { GPT_USR_SECONDARY, "usr-secondary" },
- { GPT_USR_SECONDARY_VERITY, "usr-secondary-verity" },
+ { GPT_USR_SECONDARY, "usr-secondary" },
+ { GPT_USR_SECONDARY_VERITY, "usr-secondary-verity" },
#endif
- { GPT_ESP, "esp" },
- { GPT_XBOOTLDR, "xbootldr" },
- { GPT_SWAP, "swap" },
- { GPT_HOME, "home" },
- { GPT_SRV, "srv" },
- { GPT_VAR, "var" },
- { GPT_TMP, "tmp" },
- { GPT_USER_HOME, "user-home" },
- { GPT_LINUX_GENERIC, "linux-generic" },
+ { GPT_ESP, "esp" },
+ { GPT_XBOOTLDR, "xbootldr" },
+ { GPT_SWAP, "swap" },
+ { GPT_HOME, "home" },
+ { GPT_SRV, "srv" },
+ { GPT_VAR, "var" },
+ { GPT_TMP, "tmp" },
+ { GPT_USER_HOME, "user-home" },
+ { GPT_LINUX_GENERIC, "linux-generic" },
{}
};
GPT_ROOT_ARM,
GPT_ROOT_ARM_64,
GPT_ROOT_IA64,
+ GPT_ROOT_LOONGARCH64,
GPT_ROOT_RISCV32,
GPT_ROOT_RISCV64);
}
GPT_ROOT_ARM_VERITY,
GPT_ROOT_ARM_64_VERITY,
GPT_ROOT_IA64_VERITY,
+ GPT_ROOT_LOONGARCH64_VERITY,
GPT_ROOT_RISCV32_VERITY,
GPT_ROOT_RISCV64_VERITY);
}
GPT_USR_ARM,
GPT_USR_ARM_64,
GPT_USR_IA64,
+ GPT_USR_LOONGARCH64,
GPT_USR_RISCV32,
GPT_USR_RISCV64);
}
GPT_USR_ARM_VERITY,
GPT_USR_ARM_64_VERITY,
GPT_USR_IA64_VERITY,
+ GPT_USR_LOONGARCH64_VERITY,
GPT_USR_RISCV32_VERITY,
GPT_USR_RISCV64_VERITY);
}
#include "id128-util.h"
-/* We only support root disk discovery for x86, x86-64, Itanium and ARM for now, since EFI for anything else
- * doesn't really exist, and we only care for root partitions on the same disk as the EFI ESP. */
-
-#define GPT_ROOT_X86 SD_ID128_MAKE(44,47,95,40,f2,97,41,b2,9a,f7,d1,31,d5,f0,45,8a)
-#define GPT_ROOT_X86_64 SD_ID128_MAKE(4f,68,bc,e3,e8,cd,4d,b1,96,e7,fb,ca,f9,84,b7,09)
-#define GPT_ROOT_ARM SD_ID128_MAKE(69,da,d7,10,2c,e4,4e,3c,b1,6c,21,a1,d4,9a,be,d3)
-#define GPT_ROOT_ARM_64 SD_ID128_MAKE(b9,21,b0,45,1d,f0,41,c3,af,44,4c,6f,28,0d,3f,ae)
-#define GPT_ROOT_IA64 SD_ID128_MAKE(99,3d,8d,3d,f8,0e,42,25,85,5a,9d,af,8e,d7,ea,97)
-#define GPT_ROOT_RISCV32 SD_ID128_MAKE(60,d5,a7,fe,8e,7d,43,5c,b7,14,3d,d8,16,21,44,e1)
-#define GPT_ROOT_RISCV64 SD_ID128_MAKE(72,ec,70,a6,cf,74,40,e6,bd,49,4b,da,08,e8,f2,24)
-#define GPT_USR_X86 SD_ID128_MAKE(75,25,0d,76,8c,c6,45,8e,bd,66,bd,47,cc,81,a8,12)
-#define GPT_USR_X86_64 SD_ID128_MAKE(84,84,68,0c,95,21,48,c6,9c,11,b0,72,06,56,f6,9e)
-#define GPT_USR_ARM SD_ID128_MAKE(7d,03,59,a3,02,b3,4f,0a,86,5c,65,44,03,e7,06,25)
-#define GPT_USR_ARM_64 SD_ID128_MAKE(b0,e0,10,50,ee,5f,43,90,94,9a,91,01,b1,71,04,e9)
-#define GPT_USR_IA64 SD_ID128_MAKE(43,01,d2,a6,4e,3b,4b,2a,bb,94,9e,0b,2c,42,25,ea)
-#define GPT_USR_RISCV32 SD_ID128_MAKE(b9,33,fb,22,5c,3f,4f,91,af,90,e2,bb,0f,a5,07,02)
-#define GPT_USR_RISCV64 SD_ID128_MAKE(be,ae,c3,4b,84,42,43,9b,a4,0b,98,43,81,ed,09,7d)
-#define GPT_ESP SD_ID128_MAKE(c1,2a,73,28,f8,1f,11,d2,ba,4b,00,a0,c9,3e,c9,3b)
-#define GPT_XBOOTLDR SD_ID128_MAKE(bc,13,c2,ff,59,e6,42,62,a3,52,b2,75,fd,6f,71,72)
-#define GPT_SWAP SD_ID128_MAKE(06,57,fd,6d,a4,ab,43,c4,84,e5,09,33,c8,4b,4f,4f)
-#define GPT_HOME SD_ID128_MAKE(93,3a,c7,e1,2e,b4,4f,13,b8,44,0e,14,e2,ae,f9,15)
-#define GPT_SRV SD_ID128_MAKE(3b,8f,84,25,20,e0,4f,3b,90,7f,1a,25,a7,6f,98,e8)
-#define GPT_VAR SD_ID128_MAKE(4d,21,b0,16,b5,34,45,c2,a9,fb,5c,16,e0,91,fd,2d)
-#define GPT_TMP SD_ID128_MAKE(7e,c6,f5,57,3b,c5,4a,ca,b2,93,16,ef,5d,f6,39,d1)
-#define GPT_USER_HOME SD_ID128_MAKE(77,3f,91,ef,66,d4,49,b5,bd,83,d6,83,bf,40,ad,16)
-#define GPT_LINUX_GENERIC SD_ID128_MAKE(0f,c6,3d,af,84,83,47,72,8e,79,3d,69,d8,47,7d,e4)
+/* We only support root disk discovery for x86, x86-64, Itanium, ARM and LoongArch for now,
+ * since EFI for anything else doesn't really exist, and we only care for root partitions
+ * on the same disk as the EFI ESP. */
+
+#define GPT_ROOT_X86 SD_ID128_MAKE(44,47,95,40,f2,97,41,b2,9a,f7,d1,31,d5,f0,45,8a)
+#define GPT_ROOT_X86_64 SD_ID128_MAKE(4f,68,bc,e3,e8,cd,4d,b1,96,e7,fb,ca,f9,84,b7,09)
+#define GPT_ROOT_ARM SD_ID128_MAKE(69,da,d7,10,2c,e4,4e,3c,b1,6c,21,a1,d4,9a,be,d3)
+#define GPT_ROOT_ARM_64 SD_ID128_MAKE(b9,21,b0,45,1d,f0,41,c3,af,44,4c,6f,28,0d,3f,ae)
+#define GPT_ROOT_IA64 SD_ID128_MAKE(99,3d,8d,3d,f8,0e,42,25,85,5a,9d,af,8e,d7,ea,97)
+#define GPT_ROOT_LOONGARCH64 SD_ID128_MAKE(77,05,58,00,79,2c,4f,94,b3,9a,99,c9,1b,76,2b,b6)
+#define GPT_ROOT_RISCV32 SD_ID128_MAKE(60,d5,a7,fe,8e,7d,43,5c,b7,14,3d,d8,16,21,44,e1)
+#define GPT_ROOT_RISCV64 SD_ID128_MAKE(72,ec,70,a6,cf,74,40,e6,bd,49,4b,da,08,e8,f2,24)
+#define GPT_USR_X86 SD_ID128_MAKE(75,25,0d,76,8c,c6,45,8e,bd,66,bd,47,cc,81,a8,12)
+#define GPT_USR_X86_64 SD_ID128_MAKE(84,84,68,0c,95,21,48,c6,9c,11,b0,72,06,56,f6,9e)
+#define GPT_USR_ARM SD_ID128_MAKE(7d,03,59,a3,02,b3,4f,0a,86,5c,65,44,03,e7,06,25)
+#define GPT_USR_ARM_64 SD_ID128_MAKE(b0,e0,10,50,ee,5f,43,90,94,9a,91,01,b1,71,04,e9)
+#define GPT_USR_IA64 SD_ID128_MAKE(43,01,d2,a6,4e,3b,4b,2a,bb,94,9e,0b,2c,42,25,ea)
+#define GPT_USR_LOONGARCH64 SD_ID128_MAKE(e6,11,c7,02,57,5c,4c,be,9a,46,43,4f,a0,bf,7e,3f)
+#define GPT_USR_RISCV32 SD_ID128_MAKE(b9,33,fb,22,5c,3f,4f,91,af,90,e2,bb,0f,a5,07,02)
+#define GPT_USR_RISCV64 SD_ID128_MAKE(be,ae,c3,4b,84,42,43,9b,a4,0b,98,43,81,ed,09,7d)
+#define GPT_ESP SD_ID128_MAKE(c1,2a,73,28,f8,1f,11,d2,ba,4b,00,a0,c9,3e,c9,3b)
+#define GPT_XBOOTLDR SD_ID128_MAKE(bc,13,c2,ff,59,e6,42,62,a3,52,b2,75,fd,6f,71,72)
+#define GPT_SWAP SD_ID128_MAKE(06,57,fd,6d,a4,ab,43,c4,84,e5,09,33,c8,4b,4f,4f)
+#define GPT_HOME SD_ID128_MAKE(93,3a,c7,e1,2e,b4,4f,13,b8,44,0e,14,e2,ae,f9,15)
+#define GPT_SRV SD_ID128_MAKE(3b,8f,84,25,20,e0,4f,3b,90,7f,1a,25,a7,6f,98,e8)
+#define GPT_VAR SD_ID128_MAKE(4d,21,b0,16,b5,34,45,c2,a9,fb,5c,16,e0,91,fd,2d)
+#define GPT_TMP SD_ID128_MAKE(7e,c6,f5,57,3b,c5,4a,ca,b2,93,16,ef,5d,f6,39,d1)
+#define GPT_USER_HOME SD_ID128_MAKE(77,3f,91,ef,66,d4,49,b5,bd,83,d6,83,bf,40,ad,16)
+#define GPT_LINUX_GENERIC SD_ID128_MAKE(0f,c6,3d,af,84,83,47,72,8e,79,3d,69,d8,47,7d,e4)
/* Verity partitions for the root partitions above (we only define them for the root and /usr partitions,
* because only they are commonly read-only and hence suitable for verity). */
-#define GPT_ROOT_X86_VERITY SD_ID128_MAKE(d1,3c,5d,3b,b5,d1,42,2a,b2,9f,94,54,fd,c8,9d,76)
-#define GPT_ROOT_X86_64_VERITY SD_ID128_MAKE(2c,73,57,ed,eb,d2,46,d9,ae,c1,23,d4,37,ec,2b,f5)
-#define GPT_ROOT_ARM_VERITY SD_ID128_MAKE(73,86,cd,f2,20,3c,47,a9,a4,98,f2,ec,ce,45,a2,d6)
-#define GPT_ROOT_ARM_64_VERITY SD_ID128_MAKE(df,33,00,ce,d6,9f,4c,92,97,8c,9b,fb,0f,38,d8,20)
-#define GPT_ROOT_IA64_VERITY SD_ID128_MAKE(86,ed,10,d5,b6,07,45,bb,89,57,d3,50,f2,3d,05,71)
-#define GPT_ROOT_RISCV32_VERITY SD_ID128_MAKE(ae,02,53,be,11,67,40,07,ac,68,43,92,6c,14,c5,de)
-#define GPT_ROOT_RISCV64_VERITY SD_ID128_MAKE(b6,ed,55,82,44,0b,42,09,b8,da,5f,f7,c4,19,ea,3d)
-#define GPT_USR_X86_VERITY SD_ID128_MAKE(8f,46,1b,0d,14,ee,4e,81,9a,a9,04,9b,6f,b9,7a,bd)
-#define GPT_USR_X86_64_VERITY SD_ID128_MAKE(77,ff,5f,63,e7,b6,46,33,ac,f4,15,65,b8,64,c0,e6)
-#define GPT_USR_ARM_VERITY SD_ID128_MAKE(c2,15,d7,51,7b,cd,46,49,be,90,66,27,49,0a,4c,05)
-#define GPT_USR_ARM_64_VERITY SD_ID128_MAKE(6e,11,a4,e7,fb,ca,4d,ed,b9,e9,e1,a5,12,bb,66,4e)
-#define GPT_USR_IA64_VERITY SD_ID128_MAKE(6a,49,1e,03,3b,e7,45,45,8e,38,83,32,0e,0e,a8,80)
-#define GPT_USR_RISCV32_VERITY SD_ID128_MAKE(cb,1e,e4,e3,8c,d0,41,36,a0,a4,aa,61,a3,2e,87,30)
-#define GPT_USR_RISCV64_VERITY SD_ID128_MAKE(8f,10,56,be,9b,05,47,c4,81,d6,be,53,12,8e,5b,54)
+#define GPT_ROOT_X86_VERITY SD_ID128_MAKE(d1,3c,5d,3b,b5,d1,42,2a,b2,9f,94,54,fd,c8,9d,76)
+#define GPT_ROOT_X86_64_VERITY SD_ID128_MAKE(2c,73,57,ed,eb,d2,46,d9,ae,c1,23,d4,37,ec,2b,f5)
+#define GPT_ROOT_ARM_VERITY SD_ID128_MAKE(73,86,cd,f2,20,3c,47,a9,a4,98,f2,ec,ce,45,a2,d6)
+#define GPT_ROOT_ARM_64_VERITY SD_ID128_MAKE(df,33,00,ce,d6,9f,4c,92,97,8c,9b,fb,0f,38,d8,20)
+#define GPT_ROOT_IA64_VERITY SD_ID128_MAKE(86,ed,10,d5,b6,07,45,bb,89,57,d3,50,f2,3d,05,71)
+#define GPT_ROOT_LOONGARCH64_VERITY SD_ID128_MAKE(f3,39,3b,22,e9,af,46,13,a9,48,9d,3b,fb,d0,c5,35)
+#define GPT_ROOT_RISCV32_VERITY SD_ID128_MAKE(ae,02,53,be,11,67,40,07,ac,68,43,92,6c,14,c5,de)
+#define GPT_ROOT_RISCV64_VERITY SD_ID128_MAKE(b6,ed,55,82,44,0b,42,09,b8,da,5f,f7,c4,19,ea,3d)
+#define GPT_USR_X86_VERITY SD_ID128_MAKE(8f,46,1b,0d,14,ee,4e,81,9a,a9,04,9b,6f,b9,7a,bd)
+#define GPT_USR_X86_64_VERITY SD_ID128_MAKE(77,ff,5f,63,e7,b6,46,33,ac,f4,15,65,b8,64,c0,e6)
+#define GPT_USR_ARM_VERITY SD_ID128_MAKE(c2,15,d7,51,7b,cd,46,49,be,90,66,27,49,0a,4c,05)
+#define GPT_USR_ARM_64_VERITY SD_ID128_MAKE(6e,11,a4,e7,fb,ca,4d,ed,b9,e9,e1,a5,12,bb,66,4e)
+#define GPT_USR_IA64_VERITY SD_ID128_MAKE(6a,49,1e,03,3b,e7,45,45,8e,38,83,32,0e,0e,a8,80)
+#define GPT_USR_LOONGARCH64_VERITY SD_ID128_MAKE(f4,6b,2c,26,59,ae,48,f0,91,06,c5,0e,d4,7f,67,3d)
+#define GPT_USR_RISCV32_VERITY SD_ID128_MAKE(cb,1e,e4,e3,8c,d0,41,36,a0,a4,aa,61,a3,2e,87,30)
+#define GPT_USR_RISCV64_VERITY SD_ID128_MAKE(8f,10,56,be,9b,05,47,c4,81,d6,be,53,12,8e,5b,54)
#if defined(__x86_64__)
# define GPT_ROOT_NATIVE GPT_ROOT_X86_64
# define GPT_USR_NATIVE_VERITY GPT_USR_ARM_VERITY
#endif
+#if defined(__loongarch64)
+# define GPT_ROOT_NATIVE GPT_ROOT_LOONGARCH64
+# define GPT_ROOT_NATIVE_VERITY GPT_ROOT_LOONGARCH64_VERITY
+# define GPT_USR_NATIVE GPT_USR_LOONGARCH64
+# define GPT_USR_NATIVE_VERITY GPT_USR_LOONGARCH64_VERITY
+#endif
+
#if defined(__riscv)
#if (__riscv_xlen == 32)
# define GPT_ROOT_NATIVE GPT_ROOT_RISCV32
#include "string-table.h"
#include "string-util.h"
-int import_url_last_component(const char *url, char **ret) {
- const char *e, *p;
- char *s;
+static const char *skip_protocol_and_hostname(const char *url) {
+ const char *d;
+ size_t n;
+
+ /* A very very lenient implementation of RFC3986 Section 3.2 */
+
+ /* Find colon separating protocol and hostname */
+ d = strchr(url, ':');
+ if (!d || url == d)
+ return NULL;
+ d++;
+
+ /* Skip slashes after colon */
+ d += strspn(d, "/");
+
+ /* Skip everything till next slash or end */
+ n = strcspn(d, "/?#");
+ if (n == 0)
+ return NULL;
+
+ return d + n;
+}
- e = strchrnul(url, '?');
+int import_url_last_component(
+ const char *url,
+ char **ret) {
- while (e > url && e[-1] == '/')
+ const char *e, *p, *h;
+
+ /* This extracts the last path component of the specified URI, i.e. the last non-empty substrings
+ * between two "/" characters. This ignores "Query" and "Fragment" suffixes (as per RFC3986). */
+
+ h = skip_protocol_and_hostname(url);
+ if (!h)
+ return -EINVAL;
+
+ e = h + strcspn(h, "?#"); /* Cut off "Query" and "Fragment" */
+
+ while (e > h && e[-1] == '/') /* Eat trailing slashes */
e--;
p = e;
- while (p > url && p[-1] != '/')
+ while (p > h && p[-1] != '/') /* Find component before that */
p--;
- if (e <= p)
- return -EINVAL;
+ if (e <= p) /* Empty component? */
+ return -EADDRNOTAVAIL;
- s = strndup(p, e - p);
- if (!s)
- return -ENOMEM;
+ if (ret) {
+ char *s;
+
+ s = strndup(p, e - p);
+ if (!s)
+ return -ENOMEM;
+
+ *ret = s;
+ }
- *ret = s;
return 0;
}
-int import_url_change_last_component(const char *url, const char *suffix, char **ret) {
- const char *e;
+int import_url_change_suffix(
+ const char *url,
+ size_t n_drop_components,
+ const char *suffix,
+ char **ret) {
+
+ const char *e, *h;
char *s;
assert(url);
assert(ret);
- e = strchrnul(url, '?');
+ /* This drops the specified number of path components of the specified URI, i.e. the specified number
+ * of non-empty substring between two "/" characters from the end of the string, and then append the
+ * specified suffix instead. Before doing all this it chops off the "Query" and "Fragment" suffixes
+ * (they are *not* readded to the final URL). Note that n_drop_components may be 0 (in which case the
+ * component are simply added to the end). The suffix may be specified as NULL or empty string in
+ * which case nothing is appended, only the specified number of components chopped off. Note that the
+ * function may be called with n_drop_components == 0 and suffix == NULL, in which case the "Query"
+ * and "Fragment" is chopped off, and ensured the URL ends in a single "/", and that's it. */
+
+ h = skip_protocol_and_hostname(url);
+ if (!h)
+ return -EINVAL;
- while (e > url && e[-1] == '/')
- e--;
+ e = h + strcspn(h, "?#"); /* Cut off "Query" and "Fragment" */
- while (e > url && e[-1] != '/')
+ while (e > h && e[-1] == '/') /* Eat trailing slashes */
e--;
- if (e <= url)
- return -EINVAL;
+ /* Drop the specified number of components from the end. Note that this is pretty lenient: if there
+ * are less component we silently drop those and then append the suffix to the top. */
+ while (n_drop_components > 0) {
+ while (e > h && e[-1] != '/') /* Eat last word (we don't mind if empty) */
+ e--;
+
+ while (e > h && e[-1] == '/') /* Eat slashes before the last word */
+ e--;
+
+ n_drop_components--;
+ }
- s = new(char, (e - url) + strlen(suffix) + 1);
+ s = new(char, (e - url) + 1 + strlen_ptr(suffix) + 1);
if (!s)
return -ENOMEM;
- strcpy(mempcpy(s, url, e - url), suffix);
+ strcpy(stpcpy(mempcpy(s, url, e - url), "/"), strempty(suffix));
*ret = s;
return 0;
}
} ImportVerify;
int import_url_last_component(const char *url, char **ret);
-int import_url_change_last_component(const char *url, const char *suffix, char **ret);
+
+int import_url_change_suffix(const char *url, size_t n_drop_components, const char *suffix, char **ret);
+
+static inline int import_url_change_last_component(const char *url, const char *suffix, char **ret) {
+ return import_url_change_suffix(url, 1, suffix, ret);
+}
+
+static inline int import_url_append_component(const char *url, const char *suffix, char **ret) {
+ return import_url_change_suffix(url, 0, suffix, ret);
+}
const char* import_verify_to_string(ImportVerify v) _const_;
ImportVerify import_verify_from_string(const char *s) _pure_;
break;
default:
- assert_not_reached("Unexpected unit file type.");
+ assert_not_reached();
}
*ret = state;
else if (IN_SET(scope, UNIT_FILE_GLOBAL, UNIT_FILE_USER))
dirs = user_dirs;
else
- assert_not_reached("Invalid unit file scope");
+ assert_not_reached();
return conf_files_list_strv(files, ".preset", root_dir, 0, dirs);
}
log_debug("Preset files say disable %s.", name);
return 0;
default:
- assert_not_reached("invalid preset action");
+ assert_not_reached();
}
}
return 0; /* continue */
default:
- assert_not_reached("wtf?");
+ assert_not_reached();
}
}
break;
default:
- assert_not_reached("Unexpected variant type");
+ assert_not_reached();
}
}
return offsetof(JsonVariant, value);
default:
- assert_not_reached("unexpected type");
+ assert_not_reached();
}
}
}
default:
- assert_not_reached("Unknown variant type.");
+ assert_not_reached();
}
}
}
default:
- assert_not_reached("Unexpected variant type.");
+ assert_not_reached();
}
return 0;
return -EINVAL;
default:
- assert_not_reached("Unexpected tokenizer state");
+ assert_not_reached();
}
null_return:
break;
default:
- assert_not_reached("Unexpected token");
+ assert_not_reached();
}
if (add) {
#include "parse-util.h"
#include "process-util.h"
#include "set.h"
+#include "stdio-util.h"
#include "string-util.h"
#include "terminal-util.h"
#include "util.h"
SET_FOREACH(p, pids) {
_cleanup_free_ char *s = NULL;
+ char fallback[DECIMAL_STR_MAX(pid_t)];
if (get_process_comm(PTR_TO_PID(p), &s) < 0)
- (void) asprintf(&s, PID_FMT, PTR_TO_PID(p));
+ xsprintf(fallback, PID_FMT, PTR_TO_PID(p));
- if (!strextend(&lst_child, ", ", s)) {
- log_oom();
- return;
- }
+ if (!strextend(&lst_child, ", ", s ?: fallback))
+ return (void) log_oom();
}
if (isempty(lst_child))
break;
default:
- assert_not_reached("Unexpected protocol");
+ assert_not_reached();
}
/* So ideally we'd just use IP_UNICAST_IF here to pass the ifindex info to the kernel before
break;
default:
- assert_not_reached("Unexpected protocol");
+ assert_not_reached();
}
}
break;
default:
- assert_not_reached("Unknown time format");
+ assert_not_reached();
}
}
}
}
- if (!(flags & OUTPUT_SHOW_ALL) && !utf8_is_printable(message, message_len)) {
- char bytes[FORMAT_BYTES_MAX];
- fprintf(f, "[%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
- } else {
+ if (!(flags & OUTPUT_SHOW_ALL) && !utf8_is_printable(message, message_len))
+ fprintf(f, "[%s blob data]\n", FORMAT_BYTES(message_len));
+ else {
/* URLify config_file string in message, if the message starts with it.
* Skip URLification if the highlighted pattern overlaps. */
p, valuelen,
NULL);
fputs(off, f);
- } else {
- char bytes[FORMAT_BYTES_MAX];
-
+ } else
fprintf(f, " %s%.*s=[%s blob data]%s\n",
on,
(int) (c - (const char*) data),
(const char*) data,
- format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1),
+ FORMAT_BYTES(length - (c - (const char *) data) - 1),
off);
- }
}
if (r < 0)
* use the same label for all their files. */
if (loaded_policy) {
usec_t before_relabel, after_relabel;
- char timespan[FORMAT_TIMESPAN_MAX];
const char *i;
int n_extra;
log_info("Relabelled /dev, /dev/shm, /run, /sys/fs/cgroup%s in %s.",
n_extra > 0 ? ", additional files" : "",
- format_timespan(timespan, sizeof(timespan), after_relabel - before_relabel, 0));
+ FORMAT_TIMESPAN(after_relabel - before_relabel, 0));
}
#endif
#include "alloc-util.h"
#include "dissect-image.h"
+#include "exec-util.h"
#include "extract-word.h"
#include "fd-util.h"
#include "fileio.h"
r = safe_fork("(sd-mkuserns)", FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_NEW_USERNS, &pid);
if (r < 0)
return r;
- if (r == 0) {
+ if (r == 0)
/* Child. We do nothing here, just freeze until somebody kills us. */
freeze();
- _exit(EXIT_FAILURE);
- }
xsprintf(line, UID_FMT " " UID_FMT " " UID_FMT "\n", 0, uid_shift, uid_range);
/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#include <sys/poll.h>
+#include <poll.h>
#include "fd-util.h"
#include "io-util.h"
#include "util.h"
bool urlify_enabled(void) {
+#if ENABLE_URLIFY
static int cached_urlify_enabled = -1;
if (cached_urlify_enabled < 0) {
}
return cached_urlify_enabled;
+#else
+ return 0;
+#endif
}
int terminal_urlify(const char *url, const char *text, char **ret) {
#include "stat-util.h"
#include "string-util.h"
+/* We treat tmpfs/ramfs + cgroupfs as non-physical file sytems. cgroupfs is similar to tmpfs in a way after
+ * all: we can create arbitrary directory hierarchies in it, and hence can also use rm_rf() on it to remove
+ * those again. */
static bool is_physical_fs(const struct statfs *sfs) {
return !is_temporary_fs(sfs) && !is_cgroup_fs(sfs);
}
return 0;
}
-int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) {
- _cleanup_closedir_ DIR *d = NULL;
- struct dirent *de;
- int ret = 0, r;
- struct statfs sfs;
+static int rm_rf_children_inner(
+ int fd,
+ const char *fname,
+ int is_dir,
+ RemoveFlags flags,
+ const struct stat *root_dev) {
- assert(fd >= 0);
+ struct stat st;
+ int r;
- /* This returns the first error we run into, but nevertheless tries to go on. This closes the passed
- * fd, in all cases, including on failure.. */
+ assert(fd >= 0);
+ assert(fname);
- if (!(flags & REMOVE_PHYSICAL)) {
+ if (is_dir < 0 || (is_dir > 0 && (root_dev || (flags & REMOVE_SUBVOLUME)))) {
- r = fstatfs(fd, &sfs);
- if (r < 0) {
- safe_close(fd);
- return -errno;
- }
+ r = fstatat_harder(fd, fname, &st, AT_SYMLINK_NOFOLLOW, flags);
+ if (r < 0)
+ return r;
- if (is_physical_fs(&sfs)) {
- /* We refuse to clean physical file systems with this call,
- * unless explicitly requested. This is extra paranoia just
- * to be sure we never ever remove non-state data. */
- _cleanup_free_ char *path = NULL;
+ is_dir = S_ISDIR(st.st_mode);
+ }
- (void) fd_get_path(fd, &path);
- log_error("Attempted to remove disk file system under \"%s\", and we can't allow that.",
- strna(path));
+ if (is_dir) {
+ _cleanup_close_ int subdir_fd = -1;
+ int q;
- safe_close(fd);
- return -EPERM;
- }
- }
+ /* if root_dev is set, remove subdirectories only if device is same */
+ if (root_dev && st.st_dev != root_dev->st_dev)
+ return 0;
- d = fdopendir(fd);
- if (!d) {
- safe_close(fd);
- return errno == ENOENT ? 0 : -errno;
- }
+ /* Stop at mount points */
+ r = fd_is_mount_point(fd, fname, 0);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ return 0;
- FOREACH_DIRENT_ALL(de, d, return -errno) {
- bool is_dir;
- struct stat st;
+ if ((flags & REMOVE_SUBVOLUME) && btrfs_might_be_subvol(&st)) {
- if (dot_or_dot_dot(de->d_name))
- continue;
+ /* This could be a subvolume, try to remove it */
- if (de->d_type == DT_UNKNOWN ||
- (de->d_type == DT_DIR && (root_dev || (flags & REMOVE_SUBVOLUME)))) {
- r = fstatat_harder(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW, flags);
+ r = btrfs_subvol_remove_fd(fd, fname, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
if (r < 0) {
- if (ret == 0 && r != -ENOENT)
- ret = r;
- continue;
- }
+ if (!IN_SET(r, -ENOTTY, -EINVAL))
+ return r;
- is_dir = S_ISDIR(st.st_mode);
- } else
- is_dir = de->d_type == DT_DIR;
+ /* ENOTTY, then it wasn't a btrfs subvolume, continue below. */
+ } else
+ /* It was a subvolume, done. */
+ return 1;
+ }
- if (is_dir) {
- _cleanup_close_ int subdir_fd = -1;
+ subdir_fd = openat(fd, fname, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
+ if (subdir_fd < 0)
+ return -errno;
- /* if root_dev is set, remove subdirectories only if device is same */
- if (root_dev && st.st_dev != root_dev->st_dev)
- continue;
+ /* We pass REMOVE_PHYSICAL here, to avoid doing the fstatfs() to check the file system type
+ * again for each directory */
+ q = rm_rf_children(TAKE_FD(subdir_fd), flags | REMOVE_PHYSICAL, root_dev);
- subdir_fd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
- if (subdir_fd < 0) {
- if (ret == 0 && errno != ENOENT)
- ret = -errno;
- continue;
- }
+ r = unlinkat_harder(fd, fname, AT_REMOVEDIR, flags);
+ if (r < 0)
+ return r;
+ if (q < 0)
+ return q;
- /* Stop at mount points */
- r = fd_is_mount_point(fd, de->d_name, 0);
- if (r < 0) {
- if (ret == 0 && r != -ENOENT)
- ret = r;
+ return 1;
- continue;
- }
- if (r > 0)
- continue;
+ } else if (!(flags & REMOVE_ONLY_DIRECTORIES)) {
+ r = unlinkat_harder(fd, fname, 0, flags);
+ if (r < 0)
+ return r;
- if ((flags & REMOVE_SUBVOLUME) && btrfs_might_be_subvol(&st)) {
+ return 1;
+ }
- /* This could be a subvolume, try to remove it */
+ return 0;
+}
- r = btrfs_subvol_remove_fd(fd, de->d_name, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
- if (r < 0) {
- if (!IN_SET(r, -ENOTTY, -EINVAL)) {
- if (ret == 0)
- ret = r;
+int rm_rf_children(
+ int fd,
+ RemoveFlags flags,
+ const struct stat *root_dev) {
- continue;
- }
+ _cleanup_closedir_ DIR *d = NULL;
+ struct dirent *de;
+ int ret = 0, r;
- /* ENOTTY, then it wasn't a btrfs subvolume, continue below. */
- } else
- /* It was a subvolume, continue. */
- continue;
- }
+ assert(fd >= 0);
+
+ /* This returns the first error we run into, but nevertheless tries to go on. This closes the passed
+ * fd, in all cases, including on failure. */
+
+ d = fdopendir(fd);
+ if (!d) {
+ safe_close(fd);
+ return -errno;
+ }
- /* We pass REMOVE_PHYSICAL here, to avoid doing the fstatfs() to check the file
- * system type again for each directory */
- r = rm_rf_children(TAKE_FD(subdir_fd), flags | REMOVE_PHYSICAL, root_dev);
- if (r < 0 && ret == 0)
- ret = r;
+ if (!(flags & REMOVE_PHYSICAL)) {
+ struct statfs sfs;
- r = unlinkat_harder(fd, de->d_name, AT_REMOVEDIR, flags);
- if (r < 0 && r != -ENOENT && ret == 0)
- ret = r;
+ if (fstatfs(dirfd(d), &sfs) < 0)
+ return -errno;
+
+ if (is_physical_fs(&sfs)) {
+ /* We refuse to clean physical file systems with this call, unless explicitly
+ * requested. This is extra paranoia just to be sure we never ever remove non-state
+ * data. */
- } else if (!(flags & REMOVE_ONLY_DIRECTORIES)) {
+ _cleanup_free_ char *path = NULL;
- r = unlinkat_harder(fd, de->d_name, 0, flags);
- if (r < 0 && r != -ENOENT && ret == 0)
- ret = r;
+ (void) fd_get_path(fd, &path);
+ return log_error_errno(SYNTHETIC_ERRNO(EPERM),
+ "Attempted to remove disk file system under \"%s\", and we can't allow that.",
+ strna(path));
}
}
+
+ FOREACH_DIRENT_ALL(de, d, return -errno) {
+ int is_dir;
+
+ if (dot_or_dot_dot(de->d_name))
+ continue;
+
+ is_dir =
+ de->d_type == DT_UNKNOWN ? -1 :
+ de->d_type == DT_DIR;
+
+ r = rm_rf_children_inner(dirfd(d), de->d_name, is_dir, flags, root_dev);
+ if (r < 0 && r != -ENOENT && ret == 0)
+ ret = r;
+ }
+
return ret;
}
int rm_rf(const char *path, RemoveFlags flags) {
int fd, r;
- struct statfs s;
assert(path);
if (FLAGS_SET(flags, REMOVE_ROOT)) {
if (!FLAGS_SET(flags, REMOVE_PHYSICAL)) {
+ struct statfs s;
+
if (statfs(path, &s) < 0)
return -errno;
-
if (is_physical_fs(&s))
return log_error_errno(SYNTHETIC_ERRNO(EPERM),
"Attempted to remove files from a disk file system under \"%s\", refusing.",
return r;
}
+
+int rm_rf_child(int fd, const char *name, RemoveFlags flags) {
+
+ /* Removes one specific child of the specified directory */
+
+ if (fd < 0)
+ return -EBADF;
+
+ if (!filename_is_valid(name))
+ return -EINVAL;
+
+ if ((flags & (REMOVE_ROOT|REMOVE_MISSING_OK)) != 0) /* Doesn't really make sense here, we are not supposed to remove 'fd' anyway */
+ return -EINVAL;
+
+ if (FLAGS_SET(flags, REMOVE_ONLY_DIRECTORIES|REMOVE_SUBVOLUME))
+ return -EINVAL;
+
+ return rm_rf_children_inner(fd, name, -1, flags, NULL);
+}
int fstatat_flags,
RemoveFlags remove_flags);
-int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev);
+int rm_rf_children(int fd, RemoveFlags flags, const struct stat *root_dev);
+int rm_rf_child(int fd, const char *name, RemoveFlags flags);
int rm_rf(const char *path, RemoveFlags flags);
/* Useful for usage with _cleanup_(), destroys a directory and frees the pointer */
"getpgrp\0"
"getpid\0"
"getppid\0"
+ "getrandom\0"
"getresgid\0"
"getresgid32\0"
"getresuid\0"
"restart_syscall\0"
"rseq\0"
"rt_sigreturn\0"
+ "sched_getaffinity\0"
"sched_yield\0"
"set_robust_list\0"
"set_thread_area\0"
"get_mempolicy\0"
"getcpu\0"
"getpriority\0"
- "getrandom\0"
"ioctl\0"
"ioprio_get\0"
"kcmp\0"
"remap_file_pages\0"
"sched_get_priority_max\0"
"sched_get_priority_min\0"
- "sched_getaffinity\0"
"sched_getattr\0"
"sched_getparam\0"
"sched_getscheduler\0"
static int open_label_db(void) {
struct selabel_handle *hnd;
usec_t before_timestamp, after_timestamp;
- char timespan[FORMAT_TIMESPAN_MAX];
# if HAVE_GENERIC_MALLINFO
generic_mallinfo before_mallinfo = generic_mallinfo_get();
generic_mallinfo after_mallinfo = generic_mallinfo_get();
size_t l = LESS_BY((size_t) after_mallinfo.uordblks, (size_t) before_mallinfo.uordblks);
log_debug("Successfully loaded SELinux database in %s, size on heap is %zuK.",
- format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp, 0),
+ FORMAT_TIMESPAN(after_timestamp - before_timestamp, 0),
DIV_ROUND_UP(l, 1024));
# else
log_debug("Successfully loaded SELinux database in %s.",
- format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp, 0));
+ FORMAT_TIMESPAN(after_timestamp - before_timestamp, 0));
# endif
/* release memory after measurement */
int deserialize_environment(const char *value, char ***list) {
_cleanup_free_ char *unescaped = NULL;
+ ssize_t l;
int r;
assert(value);
/* Changes the *environment strv inline. */
- r = cunescape(value, 0, &unescaped);
- if (r < 0)
- return log_error_errno(r, "Failed to unescape: %m");
+ l = cunescape(value, 0, &unescaped);
+ if (l < 0)
+ return log_error_errno(l, "Failed to unescape: %m");
r = strv_env_replace_consume(list, TAKE_PTR(unescaped));
if (r < 0)
return -EINVAL;
default:
- assert_not_reached("Unknown option code.");
+ assert_not_reached();
}
if (optind < argc)
.size = sizeof(struct sockaddr_in6),
};
else
- assert_not_reached("Family quarrel");
+ assert_not_reached();
}
}
#include <stdlib.h>
#include <unistd.h>
+#include "exec-util.h"
#include "log.h"
#include "process-util.h"
#include "spawn-ask-password-agent.h"
#include <stdlib.h>
#include <unistd.h>
+#include "exec-util.h"
#include "fd-util.h"
#include "io-util.h"
#include "log.h"
if (si.si_status == EXIT_FAILURE)
return false;
- assert_not_reached("unexpected exit code");
+ assert_not_reached();
}
bool can_memlock(void) {
void (*sym_Esys_Finalize)(ESYS_CONTEXT **context) = NULL;
TSS2_RC (*sym_Esys_FlushContext)(ESYS_CONTEXT *esysContext, ESYS_TR flushHandle) = NULL;
void (*sym_Esys_Free)(void *ptr) = NULL;
+TSS2_RC (*sym_Esys_GetCapability)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, TPM2_CAP capability, UINT32 property, UINT32 propertyCount, TPMI_YES_NO *moreData, TPMS_CAPABILITY_DATA **capabilityData);
TSS2_RC (*sym_Esys_GetRandom)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, UINT16 bytesRequested, TPM2B_DIGEST **randomBytes) = NULL;
TSS2_RC (*sym_Esys_Initialize)(ESYS_CONTEXT **esys_context, TSS2_TCTI_CONTEXT *tcti, TSS2_ABI_VERSION *abiVersion) = NULL;
TSS2_RC (*sym_Esys_Load)(ESYS_CONTEXT *esysContext, ESYS_TR parentHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_PRIVATE *inPrivate, const TPM2B_PUBLIC *inPublic, ESYS_TR *objectHandle) = NULL;
DLSYM_ARG(Esys_Finalize),
DLSYM_ARG(Esys_FlushContext),
DLSYM_ARG(Esys_Free),
+ DLSYM_ARG(Esys_GetCapability),
DLSYM_ARG(Esys_GetRandom),
DLSYM_ARG(Esys_Initialize),
DLSYM_ARG(Esys_Load),
return 0;
}
+static int tpm2_get_best_pcr_bank(
+ ESYS_CONTEXT *c,
+ TPMI_ALG_HASH *ret) {
+
+ _cleanup_(Esys_Freep) TPMS_CAPABILITY_DATA *pcap = NULL;
+ TPMI_ALG_HASH hash = TPM2_ALG_SHA1;
+ bool found = false;
+ TPMI_YES_NO more;
+ TSS2_RC rc;
+
+ rc = sym_Esys_GetCapability(
+ c,
+ ESYS_TR_NONE,
+ ESYS_TR_NONE,
+ ESYS_TR_NONE,
+ TPM2_CAP_PCRS,
+ 0,
+ 1,
+ &more,
+ &pcap);
+ if (rc != TSS2_RC_SUCCESS)
+ return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
+ "Failed to determine TPM2 PCR bank capabilities: %s", sym_Tss2_RC_Decode(rc));
+
+ assert(pcap->capability == TPM2_CAP_PCRS);
+
+ for (size_t i = 0; i < pcap->data.assignedPCR.count; i++) {
+ bool valid = true;
+
+ /* As per
+ * https://trustedcomputinggroup.org/wp-content/uploads/TCG_PCClient_PFP_r1p05_v23_pub.pdf a
+ * TPM2 on a Client PC must have at least 24 PCRs. If this TPM has less, just skip over
+ * it. */
+ if (pcap->data.assignedPCR.pcrSelections[i].sizeofSelect < TPM2_PCRS_MAX/8) {
+ log_debug("Skipping TPM2 PCR bank %s with fewer than 24 PCRs.",
+ strna(tpm2_pcr_bank_to_string(pcap->data.assignedPCR.pcrSelections[i].hash)));
+ continue;
+ }
+
+ assert_cc(TPM2_PCRS_MAX % 8 == 0);
+
+ /* It's not enought to check how many PCRs there are, we also need to check that the 24 are
+ * enabled for this bank. Otherwise this TPM doesn't qualify. */
+ for (size_t j = 0; j < TPM2_PCRS_MAX/8; j++)
+ if (pcap->data.assignedPCR.pcrSelections[i].pcrSelect[j] != 0xFF) {
+ valid = false;
+ break;
+ }
+
+ if (!valid) {
+ log_debug("TPM2 PCR bank %s has fewer than 24 PCR bits enabled, ignoring.",
+ strna(tpm2_pcr_bank_to_string(pcap->data.assignedPCR.pcrSelections[i].hash)));
+ continue;
+ }
+
+ if (pcap->data.assignedPCR.pcrSelections[i].hash == TPM2_ALG_SHA256) {
+ hash = TPM2_ALG_SHA256;
+ found = true;
+ break;
+ }
+
+ if (pcap->data.assignedPCR.pcrSelections[i].hash == TPM2_ALG_SHA1)
+ found = true;
+ }
+
+ if (!found)
+ return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+ "TPM2 module supports neither SHA1 nor SHA256 PCR banks, cannot operate.");
+
+ if (hash == TPM2_ALG_SHA256)
+ log_debug("TPM2 device supports SHA256 PCR banks, yay!");
+ else {
+ assert(hash == TPM2_ALG_SHA1);
+ log_debug("TPM2 device lacks support for SHA256 PCR banks, falling back to SHA1 banks.");
+ }
+
+ *ret = hash;
+ return 0;
+}
+
static int tpm2_make_pcr_session(
ESYS_CONTEXT *c,
uint32_t pcr_mask,
+ uint16_t pcr_bank, /* If UINT16_MAX, pick best bank automatically, otherwise specify bank explicitly. */
ESYS_TR *ret_session,
- TPM2B_DIGEST **ret_policy_digest) {
+ TPM2B_DIGEST **ret_policy_digest,
+ TPMI_ALG_HASH *ret_pcr_bank) {
static const TPMT_SYM_DEF symmetric = {
.algorithm = TPM2_ALG_AES,
};
TPML_PCR_SELECTION pcr_selection = {
.count = 1,
- .pcrSelections[0].hash = TPM2_ALG_SHA256,
+ .pcrSelections[0].hash = TPM2_ALG_SHA256, /* overriden below, depending on TPM2 capabilities */
.pcrSelections[0].sizeofSelect = 3,
.pcrSelections[0].pcrSelect[0] = pcr_mask & 0xFF,
.pcrSelections[0].pcrSelect[1] = (pcr_mask >> 8) & 0xFF,
log_debug("Starting authentication session.");
+ if (pcr_bank != UINT16_MAX)
+ pcr_selection.pcrSelections[0].hash = pcr_bank;
+ else {
+ /* No bank configured, pick automatically. Some TPM2 devices only can do SHA1. If we detect
+ * that use that, but preferably use SHA256 */
+ r = tpm2_get_best_pcr_bank(c, &pcr_selection.pcrSelections[0].hash);
+ if (r < 0)
+ return r;
+ }
+
rc = sym_Esys_StartAuthSession(
c,
ESYS_TR_NONE,
if (ret_policy_digest)
*ret_policy_digest = TAKE_PTR(policy_digest);
+ if (ret_pcr_bank)
+ *ret_pcr_bank = pcr_selection.pcrSelections[0].hash;
+
r = 0;
finish:
void **ret_blob,
size_t *ret_blob_size,
void **ret_pcr_hash,
- size_t *ret_pcr_hash_size) {
+ size_t *ret_pcr_hash_size,
+ uint16_t *ret_pcr_bank) {
_cleanup_(tpm2_context_destroy) struct tpm2_context c = {};
_cleanup_(Esys_Freep) TPM2B_DIGEST *policy_digest = NULL;
TPM2B_SENSITIVE_CREATE hmac_sensitive;
ESYS_TR primary = ESYS_TR_NONE;
TPM2B_PUBLIC hmac_template;
+ TPMI_ALG_HASH pcr_bank;
size_t k, blob_size;
usec_t start;
TSS2_RC rc;
assert(ret_blob_size);
assert(ret_pcr_hash);
assert(ret_pcr_hash_size);
+ assert(ret_pcr_bank);
assert(pcr_mask < (UINT32_C(1) << TPM2_PCRS_MAX)); /* Support 24 PCR banks */
if (r < 0)
return r;
- r = tpm2_make_pcr_session(c.esys_context, pcr_mask, NULL, &policy_digest);
+ r = tpm2_make_pcr_session(c.esys_context, pcr_mask, UINT16_MAX, NULL, &policy_digest, &pcr_bank);
if (r < 0)
goto finish;
if (!hash)
return log_oom();
- if (DEBUG_LOGGING) {
- char buf[FORMAT_TIMESPAN_MAX];
- log_debug("Completed TPM2 key sealing in %s.", format_timespan(buf, sizeof(buf), now(CLOCK_MONOTONIC) - start, 1));
- }
+ if (DEBUG_LOGGING)
+ log_debug("Completed TPM2 key sealing in %s.", FORMAT_TIMESPAN(now(CLOCK_MONOTONIC) - start, 1));
*ret_secret = TAKE_PTR(secret);
*ret_secret_size = hmac_sensitive.sensitive.data.size;
*ret_blob_size = blob_size;
*ret_pcr_hash = TAKE_PTR(hash);
*ret_pcr_hash_size = policy_digest->size;
+ *ret_pcr_bank = pcr_bank;
r = 0;
int tpm2_unseal(
const char *device,
uint32_t pcr_mask,
+ uint16_t pcr_bank,
const void *blob,
size_t blob_size,
const void *known_policy_hash,
if (r < 0)
return r;
- r = tpm2_make_pcr_session(c.esys_context, pcr_mask, &session, &policy_digest);
+ r = tpm2_make_pcr_session(c.esys_context, pcr_mask, pcr_bank, &session, &policy_digest, NULL);
if (r < 0)
goto finish;
goto finish;
}
- if (DEBUG_LOGGING) {
- char buf[FORMAT_TIMESPAN_MAX];
- log_debug("Completed TPM2 key unsealing in %s.", format_timespan(buf, sizeof(buf), now(CLOCK_MONOTONIC) - start, 1));
- }
+ if (DEBUG_LOGGING)
+ log_debug("Completed TPM2 key unsealing in %s.", FORMAT_TIMESPAN(now(CLOCK_MONOTONIC) - start, 1));
*ret_secret = TAKE_PTR(secret);
*ret_secret_size = unsealed->size;
int tpm2_make_luks2_json(
int keyslot,
uint32_t pcr_mask,
+ uint16_t pcr_bank,
const void *blob,
size_t blob_size,
const void *policy_hash,
JSON_BUILD_PAIR("keyslots", JSON_BUILD_ARRAY(JSON_BUILD_STRING(keyslot_as_string))),
JSON_BUILD_PAIR("tpm2-blob", JSON_BUILD_BASE64(blob, blob_size)),
JSON_BUILD_PAIR("tpm2-pcrs", JSON_BUILD_VARIANT(a)),
+ JSON_BUILD_PAIR_CONDITION(!!tpm2_pcr_bank_to_string(pcr_bank), "tpm2-pcr-bank", JSON_BUILD_STRING(tpm2_pcr_bank_to_string(pcr_bank))),
JSON_BUILD_PAIR("tpm2-policy-hash", JSON_BUILD_HEX(policy_hash, policy_hash_size))));
if (r < 0)
return r;
return keyslot;
}
+
+/* We want the helpers below to work also if TPM2 libs are not available, hence define these two defines if
+ * they are missing. */
+#ifndef TPM2_ALG_SHA256
+#define TPM2_ALG_SHA256 0xB
+#endif
+
+#ifndef TPM2_ALG_SHA1
+#define TPM2_ALG_SHA1 0x4
+#endif
+
+int tpm2_pcr_bank_supported(uint16_t bank) {
+ /* For now, let's officially only support these two. We can extend this later on, should the need
+ * arise. */
+ return IN_SET(bank, TPM2_ALG_SHA256, TPM2_ALG_SHA1);
+}
+
+const char *tpm2_pcr_bank_to_string(uint16_t bank) {
+ /* Similar here, only support the two for now, we can always extend this later. */
+ if (bank == TPM2_ALG_SHA256)
+ return "sha256";
+ if (bank == TPM2_ALG_SHA1)
+ return "sha1";
+ return NULL;
+}
+
+int tpm2_pcr_bank_from_string(const char *bank) {
+ if (streq_ptr(bank, "sha256"))
+ return TPM2_ALG_SHA256;
+ if (streq_ptr(bank, "sha1"))
+ return TPM2_ALG_SHA1;
+ return -EINVAL;
+}
extern void (*sym_Esys_Finalize)(ESYS_CONTEXT **context);
extern TSS2_RC (*sym_Esys_FlushContext)(ESYS_CONTEXT *esysContext, ESYS_TR flushHandle);
extern void (*sym_Esys_Free)(void *ptr);
+extern TSS2_RC (*sym_Esys_GetCapability)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, TPM2_CAP capability, UINT32 property, UINT32 propertyCount, TPMI_YES_NO *moreData, TPMS_CAPABILITY_DATA **capabilityData);
extern TSS2_RC (*sym_Esys_GetRandom)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, UINT16 bytesRequested, TPM2B_DIGEST **randomBytes);
extern TSS2_RC (*sym_Esys_Initialize)(ESYS_CONTEXT **esys_context, TSS2_TCTI_CONTEXT *tcti, TSS2_ABI_VERSION *abiVersion);
extern TSS2_RC (*sym_Esys_Load)(ESYS_CONTEXT *esysContext, ESYS_TR parentHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_PRIVATE *inPrivate, const TPM2B_PUBLIC *inPublic, ESYS_TR *objectHandle);
int dlopen_tpm2(void);
-int tpm2_seal(const char *device, uint32_t pcr_mask, void **ret_secret, size_t *ret_secret_size, void **ret_blob, size_t *ret_blob_size, void **ret_pcr_hash, size_t *ret_pcr_hash_size);
-int tpm2_unseal(const char *device, uint32_t pcr_mask, const void *blob, size_t blob_size, const void *pcr_hash, size_t pcr_hash_size, void **ret_secret, size_t *ret_secret_size);
+int tpm2_seal(const char *device, uint32_t pcr_mask, void **ret_secret, size_t *ret_secret_size, void **ret_blob, size_t *ret_blob_size, void **ret_pcr_hash, size_t *ret_pcr_hash_size, uint16_t *ret_pcr_bank);
+int tpm2_unseal(const char *device, uint32_t pcr_mask, uint16_t pcr_bank, const void *blob, size_t blob_size, const void *pcr_hash, size_t pcr_hash_size, void **ret_secret, size_t *ret_secret_size);
#endif
int tpm2_parse_pcrs(const char *s, uint32_t *ret);
-int tpm2_make_luks2_json(int keyslot, uint32_t pcr_mask, const void *blob, size_t blob_size, const void *policy_hash, size_t policy_hash_size, JsonVariant **ret);
+int tpm2_make_luks2_json(int keyslot, uint32_t pcr_mask, uint16_t pcr_bank, const void *blob, size_t blob_size, const void *policy_hash, size_t policy_hash_size, JsonVariant **ret);
#define TPM2_PCRS_MAX 24
/* Default to PCR 7 only */
#define TPM2_PCR_MASK_DEFAULT (UINT32_C(1) << 7)
+
+int tpm2_pcr_bank_supported(uint16_t bank);
+const char *tpm2_pcr_bank_to_string(uint16_t bank);
+int tpm2_pcr_bank_from_string(const char *bank);
+
+typedef struct {
+ uint32_t search_pcr_mask;
+ const char *device;
+} systemd_tpm2_plugin_params;
int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos) {
char *i, *j;
- int r;
bool is_escaped;
/* value must be double quotated */
j[0] = '\0';
} else {
_cleanup_free_ char *unescaped = NULL;
+ ssize_t l;
/* find the end position of value */
for (i = str; *i != '"'; i++) {
}
i[0] = '\0';
- r = cunescape_length(str, i - str, 0, &unescaped);
- if (r < 0)
- return r;
- assert(r <= i - str);
- memcpy(str, unescaped, r + 1);
+ l = cunescape_length(str, i - str, 0, &unescaped);
+ if (l < 0)
+ return l;
+
+ assert(l <= i - str);
+ memcpy(str, unescaped, l + 1);
}
*ret_value = str;
printf(" Disposition: %s\n", user_disposition_to_string(user_record_disposition(hr)));
if (hr->last_change_usec != USEC_INFINITY) {
- char buf[FORMAT_TIMESTAMP_MAX];
- printf(" Last Change: %s\n", format_timestamp(buf, sizeof(buf), hr->last_change_usec));
+ printf(" Last Change: %s\n", FORMAT_TIMESTAMP(hr->last_change_usec));
if (hr->last_change_usec > now(CLOCK_REALTIME))
printf(" %sModification time lies in the future, system clock wrong?%s\n",
}
if (hr->last_password_change_usec != USEC_INFINITY &&
- hr->last_password_change_usec != hr->last_change_usec) {
- char buf[FORMAT_TIMESTAMP_MAX];
- printf(" Last Passw.: %s\n", format_timestamp(buf, sizeof(buf), hr->last_password_change_usec));
- }
+ hr->last_password_change_usec != hr->last_change_usec)
+ printf(" Last Passw.: %s\n", FORMAT_TIMESTAMP(hr->last_password_change_usec));
r = user_record_test_blocked(hr);
switch (r) {
if (hr->locked >= 0)
printf(" Locked: %s\n", yes_no(hr->locked));
- if (hr->not_before_usec != UINT64_MAX) {
- char buf[FORMAT_TIMESTAMP_MAX];
- printf(" Not Before: %s\n", format_timestamp(buf, sizeof(buf), hr->not_before_usec));
- }
+ if (hr->not_before_usec != UINT64_MAX)
+ printf(" Not Before: %s\n", FORMAT_TIMESTAMP(hr->not_before_usec));
- if (hr->not_after_usec != UINT64_MAX) {
- char buf[FORMAT_TIMESTAMP_MAX];
- printf(" Not After: %s\n", format_timestamp(buf, sizeof(buf), hr->not_after_usec));
- }
+ if (hr->not_after_usec != UINT64_MAX)
+ printf(" Not After: %s\n", FORMAT_TIMESTAMP(hr->not_after_usec));
if (hr->umask != MODE_INVALID)
printf(" UMask: 0%03o\n", hr->umask);
if (hr->tasks_max != UINT64_MAX)
printf(" Tasks Max: %" PRIu64 "\n", hr->tasks_max);
- if (hr->memory_high != UINT64_MAX) {
- char buf[FORMAT_BYTES_MAX];
- printf(" Memory High: %s\n", format_bytes(buf, sizeof(buf), hr->memory_high));
- }
+ if (hr->memory_high != UINT64_MAX)
+ printf(" Memory High: %s\n", FORMAT_BYTES(hr->memory_high));
- if (hr->memory_max != UINT64_MAX) {
- char buf[FORMAT_BYTES_MAX];
- printf(" Memory Max: %s\n", format_bytes(buf, sizeof(buf), hr->memory_max));
- }
+ if (hr->memory_max != UINT64_MAX)
+ printf(" Memory Max: %s\n", FORMAT_BYTES(hr->memory_max));
if (hr->cpu_weight != UINT64_MAX)
printf(" CPU Weight: %" PRIu64 "\n", hr->cpu_weight);
printf(" PBKDF Type: %s\n", hr->luks_pbkdf_type);
if (hr->luks_pbkdf_hash_algorithm)
printf(" PBKDF Hash: %s\n", hr->luks_pbkdf_hash_algorithm);
- if (hr->luks_pbkdf_time_cost_usec != UINT64_MAX) {
- char buf[FORMAT_TIMESPAN_MAX];
- printf(" PBKDF Time: %s\n", format_timespan(buf, sizeof(buf), hr->luks_pbkdf_time_cost_usec, 0));
- }
- if (hr->luks_pbkdf_memory_cost != UINT64_MAX) {
- char buf[FORMAT_BYTES_MAX];
- printf(" PBKDF Bytes: %s\n", format_bytes(buf, sizeof(buf), hr->luks_pbkdf_memory_cost));
- }
+ if (hr->luks_pbkdf_time_cost_usec != UINT64_MAX)
+ printf(" PBKDF Time: %s\n", FORMAT_TIMESPAN(hr->luks_pbkdf_time_cost_usec, 0));
+ if (hr->luks_pbkdf_memory_cost != UINT64_MAX)
+ printf(" PBKDF Bytes: %s\n", FORMAT_BYTES(hr->luks_pbkdf_memory_cost));
+
if (hr->luks_pbkdf_parallel_threads != UINT64_MAX)
printf("PBKDF Thread: %" PRIu64 "\n", hr->luks_pbkdf_parallel_threads);
if (hr->skeleton_directory)
printf(" Skel. Dir.: %s\n", user_record_skeleton_directory(hr));
- if (hr->disk_size != UINT64_MAX) {
- char buf[FORMAT_BYTES_MAX];
- printf(" Disk Size: %s\n", format_bytes(buf, sizeof(buf), hr->disk_size));
- }
+ if (hr->disk_size != UINT64_MAX)
+ printf(" Disk Size: %s\n", FORMAT_BYTES(hr->disk_size));
if (hr->disk_usage != UINT64_MAX) {
- char buf[FORMAT_BYTES_MAX];
-
if (hr->disk_size != UINT64_MAX) {
unsigned permille;
permille = (unsigned) DIV_ROUND_UP(hr->disk_usage * 1000U, hr->disk_size); /* Round up! */
printf(" Disk Usage: %s (= %u.%01u%%)\n",
- format_bytes(buf, sizeof(buf), hr->disk_usage),
+ FORMAT_BYTES(hr->disk_usage),
permille / 10, permille % 10);
} else
- printf(" Disk Usage: %s\n", format_bytes(buf, sizeof(buf), hr->disk_usage));
+ printf(" Disk Usage: %s\n", FORMAT_BYTES(hr->disk_usage));
}
if (hr->disk_free != UINT64_MAX) {
- char buf[FORMAT_BYTES_MAX];
-
if (hr->disk_size != UINT64_MAX) {
const char *color_on, *color_off;
unsigned permille;
printf(" Disk Free: %s%s (= %u.%01u%%)%s\n",
color_on,
- format_bytes(buf, sizeof(buf), hr->disk_free),
+ FORMAT_BYTES(hr->disk_free),
permille / 10, permille % 10,
color_off);
} else
- printf(" Disk Free: %s\n", format_bytes(buf, sizeof(buf), hr->disk_free));
+ printf(" Disk Free: %s\n", FORMAT_BYTES(hr->disk_free));
}
- if (hr->disk_floor != UINT64_MAX) {
- char buf[FORMAT_BYTES_MAX];
- printf(" Disk Floor: %s\n", format_bytes(buf, sizeof(buf), hr->disk_floor));
- }
+ if (hr->disk_floor != UINT64_MAX)
+ printf(" Disk Floor: %s\n", FORMAT_BYTES(hr->disk_floor));
- if (hr->disk_ceiling != UINT64_MAX) {
- char buf[FORMAT_BYTES_MAX];
- printf("Disk Ceiling: %s\n", format_bytes(buf, sizeof(buf), hr->disk_ceiling));
- }
+ if (hr->disk_ceiling != UINT64_MAX)
+ printf("Disk Ceiling: %s\n", FORMAT_BYTES(hr->disk_ceiling));
if (hr->good_authentication_counter != UINT64_MAX)
printf(" Good Auth.: %" PRIu64 "\n", hr->good_authentication_counter);
- if (hr->last_good_authentication_usec != UINT64_MAX) {
- char buf[FORMAT_TIMESTAMP_MAX];
- printf(" Last Good: %s\n", format_timestamp(buf, sizeof(buf), hr->last_good_authentication_usec));
- }
+ if (hr->last_good_authentication_usec != UINT64_MAX)
+ printf(" Last Good: %s\n", FORMAT_TIMESTAMP(hr->last_good_authentication_usec));
if (hr->bad_authentication_counter != UINT64_MAX)
printf(" Bad Auth.: %" PRIu64 "\n", hr->bad_authentication_counter);
- if (hr->last_bad_authentication_usec != UINT64_MAX) {
- char buf[FORMAT_TIMESTAMP_MAX];
- printf(" Last Bad: %s\n", format_timestamp(buf, sizeof(buf), hr->last_bad_authentication_usec));
- }
+ if (hr->last_bad_authentication_usec != UINT64_MAX)
+ printf(" Last Bad: %s\n", FORMAT_TIMESTAMP(hr->last_bad_authentication_usec));
t = user_record_ratelimit_next_try(hr);
if (t != USEC_INFINITY) {
if (t <= n)
printf(" Next Try: anytime\n");
- else {
- char buf[FORMAT_TIMESPAN_MAX];
+ else
printf(" Next Try: %sin %s%s\n",
ansi_highlight_red(),
- format_timespan(buf, sizeof(buf), t - n, USEC_PER_SEC),
+ FORMAT_TIMESPAN(t - n, USEC_PER_SEC),
ansi_normal());
- }
}
- if (storage != USER_CLASSIC) {
- char buf[FORMAT_TIMESPAN_MAX];
+ if (storage != USER_CLASSIC)
printf(" Auth. Limit: %" PRIu64 " attempts per %s\n", user_record_ratelimit_burst(hr),
- format_timespan(buf, sizeof(buf), user_record_ratelimit_interval_usec(hr), 0));
- }
+ FORMAT_TIMESPAN(user_record_ratelimit_interval_usec(hr), 0));
if (hr->enforce_password_policy >= 0)
printf(" Passwd Pol.: %s\n", yes_no(hr->enforce_password_policy));
hr->password_change_warn_usec != UINT64_MAX ||
hr->password_change_inactive_usec != UINT64_MAX) {
- char buf[FORMAT_TIMESPAN_MAX];
printf(" Passwd Chg.:");
if (hr->password_change_min_usec != UINT64_MAX) {
- printf(" min %s", format_timespan(buf, sizeof(buf), hr->password_change_min_usec, 0));
+ printf(" min %s", FORMAT_TIMESPAN(hr->password_change_min_usec, 0));
if (hr->password_change_max_usec != UINT64_MAX)
printf(" …");
}
if (hr->password_change_max_usec != UINT64_MAX)
- printf(" max %s", format_timespan(buf, sizeof(buf), hr->password_change_max_usec, 0));
+ printf(" max %s", FORMAT_TIMESPAN(hr->password_change_max_usec, 0));
if (hr->password_change_warn_usec != UINT64_MAX)
- printf("/warn %s", format_timespan(buf, sizeof(buf), hr->password_change_warn_usec, 0));
+ printf("/warn %s", FORMAT_TIMESPAN(hr->password_change_warn_usec, 0));
if (hr->password_change_inactive_usec != UINT64_MAX)
- printf("/inactive %s", format_timespan(buf, sizeof(buf), hr->password_change_inactive_usec, 0));
+ printf("/inactive %s", FORMAT_TIMESPAN(hr->password_change_inactive_usec, 0));
printf("\n");
}
if (hr->signed_locally >= 0)
printf(" Local Sig.: %s\n", yes_no(hr->signed_locally));
- if (hr->stop_delay_usec != UINT64_MAX) {
- char buf[FORMAT_TIMESPAN_MAX];
- printf(" Stop Delay: %s\n", format_timespan(buf, sizeof(buf), hr->stop_delay_usec, 0));
- }
+ if (hr->stop_delay_usec != UINT64_MAX)
+ printf(" Stop Delay: %s\n", FORMAT_TIMESPAN(hr->stop_delay_usec, 0));
if (hr->auto_login >= 0)
printf("Autom. Login: %s\n", yes_no(hr->auto_login));
printf(" Disposition: %s\n", user_disposition_to_string(group_record_disposition(gr)));
- if (gr->last_change_usec != USEC_INFINITY) {
- char buf[FORMAT_TIMESTAMP_MAX];
- printf(" Last Change: %s\n", format_timestamp(buf, sizeof(buf), gr->last_change_usec));
- }
+ if (gr->last_change_usec != USEC_INFINITY)
+ printf(" Last Change: %s\n", FORMAT_TIMESTAMP(gr->last_change_usec));
if (gid_is_valid(gr->gid))
printf(" GID: " GID_FMT "\n", gr->gid);
break;
default:
- assert_not_reached("Unexpected state?");
+ assert_not_reached();
}
sd_event_unref(iterator->event);
}
default:
- assert_not_reached("unexpected lookup");
+ assert_not_reached();
}
finish:
void *userdata) {
_cleanup_free_ char *text = NULL, *hn = NULL, *un = NULL, *stdin_tty = NULL;
- char date[FORMAT_TIMESTAMP_MAX];
struct utmpx *u;
int r;
"%s\r\n\r\n",
un ?: username, hn,
origin_tty ? " on " : "", strempty(origin_tty),
- format_timestamp(date, sizeof(date), now(CLOCK_REALTIME)),
+ FORMAT_TIMESTAMP(now(CLOCK_REALTIME)),
message) < 0)
return -ENOMEM;
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <malloc.h>
-#include <sys/poll.h>
+#include <poll.h>
#include "alloc-util.h"
#include "errno-util.h"
break;
default:
- assert_not_reached("Unexpected state");
+ assert_not_reached();
}
return varlink_log_errno(v, SYNTHETIC_ERRNO(ETIME), "Connection timed out.");
default:
- assert_not_reached("Unexpected state after method call.");
+ assert_not_reached();
}
}
v->ucred_acquired = true;
}
- (void) asprintf(&v->description, "%s-%i", server->description ?: "varlink", v->fd);
+ _cleanup_free_ char *desc = NULL;
+ if (asprintf(&desc, "%s-%i", server->description ?: "varlink", v->fd) >= 0)
+ v->description = TAKE_PTR(desc);
/* Link up the server and the connection, and take reference in both directions. Note that the
* reference on the connection is left dangling. It will be dropped when the connection is closed,
if (ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags) < 0)
return log_warning_errno(errno, "Failed to disable hardware watchdog: %m");
} else {
- char buf[FORMAT_TIMESPAN_MAX];
int sec, flags;
usec_t t;
if (ioctl(watchdog_fd, WDIOC_SETTIMEOUT, &sec) < 0)
return log_warning_errno(errno, "Failed to set timeout to %is: %m", sec);
- watchdog_timeout = (usec_t) sec * USEC_PER_SEC;
- log_info("Set hardware watchdog to %s.", format_timespan(buf, sizeof(buf), watchdog_timeout, 0));
+ log_info("Set hardware watchdog to %s.", FORMAT_TIMESPAN(sec * USEC_PER_SEC, 0));
flags = WDIOS_ENABLECARD;
if (ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags) < 0) {
}
- assert_not_reached("Bad state");
+ assert_not_reached();
}
return -EINVAL;
default:
- assert_not_reached("Unhandled option code.");
+ assert_not_reached();
}
if (!arg_verb)
break;
default:
- assert_not_reached("Unknown magic");
+ assert_not_reached();
}
(void) reboot(cmd);
static int execute_s2h(const SleepConfig *sleep_config) {
_cleanup_close_ int tfd = -1;
- char buf[FORMAT_TIMESPAN_MAX];
struct itimerspec ts = {};
int r;
return log_error_errno(errno, "Error creating timerfd: %m");
log_debug("Set timerfd wake alarm for %s",
- format_timespan(buf, sizeof(buf), sleep_config->hibernate_delay_sec, USEC_PER_SEC));
+ FORMAT_TIMESPAN(sleep_config->hibernate_delay_sec, USEC_PER_SEC));
timespec_store(&ts.it_value, sleep_config->hibernate_delay_sec);
/* If woken up after alarm time, hibernate */
log_debug("Attempting to hibernate after waking from %s timer",
- format_timespan(buf, sizeof(buf), sleep_config->hibernate_delay_sec, USEC_PER_SEC));
+ FORMAT_TIMESPAN(sleep_config->hibernate_delay_sec, USEC_PER_SEC));
r = execute(sleep_config, SLEEP_HIBERNATE, NULL);
if (r < 0) {
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
if (argc - optind != 1)
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
if (optind >= argc)
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
if (arg_cat_config && argc > optind)
break;
}
default:
- assert_not_reached("Unsupported image type");
+ assert_not_reached();
}
r = validate_version(
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
return 1;
else if (streq(verb, "add-requires"))
dep = UNIT_REQUIRES;
else
- assert_not_reached("Unknown verb");
+ assert_not_reached();
if (install_client_side()) {
r = unit_file_add_dependency(arg_scope, unit_file_flags_from_args(), arg_root, names, target, dep, &changes, &n_changes);
else if (streq(argv[0], "thaw"))
method = "ThawUnit";
else
- assert_not_reached("Unhandled method");
+ assert_not_reached();
STRV_FOREACH(name, names) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
if (arg_action == ACTION_REBOOT && (argc == optind || argc == optind + 1)) {
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
if (optind < argc)
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
if (optind >= argc)
break;
default:
- assert_not_reached("Unexpected action");
+ assert_not_reached();
}
r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, method);
else if (streq(verb, "revert"))
r = unit_file_revert(arg_scope, arg_root, names, &changes, &n_changes);
else
- assert_not_reached("Unknown verb");
+ assert_not_reached();
unit_file_dump_changes(r, verb, changes, n_changes, arg_quiet);
if (r < 0)
method = "RevertUnitFiles";
send_runtime = send_force = false;
} else
- assert_not_reached("Unknown verb");
+ assert_not_reached();
r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, method);
if (r < 0)
#if ENABLE_LOGIND
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- char date[FORMAT_TIMESTAMP_MAX];
const char *action;
const char *log_action;
sd_bus *bus;
return log_warning_errno(r, "Failed to call ScheduleShutdown in logind, proceeding with immediate shutdown: %s", bus_error_message(&error, r));
if (!arg_quiet)
- log_info("%s scheduled for %s, use 'shutdown -c' to cancel.", log_action, format_timestamp_style(date, sizeof(date), arg_when, arg_timestamp_style));
+ log_info("%s scheduled for %s, use 'shutdown -c' to cancel.",
+ log_action,
+ FORMAT_TIMESTAMP_STYLE(arg_when, arg_timestamp_style));
return 0;
#else
return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
#include "systemctl-util.h"
#include "systemctl.h"
-int set_property(int argc, char *argv[], void *userdata) {
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+static int set_property_one(sd_bus *bus, const char *name, char **properties) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_free_ char *n = NULL;
- UnitType t;
- sd_bus *bus;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
int r;
- r = acquire_bus(BUS_MANAGER, &bus);
- if (r < 0)
- return r;
-
- polkit_agent_open_maybe();
-
r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "SetUnitProperties");
if (r < 0)
return bus_log_create_error(r);
- r = unit_name_mangle(argv[1], arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN, &n);
- if (r < 0)
- return log_error_errno(r, "Failed to mangle unit name: %m");
-
- t = unit_name_to_type(n);
+ UnitType t = unit_name_to_type(name);
if (t < 0)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid unit type: %s", n);
+ return log_error_errno(t, "Invalid unit type: %s", name);
- r = sd_bus_message_append(m, "sb", n, arg_runtime);
+ r = sd_bus_message_append(m, "sb", name, arg_runtime);
if (r < 0)
return bus_log_create_error(r);
if (r < 0)
return bus_log_create_error(r);
- r = bus_append_unit_property_assignment_many(m, t, strv_skip(argv, 2));
+ r = bus_append_unit_property_assignment_many(m, t, properties);
if (r < 0)
return r;
r = sd_bus_call(bus, m, 0, &error, NULL);
if (r < 0)
- return log_error_errno(r, "Failed to set unit properties on %s: %s", n, bus_error_message(&error, r));
+ return log_error_errno(r, "Failed to set unit properties on %s: %s",
+ name, bus_error_message(&error, r));
return 0;
}
+
+int set_property(int argc, char *argv[], void *userdata) {
+ sd_bus *bus;
+ _cleanup_strv_free_ char **names = NULL;
+ char **name;
+ int r, k;
+
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ polkit_agent_open_maybe();
+
+ r = expand_unit_names(bus, STRV_MAKE(argv[1]), NULL, &names, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to expand '%s' into names: %m", argv[1]);
+
+ r = 0;
+ STRV_FOREACH(name, names) {
+ k = set_property_one(bus, *name, strv_skip(argv, 2));
+ if (k < 0 && r >= 0)
+ r = k;
+ }
+ return r;
+}
UnitStatusInfo *i,
bool *ellipsized) {
- char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], since2[FORMAT_TIMESTAMP_MAX];
- const char *s1, *s2, *active_on, *active_off, *on, *off, *ss, *fs;
+ const char *active_on, *active_off, *on, *off, *ss, *fs;
_cleanup_free_ char *formatted_path = NULL;
ExecStatusInfo *p;
usec_t timestamp;
STRPTR_IN_SET(i->active_state, "activating") ? i->inactive_exit_timestamp :
i->active_exit_timestamp;
- s1 = format_timestamp_relative(since1, sizeof(since1), timestamp);
- s2 = format_timestamp_style(since2, sizeof(since2), timestamp, arg_timestamp_style);
-
- if (s1)
- printf(" since %s; %s\n", s2, s1);
- else if (s2)
- printf(" since %s\n", s2);
+ if (timestamp > 0 && timestamp < USEC_INFINITY)
+ printf(" since %s; %s\n",
+ FORMAT_TIMESTAMP_STYLE(timestamp, arg_timestamp_style),
+ FORMAT_TIMESTAMP_RELATIVE(timestamp));
else
printf("\n");
}
if (endswith(i->id, ".timer")) {
- char tstamp1[FORMAT_TIMESTAMP_RELATIVE_MAX],
- tstamp2[FORMAT_TIMESTAMP_MAX];
- const char *next_rel_time, *next_time;
- dual_timestamp nw, next = {i->next_elapse_real,
- i->next_elapse_monotonic};
+ dual_timestamp nw, next = {i->next_elapse_real, i->next_elapse_monotonic};
usec_t next_elapse;
- printf(" Trigger: ");
-
dual_timestamp_get(&nw);
next_elapse = calc_next_elapse(&nw, &next);
- next_rel_time = format_timestamp_relative(tstamp1, sizeof tstamp1, next_elapse);
- next_time = format_timestamp_style(tstamp2, sizeof tstamp2, next_elapse, arg_timestamp_style);
- if (next_time && next_rel_time)
- printf("%s; %s\n", next_time, next_rel_time);
+ if (next_elapse > 0 && next_elapse < USEC_INFINITY)
+ printf(" Trigger: %s; %s\n",
+ FORMAT_TIMESTAMP_STYLE(next_elapse, arg_timestamp_style),
+ FORMAT_TIMESTAMP_RELATIVE(next_elapse));
else
- printf("n/a\n");
+ printf(" Trigger: n/a\n");
}
STRV_FOREACH(t, i->triggers) {
UnitCondition *c;
int n = 0;
- s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
- s2 = format_timestamp_style(since2, sizeof(since2), i->condition_timestamp, arg_timestamp_style);
-
- printf(" Condition: start %scondition failed%s at %s%s%s\n",
+ printf(" Condition: start %scondition failed%s at %s; %s\n",
ansi_highlight_yellow(), ansi_normal(),
- s2, s1 ? "; " : "", strempty(s1));
+ FORMAT_TIMESTAMP_STYLE(i->condition_timestamp, arg_timestamp_style),
+ FORMAT_TIMESTAMP_RELATIVE(i->condition_timestamp));
LIST_FOREACH(conditions, c, i->conditions)
if (c->tristate < 0)
}
if (!i->assert_result && i->assert_timestamp > 0) {
- s1 = format_timestamp_relative(since1, sizeof(since1), i->assert_timestamp);
- s2 = format_timestamp_style(since2, sizeof(since2), i->assert_timestamp, arg_timestamp_style);
-
- printf(" Assert: start %sassertion failed%s at %s%s%s\n",
+ printf(" Assert: start %sassertion failed%s at %s; %s\n",
ansi_highlight_red(), ansi_normal(),
- s2, s1 ? "; " : "", strempty(s1));
+ FORMAT_TIMESTAMP_STYLE(i->assert_timestamp, arg_timestamp_style),
+ FORMAT_TIMESTAMP_RELATIVE(i->assert_timestamp));
if (i->failed_assert_trigger)
printf(" none of the trigger assertions were met\n");
else if (i->failed_assert)
if (i->status_errno > 0)
printf(" Error: %i (%s)\n", i->status_errno, strerror_safe(i->status_errno));
- if (i->ip_ingress_bytes != UINT64_MAX && i->ip_egress_bytes != UINT64_MAX) {
- char buf_in[FORMAT_BYTES_MAX], buf_out[FORMAT_BYTES_MAX];
-
+ if (i->ip_ingress_bytes != UINT64_MAX && i->ip_egress_bytes != UINT64_MAX)
printf(" IP: %s in, %s out\n",
- format_bytes(buf_in, sizeof(buf_in), i->ip_ingress_bytes),
- format_bytes(buf_out, sizeof(buf_out), i->ip_egress_bytes));
- }
-
- if (i->io_read_bytes != UINT64_MAX && i->io_write_bytes != UINT64_MAX) {
- char buf_in[FORMAT_BYTES_MAX], buf_out[FORMAT_BYTES_MAX];
+ FORMAT_BYTES(i->ip_ingress_bytes),
+ FORMAT_BYTES(i->ip_egress_bytes));
+ if (i->io_read_bytes != UINT64_MAX && i->io_write_bytes != UINT64_MAX)
printf(" IO: %s read, %s written\n",
- format_bytes(buf_in, sizeof(buf_in), i->io_read_bytes),
- format_bytes(buf_out, sizeof(buf_out), i->io_write_bytes));
- }
+ FORMAT_BYTES(i->io_read_bytes),
+ FORMAT_BYTES(i->io_write_bytes));
if (i->tasks_current != UINT64_MAX) {
printf(" Tasks: %" PRIu64, i->tasks_current);
}
if (i->memory_current != UINT64_MAX) {
- char buf[FORMAT_BYTES_MAX];
-
- printf(" Memory: %s", format_bytes(buf, sizeof(buf), i->memory_current));
+ printf(" Memory: %s", FORMAT_BYTES(i->memory_current));
if (i->memory_min > 0 || i->memory_low > 0 ||
i->memory_high != CGROUP_LIMIT_MAX || i->memory_max != CGROUP_LIMIT_MAX ||
printf(" (");
if (i->memory_min > 0) {
- printf("%smin: %s", prefix, format_bytes_cgroup_protection(buf, sizeof(buf), i->memory_min));
+ printf("%smin: %s", prefix, FORMAT_BYTES_CGROUP_PROTECTION(i->memory_min));
prefix = " ";
}
if (i->memory_low > 0) {
- printf("%slow: %s", prefix, format_bytes_cgroup_protection(buf, sizeof(buf), i->memory_low));
+ printf("%slow: %s", prefix, FORMAT_BYTES_CGROUP_PROTECTION(i->memory_low));
prefix = " ";
}
if (i->memory_high != CGROUP_LIMIT_MAX) {
- printf("%shigh: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_high));
+ printf("%shigh: %s", prefix, FORMAT_BYTES(i->memory_high));
prefix = " ";
}
if (i->memory_max != CGROUP_LIMIT_MAX) {
- printf("%smax: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_max));
+ printf("%smax: %s", prefix, FORMAT_BYTES(i->memory_max));
prefix = " ";
}
if (i->memory_swap_max != CGROUP_LIMIT_MAX) {
- printf("%sswap max: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_swap_max));
+ printf("%sswap max: %s", prefix, FORMAT_BYTES(i->memory_swap_max));
prefix = " ";
}
if (i->memory_limit != CGROUP_LIMIT_MAX) {
- printf("%slimit: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_limit));
+ printf("%slimit: %s", prefix, FORMAT_BYTES(i->memory_limit));
prefix = " ";
}
if (i->memory_available != CGROUP_LIMIT_MAX) {
- printf("%savailable: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_available));
+ printf("%savailable: %s", prefix, FORMAT_BYTES(i->memory_available));
prefix = " ";
}
printf(")");
printf("\n");
}
- if (i->cpu_usage_nsec != UINT64_MAX) {
- char buf[FORMAT_TIMESPAN_MAX];
- printf(" CPU: %s\n", format_timespan(buf, sizeof(buf), i->cpu_usage_nsec / NSEC_PER_USEC, USEC_PER_MSEC));
- }
+ if (i->cpu_usage_nsec != UINT64_MAX)
+ printf(" CPU: %s\n", FORMAT_TIMESPAN(i->cpu_usage_nsec / NSEC_PER_USEC, USEC_PER_MSEC));
if (i->control_group) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
if (r < 0)
return bus_log_parse_error(r);
- while ((r = sd_bus_message_read(m, "(stt)", &base, &v, &next_elapse)) > 0) {
- char timespan1[FORMAT_TIMESPAN_MAX] = "n/a", timespan2[FORMAT_TIMESPAN_MAX] = "n/a";
-
- (void) format_timespan(timespan1, sizeof timespan1, v, 0);
- (void) format_timespan(timespan2, sizeof timespan2, next_elapse, 0);
-
+ while ((r = sd_bus_message_read(m, "(stt)", &base, &v, &next_elapse)) > 0)
bus_print_property_valuef(name, expected_value, flags,
- "{ %s=%s ; next_elapse=%s }", base, timespan1, timespan2);
- }
+ "{ %s=%s ; next_elapse=%s }",
+ base,
+ strna(FORMAT_TIMESPAN(v, 0)),
+ strna(FORMAT_TIMESPAN(next_elapse, 0)));
if (r < 0)
return bus_log_parse_error(r);
if (r < 0)
return bus_log_parse_error(r);
- while ((r = sd_bus_message_read(m, "(sst)", &base, &spec, &next_elapse)) > 0) {
- char timestamp[FORMAT_TIMESTAMP_MAX] = "n/a";
-
- (void) format_timestamp_style(timestamp, sizeof(timestamp), next_elapse, arg_timestamp_style);
+ while ((r = sd_bus_message_read(m, "(sst)", &base, &spec, &next_elapse)) > 0)
bus_print_property_valuef(name, expected_value, flags,
- "{ %s=%s ; next_elapse=%s }", base, spec, timestamp);
- }
+ "{ %s=%s ; next_elapse=%s }", base, spec,
+ FORMAT_TIMESTAMP_STYLE(next_elapse, arg_timestamp_style));
if (r < 0)
return bus_log_parse_error(r);
return bus_log_parse_error(r);
while ((r = exec_status_info_deserialize(m, &info, is_ex_prop)) > 0) {
- char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
_cleanup_strv_free_ char **optv = NULL;
_cleanup_free_ char *tt = NULL, *o = NULL;
strna(info.path),
strna(tt),
strna(o),
- strna(format_timestamp_style(timestamp1, sizeof(timestamp1), info.start_timestamp, arg_timestamp_style)),
- strna(format_timestamp_style(timestamp2, sizeof(timestamp2), info.exit_timestamp, arg_timestamp_style)),
+ strna(FORMAT_TIMESTAMP_STYLE(info.start_timestamp, arg_timestamp_style)),
+ strna(FORMAT_TIMESTAMP_STYLE(info.exit_timestamp, arg_timestamp_style)),
info.pid,
sigchld_code_to_string(info.code),
info.status,
strna(info.path),
strna(tt),
yes_no(info.ignore),
- strna(format_timestamp_style(timestamp1, sizeof(timestamp1), info.start_timestamp, arg_timestamp_style)),
- strna(format_timestamp_style(timestamp2, sizeof(timestamp2), info.exit_timestamp, arg_timestamp_style)),
+ strna(FORMAT_TIMESTAMP_STYLE(info.start_timestamp, arg_timestamp_style)),
+ strna(FORMAT_TIMESTAMP_STYLE(info.exit_timestamp, arg_timestamp_style)),
info.pid,
sigchld_code_to_string(info.code),
info.status,
} else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN &&
streq(name, "IODeviceLatencyTargetUSec")) {
- char ts[FORMAT_TIMESPAN_MAX];
const char *path;
uint64_t target;
while ((r = sd_bus_message_read(m, "(st)", &path, &target)) > 0)
bus_print_property_valuef(name, expected_value, flags, "%s %s", strna(path),
- format_timespan(ts, sizeof(ts), target, 1));
+ FORMAT_TIMESPAN(target, 1));
if (r < 0)
return bus_log_parse_error(r);
return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r));
if (unit && streq_ptr(info.load_state, "not-found") && streq_ptr(info.active_state, "inactive")) {
- log_full(show_mode == SYSTEMCTL_SHOW_STATUS ? LOG_ERR : LOG_DEBUG,
+ log_full(show_mode == SYSTEMCTL_SHOW_PROPERTIES ? LOG_DEBUG : LOG_ERR,
"Unit %s could not be found.", unit);
if (show_mode == SYSTEMCTL_SHOW_STATUS)
}
static int show_system_status(sd_bus *bus) {
- char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], since2[FORMAT_TIMESTAMP_MAX];
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(machine_info_clear) struct machine_info mi = {};
_cleanup_free_ char *hn = NULL;
printf(" Failed: %" PRIu32 " units\n", mi.n_failed_units);
printf(" Since: %s; %s\n",
- format_timestamp_style(since2, sizeof(since2), mi.timestamp, arg_timestamp_style),
- format_timestamp_relative(since1, sizeof(since1), mi.timestamp));
+ FORMAT_TIMESTAMP_STYLE(mi.timestamp, arg_timestamp_style),
+ FORMAT_TIMESTAMP_RELATIVE(mi.timestamp));
printf(" CGroup: %s\n", mi.control_group ?: "/");
if (IN_SET(arg_transport,
return log_error_errno(r,
"No kexec kernel loaded and autodetection failed.\n%s",
is_efi_boot()
- ? "Cannot automatically load kernel: ESP partition mount point not found."
+ ? "Cannot automatically load kernel: ESP mount point not found."
: "Automatic loading works only on systems booted with EFI.");
if (r < 0)
return r;
(arg_dry_run ? REBOOT_DRY_RUN : 0));
default:
- assert_not_reached("Unknown action.");
+ assert_not_reached();
}
}
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
if (arg_transport == BUS_TRANSPORT_REMOTE && arg_scope != UNIT_FILE_SYSTEM)
case _ACTION_INVALID:
default:
- assert_not_reached("Unknown action");
+ assert_not_reached();
}
finish:
check_compilation_sh,
args : cc.cmd_array() + ['-c', '-x'] + opt +
['-Werror', '-include',
- join_paths(meson.current_source_dir(), header)])
+ meson.current_source_dir() / header])
endif
endforeach
endforeach
uint64_t features;
const unsigned *vtable_format_reference;
} start;
+ struct {
+ /* This field exists only to make sure we have something to initialize in
+ * SD_BUS_VTABLE_END in a way that is both compatible with pedantic versions of C and
+ * C++. It's unused otherwise. */
+ size_t _reserved;
+ } end;
struct {
const char *member;
const char *signature;
.type = _SD_BUS_VTABLE_START, \
.flags = _flags, \
.x = { \
- .start = { \
- .element_size = sizeof(sd_bus_vtable), \
- .features = _SD_BUS_VTABLE_PARAM_NAMES, \
- .vtable_format_reference = &sd_bus_object_vtable_format, \
- }, \
+ .start = { \
+ .element_size = sizeof(sd_bus_vtable), \
+ .features = _SD_BUS_VTABLE_PARAM_NAMES, \
+ .vtable_format_reference = &sd_bus_object_vtable_format, \
+ }, \
}, \
}
.type = _SD_BUS_VTABLE_METHOD, \
.flags = _flags, \
.x = { \
- .method = { \
- .member = _member, \
- .signature = _signature, \
- .result = _result, \
- .handler = _handler, \
- .offset = _offset, \
- .names = _in_names _out_names, \
- }, \
+ .method = { \
+ .member = _member, \
+ .signature = _signature, \
+ .result = _result, \
+ .handler = _handler, \
+ .offset = _offset, \
+ .names = _in_names _out_names, \
+ }, \
}, \
}
#define SD_BUS_METHOD_WITH_OFFSET(_member, _signature, _result, _handler, _offset, _flags) \
.type = _SD_BUS_VTABLE_SIGNAL, \
.flags = _flags, \
.x = { \
- .signal = { \
- .member = _member, \
- .signature = _signature, \
- .names = _out_names, \
- }, \
+ .signal = { \
+ .member = _member, \
+ .signature = _signature, \
+ .names = _out_names, \
+ }, \
}, \
- }
-#define SD_BUS_SIGNAL(_member, _signature, _flags) \
+ }
+#define SD_BUS_SIGNAL(_member, _signature, _flags) \
SD_BUS_SIGNAL_WITH_NAMES(_member, _signature, "", _flags)
#define SD_BUS_PROPERTY(_member, _signature, _get, _offset, _flags) \
.type = _SD_BUS_VTABLE_PROPERTY, \
.flags = _flags, \
.x = { \
- .property = { \
- .member = _member, \
- .signature = _signature, \
- .get = _get, \
- .set = NULL, \
- .offset = _offset, \
- }, \
+ .property = { \
+ .member = _member, \
+ .signature = _signature, \
+ .get = _get, \
+ .set = NULL, \
+ .offset = _offset, \
+ }, \
}, \
}
.type = _SD_BUS_VTABLE_WRITABLE_PROPERTY, \
.flags = _flags, \
.x = { \
- .property = { \
- .member = _member, \
- .signature = _signature, \
- .get = _get, \
- .set = _set, \
- .offset = _offset, \
- }, \
+ .property = { \
+ .member = _member, \
+ .signature = _signature, \
+ .get = _get, \
+ .set = _set, \
+ .offset = _offset, \
+ }, \
}, \
}
{ \
.type = _SD_BUS_VTABLE_END, \
.flags = 0, \
- .x = { { 0 } }, \
+ .x = { \
+ .end = { \
+ ._reserved = 0, \
+ }, \
+ }, \
}
#define _SD_ECHO(X) X
return add_group(i);
default:
- assert_not_reached("Unknown item type");
+ assert_not_reached();
}
}
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
if (arg_replace && arg_cat_config)
test_env = environment()
test_env.set('SYSTEMD_KBD_MODEL_MAP', kbd_model_map)
test_env.set('SYSTEMD_LANGUAGE_FALLBACK_MAP', language_fallback_map)
-test_env.set('PATH', '@0@:@1@'.format(meson.build_root(), path))
+test_env.set('PATH', project_build_root + ':' + path)
############################################################
tests += [
[['src/test/test-device-nodes.c']],
+ [['src/test/test-ether-addr-util.c']],
+
[['src/test/test-engine.c'],
[libcore,
libshared],
[['src/test/test-sysctl-util.c']],
+ [['src/test/test-import-util.c']],
+
[['src/test/test-user-record.c']],
[['src/test/test-user-util.c']],
bitmap_unset(b, 32);
BITMAP_FOREACH(n, NULL)
- assert_not_reached("NULL bitmap");
+ assert_not_reached();
assert_se(bitmap_set(b, 0) == 0);
assert_se(bitmap_set(b, 1) == 0);
#include "util.h"
static int test_acpi_fpdt(void) {
- char ts_start[FORMAT_TIMESPAN_MAX], ts_exit[FORMAT_TIMESPAN_MAX], ts_span[FORMAT_TIMESPAN_MAX];
usec_t loader_start, loader_exit;
int r;
}
log_info("ACPI FPDT: loader start=%s exit=%s duration=%s",
- format_timespan(ts_start, sizeof(ts_start), loader_start, USEC_PER_MSEC),
- format_timespan(ts_exit, sizeof(ts_exit), loader_exit, USEC_PER_MSEC),
- format_timespan(ts_span, sizeof(ts_span), loader_exit - loader_start, USEC_PER_MSEC));
+ FORMAT_TIMESPAN(loader_start, USEC_PER_MSEC),
+ FORMAT_TIMESPAN(loader_exit, USEC_PER_MSEC),
+ FORMAT_TIMESPAN(loader_exit - loader_start, USEC_PER_MSEC));
return 1;
}
static int test_efi_loader(void) {
- char ts_start[FORMAT_TIMESPAN_MAX], ts_exit[FORMAT_TIMESPAN_MAX], ts_span[FORMAT_TIMESPAN_MAX];
usec_t loader_start, loader_exit;
int r;
}
log_info("EFI Loader: start=%s exit=%s duration=%s",
- format_timespan(ts_start, sizeof(ts_start), loader_start, USEC_PER_MSEC),
- format_timespan(ts_exit, sizeof(ts_exit), loader_exit, USEC_PER_MSEC),
- format_timespan(ts_span, sizeof(ts_span), loader_exit - loader_start, USEC_PER_MSEC));
+ FORMAT_TIMESPAN(loader_start, USEC_PER_MSEC),
+ FORMAT_TIMESPAN(loader_exit, USEC_PER_MSEC),
+ FORMAT_TIMESPAN(loader_exit - loader_start, USEC_PER_MSEC));
return 1;
}
static int test_boot_timestamps(void) {
- char s[MAX(FORMAT_TIMESPAN_MAX, FORMAT_TIMESTAMP_MAX)];
dual_timestamp fw, l, k;
int r;
return ok ? 0 : r;
}
- log_info("Firmware began %s before kernel.", format_timespan(s, sizeof(s), fw.monotonic, 0));
- log_info("Loader began %s before kernel.", format_timespan(s, sizeof(s), l.monotonic, 0));
- log_info("Firmware began %s.", format_timestamp(s, sizeof(s), fw.realtime));
- log_info("Loader began %s.", format_timestamp(s, sizeof(s), l.realtime));
- log_info("Kernel began %s.", format_timestamp(s, sizeof(s), k.realtime));
+ log_info("Firmware began %s before kernel.", FORMAT_TIMESPAN(fw.monotonic, 0));
+ log_info("Loader began %s before kernel.", FORMAT_TIMESPAN(l.monotonic, 0));
+ log_info("Firmware began %s.", FORMAT_TIMESTAMP(fw.realtime));
+ log_info("Loader began %s.", FORMAT_TIMESTAMP(l.realtime));
+ log_info("Kernel began %s.", FORMAT_TIMESTAMP(k.realtime));
return 1;
}
if (fd < 0)
log_error_errno(errno, "Failed to open root directory: %m");
else {
- char ts[FORMAT_TIMESTAMP_MAX], bs[FORMAT_BYTES_MAX];
BtrfsSubvolInfo info;
r = btrfs_subvol_get_info_fd(fd, 0, &info);
if (r < 0)
log_error_errno(r, "Failed to get subvolume info: %m");
else {
- log_info("otime: %s", format_timestamp(ts, sizeof(ts), info.otime));
+ log_info("otime: %s", FORMAT_TIMESTAMP(info.otime));
log_info("read-only (search): %s", yes_no(info.read_only));
}
if (r < 0)
log_error_errno(r, "Failed to get quota info: %m");
else {
- log_info("referenced: %s", strna(format_bytes(bs, sizeof(bs), quota.referenced)));
- log_info("exclusive: %s", strna(format_bytes(bs, sizeof(bs), quota.exclusive)));
- log_info("referenced_max: %s", strna(format_bytes(bs, sizeof(bs), quota.referenced_max)));
- log_info("exclusive_max: %s", strna(format_bytes(bs, sizeof(bs), quota.exclusive_max)));
+ log_info("referenced: %s", strna(FORMAT_BYTES(quota.referenced)));
+ log_info("exclusive: %s", strna(FORMAT_BYTES(quota.exclusive)));
+ log_info("referenced_max: %s", strna(FORMAT_BYTES(quota.referenced_max)));
+ log_info("exclusive_max: %s", strna(FORMAT_BYTES(quota.exclusive_max)));
}
r = btrfs_subvol_get_read_only_fd(fd);
CalendarSpec *c;
_cleanup_free_ char *p = NULL, *q = NULL;
usec_t u;
- char buf[FORMAT_TIMESTAMP_MAX];
int r;
assert_se(calendar_spec_from_string(input, &c) >= 0);
u = now(CLOCK_REALTIME);
r = calendar_spec_next_usec(c, u, &u);
- log_info("Next: %s", r < 0 ? strerror_safe(r) : format_timestamp(buf, sizeof buf, u));
+ log_info("Next: %s", r < 0 ? strerror_safe(r) : FORMAT_TIMESTAMP(u));
calendar_spec_free(c);
assert_se(calendar_spec_from_string(p, &c) >= 0);
CalendarSpec *c;
usec_t u;
char *old_tz;
- char buf[FORMAT_TIMESTAMP_MAX];
int r;
old_tz = getenv("TZ");
u = after;
r = calendar_spec_next_usec(c, after, &u);
- log_info("At: %s", r < 0 ? strerror_safe(r) : format_timestamp_style(buf, sizeof buf, u, TIMESTAMP_US));
+ log_info("At: %s", r < 0 ? strerror_safe(r) : FORMAT_TIMESTAMP_STYLE(u, TIMESTAMP_US));
if (expect != USEC_INFINITY)
assert_se(r >= 0 && u == expect);
else
static void test_hourly_bug_4031(void) {
CalendarSpec *c;
usec_t n, u, w;
- char buf[FORMAT_TIMESTAMP_MAX], zaf[FORMAT_TIMESTAMP_MAX];
int r;
assert_se(calendar_spec_from_string("hourly", &c) >= 0);
n = now(CLOCK_REALTIME);
assert_se((r = calendar_spec_next_usec(c, n, &u)) >= 0);
- log_info("Now: %s (%"PRIu64")", format_timestamp_style(buf, sizeof buf, n, TIMESTAMP_US), n);
- log_info("Next hourly: %s (%"PRIu64")", r < 0 ? strerror_safe(r) : format_timestamp_style(buf, sizeof buf, u, TIMESTAMP_US), u);
+ log_info("Now: %s (%"PRIu64")", FORMAT_TIMESTAMP_STYLE(n, TIMESTAMP_US), n);
+ log_info("Next hourly: %s (%"PRIu64")", r < 0 ? strerror_safe(r) : FORMAT_TIMESTAMP_STYLE(u, TIMESTAMP_US), u);
assert_se((r = calendar_spec_next_usec(c, u, &w)) >= 0);
- log_info("Next hourly: %s (%"PRIu64")", r < 0 ? strerror_safe(r) : format_timestamp_style(zaf, sizeof zaf, w, TIMESTAMP_US), w);
+ log_info("Next hourly: %s (%"PRIu64")", r < 0 ? strerror_safe(r) : FORMAT_TIMESTAMP_STYLE(w, TIMESTAMP_US), w);
assert_se(n < u);
assert_se(u <= n + USEC_PER_HOUR);
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
if (optind == argc)
log_info("\"%s\" → \"%s\"", p, buf);
assert_se(parse_timestamp(buf, &q) >= 0);
- if (q != t) {
- char tmp[FORMAT_TIMESTAMP_MAX];
-
+ if (q != t)
log_error("round-trip failed: \"%s\" → \"%s\"",
- buf, format_timestamp_style(tmp, sizeof(tmp), q, TIMESTAMP_US));
- }
+ buf, FORMAT_TIMESTAMP_STYLE(q, TIMESTAMP_US));
assert_se(q == t);
assert_se(format_timestamp_relative(buf_relative, sizeof(buf_relative), t));
static void test_cescape(void) {
_cleanup_free_ char *t;
+ log_info("/* %s */", __func__);
+
assert_se(t = cescape("abc\\\"\b\f\n\r\t\v\a\003\177\234\313"));
assert_se(streq(t, "abc\\\\\\\"\\b\\f\\n\\r\\t\\v\\a\\003\\177\\234\\313"));
}
static void test_xescape(void) {
_cleanup_free_ char *t;
+ log_info("/* %s */", __func__);
+
assert_se(t = xescape("abc\\\"\b\f\n\r\t\v\a\003\177\234\313", ""));
assert_se(streq(t, "abc\\x5c\"\\x08\\x0c\\x0a\\x0d\\x09\\x0b\\x07\\x03\\x7f\\x9c\\xcb"));
}
const unsigned full_fit = !eight_bits ? 55 : 46;
XEscapeFlags flags = eight_bits * XESCAPE_8_BIT;
+ log_info("/* %s */", __func__);
+
for (unsigned i = 0; i < 60; i++) {
_cleanup_free_ char *t, *q;
static void test_cunescape(void) {
_cleanup_free_ char *unescaped;
+ log_info("/* %s */", __func__);
+
assert_se(cunescape("abc\\\\\\\"\\b\\f\\a\\n\\r\\t\\v\\003\\177\\234\\313\\000\\x00", 0, &unescaped) < 0);
assert_se(cunescape("abc\\\\\\\"\\b\\f\\a\\n\\r\\t\\v\\003\\177\\234\\313\\000\\x00", UNESCAPE_RELAX, &unescaped) >= 0);
assert_se(streq_ptr(unescaped, "abc\\\"\b\f\a\n\r\t\v\003\177\234\313\\000\\x00"));
}
static void test_shell_escape(void) {
+ log_info("/* %s */", __func__);
+
test_shell_escape_one("", "", "");
test_shell_escape_one("\\", "", "\\\\");
test_shell_escape_one("foobar", "", "foobar");
}
static void test_shell_maybe_quote(void) {
+ log_info("/* %s */", __func__);
test_shell_maybe_quote_one("", 0, "");
test_shell_maybe_quote_one("", SHELL_ESCAPE_EMPTY, "\"\"");
test_shell_maybe_quote_one("głąb\002\003rząd", SHELL_ESCAPE_POSIX, "$'głąb\\002\\003rząd'");
}
+static void test_quote_command_line_one(char **argv, const char *expected) {
+ _cleanup_free_ char *s;
+
+ assert_se(s = quote_command_line(argv));
+ log_info("%s", s);
+ assert_se(streq(s, expected));
+}
+
+static void test_quote_command_line(void) {
+ log_info("/* %s */", __func__);
+
+ test_quote_command_line_one(STRV_MAKE("true", "true"),
+ "true true");
+ test_quote_command_line_one(STRV_MAKE("true", "with a space"),
+ "true \"with a space\"");
+ test_quote_command_line_one(STRV_MAKE("true", "with a 'quote'"),
+ "true \"with a 'quote'\"");
+ test_quote_command_line_one(STRV_MAKE("true", "with a \"quote\""),
+ "true \"with a \\\"quote\\\"\"");
+ test_quote_command_line_one(STRV_MAKE("true", "$dollar"),
+ "true \"\\$dollar\"");
+}
+
int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
test_cunescape();
test_shell_escape();
test_shell_maybe_quote();
+ test_quote_command_line();
return 0;
}
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "ether-addr-util.h"
+#include "tests.h"
+
+#define INFINIBAD_ADDR_1 ((const struct hw_addr_data){ .length = 20, .infiniband = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20} })
+
+static void test_HW_ADDR_TO_STRING(void) {
+ log_info("/* %s */", __func__);
+
+ const char *s = HW_ADDR_TO_STR(&(const struct hw_addr_data){6});
+ log_info("null: %s", s);
+
+ log_info("null×2: %s, %s",
+ HW_ADDR_TO_STR(&(const struct hw_addr_data){6}),
+ HW_ADDR_TO_STR(&(const struct hw_addr_data){6}));
+ log_info("null×3: %s, %s, %s",
+ HW_ADDR_TO_STR(&(const struct hw_addr_data){6}),
+ s,
+ HW_ADDR_TO_STR(&(const struct hw_addr_data){6}));
+
+ log_info("infiniband: %s", HW_ADDR_TO_STR(&INFINIBAD_ADDR_1));
+
+ /* Let's nest function calls in a stupid way. */
+ _cleanup_free_ char *t = NULL;
+ log_info("infiniband×3: %s\n%14s%s\n%14s%s",
+ HW_ADDR_TO_STR(&(const struct hw_addr_data){20}), "",
+ t = strdup(HW_ADDR_TO_STR(&INFINIBAD_ADDR_1)), "",
+ HW_ADDR_TO_STR(&(const struct hw_addr_data){20}));
+
+ const char *p;
+ /* Let's use a separate selection statement */
+ if ((p = HW_ADDR_TO_STR(&(const struct hw_addr_data){6})))
+ log_info("joint: %s, %s", s, p);
+}
+
+int main(int argc, char *argv[]) {
+ test_setup_logging(LOG_INFO);
+
+ test_HW_ADDR_TO_STRING();
+ return 0;
+}
#include "macro.h"
#include "string-util.h"
+/* Do some basic checks on STRLEN() and DECIMAL_STR_MAX() */
+assert_cc(STRLEN("xxx") == 3);
+assert_cc(STRLEN("") == 0);
+assert_cc(DECIMAL_STR_MAX(uint8_t) == 5);
+assert_cc(DECIMAL_STR_MAX(int8_t) == 5);
+assert_cc(DECIMAL_STR_MAX(uint64_t) == 22);
+assert_cc(DECIMAL_STR_MAX(char) == 5);
+assert_cc(CONST_MAX(DECIMAL_STR_MAX(int8_t), STRLEN("xxx")) == 5);
+
static void test_format_bytes_one(uint64_t val, bool trailing_B, const char *iec_with_p, const char *iec_without_p,
const char *si_with_p, const char *si_without_p) {
char buf[FORMAT_BYTES_MAX];
for (j = 0; j < ELEMENTSOF(tests); j++) {
usec_t ts = now(CLOCK_MONOTONIC), n;
- char b[FORMAT_TIMESPAN_MAX];
assert_se(h = hashmap_new(tests[j].ops));
hashmap_free(h);
n = now(CLOCK_MONOTONIC);
- log_info("test took %s", format_timespan(b, sizeof b, n - ts, 0));
+ log_info("test took %s", FORMAT_TIMESPAN(n - ts, 0));
}
}
Hashmap *h;
bool slow = slow_tests_enabled();
usec_t ts, n;
- char b[FORMAT_TIMESPAN_MAX];
unsigned n_entries = slow ? 1 << 20 : 240;
const struct {
hashmap_free(h);
n = now(CLOCK_MONOTONIC);
- log_info("%s test took %s", tests[j].title, format_timespan(b, sizeof b, n - ts, 0));
+ log_info("%s test took %s", tests[j].title, FORMAT_TIMESPAN(n - ts, 0));
assert_se(custom_counter == tests[j].expect_counter);
}
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "alloc-util.h"
+#include "import-util.h"
+#include "log.h"
+#include "string-util.h"
+#include "tests.h"
+
+static void test_import_url_last_component_one(const char *input, const char *output, int ret) {
+ _cleanup_free_ char *s = NULL;
+
+ assert_se(import_url_last_component(input, &s) == ret);
+ assert_se(streq_ptr(output, s));
+}
+
+static void test_import_url_last_component(void) {
+ test_import_url_last_component_one("https://foobar/waldo/quux", "quux", 0);
+ test_import_url_last_component_one("https://foobar/waldo/quux/", "quux", 0);
+ test_import_url_last_component_one("https://foobar/waldo/", "waldo", 0);
+ test_import_url_last_component_one("https://foobar/", NULL, -EADDRNOTAVAIL);
+ test_import_url_last_component_one("https://foobar", NULL, -EADDRNOTAVAIL);
+ test_import_url_last_component_one("https://foobar/waldo/quux?foo=bar", "quux", 0);
+ test_import_url_last_component_one("https://foobar/waldo/quux/?foo=bar", "quux", 0);
+ test_import_url_last_component_one("https://foobar/waldo/quux/?foo=bar#piep", "quux", 0);
+ test_import_url_last_component_one("https://foobar/waldo/quux/#piep", "quux", 0);
+ test_import_url_last_component_one("https://foobar/waldo/quux#piep", "quux", 0);
+ test_import_url_last_component_one("https://", NULL, -EINVAL);
+ test_import_url_last_component_one("", NULL, -EINVAL);
+ test_import_url_last_component_one(":", NULL, -EINVAL);
+ test_import_url_last_component_one(":/", NULL, -EINVAL);
+ test_import_url_last_component_one("x:/", NULL, -EINVAL);
+ test_import_url_last_component_one("x:y", NULL, -EADDRNOTAVAIL);
+ test_import_url_last_component_one("x:y/z", "z", 0);
+}
+
+static void test_import_url_change_suffix_one(const char *input, size_t n, const char *suffix, const char *output, int ret) {
+ _cleanup_free_ char *s = NULL;
+
+ assert_se(import_url_change_suffix(input, n, suffix, &s) == ret);
+ assert_se(streq_ptr(output, s));
+}
+
+static void test_import_url_change_suffix(void) {
+ test_import_url_change_suffix_one("https://foobar/waldo/quux", 1, "wuff", "https://foobar/waldo/wuff", 0);
+ test_import_url_change_suffix_one("https://foobar/waldo/quux/", 1, "wuff", "https://foobar/waldo/wuff", 0);
+ test_import_url_change_suffix_one("https://foobar/waldo/quux///?mief", 1, "wuff", "https://foobar/waldo/wuff", 0);
+ test_import_url_change_suffix_one("https://foobar/waldo/quux///?mief#opopo", 1, "wuff", "https://foobar/waldo/wuff", 0);
+ test_import_url_change_suffix_one("https://foobar/waldo/quux/quff", 2, "wuff", "https://foobar/waldo/wuff", 0);
+ test_import_url_change_suffix_one("https://foobar/waldo/quux/quff/", 2, "wuff", "https://foobar/waldo/wuff", 0);
+ test_import_url_change_suffix_one("https://foobar/waldo/quux/quff", 0, "wuff", "https://foobar/waldo/quux/quff/wuff", 0);
+ test_import_url_change_suffix_one("https://foobar/waldo/quux/quff?aa?bb##4", 0, "wuff", "https://foobar/waldo/quux/quff/wuff", 0);
+ test_import_url_change_suffix_one("https://", 0, "wuff", NULL, -EINVAL);
+ test_import_url_change_suffix_one("", 0, "wuff", NULL, -EINVAL);
+ test_import_url_change_suffix_one(":", 0, "wuff", NULL, -EINVAL);
+ test_import_url_change_suffix_one(":/", 0, "wuff", NULL, -EINVAL);
+ test_import_url_change_suffix_one("x:/", 0, "wuff", NULL, -EINVAL);
+ test_import_url_change_suffix_one("x:y", 0, "wuff", "x:y/wuff", 0);
+ test_import_url_change_suffix_one("x:y/z", 0, "wuff", "x:y/z/wuff", 0);
+ test_import_url_change_suffix_one("x:y/z/", 0, "wuff", "x:y/z/wuff", 0);
+ test_import_url_change_suffix_one("x:y/z/", 1, "wuff", "x:y/wuff", 0);
+ test_import_url_change_suffix_one("x:y/z/", 2, "wuff", "x:y/wuff", 0);
+}
+
+int main(int argc, char *argv[]) {
+
+ test_setup_logging(LOG_INFO);
+
+ test_import_url_last_component();
+ test_import_url_change_suffix();
+
+ return 0;
+}
else if (q && streq(changes[i].path, q))
q = NULL;
else
- assert_not_reached("wut?");
+ assert_not_reached();
}
assert(!p && !q);
unit_file_changes_free(changes, n_changes);
else if (q && streq(changes[i].path, q))
q = NULL;
else
- assert_not_reached("wut?");
+ assert_not_reached();
}
assert(!p && !q);
unit_file_changes_free(changes, n_changes);
else if (q && streq(changes[i].path, q))
q = NULL;
else
- assert_not_reached("wut?");
+ assert_not_reached();
}
assert(!p && !q);
unit_file_changes_free(changes, n_changes);
#define dump_glyph(x) log_info(STRINGIFY(x) ": %s", special_glyph(x))
static void dump_special_glyphs(void) {
- assert_cc(SPECIAL_GLYPH_TOUCH + 1 == _SPECIAL_GLYPH_MAX);
+ assert_cc(SPECIAL_GLYPH_SPARKLES + 1 == _SPECIAL_GLYPH_MAX);
log_info("/* %s */", __func__);
dump_glyph(SPECIAL_GLYPH_DEPRESSED_SMILEY);
dump_glyph(SPECIAL_GLYPH_LOCK_AND_KEY);
dump_glyph(SPECIAL_GLYPH_TOUCH);
+ dump_glyph(SPECIAL_GLYPH_RECYCLING);
+ dump_glyph(SPECIAL_GLYPH_DOWNLOAD);
+ dump_glyph(SPECIAL_GLYPH_SPARKLES);
}
int main(int argc, char *argv[]) {
assert_se(values[i] == NULL);
PATH_FOREACH_PREFIX(s, "////")
- assert_not_reached("Wut?");
+ assert_not_reached();
b = false;
PATH_FOREACH_PREFIX_MORE(s, "////") {
assert_se(b);
PATH_FOREACH_PREFIX(s, "")
- assert_not_reached("wut?");
+ assert_not_reached();
b = false;
PATH_FOREACH_PREFIX_MORE(s, "") {
else if (in_initrd() && !*strip && proc_cmdline_key_streq(key, "rd.zumm"))
assert_se(!value);
else
- assert_not_reached("Bad key!");
+ assert_not_reached();
return 0;
}
#include "tests.h"
int main(int argc, char *argv[]) {
- char buf[CONST_MAX(FORMAT_TIMESPAN_MAX, FORMAT_BYTES_MAX)];
nsec_t nsec;
uint64_t v;
int r;
log_open();
assert_se(procfs_cpu_get_usage(&nsec) >= 0);
- log_info("Current system CPU time: %s", format_timespan(buf, sizeof(buf), nsec/NSEC_PER_USEC, 1));
+ log_info("Current system CPU time: %s", FORMAT_TIMESPAN(nsec/NSEC_PER_USEC, 1));
assert_se(procfs_memory_get_used(&v) >= 0);
- log_info("Current memory usage: %s", format_bytes(buf, sizeof(buf), v));
+ log_info("Current memory usage: %s", FORMAT_BYTES(v));
assert_se(procfs_tasks_get_current(&v) >= 0);
log_info("Current number of tasks: %" PRIu64, v);
assert_se(streq_ptr(*check, input_table_multiple[i--]));
STRV_FOREACH_BACKWARDS(check, (char**) NULL)
- assert_not_reached("Let's see that we check empty strv right, too.");
+ assert_not_reached();
STRV_FOREACH_BACKWARDS(check, (char**) { NULL })
- assert_not_reached("Let's see that we check empty strv right, too.");
+ assert_not_reached();
}
static void test_strv_foreach_pair(void) {
char buf[MAX(FORMAT_TIMESTAMP_MAX, FORMAT_TIMESPAN_MAX)];
usec_t x, y;
- random_bytes(&x, sizeof(x));
- x = x % (2147483600 * USEC_PER_SEC) + 1;
+ x = random_u64_range(2147483600 * USEC_PER_SEC) + 1;
assert_se(format_timestamp(buf, sizeof(buf), x));
log_debug("%s", buf);
}
}
+static void test_FORMAT_TIMESTAMP(void) {
+ log_info("/* %s */", __func__);
+
+ for (unsigned i = 0; i < 100; i++) {
+ _cleanup_free_ char *buf;
+ usec_t x, y;
+
+ x = random_u64_range(2147483600 * USEC_PER_SEC) + 1;
+
+ /* strbuf() is to test the macro in an argument to a function call. */
+ assert_se(buf = strdup(FORMAT_TIMESTAMP(x)));
+ log_debug("%s", buf);
+ assert_se(parse_timestamp(buf, &y) >= 0);
+ assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC);
+
+ assert_se(streq(FORMAT_TIMESTAMP(x), buf));
+ }
+}
+
static void test_format_timestamp_relative(void) {
log_info("/* %s */", __func__);
test_usec_sub_signed();
test_usec_sub_unsigned();
test_format_timestamp();
+ test_FORMAT_TIMESTAMP();
test_format_timestamp_relative();
test_format_timestamp_utc();
test_deserialize_dual_timestamp();
static void test_physical_memory(void) {
uint64_t p;
- char buf[FORMAT_BYTES_MAX];
log_info("/* %s */", __func__);
assert_se(p < UINT64_MAX);
assert_se(p % page_size() == 0);
- log_info("Memory: %s (%" PRIu64 ")", format_bytes(buf, sizeof(buf), p), p);
+ log_info("Memory: %s (%" PRIu64 ")", FORMAT_BYTES(p), p);
}
static void test_physical_memory_scale(void) {
break;
default:
- assert_not_reached("unexpected index");
+ assert_not_reached();
break;
}
break;
default:
- assert_not_reached("unexpected index");
+ assert_not_reached();
break;
}
}
static void test_getcrtime(void) {
-
_cleanup_close_ int fd = -1;
- char ts[FORMAT_TIMESTAMP_MAX];
const char *vt;
usec_t usec, k;
int r;
if (r < 0)
log_debug_errno(r, "btime: %m");
else
- log_debug("btime: %s", format_timestamp(ts, sizeof(ts), usec));
+ log_debug("btime: %s", FORMAT_TIMESTAMP(usec));
k = now(CLOCK_REALTIME);
REENABLE_WARNING;
static int print_ntp_status_info(NTPStatusInfo *i) {
- char ts[FORMAT_TIMESPAN_MAX], jitter[FORMAT_TIMESPAN_MAX],
- tmin[FORMAT_TIMESPAN_MAX], tmax[FORMAT_TIMESPAN_MAX];
usec_t delay, t14, t23, offset, root_distance;
_cleanup_(table_unrefp) Table *table = NULL;
bool offset_sign;
return table_log_add_error(r);
r = table_add_cell_stringf(table, NULL, "%s (min: %s; max %s)",
- format_timespan(ts, sizeof(ts), i->poll_interval, 0),
- format_timespan(tmin, sizeof(tmin), i->poll_min, 0),
- format_timespan(tmax, sizeof(tmax), i->poll_max, 0));
+ FORMAT_TIMESPAN(i->poll_interval, 0),
+ FORMAT_TIMESPAN(i->poll_min, 0),
+ FORMAT_TIMESPAN(i->poll_max, 0));
if (r < 0)
return table_log_add_error(r);
return table_log_add_error(r);
r = table_add_cell_stringf(table, NULL, "%s (%" PRIi32 ")",
- format_timespan(ts, sizeof(ts), DIV_ROUND_UP((nsec_t) (exp2(i->precision) * NSEC_PER_SEC), NSEC_PER_USEC), 0),
+ FORMAT_TIMESPAN(DIV_ROUND_UP((nsec_t) (exp2(i->precision) * NSEC_PER_SEC), NSEC_PER_USEC), 0),
i->precision);
if (r < 0)
return table_log_add_error(r);
return table_log_add_error(r);
r = table_add_cell_stringf(table, NULL, "%s (max: %s)",
- format_timespan(ts, sizeof(ts), root_distance, 0),
- format_timespan(tmax, sizeof(tmax), i->root_distance_max, 0));
+ FORMAT_TIMESPAN(root_distance, 0),
+ FORMAT_TIMESPAN(i->root_distance_max, 0));
if (r < 0)
return table_log_add_error(r);
r = table_add_cell_stringf(table, NULL, "%s%s",
offset_sign ? "+" : "-",
- format_timespan(ts, sizeof(ts), offset, 0));
+ FORMAT_TIMESPAN(offset, 0));
if (r < 0)
return table_log_add_error(r);
r = table_add_many(table,
TABLE_STRING, "Delay:",
- TABLE_STRING, format_timespan(ts, sizeof(ts), delay, 0),
+ TABLE_STRING, FORMAT_TIMESPAN(delay, 0),
TABLE_STRING, "Jitter:",
- TABLE_STRING, format_timespan(jitter, sizeof(jitter), i->jitter, 0),
+ TABLE_STRING, FORMAT_TIMESPAN(i->jitter, 0),
TABLE_STRING, "Packet count:",
TABLE_UINT64, i->packet_count);
if (r < 0)
case SD_BUS_TYPE_STRUCT:
if (streq(name, "NTPMessage")) {
_cleanup_(ntp_status_info_clear) NTPStatusInfo i = {};
- char ts[FORMAT_TIMESPAN_MAX], stamp[FORMAT_TIMESTAMP_MAX];
r = map_ntp_message(NULL, NULL, m, NULL, &i);
if (r < 0)
printf("{ Leap=%u, Version=%u, Mode=%u, Stratum=%u, Precision=%i,",
i.leap, i.version, i.mode, i.stratum, i.precision);
- printf(" RootDelay=%s,",
- format_timespan(ts, sizeof(ts), i.root_delay, 0));
- printf(" RootDispersion=%s,",
- format_timespan(ts, sizeof(ts), i.root_dispersion, 0));
+ printf(" RootDelay=%s,", FORMAT_TIMESPAN(i.root_delay, 0));
+ printf(" RootDispersion=%s,", FORMAT_TIMESPAN(i.root_dispersion, 0));
if (i.stratum == 1)
printf(" Reference=%s,", i.reference.str);
else
printf(" Reference=%" PRIX32 ",", be32toh(i.reference.val));
- printf(" OriginateTimestamp=%s,",
- format_timestamp(stamp, sizeof(stamp), i.origin));
- printf(" ReceiveTimestamp=%s,",
- format_timestamp(stamp, sizeof(stamp), i.recv));
- printf(" TransmitTimestamp=%s,",
- format_timestamp(stamp, sizeof(stamp), i.trans));
- printf(" DestinationTimestamp=%s,",
- format_timestamp(stamp, sizeof(stamp), i.dest));
+ printf(" OriginateTimestamp=%s,", FORMAT_TIMESTAMP(i.origin));
+ printf(" ReceiveTimestamp=%s,", FORMAT_TIMESTAMP(i.recv));
+ printf(" TransmitTimestamp=%s,", FORMAT_TIMESTAMP(i.trans));
+ printf(" DestinationTimestamp=%s,", FORMAT_TIMESTAMP(i.dest));
printf(" Ignored=%s PacketCount=%" PRIu64 ",",
yes_no(i.spike), i.packet_count);
- printf(" Jitter=%s }\n",
- format_timespan(ts, sizeof(ts), i.jitter, 0));
+ printf(" Jitter=%s }\n", FORMAT_TIMESPAN(i.jitter, 0));
return 1;
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
return 1;
LIST_FIND_TAIL(names, m->fallback_servers, tail);
LIST_INSERT_AFTER(names, m->fallback_servers, tail, n);
} else
- assert_not_reached("Unknown server type");
+ assert_not_reached();
n->manager = m;
else if (n->type == SERVER_FALLBACK)
LIST_REMOVE(names, n->manager->fallback_servers, n);
else
- assert_not_reached("Unknown server type");
+ assert_not_reached();
if (n->manager->current_server_name == n)
manager_set_server_name(n->manager, NULL);
ClockState *sp,
sd_event *event) {
- char buf[MAX((size_t)FORMAT_TIMESTAMP_MAX, STRLEN("unrepresentable"))];
struct timex tx = {};
- const char * ts;
usec_t t;
int r;
if (tx.status & STA_NANO)
tx.time.tv_usec /= 1000;
t = timeval_load(&tx.time);
- ts = format_timestamp_style(buf, sizeof(buf), t, TIMESTAMP_US_UTC);
- if (!ts)
- strcpy(buf, "unrepresentable");
- log_info("adjtime state %d status %x time %s", sp->adjtime_state, tx.status, ts);
+
+ log_info("adjtime state %d status %x time %s", sp->adjtime_state, tx.status,
+ FORMAT_TIMESTAMP_STYLE(t, TIMESTAMP_US_UTC) ?: "unrepresentable");
sp->has_watchfile = access("/run/systemd/timesync/synchronized", F_OK) >= 0;
if (sp->has_watchfile)
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
return 0;
bool is_dir) {
if (FLAGS_SET(age_by, AGE_BY_MTIME) && mtime != NSEC_INFINITY && mtime >= cutoff) {
- char a[FORMAT_TIMESTAMP_MAX];
/* Follows spelling in stat(1). */
log_debug("%s \"%s\": modify time %s is too new.",
is_dir ? "Directory" : "File",
sub_path,
- format_timestamp_style(a, sizeof(a), mtime / NSEC_PER_USEC, TIMESTAMP_US));
+ FORMAT_TIMESTAMP_STYLE(mtime / NSEC_PER_USEC, TIMESTAMP_US));
return false;
}
if (FLAGS_SET(age_by, AGE_BY_ATIME) && atime != NSEC_INFINITY && atime >= cutoff) {
- char a[FORMAT_TIMESTAMP_MAX];
log_debug("%s \"%s\": access time %s is too new.",
is_dir ? "Directory" : "File",
sub_path,
- format_timestamp_style(a, sizeof(a), atime / NSEC_PER_USEC, TIMESTAMP_US));
+ FORMAT_TIMESTAMP_STYLE(atime / NSEC_PER_USEC, TIMESTAMP_US));
return false;
}
* by default for directories, because we change it when deleting.
*/
if (FLAGS_SET(age_by, AGE_BY_CTIME) && ctime != NSEC_INFINITY && ctime >= cutoff) {
- char a[FORMAT_TIMESTAMP_MAX];
log_debug("%s \"%s\": change time %s is too new.",
is_dir ? "Directory" : "File",
sub_path,
- format_timestamp_style(a, sizeof(a), ctime / NSEC_PER_USEC, TIMESTAMP_US));
+ FORMAT_TIMESTAMP_STYLE(ctime / NSEC_PER_USEC, TIMESTAMP_US));
return false;
}
if (FLAGS_SET(age_by, AGE_BY_BTIME) && btime != NSEC_INFINITY && btime >= cutoff) {
- char a[FORMAT_TIMESTAMP_MAX];
log_debug("%s \"%s\": birth time %s is too new.",
is_dir ? "Directory" : "File",
sub_path,
- format_timestamp_style(a, sizeof(a), btime / NSEC_PER_USEC, TIMESTAMP_US));
+ FORMAT_TIMESTAMP_STYLE(btime / NSEC_PER_USEC, TIMESTAMP_US));
return false;
}
finish:
if (deleted) {
- char a[FORMAT_TIMESTAMP_MAX], m[FORMAT_TIMESTAMP_MAX];
struct timespec ts[2];
log_debug("Restoring access and modification time on \"%s\": %s, %s",
p,
- format_timestamp_style(a, sizeof(a), self_atime_nsec / NSEC_PER_USEC, TIMESTAMP_US),
- format_timestamp_style(m, sizeof(m), self_mtime_nsec / NSEC_PER_USEC, TIMESTAMP_US));
+ FORMAT_TIMESTAMP_STYLE(self_atime_nsec / NSEC_PER_USEC, TIMESTAMP_US),
+ FORMAT_TIMESTAMP_STYLE(self_mtime_nsec / NSEC_PER_USEC, TIMESTAMP_US));
timespec_store_nsec(ts + 0, self_atime_nsec);
timespec_store_nsec(ts + 1, self_mtime_nsec);
break;
default:
- assert_not_reached("wut?");
+ assert_not_reached();
}
return 0;
}
static int clean_item_instance(Item *i, const char* instance) {
- char timestamp[FORMAT_TIMESTAMP_MAX];
_cleanup_closedir_ DIR *d = NULL;
STRUCT_STATX_DEFINE(sx);
int mountpoint, r;
log_debug("Cleanup threshold for %s \"%s\" is %s; age-by: %s%s",
mountpoint ? "mount point" : "directory",
instance,
- format_timestamp_style(timestamp, sizeof(timestamp), cutoff, TIMESTAMP_US),
+ FORMAT_TIMESTAMP_STYLE(cutoff, TIMESTAMP_US),
ab_f, ab_d);
}
}
static int specifier_expansion_from_arg(Item *i) {
- _cleanup_free_ char *unescaped = NULL, *resolved = NULL;
- char **xattr;
int r;
assert(i);
case CREATE_SYMLINK:
case CREATE_FILE:
case TRUNCATE_FILE:
- case WRITE_FILE:
- r = cunescape(i->argument, 0, &unescaped);
- if (r < 0)
- return log_error_errno(r, "Failed to unescape parameter to write: %s", i->argument);
+ case WRITE_FILE: {
+ _cleanup_free_ char *unescaped = NULL, *resolved = NULL;
+ ssize_t l;
+
+ l = cunescape(i->argument, 0, &unescaped);
+ if (l < 0)
+ return log_error_errno(l, "Failed to unescape parameter to write: %s", i->argument);
r = specifier_printf(unescaped, PATH_MAX-1, specifier_table, arg_root, NULL, &resolved);
if (r < 0)
return r;
- free_and_replace(i->argument, resolved);
- break;
-
+ return free_and_replace(i->argument, resolved);
+ }
case SET_XATTR:
- case RECURSIVE_SET_XATTR:
+ case RECURSIVE_SET_XATTR: {
+ char **xattr;
STRV_FOREACH(xattr, i->xattrs) {
+ _cleanup_free_ char *resolved = NULL;
+
r = specifier_printf(*xattr, SIZE_MAX, specifier_table, arg_root, NULL, &resolved);
if (r < 0)
return r;
free_and_replace(*xattr, resolved);
}
- break;
-
+ return 0;
+ }
default:
- break;
+ return 0;
}
- return 0;
}
static int patch_var_run(const char *fname, unsigned line, char **path) {
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
if (arg_operation == 0 && !arg_cat_config)
else if (phase == PHASE_CREATE)
op = arg_operation & OPERATION_CREATE;
else
- assert_not_reached("unexpected phase");
+ assert_not_reached();
if (op == 0) /* Nothing requested in this phase */
continue;
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
if (optind != argc)
case 'h':
return help();
default:
- assert_not_reached("Unknown option");
+ assert_not_reached();
}
arg_node = argv[optind];
case '?':
return -EINVAL;
default:
- assert_not_reached("Unknown option");
+ assert_not_reached();
}
return 1;
link_with : udev_link_with,
dependencies : [libblkid, libkmod])
-udev_id_progs = [['ata_id/ata_id.c'],
- ['cdrom_id/cdrom_id.c'],
- ['fido_id/fido_id.c',
- 'fido_id/fido_id_desc.c',
- 'fido_id/fido_id_desc.h'],
- ['scsi_id/scsi_id.c',
- 'scsi_id/scsi_id.h',
- 'scsi_id/scsi_serial.c',
- 'scsi_id/scsi.h'],
- ['v4l_id/v4l_id.c'],
- ['mtd_probe/mtd_probe.c',
- 'mtd_probe/mtd_probe.h',
- 'mtd_probe/probe_smartmedia.c']]
+udev_progs = [['ata_id/ata_id.c'],
+ ['cdrom_id/cdrom_id.c'],
+ ['fido_id/fido_id.c',
+ 'fido_id/fido_id_desc.c',
+ 'fido_id/fido_id_desc.h'],
+ ['scsi_id/scsi_id.c',
+ 'scsi_id/scsi_id.h',
+ 'scsi_id/scsi_serial.c',
+ 'scsi_id/scsi.h'],
+ ['v4l_id/v4l_id.c'],
+ ['mtd_probe/mtd_probe.c',
+ 'mtd_probe/mtd_probe.h',
+ 'mtd_probe/probe_smartmedia.c']]
dmi_arches = ['x86', 'x86_64', 'aarch64', 'arm', 'ia64', 'mips']
if dmi_arches.contains(host_machine.cpu_family())
- udev_id_progs += [['dmi_memory_id/dmi_memory_id.c']]
+ udev_progs += [['dmi_memory_id/dmi_memory_id.c']]
endif
-foreach prog : udev_id_progs
+udev_prog_paths = {}
+foreach prog : udev_progs
name = prog[0].split('/')[0]
exe = executable(
name,
prog,
include_directories : includes,
- dependencies : [versiondep],
+ dependencies : versiondep,
link_with : udev_link_with,
install_rpath : udev_rpath,
install : true,
install_dir : udevlibexecdir)
- # TODO: let's use a dictionary instead as soon as we can depend on meson >= 0.47.
- if name == 'dmi_memory_id'
- dmi_memory_id_path = exe.full_path()
- endif
+ udev_prog_paths += {name : exe.full_path()}
endforeach
if install_sysconfdir_samples
install_data('udev.conf',
- install_dir : join_paths(sysconfdir, 'udev'))
+ install_dir : sysconfdir / 'udev')
endif
custom_target(
if install_sysconfdir
meson.add_install_script('sh', '-c',
- mkdir_p.format(join_paths(sysconfdir, 'udev/rules.d')))
+ mkdir_p.format(sysconfdir / 'udev/rules.d'))
endif
fuzzers += [
(void) sd_device_get_property_value(device, "ID_NET_NAME_MAC", &new_name);
break;
default:
- assert_not_reached("invalid policy");
+ assert_not_reached();
}
if (ifname_valid(new_name)) {
log_device_debug(device, "Policy *%s* yields \"%s\".", name_policy_to_string(policy), new_name);
(void) sd_device_get_property_value(device, "ID_NET_NAME_MAC", &n);
break;
default:
- assert_not_reached("invalid policy");
+ assert_not_reached();
}
if (!isempty(n)) {
r = strv_extend(&altnames, n);
return -1;
default:
- assert_not_reached("Unknown option");
+ assert_not_reached();
}
if (optind < argc && !dev_specified) {
else if (streq(argv[1], "test2"))
test2();
else
- assert_not_reached("unknown command.");
+ assert_not_reached();
return 0;
}
r = link_config_get(ctx, dev, &link);
if (r < 0) {
- if (r == -ENOENT)
- return log_device_debug_errno(dev, r, "No matching link configuration found.");
if (r == -ENODEV)
return log_device_debug_errno(dev, r, "Link vanished while searching for configuration for it.");
+ if (r == -ENOENT) {
+ log_device_debug_errno(dev, r, "No matching link configuration found, ignoring device.");
+ return 0;
+ }
return log_device_error_errno(dev, r, "Failed to get link config: %m");
}
r = sd_device_get_devpath(dev, &val);
if (r < 0)
return r;
- l = strpcpy(&s, l, val);
+ strpcpy(&s, l, val);
break;
case FORMAT_SUBST_KERNEL:
r = sd_device_get_sysname(dev, &val);
if (r < 0)
return r;
- l = strpcpy(&s, l, val);
+ strpcpy(&s, l, val);
break;
case FORMAT_SUBST_KERNEL_NUMBER:
r = sd_device_get_sysnum(dev, &val);
goto null_terminate;
if (r < 0)
return r;
- l = strpcpy(&s, l, val);
+ strpcpy(&s, l, val);
break;
case FORMAT_SUBST_ID:
if (!event->dev_parent)
r = sd_device_get_sysname(event->dev_parent, &val);
if (r < 0)
return r;
- l = strpcpy(&s, l, val);
+ strpcpy(&s, l, val);
break;
case FORMAT_SUBST_DRIVER:
if (!event->dev_parent)
goto null_terminate;
if (r < 0)
return r;
- l = strpcpy(&s, l, val);
+ strpcpy(&s, l, val);
break;
case FORMAT_SUBST_MAJOR:
case FORMAT_SUBST_MINOR: {
r = sd_device_get_devnum(dev, &devnum);
if (r < 0 && r != -ENOENT)
return r;
- l = strpcpyf(&s, l, "%u", r < 0 ? 0 : type == FORMAT_SUBST_MAJOR ? major(devnum) : minor(devnum));
+ strpcpyf(&s, l, "%u", r < 0 ? 0 : type == FORMAT_SUBST_MAJOR ? major(devnum) : minor(devnum));
break;
}
case FORMAT_SUBST_RESULT: {
}
if (index == 0)
- l = strpcpy(&s, l, event->program_result);
+ strpcpy(&s, l, event->program_result);
else {
const char *start, *p;
unsigned i;
start = p;
/* %c{2+} copies the whole string from the second part on */
if (has_plus)
- l = strpcpy(&s, l, start);
+ strpcpy(&s, l, start);
else {
while (*p && !strchr(WHITESPACE, *p))
p++;
- l = strnpcpy(&s, l, start, p - start);
+ strnpcpy(&s, l, start, p - start);
}
}
break;
count = udev_replace_chars(vbuf, UDEV_ALLOWED_CHARS_INPUT);
if (count > 0)
log_device_debug(dev, "%i character(s) replaced", count);
- l = strpcpy(&s, l, vbuf);
+ strpcpy(&s, l, vbuf);
break;
}
case FORMAT_SUBST_PARENT:
goto null_terminate;
if (r < 0)
return r;
- l = strpcpy(&s, l, val + STRLEN("/dev/"));
+ strpcpy(&s, l, val + STRLEN("/dev/"));
break;
case FORMAT_SUBST_DEVNODE:
r = sd_device_get_devname(dev, &val);
goto null_terminate;
if (r < 0)
return r;
- l = strpcpy(&s, l, val);
+ strpcpy(&s, l, val);
break;
case FORMAT_SUBST_NAME:
if (event->name)
- l = strpcpy(&s, l, event->name);
+ strpcpy(&s, l, event->name);
else if (sd_device_get_devname(dev, &val) >= 0)
- l = strpcpy(&s, l, val + STRLEN("/dev/"));
+ strpcpy(&s, l, val + STRLEN("/dev/"));
else {
r = sd_device_get_sysname(dev, &val);
if (r < 0)
return r;
- l = strpcpy(&s, l, val);
+ strpcpy(&s, l, val);
}
break;
case FORMAT_SUBST_LINKS:
FOREACH_DEVICE_DEVLINK(dev, val)
if (s == dest)
- l = strpcpy(&s, l, val + STRLEN("/dev/"));
+ strpcpy(&s, l, val + STRLEN("/dev/"));
else
- l = strpcpyl(&s, l, " ", val + STRLEN("/dev/"), NULL);
+ strpcpyl(&s, l, " ", val + STRLEN("/dev/"), NULL);
if (s == dest)
goto null_terminate;
break;
case FORMAT_SUBST_ROOT:
- l = strpcpy(&s, l, "/dev");
+ strpcpy(&s, l, "/dev");
break;
case FORMAT_SUBST_SYS:
- l = strpcpy(&s, l, "/sys");
+ strpcpy(&s, l, "/sys");
break;
case FORMAT_SUBST_ENV:
if (isempty(attr))
goto null_terminate;
if (r < 0)
return r;
- l = strpcpy(&s, l, val);
+ strpcpy(&s, l, val);
break;
default:
- assert_not_reached("Unknown format substitution type");
+ assert_not_reached();
}
return s - dest;
static int on_spawn_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
Spawn *spawn = userdata;
- char timeout[FORMAT_TIMESPAN_MAX];
assert(spawn);
log_device_error(spawn->device, "Spawned process '%s' ["PID_FMT"] timed out after %s, killing",
spawn->cmd, spawn->pid,
- format_timespan(timeout, sizeof(timeout), spawn->timeout_usec, USEC_PER_SEC));
+ FORMAT_TIMESPAN(spawn->timeout_usec, USEC_PER_SEC));
return 1;
}
static int on_spawn_timeout_warning(sd_event_source *s, uint64_t usec, void *userdata) {
Spawn *spawn = userdata;
- char timeout[FORMAT_TIMESPAN_MAX];
assert(spawn);
log_device_warning(spawn->device, "Spawned process '%s' ["PID_FMT"] is taking longer than %s to complete",
spawn->cmd, spawn->pid,
- format_timespan(timeout, sizeof(timeout), spawn->timeout_warn_usec, USEC_PER_SEC));
+ FORMAT_TIMESPAN(spawn->timeout_warn_usec, USEC_PER_SEC));
return 1;
}
log_device_debug_errno(event->dev, r, "Failed to run built-in command \"%s\", ignoring: %m", command);
} else {
if (event->exec_delay_usec > 0) {
- char buf[FORMAT_TIMESPAN_MAX];
-
log_device_debug(event->dev, "Delaying execution of \"%s\" for %s.",
- command, format_timespan(buf, sizeof(buf), event->exec_delay_usec, USEC_PER_SEC));
+ command, FORMAT_TIMESPAN(event->exec_delay_usec, USEC_PER_SEC));
(void) usleep(event->exec_delay_usec);
}
}
break;
default:
- assert_not_reached("Invalid match type");
+ assert_not_reached();
}
return token->op == (match ? OP_MATCH : OP_NOMATCH);
value = vbuf;
break;
default:
- assert_not_reached("Invalid attribute substitution type");
+ assert_not_reached();
}
/* remove trailing whitespace, if not asked to match for it */
else if (streq(k, "virt"))
val = virtualization_to_string(detect_virtualization());
else
- assert_not_reached("Invalid CONST key");
+ assert_not_reached();
return token_match_string(token, val);
}
case TK_M_TAG:
/* do nothing for events. */
break;
default:
- assert_not_reached("Invalid token type");
+ assert_not_reached();
}
return true;
case '?':
return -EINVAL;
default:
- assert_not_reached("Unknown option.");
+ assert_not_reached();
}
if (optind < argc)
case '?':
return -EINVAL;
default:
- assert_not_reached("Unknown option");
+ assert_not_reached();
}
return 1;
return print_record(device);
}
- assert_not_reached("unknown query type");
+ assert_not_reached();
return 0;
}
case '?':
return -EINVAL;
default:
- assert_not_reached("Unknown option");
+ assert_not_reached();
}
if (action == ACTION_DEVICE_ID_FILE) {
else if (action == ACTION_ATTRIBUTE_WALK)
r = print_device_chain(device);
else
- assert_not_reached("Unknown action");
+ assert_not_reached();
if (r < 0)
return r;
}
case '?':
return -EINVAL;
default:
- assert_not_reached("Unknown option.");
+ assert_not_reached();
}
if (!arg_print_kernel && !arg_print_udev) {
case '?':
return -EINVAL;
default:
- assert_not_reached("Unknown option.");
+ assert_not_reached();
}
}
case '?':
return -EINVAL;
default:
- assert_not_reached("Unknown option");
+ assert_not_reached();
}
arg_command = argv[optind++];
case '?':
return -EINVAL;
default:
- assert_not_reached("Unknown option");
+ assert_not_reached();
}
if (!argv[optind])
case '?':
return -EINVAL;
default:
- assert_not_reached("Unknown option");
+ assert_not_reached();
}
}
return log_error_errno(r, "Failed to scan devices: %m");
break;
default:
- assert_not_reached("Unknown device type");
+ assert_not_reached();
}
r = exec_list(e, action, settle_hashmap);
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
return 1; /* work to do */
case '?':
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
}
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
device = argv[optind];
break;
default:
- assert_not_reached("Unexpected output mode");
+ assert_not_reached();
}
return 0;
break;
default:
- assert_not_reached("Unexpected display mode");
+ assert_not_reached();
}
return 0;
break;
default:
- assert_not_reached("Unexpected output mode");
+ assert_not_reached();
}
return 0;
if (r < 0)
return log_error_errno(r, "Failed to enumerate groups of user: %m");
} else
- assert_not_reached("Unexpected verb");
+ assert_not_reached();
for (;;) {
_cleanup_free_ char *user = NULL, *group = NULL;
return -EINVAL;
default:
- assert_not_reached("Unhandled option");
+ assert_not_reached();
}
}
n = now(CLOCK_MONOTONIC);
if (n >= usec_add(start_time, RUNTIME_MAX_USEC)) {
- char buf[FORMAT_TIMESPAN_MAX];
log_debug("Exiting worker, ran for %s, that's enough.",
- format_timespan(buf, sizeof(buf), usec_sub_unsigned(n, start_time), 0));
+ FORMAT_TIMESPAN(usec_sub_unsigned(n, start_time), 0));
break;
}
if (last_busy_usec == USEC_INFINITY)
last_busy_usec = n;
else if (listen_idle_usec != USEC_INFINITY && n >= usec_add(last_busy_usec, listen_idle_usec)) {
- char buf[FORMAT_TIMESPAN_MAX];
log_debug("Exiting worker, been idle for %s.",
- format_timespan(buf, sizeof(buf), usec_sub_unsigned(n, last_busy_usec), 0));
+ FORMAT_TIMESPAN(usec_sub_unsigned(n, last_busy_usec), 0));
break;
}
printf("%s attach VOLUME DATADEVICE HASHDEVICE ROOTHASH [OPTIONS]\n"
"%s detach VOLUME\n\n"
- "Attaches or detaches an integrity protected block device.\n"
+ "Attach or detach an integrity protected block device.\n"
"\nSee the %s for details.\n",
program_invocation_short_name,
program_invocation_short_name,
_cleanup_(crypt_freep) struct crypt_device *cd = NULL;
int r;
- if (argc <= 1)
+ if (argc <= 1 ||
+ strv_contains(strv_skip(argv, 1), "--help") ||
+ strv_contains(strv_skip(argv, 1), "-h") ||
+ streq(argv[1], "help"))
return help();
if (argc < 3)
first_arg = true;
for (i = n = 0; exec_split[i]; i++) {
_cleanup_free_ char *c = NULL, *raw = NULL, *p = NULL, *escaped = NULL, *quoted = NULL;
+ ssize_t l;
- r = cunescape(exec_split[i], 0, &c);
- if (r < 0)
- return log_debug_errno(r, "Failed to unescape '%s': %m", exec_split[i]);
+ l = cunescape(exec_split[i], 0, &c);
+ if (l < 0)
+ return log_debug_errno(l, "Failed to unescape '%s': %m", exec_split[i]);
if (first_arg) {
_cleanup_free_ char *executable = NULL;
if (!escaped)
return log_oom();
- free(exec_split[n]);
- exec_split[n++] = TAKE_PTR(escaped);
+ free_and_replace(exec_split[n++], escaped);
continue;
}
if (!quoted)
return log_oom();
- free(exec_split[n]);
- exec_split[n++] = TAKE_PTR(quoted);
+ free_and_replace(exec_split[n++], quoted);
}
for (; exec_split[n]; n++)
exec_split[n] = mfree(exec_split[n]);
if install_sysconfdir
meson.add_install_script('sh', '-c',
- mkdir_p.format(join_paths(sysconfdir, 'sysctl.d')))
+ mkdir_p.format(sysconfdir / 'sysctl.d'))
endif
(
local workspace="${1:?}"
+ if selinuxenabled >/dev/null; then
+ dracut_install selinuxenabled
+ cp -ar /etc/selinux "$workspace/etc/selinux"
+ fi
+
"$TEST_BASE_DIR/create-busybox-container" "$workspace/testsuite-13.nc-container"
initdir="$workspace/testsuite-13.nc-container" dracut_install nc ip md5sum
)
# Using timeout because if the test fails it can loop.
# The reason is because the poweroff executed by end.service
# could turn into a reboot if the test fails.
-NSPAWN_TIMEOUT=20
+NSPAWN_TIMEOUT=60
# Remove this file if it exists. This is used along with
# the make target "finish". Since concrete confirmation is
endif
foreach p : out.stdout().split()
- source = join_paths(project_source_root, p)
+ source = project_source_root / p
name = 'dmidecode_' + p.split('/')[-1].split('.')[0]
test(name,
udev_dmi_memory_id_test,
- args : [dmi_memory_id_path, source, source + '.txt'])
+ args : [udev_prog_paths['dmi_memory_id'],
+ source,
+ source + '.txt'])
endforeach
endif
# To force creating a new image from scratch (eg: to encrypt it), also define
# TEST_FORCE_NEWIMAGE=1 in the test setup script.
IMAGE_NAME=${IMAGE_NAME:-default}
+STRIP_BINARIES="${STRIP_BINARIES:-yes}"
TEST_REQUIRE_INSTALL_TESTS="${TEST_REQUIRE_INSTALL_TESTS:-1}"
TEST_PARALLELIZE="${TEST_PARALLELIZE:-0}"
LOOPDEV=
# Borrowed from https://github.com/google/oss-fuzz/blob/cd9acd02f9d3f6e80011cc1e9549be526ce5f270/infra/base-images/base-runner/bad_build_check#L182
local _asan_calls
- _asan_calls="$(objdump -dC "$SYSTEMD_JOURNALD" | grep -E "callq?\s+[0-9a-f]+\s+<__asan" -c)"
+ _asan_calls="$(objdump -dC "$SYSTEMD_JOURNALD" | grep -E "(callq?|brasl?)\s+[^ <]+\s+<__asan" -c)"
if ((_asan_calls < 1000)); then
return 1
else
"loglevel=2"
"init=$PATH_TO_INIT"
"console=$CONSOLE"
- "selinux=0"
"SYSTEMD_UNIT_PATH=/usr/lib/systemd/tests/testdata/testsuite-$1.units:/usr/lib/systemd/tests/testdata/units:"
"systemd.unit=testsuite.target"
"systemd.wants=testsuite-$1.service"
--- /dev/null
+[Network]
+ManageForeignRoutes=no
network_unit_file_path='/run/systemd/network'
networkd_runtime_directory='/run/systemd/netif'
+networkd_conf_dropin_path='/run/systemd/networkd.conf.d'
networkd_ci_path='/run/networkd-ci'
network_sysctl_ipv6_path='/proc/sys/net/ipv6/conf'
network_sysctl_ipv4_path='/proc/sys/net/ipv4/conf'
global running_units
os.makedirs(network_unit_file_path, exist_ok=True)
+ os.makedirs(networkd_conf_dropin_path, exist_ok=True)
os.makedirs(networkd_ci_path, exist_ok=True)
shutil.rmtree(networkd_ci_path)
if (os.path.exists(os.path.join(network_unit_file_path, unit + '.d'))):
shutil.rmtree(os.path.join(network_unit_file_path, unit + '.d'))
+def copy_networkd_conf_dropin(*dropins):
+ """Copy networkd.conf dropin files into the testbed."""
+ for dropin in dropins:
+ shutil.copy(os.path.join(networkd_ci_path, dropin), networkd_conf_dropin_path)
+
+def remove_networkd_conf_dropin(dropins):
+ """Remove previously copied networkd.conf dropin files from the testbed."""
+ for dropin in dropins:
+ if (os.path.exists(os.path.join(networkd_conf_dropin_path, dropin))):
+ os.remove(os.path.join(networkd_conf_dropin_path, dropin))
+
def start_dnsmasq(additional_options='', ipv4_range='192.168.5.10,192.168.5.200', ipv6_range='2600::10,2600::20', lease_time='1h'):
dnsmasq_command = f'dnsmasq -8 /var/run/networkd-ci/test-dnsmasq-log-file --log-queries=extra --log-dhcp --pid-file=/var/run/networkd-ci/test-test-dnsmasq.pid --conf-file=/dev/null --interface=veth-peer --enable-ra --dhcp-range={ipv6_range},{lease_time} --dhcp-range={ipv4_range},{lease_time} -R --dhcp-leasefile=/var/run/networkd-ci/lease --dhcp-option=26,1492 --dhcp-option=option:router,192.168.5.1 --port=0 ' + additional_options
check_output(dnsmasq_command)
'routing-policy-rule-reconfigure2.network',
]
+ networkd_conf_dropins = [
+ 'networkd-manage-foreign-routes-no.conf',
+ ]
+
routing_policy_rule_tables = ['7', '8', '9', '10', '1011']
routes = [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
remove_routes(self.routes)
remove_links(self.links)
remove_unit_from_networkd_path(self.units)
+ remove_networkd_conf_dropin(self.networkd_conf_dropins)
stop_networkd(show_logs=True)
call('ip netns del ns99', stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
self.assertRegex(output, 'lookup 7')
self.assertRegex(output, 'uidrange 100-200')
- def test_route_static(self):
+ def _test_route_static(self, manage_foreign_routes):
+ if not manage_foreign_routes:
+ copy_networkd_conf_dropin('networkd-manage-foreign-routes-no.conf')
+
copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
start_networkd()
self.wait_online(['dummy98:routable'])
print(output)
self.assertEqual(output, '')
+ self.tearDown()
+
+ def test_route_static(self):
+ for manage_foreign_routes in [True, False]:
+ with self.subTest(manage_foreign_routes=manage_foreign_routes):
+ self._test_route_static(manage_foreign_routes)
+
@expectedFailureIfRTA_VIAIsNotSupported()
def test_route_via_ipv6(self):
copy_unit_to_networkd_unit_path('25-route-via-ipv6.network', '12-dummy.netdev')
# Check UseGateway=
if use_gateway and (not classless or not use_routes):
self.assertRegex(output, r'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
- self.assertRegex(output, r'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
else:
self.assertNotRegex(output, r'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
+
+ # Check route to gateway
+ if (use_gateway or dns_and_ntp_routes) and (not classless or not use_routes):
+ self.assertRegex(output, r'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
+ else:
self.assertNotRegex(output, r'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
# Check RoutesToDNS= and RoutesToNTP=
if classless and use_routes:
self.assertRegex(output, r'8.8.8.8 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024')
self.assertRegex(output, r'9.9.9.9 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024')
- elif use_gateway:
+ else:
self.assertRegex(output, r'8.8.8.8 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
self.assertRegex(output, r'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
- else:
- self.assertNotRegex(output, r'8.8.8.8 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024')
- self.assertNotRegex(output, r'9.9.9.9 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024')
else:
self.assertNotRegex(output, r'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
self.assertNotRegex(output, r'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
start_dnsmasq()
self.wait_online(['veth99:routable', 'veth-peer:routable'])
- output = check_output('ip route list dev veth99 10.0.0.0/8')
+ output = check_output('ip route list dev veth99')
+ print(output)
+ self.assertRegex(output, 'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]*')
+ self.assertIn('10.0.0.0/8 via 192.168.5.1 proto dhcp', output)
+
+ with open(os.path.join(network_unit_file_path, 'dhcp-client-gateway-ipv4.network'), mode='a') as f:
+ f.write('[DHCPv4]\nUseGateway=no\n')
+
+ rc = call(*networkctl_cmd, 'reload', env=env)
+ self.assertEqual(rc, 0)
+
+ time.sleep(2)
+ self.wait_online(['veth99:routable', 'veth-peer:routable'])
+
+ output = check_output('ip route list dev veth99')
print(output)
- self.assertRegex(output, '10.0.0.0/8 via 192.168.5.1 proto dhcp')
+ self.assertNotRegex(output, 'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]*')
+ self.assertIn('10.0.0.0/8 via 192.168.5.1 proto dhcp', output)
def test_dhcp_client_gateway_ipv6(self):
copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
return "$(systemctl show -P ExecMainStatus nspawn_machinectl_bind.service)"
}
+function check_selinux {
+ if ! selinuxenabled; then
+ echo >&2 "SELinux is not enabled, skipping SELinux-related tests"
+ return 0
+ fi
+
+ # Basic test coverage to avoid issues like https://github.com/systemd/systemd/issues/19976
+ systemd-nspawn "${SUSE_OPTS[@]}" --register=no -b -D /testsuite-13.nc-container --selinux-apifs-context=system_u:object_r:container_file_t:s0:c0,c1 --selinux-context=system_u:system_r:container_t:s0:c0,c1
+}
+
function run {
if [[ "$1" = "yes" && "$is_v2_supported" = "no" ]]; then
printf "Unified cgroup hierarchy is not supported. Skipping.\n" >&2
check_machinectl_bind
+check_selinux
+
touch /testok
startStrace() {
coproc strace -qq -p 1 -o "$straceLog" -e set_mempolicy -s 1024 ${1:+"$1"}
- # Wait for strace to properly "initialize"
- sleep $sleepAfterStart
+ # Wait for strace to properly "initialize", i.e. until PID 1 has the TracerPid
+ # field set to the current strace's PID
+ while ! awk -v spid="$COPROC_PID" '/^TracerPid:/ {exit !($2 == spid);}' /proc/1/status; do sleep 0.1; done
}
stopStrace() {
rm -rf /etc/systemd/system/testsuite-55-testbloat.service.d
-echo "DefaultMemoryPressureDurationSec=5s" >>/etc/systemd/oomd.conf
+echo "DefaultMemoryPressureDurationSec=2s" >>/etc/systemd/oomd.conf
+
+mkdir -p /etc/systemd/system/systemd-oomd.service.d/
+echo -e "[Service]\nEnvironment=SYSTEMD_LOG_LEVEL=debug" >/etc/systemd/system/systemd-oomd.service.d/debug.conf
+
+systemctl daemon-reload
+
+# if oomd is already running for some reasons, then restart it to make sure the above settings to be applied
+if systemctl is-active systemd-oomd.service; then
+ systemctl restart systemd-oomd.service
+fi
systemctl start testsuite-55-testchill.service
systemctl start testsuite-55-testbloat.service
# Verify systemd-oomd is monitoring the expected units
oomctl | grep "/testsuite-55-workload.slice"
oomctl | grep "1.00%"
-oomctl | grep "Default Memory Pressure Duration: 5s"
+oomctl | grep "Default Memory Pressure Duration: 2s"
+
+systemctl status testsuite-55-testchill.service
-# systemd-oomd watches for elevated pressure for 5 seconds before acting.
+# systemd-oomd watches for elevated pressure for 2 seconds before acting.
# It can take time to build up pressure so either wait 2 minutes or for the service to fail.
timeout="$(date -ud "2 minutes" +%s)"
while [[ $(date -u +%s) -le $timeout ]]; do
if ! systemctl status testsuite-55-testbloat.service; then
break
fi
- sleep 5
+ sleep 2
done
# testbloat should be killed and testchill should be fine
# figure out if we have entered the rate limit state
+entered_rl=0
exited_rl=0
timeout="$(date -ud "2 minutes" +%s)"
while [[ $(date -u +%s) -le ${timeout} ]]; do
d /run/lock 0755 root root -
L /var/lock - - - - ../run/lock
+{% if CREATE_LOG_DIRS %}
+L /var/log/README - - - - ../..{{DOC_DIR}}/README.logs
+{% endif %}
# /run/lock/subsys is used for serializing SysV service execution, and
# hence without use on SysV-less systems.
['systemd-pstore.conf', 'ENABLE_PSTORE'],
['tmp.conf', ''],
['x11.conf', ''],
- ['legacy.conf', 'HAVE_SYSV_COMPAT'],
]
foreach pair : files
endif
endforeach
-in_files = ['etc.conf',
- 'static-nodes-permissions.conf',
- 'systemd.conf',
- 'var.conf']
+in_files = [['etc.conf', ''],
+ ['legacy.conf', 'HAVE_SYSV_COMPAT'],
+ ['static-nodes-permissions.conf', ''],
+ ['systemd.conf', ''],
+ ['var.conf', ''],
+ ]
-foreach file : in_files
- custom_target(
- # XXX: workaround for old meson. Drop when upgrading.
- 'tmpfiles+' + file,
- input : file + '.in',
- output: file,
- command : [meson_render_jinja2, config_h, '@INPUT@'],
- capture : true,
- install : enable_tmpfiles,
- install_dir : tmpfilesdir)
+foreach pair : in_files
+ if not enable_tmpfiles
+ # do nothing
+ elif pair[1] == '' or conf.get(pair[1]) == 1
+ custom_target(
+ pair[0],
+ input : pair[0] + '.in',
+ output: pair[0],
+ command : [meson_render_jinja2, config_h, '@INPUT@'],
+ capture : true,
+ install : enable_tmpfiles,
+ install_dir : tmpfilesdir)
+ else
+ message('Not installing tmpfiles.d/@0@ because @1@ is @2@'
+ .format(pair[0], pair[1], conf.get(pair[1], 0)))
+ endif
endforeach
if enable_tmpfiles and install_sysconfdir
meson.add_install_script(
- 'sh', '-c',
- mkdir_p.format(join_paths(sysconfdir, 'tmpfiles.d')))
+ 'sh', '-c', mkdir_p.format(sysconfdir / 'tmpfiles.d'))
endif
tag="$(git describe --abbrev=0 --match 'v[0-9][0-9][0-9]')"
git log --pretty=tformat:%aN --author=noreply@weblate.org --invert-grep -s "${tag}.." | \
- sed 's/ / /g; s/--/-/g; s/.*/ \0,/' |
- sort -u
+ sed 's/ / /g; s/--/-/g; s/.*/\0,/' |
+ sort -u | tr '\n' ' ' | sed -e "s/^/Contributions from: /g" -e "s/,\s*$/\n/g" | fold -w 72 -s | \
+ sed -e "s/^/ /g" -e "s/\s*$//g"
if install_sysconfdir
meson.add_install_script(meson_make_symlink,
- join_paths(pkgsysconfdir, 'user'),
- join_paths(sysconfdir, 'xdg/systemd/user'))
+ pkgsysconfdir / 'user',
+ sysconfdir / 'xdg/systemd/user')
endif
meson.add_install_script(meson_make_symlink,
- join_paths(dbussystemservicedir, 'org.freedesktop.systemd1.service'),
- join_paths(dbussessionservicedir, 'org.freedesktop.systemd1.service'))
+ dbussystemservicedir / 'org.freedesktop.systemd1.service',
+ dbussessionservicedir / 'org.freedesktop.systemd1.service')
if conf.get('HAVE_SYSV_COMPAT') == 1
foreach i : [1, 2, 3, 4, 5]
meson.add_install_script(
'sh', '-c',
- mkdir_p.format(join_paths(systemunitdir, 'runlevel@0@.target.wants'.format(i))))
+ mkdir_p.format(systemunitdir / 'runlevel@0@.target.wants'.format(i)))
endforeach
endif
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-or-later
+#
+# 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=Automatic Boot Loader Update
+Documentation=man:bootctl(1)
+DefaultDependencies=no
+Conflicts=shutdown.target
+After=local-fs.target
+Before=sysinit.target shutdown.target systemd-update-done.service
+
+[Service]
+Type=oneshot
+RemainAfterExit=yes
+ExecStart=bootctl --no-variables --graceful update
+
+[Install]
+WantedBy=sysinit.target
DeviceAllow=/dev/loop-control rw
DeviceAllow=/dev/mapper/control rw
DeviceAllow=block-* rw
+DeviceAllow=char-hidraw rw
ExecStart={{ROOTLIBEXECDIR}}/systemd-homed
IPAddressDeny=any
KillMode=mixed