steps:
- name: Repository checkout
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633
- # FIXME: drop once https://github.com/actions/runner-images/issues/9491 is resolved
- - name: Reduce ASLR entropy
- run: sudo sysctl -w vm.mmap_rnd_bits=28
- name: Build check
run: .github/workflows/build_test.sh
types:
- completed
-env:
- PULL_REQUEST_METADATA_DIR: pull_request
- PULL_REQUEST_METADATA_FILE: metadata
-
permissions:
contents: read
pull-requests: write
steps:
- - name: Download Pull Request Metadata artifact
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea
- with:
- script: |
- const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
- owner: context.repo.owner,
- repo: context.repo.repo,
- run_id: ${{ github.event.workflow_run.id }},
- });
-
- const matchArtifact = artifacts.data.artifacts.filter((artifact) => {
- return artifact.name == "${{ env.PULL_REQUEST_METADATA_FILE }}"
- })[0];
-
- const download = await github.rest.actions.downloadArtifact({
- owner: context.repo.owner,
- repo: context.repo.repo,
- artifact_id: matchArtifact.id,
- archive_format: 'zip',
- });
-
- const fs = require('fs');
- fs.writeFileSync('${{ github.workspace }}/${{ env.PULL_REQUEST_METADATA_FILE }}.zip', Buffer.from(download.data));
-
- - run: unzip ${{ env.PULL_REQUEST_METADATA_FILE }}.zip
-
- - name: 'Get Pull Request number'
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea
+ - id: artifact
+ name: Download Pull Request Metadata artifact
+ uses: redhat-plumbers-in-action/download-artifact@463ae626ac2dd333491c7beccaa24c12c5c259b8
with:
- github-token: ${{ secrets.GITHUB_TOKEN }}
- script: |
- const fs = require('fs');
- const pr_number = Number(fs.readFileSync('./${{ env.PULL_REQUEST_METADATA_FILE }}'));
- core.exportVariable('pr_number', pr_number);
+ name: Pull Request Metadata
- name: Repository checkout
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633
fetch-depth: 0
- name: Development Freezer
- uses: redhat-plumbers-in-action/devel-freezer@67aec4a153bd9fca5322e1c4dd4d7c419fb36362
+ uses: redhat-plumbers-in-action/devel-freezer@396c94ba8cb417474e6626c83a42addea210a403
with:
- pr-number: ${{ env.pr_number }}
+ pr-number: ${{ fromJSON(steps.artifact.outputs.pr-metadata-json).number }}
+ # delay start of validation to allow for some milestone/labels tweaking
+ delay: 20
token: ${{ secrets.GITHUB_TOKEN }}
pull_request:
branches: [ main ]
-env:
- PULL_REQUEST_METADATA_DIR: pull_request
- PULL_REQUEST_METADATA_FILE: metadata
-
permissions:
contents: read
steps:
- name: Repository checkout
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633
- with:
- fetch-depth: 0
- - name: Store PR number in file
- run: |
- mkdir -p ./${{ env.PULL_REQUEST_METADATA_DIR }}
- echo ${{ github.event.number }} >./${{ env.PULL_REQUEST_METADATA_DIR }}/${{ env.PULL_REQUEST_METADATA_FILE }}
+ - id: metadata
+ name: Gather Pull Request Metadata
+ uses: redhat-plumbers-in-action/gather-pull-request-metadata@69c703f376018c1a41c8ccce21dc2e16a79f3324
- name: Upload Pull Request Metadata artifact
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3
with:
- name: ${{ env.PULL_REQUEST_METADATA_FILE }}
- path: ${{ env.PULL_REQUEST_METADATA_DIR }}
+ name: Pull Request Metadata
+ path: ${{ steps.metadata.outputs.metadata-file }}
retention-days: 1
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633
- uses: systemd/mkosi@1445b389750af22756c0fde6facc1f2f343340b4
+ # Freeing up disk space with rm -rf can take multiple minutes. Since we don't need the extra free space
+ # immediately, we remove the files in the background. However, we first move them to a different location
+ # so that nothing tries to use anything in these directories anymore while we're busy deleting them.
- name: Free disk space
run: |
- sudo rm -rf /usr/local
- sudo rm -rf /opt/hostedtoolcache
+ sudo mv /usr/local /usr/local.trash
+ sudo mv /opt/hostedtoolcache /opt/hostedtoolcache.trash
+ sudo systemd-run rm -rf /usr/local.trash /opt/hostedtoolcache.trash
- name: Configure
run: |
steps:
- name: Repository checkout
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633
- # FIXME: drop once https://github.com/actions/runner-images/issues/9491 is resolved
- - name: Reduce ASLR entropy
- run: sudo sysctl -w vm.mmap_rnd_bits=28
- name: Install build dependencies
run: |
# Drop XDG_* stuff from /etc/environment, so we don't get the user
branch = rawhide
[submodule "pkg/opensuse"]
path = pkg/opensuse
- url = https://code.opensuse.org/package/systemd
- branch = master
+ url = https://src.opensuse.org/rpm/systemd
+ branch = factory
[submodule "pkg/debian"]
path = pkg/debian
- url = https://salsa.debian.org/systemd-team/systemd
+ url = https://salsa.debian.org/systemd-team/systemd.git
branch = debian/master
[submodule "pkg/centos"]
path = pkg/centos
branch = c9s-sig-hyperscale
[submodule "pkg/arch"]
path = pkg/arch
- url = https://gitlab.archlinux.org/daandemeyer/systemd
- branch = strip
+ url = https://gitlab.archlinux.org/archlinux/packaging/packages/systemd
+ branch = main
dropped in a future release.
* Support for cgroup v1 ('legacy' and 'hybrid' hierarchies) is now
- considered obsolete and systemd by default will refuse to boot under it.
- To forcibly reenable cgroup v1 support, SYSTEMD_CGROUP_ENABLE_LEGACY_FORCE=1
- must be set on kernel command line. The meson option 'default-hierarchy='
- is also deprecated, i.e. only cgroup v2 ('unified' hierarchy) can be
- selected as build-time default.
-
- * Previously, systemd-networkd did not explicitly remove any bridge VLAN
- IDs assigned on bridge master and ports. Since v256, if a .network
- file for an interface has at least one valid settings in [BridgeVLAN]
- section, then all assigned VLAN IDs on the interface that are not
- configured in the .network file are removed.
+ considered obsolete and systemd by default will refuse to boot under
+ it. To forcibly reenable cgroup v1 support,
+ SYSTEMD_CGROUP_ENABLE_LEGACY_FORCE=1 must be set on kernel command
+ line. The meson option 'default-hierarchy=' is also deprecated, i.e.
+ only cgroup v2 ('unified' hierarchy) can be selected as build-time
+ default.
+
+ * Previously, systemd-networkd did not explicitly remove any bridge
+ VLAN IDs assigned on bridge master and ports. Since version 256, if a
+ .network file for an interface has at least one valid setting in the
+ [BridgeVLAN] section, then all assigned VLAN IDs on the interface
+ that are not configured in the .network file are removed.
* systemd-gpt-auto-generator will stop generating units for ESP or
XBOOTLDR partitions if it finds mount entries in the /boot/ or /efi/
hierarchies in fstab. This is to prevent the generator from
interfering with systems where ESP is explicitly configured to be
mounted at some path, for example /boot/efi/ (this type of setup is
- obsolete but is still commonly found).
+ obsolete but still commonly found).
* The behavior of systemd-sleep and systemd-homed has been updated to
freeze user sessions when entering the various sleep modes or when
and related services, and SYSTEMD_HOME_LOCK_FREEZE_SESSION=false for
systemd-homed.service.
+ * systemd-tmpfiles and systemd-sysusers, when given a relative path
+ (with at least one directory separator '/'), will open the file
+ directly, instead of searching for the given partial path in the
+ standard locations. The old mode wasn't useful because tmpfiles.d and
+ sysusers.d configuration has a flat structure with no subdirectories
+ under the standard locations and this change makes it easier to work
+ with local files with those tools.
+
+ * systemd-tmpfiles now properly applies nested configuration to 'R' and
+ 'D' stanzas. For example, with 'R /foo; x /foo/bar', /foo/bar will
+ now be excluded from removal.
+
+ General Changes and New Features:
+
+ * Various programs will load the main configuration from under
+ /usr/lib/, /usr/local/lib/, and /run/, not just from under /etc/. For
+ example, systemd-logind will look for /etc/systemd/logind.conf,
+ /run/systemd/logind.conf, /usr/local/lib/systemd/logind.conf, and
+ /usr/lib/systemd/logind.conf, and use the first file that is found.
+ This means that the location logic for the main config file and for
+ drop-ins is now the same.
+
+ ukify will look for the config files in /usr/lib/kernel/ and the
+ other locations, and now also supports drop-ins.
+
+ systemd-udevd now supports drop-ins for udev.conf.
+
+ * A new 'systemd-vpick' binary has been added. It implements the new
+ vpick protocol, where a .v directory may contain multiple files with
+ a version, following the UAPI version format specification, embedded
+ in the file name. The files are ordered by version and the newest one
+ is selected.
+
+ systemd-nspawn, systemd-dissect, and the RootDirectory=, RootImage=,
+ ExtensionImages=, and ExtensionDirectories= settings for units now
+ support the vpick protocol and allow the latest version to be
+ selected automatically if a "*.v/" directory is specified as the
+ source.
+
+ * Credentials can now be made accessible to and used by unprivileged
+ users. 'systemd-creds --user --uid=<user>' will encrypt or decrypt a
+ credential for a specific user.
+
+ * With systemd-homed, it is now possible to log in and activate an
+ encrypted home area over SSH.
+
+ homectl is now installed as a multi-call binary. When invoked as
+ systemd-home-fallback-shell it can be used as a temporary shell which
+ allows the home area to interactively unlocked. When the home area
+ becomes available, the temporary shell executes the normal one.
+
+ systemd-homed gained new methods
+ org.freedesktop.home1.Manager.RefHomeUnrestricted,
+ org.freedesktop.home1.Home.RefUnrestricted,
+ org.freedesktop.home1.Manager.ActivateHomeIfReferenced, and
+ org.freedesktop.home1.Home.ActivateIfReferenced to allow logging in
+ without activating the home area and then activating the home area
+ later.
+
+ * JSON User Records have been extended with a separate storage area
+ called "User Record Blob Directories". This is intended to store the
+ user's background image, avatar picture, and other similar items
+ which are too large to fit into the User Record itself.
+
+ systemd-homed, userdbctl, and homectl gained support for blob
+ directories.
+
+ * New command-line tool 'importctl' to download, import, and export
+ disk images via systemd-importd is added with the following verbs:
+ pull-tar, pull-raw, import-tar, import-raw, import-fs, export-tar,
+ export-raw, list-transfers, cancel-transfer.
+
+ Service Manager:
+
+ * New manager setting ProtectSystem= has been added. It is analogous to
+ the unit setting, but applies to the whole system. It is enabled by
+ default in the initrd.
+
+ * New unit setting WantsMountsFor= has been added. It is analogous to
+ RequiresMountsFor=, but with a Wants= dependency instead of
+ Requires=. This new logic is used in various places where mounts were
+ added as dependencies for other settings (WorkingDirectory=-…,
+ PrivateTmp=yes, cryptsetup lines with 'nofail').
+
+ * New unit setting MemoryZSwapWriteback= can be used to control the new
+ memory.zswap.writeback cgroup knob added in kernel 6.8.
+
+ * The manager gained a org.freedesktop.systemd1.StartAuxiliaryScope()
+ method to devolve some processes from a service into a new scope.
+ This new scope will remain even if the original service unit is
+ restarted. Cgroup properties of the new scope are copied from the
+ service, so various limits are retained.
+
+ * Units now expose properties EffectiveMemoryMax=,
+ EffectiveMemoryHigh=, and EffectiveTasksMax=, which report the
+ most stringent limit systemd is aware of for the given unit.
+
+ * A new specifier %D expands to $XDG_DATA_HOME.
+
+ * AllowedCPUs= now supports specifier expansion.
+
+ * What= setting in .mount and .swap units now accepts fstab-style
+ identifiers, for example UUID=… or LABEL=….
+
+ * RestrictNetworkInterfaces= now supports alternative network interface
+ names.
+
+ * PAMName= now implies SetLoginEnvironment=yes.
+
+ * homectl gained a new verb 'firstboot', and a new
+ systemd-homed-firstboot.service unit uses this verb to create users
+ in a first boot environment, either from credentials or by querying
+ interactively.
+
+ * systemd.firstboot=no can be used on the kernel command-line to
+ disable interactive queries, but allow other first boot configuration
+ to happen based on credentials.
+
+ * A new kernel command-line option systemd.default_debug_tty= can be
+ used to specify the TTY for the debug shell, independently of
+ enabling or disabling it.
+
+ * Systemd hostname can be configured via the systemd.hostname
+ credential.
+
+ The Journal:
+
+ * systemd-journald can now forward journal entries to a socket
+ (AF_INET, AF_INET6, AF_UNIX, or AF_VSOCK). The socket can be
+ specified in journald.conf via a new option ForwardAddress= or via
+ the 'journald.forward_address' credential.
+
+ * systemd-journal-remote now also accepts AF_VSOCK and AF_UNIX sockets
+ (so it can be used to receive entries forwarded by systemd-journald).
+
+ * systemd-vmspawn gained a new --forward-journal= option to forward the
+ virtual machine's journal entries to the host. This is done over a
+ AF_VSOCK socket, i.e. it does not require networking in the guest.
+
+ * journalctl gained option '-i' as a shortcut for --file=.
+
+ * journalctl gained a new -T/--exclude-identifier= option to filter
+ out certain syslog identifiers.
+
+ * journalctl gained a new --list-namespaces option.
+
+ * systemd-journal-gatewayd allows restricting the time range of
+ retrieved entries with realtime=[<since>]:[<until>].
+
+ Device Management:
+
+ * Udev now creates symlinks that combine by-path and by-{label,uuid}
+ information:
+ /dev/disk/by-path/<path>/by-<label|uuid|…>/<label|uuid|…>.
+ This allows distinguishing partitions with identical contents on
+ multiple storage devices. This is useful, for example, when copying
+ raw disk contents between devices.
+
+ * Udev now creates persistent /dev/media/by-path symlinks for media
+ controllers. For example, the uvcvideo driver may create /dev/media0
+ which will be linked as
+ /dev/media/by-path/pci-0000:04:00.3-usb-0:1:1.0-media-controller.
+
+ * An allowlist/denylist may be specified to filter which sysfs
+ attributes are used when crafting network interface names. Those
+ lists are stored as HWDB entries
+ ID_NET_NAME_ALLOW_<sysfsattr>=0|1
+ and
+ ID_NET_NAME_ALLOW=0|1.
+ The goal is to avoid unexpected changes to interface names when the
+ kernel is updated and new sysfs attributes become visible.
+
+ * A new unit tpm2.target has been added to provide a synchronization
+ point for units which expect the TPM hardware to be available.
+
+ * systemd-backlight now properly supports numbered devices which the
+ kernel creates to avoid collisions in the leds subsystem.
+
+ * systemd-hwdb update operation can be disabled with environment
+ variable SYSTEMD_HWDB_UPDATE_BYPASS=1.
+
+ * systemd-logind gained a new org.freedesktop.login1.Manager.Sleep()
+ method that automatically redirects to SuspendThenHibernate(),
+ Suspend(), HybridSleep(), or Hibernate(), depending on what is
+ supported and configured, a new configuration setting SleepOperation=,
+ and an accompanying helper method
+ org.freedesktop.login1.Manager.CanSleep() and property
+ org.freedesktop.login1.Manager.SleepOperation.
+
+ 'systemctl sleep' calls the new method to automatically put the
+ machine to sleep in the most appropriate way.
+
+ * systemd-hostnamed now exposes the machine ID and boot ID via D-Bus.
+
+ * systemd-hostnamed now provides a Varlink interface.
+
+ * systemd-hostnamed exports the data in os-release(5) and
+ machine-info(5) via D-Bus and Varlink.
+
Network Management:
+ * systemd-networkd now provides a Varlink interface.
+
* systemd-networkd's proxy support gained a new option to configure
a private VLAN variant of the proxy ARP supported by the kernel
under the name IPv4ProxyARPPrivateVLAN=.
- * TPM 1.2 PCR measurement support has been removed from
- systemd-stub. TPM 1.2 is obsolete and — due to the (by today's
- standards) weak cryptographic algorithms it only supports — does not
- actually provide the security benefits it's supposed to
- provide. Given that the rest of systemd's codebase never supported
- TPM 1.2 the support has now been removed from systemd-stub as well.
+ * systemd-networkd now exports the NamespaceId and NamespaceNSID
+ properties via D-Bus and Varlink.
+
+ * systemd-networkd now supports IPv6RetransmissionTimeSec= and
+ UseRetransmissionTime= settings in .network files to configure
+ retransmission time for IPv6 neighbor solicitation messages.
+
+ * networkctl gained new verbs 'mask' and 'unmask'.
+
+ * 'networkctl edit --runtime' allows editing volatile configuration
+ under /run/systemd/network/.
+
+ * The implementation behind TTLPropagate= network setting has been
+ removed and the setting is now ignored.
+
+ * systemd-network-generator will now pick up .netdev/.link/.network
+ configuration from credentials.
+
+ * systemd-networkd will now pick up wireguard configuration from
+ credentials.
+
+ * systemd-ssh-proxy is a new SSH client plugin that allows connecting
+ to AF_SOCK or AF_UNIX sockets.
+
+ * systemd-nspawn now provides a /run/systemd/nspawn/unix-export/
+ directory where the container payload can expose AF_UNIX sockets to
+ allow them them to be accessed from outside.
+
+ * systemd-nspawn will tint the background for container output.
+ This can be controller with the new --backgroup= option.
+
+ * systemd-nspawn gained support for the 'owneridmap' option for bind
+ mounts to map the target directory owner from inside the container to
+ the owner of the directory bound from the host filesystem.
+
+ * An sshd config drop-in to allow ssh keys acquired via userdbctl to be
+ used for authorization.
+
+ * New generator systemd-ssh-generator can be used to bind a
+ socket-activated SSH instance to a local AF_SOCK or AF_UNIX socket.
+ This generator will automatically bind /run/host/unix-export/ssh.
+
+ * systemd-resolved now implements RFC 8914 EDE error codes.
+
+ * systemd-resolved and resolvectl now support RFC 9460 SVCB and HTTPS
+ records.
+
+ * resolvectl gained a new option --relax-single-label= to allow
+ querying single-label hostnames via DNS.
+
+ Systemd-boot and systemd-stub and Related Tools:
+
+ * TPM 1.2 PCR measurement support has been removed from systemd-stub.
+ TPM 1.2 is obsolete and – due to the (by today's standards) weak
+ cryptographic algorithms it only supports – does not actually provide
+ the security benefits it's supposed to provide. Given that the rest
+ of systemd's codebase never supported TPM 1.2, the support has now
+ been removed from systemd-stub as well.
+
+ * Confexts are loaded by systemd-stub from the ESP as well.
+
+ * The pcrlock policy is saved in an unencrypted credential file
+ "pcrlock.<entry-token>.cred" under XBOOTLDR/ESP in the
+ /loader/credentials/ directory. It will be picked up at boot by
+ systemd-stub and passed to the initrd, where it can be used to unlock
+ the root file system.
+
+ * kernel-install gained support for --root= for the 'list' verb.
+
+ * systemd-pcrlock gained an --entry-token= option to configure the
+ entry-token.
+
+ * systemd-pcrlock now provides a Varlink interface and can be
+ run as a daemon via a template unit.
+
+ * bootctl now provides a Varlink interface and can be run as a daemon
+ via a template unit.
+
+ * ukify gained support for signing of PCR signatures via OpenSSL's
+ engines and providers.
+
+ * ukify now supports zboot kernels.
+
+ Command-line tools:
+
+ * systemd-run is now a multi-call binary. When invoked as 'run0', it
+ provides as interface similar to 'sudo', with all arguments starting
+ at the first non-option parameter being treated the command to
+ invoke as root. Unlike 'sudo' and similar tools, it does not make use
+ of setuid binaries or other privilege escalation methods, but instead
+ runs the specified command as a transient unit, which is started by
+ the system service manager, so privileges are dropped, rather than
+ gained, thus implementing a much more robust and safe security model.
+
+ * systemd-run gained a new option '--ignore-failure' to suppress
+ command failures.
+
+ * systemd-creds gained new options --user/--uid=.
+
+ * 'systemctl edit --stdin' allows creation of unit files and drop-ins
+ with contents supplied via standard input. This is useful when creating
+ configuration programmatically; the tool takes care of figuring out
+ the file name, creating any directories, and reloading the manager
+ afterwards.
+
+ * 'systemctl disable --now' and 'systemctl mask --now' now work
+ correctly with template units.
+
+ * 'systemd-analyze architectures' lists known CPU architectures.
+
+ * 'systemd-analyze --json=…' is supported for 'architectures',
+ 'capability', 'exit-status'.
+
+ * 'systemd-tmpfiles --purge' will purge (remove) all files and
+ directories created via tmpfiles.d configuration.
+
+ * systemd-id128 gained new options --no-pager, --no-legend, and
+ -j/--json=.
+
+ * hostnamectl gained '-j' as shortcut for '--json=pretty' or
+ '--json=short'.
+
+ * loginctl now supports -j/--json=.
+
+ * resolvectl now supports -j/--json= for --type=.
+
+ * systemd-vmspawn gained a new --firmware= option to configure or list
+ firmware definitions for Qemu, a new --tpm= option to enable or
+ disable the use of a software TPM, a new --linux= option to specify a
+ kernel binary for direct kernel boot, a new --initrd= option to
+ specify an initrd for direct kernel boot, a new -D/--directory option
+ to use a plain directory as the root file system, a new
+ --private-users option similar to the one in systemd-nspawn, new
+ options --bind= and --bind-ro= to bind part of the host's file system
+ hierarchy into the guest, a new --extra-drive= option to attach
+ additional storage, and -n/--network-tap/--network-user-mode to
+ configure networking.
+
+ * A new systemd-vmspawn@.service can be used to launch systemd-vmspawn
+ as a service.
+
+ * varlinkctl gained support for the "ssh:" transport. This requires
+ OpenSSH 9.4 or newer.
+
+ * varlinkctl gained a new --collect switch to collect all responses of
+ a method call emitted in JSON_SEQ mode and turn them into normal
+ JSON.
+
+ * systemd-sysext gained support for mutable system extensions, where a
+ writeable upperdir is stored under /var/lib/extensions.mutable/, and
+ a new --mutable option to configure this behaviour.
+
+ * systemd-dissect gained a new --make-archive-option to generate an
+ archive file from a disk image.
+
+ * systemd-repart gained new options --generate-fstab= and
+ --generate-crypttab= to write the fstab and crypttab files.
+
+ * systemd-repart gained a new option --private-key-source= to allow
+ using OpenSSL's "engines" or "providers" as the signing mechanism to
+ use when creating verity signature partitions.
+
+ * systemd-measure gained new options --certificate=, --private-key=,
+ and --private-key-source= to allow using OpenSSL's "engines" or
+ "providers" as the signing mechanism to use when creating signed
+ TPM2 PCR measurement values.
+
+ * systemd-tmpfiles gained a new option --dry-run to print what would be
+ done without actually taking action.
+
+ * systemd-bsod gained a new option --tty= to specify the output TTY
+
+ * timedatectl and machinectl gained option '-P', an alias for
+ '--value --property=…'.
+
+ * Various tools that pretty-print config files will now highlight
+ configuration directives.
+
+ Libraries:
+
+ * libsystemd gained new call sd_bus_creds_new_from_pidfd to get a
+ credentials object for a pidfd and sd_bus_creds_get_pidfd_dup() to
+ retrieve the pidfd from a credentials object.
+
+ * RPM macro %_kernel_install_dir has been added with the path
+ to the directory for kernel-install plugins.
+
+ Other:
+
+ * systemd-logind now supports a new "background-light" session class
+ which does not pull in the user@.service unit. This is intended in
+ particular for cron jobs.
+
+ systemd-logind now also supports a new "user-incomplete" session
+ class for a user session that does not have a running user manager,
+ but may be upgraded to a full "user" session later on. This has
+ been hooked into the PAM stack to appropriately classify sessions
+ while they are being started.
+
+ systemd-logind gained a new org.freedesktop.login1.Session.SetClass()
+ method to change the session class.
+
+ systemd-logind will not allow background, background-light, manager,
+ and manager-early session types to take control of devices or change
+ the session type.
+
+ * systemd-logind gained a new
+ org.freedesktop.login1.Manager.ListSessionsEx() method that provides
+ additional metadata compared to ListSessions(). loginctl makes use of
+ this to list additional fields in list-sessions.
+
+ * systemd-cryptenroll can now enroll directly with a PKCS11 public key
+ (instead of a certificate).
+
+ * Core dumps are now retained for two weeks by default.
+
+ * systemd-cryptsetup gained support for crypttab option
+ link-volume-key= to enter the volume key into the kernel keyring when
+ the volume is opened.
+
+ * portablectl --copy= parameter gained a new 'mixed' argument, that will
+ result in resources owned by the OS (e.g.: portable profiles) to be linked
+ but resources owned by the portable image (e.g.: the unit files and the
+ images themselves) to be copied.
+
+ * The remaining documentation that was on
+ https://freedesktop.org/wiki/Software/systemd/ has been moved to
+ https://systemd.io.
+
CHANGES WITH 255:
Features:
+* insert the new pidfs inode number as a third field into PidRef, so that
+ PidRef are reasonably serializable without having to pass around fds.
+
+* systemd-analyze smbios11 to dump smbios type 11 vendor strings
+
* move documentation about our common env vars (SYSTEMD_LOG_LEVEL,
SYSTEMD_PAGER, …) into a man page of its own, and just link it from our
various man pages that so far embed the whole list again and again, in an
speed than SHA256 on 64bit archs (since based on 64bit words unlike SHA256
which uses 32bit words).
-* send out sd_notify() from PID 1 when we determined hostname and machine ID
-
-* send out sd_notify() from PID 1 whenever we reach a target unit. Then
- introduce ssh.target or so. And in vmspawn/nspawn wait for that as indication
- whether/when SSH is available. Similar for D-Bus (but just use sockets.target for that)
+* In vmspawn/nspawn/machined wait for X_SYSTEMD_UNIT_ACTIVE=ssh-active.target
+ and X_SYSTEMD_SIGNAL_LEVEL=2 as indication whether/when SSH and the POSIX
+ signals are available. Similar for D-Bus (but just use sockets.target for
+ that). Report as property for the machine.
* teach nspawn/machined a new bus call/verb that gets you a
shell in containers that have no sensible pid1, via joining the container,
SOURCE_DATE_EPOCH (maybe even under that name?). Would then be used to
initialize the timestamp logic of ConditionNeedsUpdate=.
-* ptyfwd: look for window title ANSI sequences and insert colored dot in front
- of it while passing it through, to indicate whether we are in privileged, VM,
- container terminal sessions.
-
* nspawn/vmspawn/pid1: add ability to easily insert fully booted VMs/FOSC into
shell pipelines, i.e. add easy to use switch that turns off console status
output, and generates the right credentials for systemd-run-generator so that
* add a new ExecStart= flag that inserts the configured user's shell as first
word in the command line. (maybe use character '.'). Usecase: tool such as
- uid0 can use that to spawn the target user's default shell.
+ run0 can use that to spawn the target user's default shell.
* varlink: figure out how to do docs for our varlink interfaces. Idea: install
interface files augmented with docs in /usr/share/ somewhere. And have
systemd.import_encrypted_creds=foobar.waldo,tmpfiles.extra to protect locked
down kernels from credentials generated on the host with a weak kernel
+* Merge systemd-creds options --uid= (which accepts user names) and --user.
+
* Add support for extra verity configuration options to systemd-repart (FEC,
hash type, etc)
* systemd-analyze netif that explains predictable interface (or networkctl)
+* Figure out naming of verbs in systemd-analyze: we have (singular) capability,
+ exit-status, but (plural) filesystems, architectures.
+
* Add service setting to run a service within the specified VRF. i.e. do the
equivalent of "ip vrf exec".
# The Container Interface
Also consult [Writing Virtual Machine or Container
-Managers](https://www.freedesktop.org/wiki/Software/systemd/writing-vm-managers).
+Managers](https://systemd.io/WRITING_VM_AND_CONTAINER_MANAGERS).
systemd has a number of interfaces for interacting with container managers,
when systemd is used inside of an OS container. If you work on a container
variable's name you may only specify ptys, and not other types of ttys. Also
you need to specify the pty itself, a symlink will not suffice. This is
implemented in
- [systemd-getty-generator(8)](https://www.freedesktop.org/software/systemd/man/systemd-getty-generator.html).
+ [systemd-getty-generator(8)](https://www.freedesktop.org/software/systemd/man/latest/systemd-getty-generator.html).
Note that this variable should not include the pty that `/dev/console` maps
to if it maps to one (see below). Example: if the container receives
`container_ttys=pts/7 pts/8 pts/14` it will spawn three additional login
running the container manager, if this is considered desirable, please parse
the host's `/etc/os-release` and set a `$container_host_<key>=<VALUE>`
environment variable for the ID fields described by the [os-release
- interface](https://www.freedesktop.org/software/systemd/man/os-release.html), eg:
+ interface](https://www.freedesktop.org/software/systemd/man/latest/os-release.html), eg:
`$container_host_id=debian`
`$container_host_build_id=2020-06-15`
`$container_host_variant_id=server`
issuing `journalctl -m`. The container machine ID can be determined from
`/etc/machine-id` in the container.
-3. If the container manager wants to cleanly shutdown the container, it might
+3. If the container manager wants to cleanly shut down the container, it might
be a good idea to send `SIGRTMIN+3` to its init process. systemd will then
do a clean shutdown. Note however, that since only systemd understands
- `SIGRTMIN+3` like this, this might confuse other init systems.
+ `SIGRTMIN+3` like this, this might confuse other init systems. A container
+ manager may implement the `$NOTIFY_SOCKET` protocol mentioned below in which
+ case it will receive a notification message `X_SYSTEMD_SIGNALS_LEVEL=2` that
+ indicates if and when these additional signal handlers are installed. If
+ these signals are sent to the container's PID 1 before this notification
+ message is sent they might not be handled correctly yet.
4. To support [Socket Activated
Containers](https://0pointer.de/blog/projects/socket-activated-containers.html)
unit they created for their container. That's private property of systemd,
and no other code should modify it.
-6. systemd running inside the container can report when boot-up is complete
- using the usual `sd_notify()` protocol that is also used when a service
- wants to tell the service manager about readiness. A container manager can
- set the `$NOTIFY_SOCKET` environment variable to a suitable socket path to
- make use of this functionality. (Also see information about
- `/run/host/notify` below.)
+6. systemd running inside the container can report when boot-up is complete,
+ boot progress and functionality as well as various other bits of system
+ information using the `sd_notify()` protocol that is also used when a
+ service wants to tell the service manager about readiness. A container
+ manager can set the `$NOTIFY_SOCKET` environment variable to a suitable
+ socket path to make use of this functionality. (Also see information about
+ `/run/host/notify` below, as well as the Readiness Protocol section on
+ [systemd(1)](https://www.freedesktop.org/software/systemd/man/latest/systemd.html)
## Networking
to receive a notification via VSOCK when a virtual machine has finished booting.
Note that in case the hypervisor does not support `SOCK_DGRAM` over `AF_VSOCK`,
`SOCK_SEQPACKET` will be tried instead. The credential payload should be in the
- form: `vsock:<CID>:<PORT>`. Also note that this requires support for VHOST to be
+ form: `vsock:<CID>:<PORT>`. `vsock` may be replaced with `vsock-stream`, `vsock-dgram` or `vsock-seqpacket`
+ to force usage of the corresponding socket type. Also note that this requires support for VHOST to be
built-in both the guest and the host kernels, and the kernel modules to be loaded.
* [`systemd-sysusers(8)`](https://www.freedesktop.org/software/systemd/man/systemd-sysusers.html)
**/etc/systemd/system/my-nginx.socket**
```
+[Unit]
+After=network.target
+Requires=network.target
+
[Socket]
ListenStream=80
ListenStream=0.0.0.0:80
BindIPv6Only=ipv6-only
-After=network.target
-Requires=network.target
[Install]
WantedBy=sockets.target
`systemd-gpt-auto-generator` to ensure the root partition is mounted writable
in accordance to the GPT partition flags.
-`systemd-firstboot` and `localectl`:
+`systemd-firstboot`, `localectl`, and `systemd-localed`:
* `$SYSTEMD_LIST_NON_UTF8_LOCALES=1` — if set, non-UTF-8 locales are listed among
the installed ones. By default non-UTF-8 locales are suppressed from the
selection, since we are living in the 21st century.
+* `$SYSTEMD_KEYMAP_DIRECTORIES=` — takes a colon (`:`) separated list of keymap
+ directories. The directories must be absolute and normalized. If unset, the
+ default keymap directories (/usr/share/keymaps/, /usr/share/kbd/keymaps/, and
+ /usr/lib/kbd/keymaps/) will be used.
+
`systemd-resolved`:
* `$SYSTEMD_RESOLVED_SYNTHESIZE_HOSTNAME` — if set to "0", `systemd-resolved`
`nftables`. Selects the firewall backend to use. If not specified tries to
use `nftables` and falls back to `iptables` if that's not available.
+`systemd-networkd`:
+
+* `$SYSTEMD_NETWORK_PERSISTENT_STORAGE_READY` – takes a boolean. If true,
+ systemd-networkd tries to open the persistent storage on start. To make this
+ work, ProtectSystem=strict in systemd-networkd.service needs to be downgraded
+ or disabled.
+
`systemd-storagetm`:
* `$SYSTEMD_NVME_MODEL`, `$SYSTEMD_NVME_FIRMWARE`, `$SYSTEMD_NVME_SERIAL`,
Please make sure to follow our [Coding Style](CODING_STYLE) when submitting
patches. Also have a look at our [Contribution Guidelines](CONTRIBUTING).
+To start, run the following commands in the systemd git repository to set up
+git correctly (running `meson` will run these commands for you automatically):
+
+```shell
+$ git config submodule.recurse true
+$ git config fetch.recurseSubmodules on-demand
+$ git config push.recurseSubmodules no
+```
+
When adding new functionality, tests should be added. For shared functionality
(in `src/basic/` and `src/shared/`) unit tests should be sufficient. The general
policy is to keep tests in matching files underneath `src/test/`,
--- /dev/null
+---
+title: VM Interface
+category: Interfaces
+layout: default
+SPDX-License-Identifier: LGPL-2.1-or-later
+---
+
+# The VM Interface
+
+Also consult [Writing Virtual Machine or Container
+Managers](https://systemd.io/WRITING_VM_AND_CONTAINER_MANAGERS).
+
+systemd has a number of interfaces for interacting with virtual machine
+managers, when systemd is used inside of a VM. If you work on a VM manager,
+please consider supporting the following interfaces.
+
+1. systemd supports passing immutable binary data blobs with limited size and
+ restricted access to services via the `ImportCredential=`, `LoadCredential=`
+ and `SetCredential=` settings. These credentials may be passed into a system
+ via SMBIOS Type 11 vendor strings, see
+ [systemd(1)](https://www.freedesktop.org/software/systemd/man/latest/systemd.html)
+ for details. This concept may be used to flexibly configure various facets
+ ot the guest system. See
+ [systemd.system-credentials(7)](https://www.freedesktop.org/software/systemd/man/latest/systemd.system-credentials.html)
+ for a list of system credentials implemented by various systemd components.
+
+2. Readiness, information about various system properties and functionality, as
+ well as progress of boot may be reported by systemd to a machine manager via
+ the `sd_notify()` protocol via `AF_VSOCK` sockets. The address of this
+ socket may be configured via the `vmm.notify_socket` system credential. See
+ [systemd(1)](https://www.freedesktop.org/software/systemd/man/latest/systemd.html).
+
+3. The
+ [systemd-ssh-generator(8)](https://www.freedesktop.org/software/systemd/man/latest/systemd-ssh-generator.html)
+ functionality will automatically bind SSH login functionality to `AF_VSOCK`
+ port 22, if the system runs in a VM.
+
+4. If not initialized yet the system's
+ [machine-id(5)](https://www.freedesktop.org/software/systemd/man/latest/machine-id.html)
+ is automatically set to the SMBIOS product UUID if available and invocation
+ in an VM environment is detected.
+
+5. The
+ [`systemd-boot(7)`](https://www.freedesktop.org/software/systemd/man/latest/systemd-boot.html)
+ and
+ [`systemd-stub(7)`](https://www.freedesktop.org/software/systemd/man/latest/systemd-stub.html)
+ components support two SMBIOS Type 11 vendor strings that may be used to
+ extend the kernel command line of booted Linux environments:
+ `io.systemd.stub.kernel-cmdline-extra=` and
+ `io.systemd.boot.kernel-cmdline-extra=`.
+
+Also see
+[smbios-type-11(7)](https://www.freedesktop.org/software/systemd/man/latest/smbios-type-11.html)
+for a list of supported SMBIOS Type 11 vendor strings.
SPDX-License-Identifier: LGPL-2.1-or-later
---
-
# Writing VM and Container Managers
_Or: How to hook up your favorite VM or container manager with systemd_
-Nomenclature: a _Virtual Machine_ shall refer to a system running on virtualized hardware consisting of a full OS with its own kernel. A _Container_ shall refer to a system running on the same shared kernel of the host, but running a mostly complete OS with its own init system. Both kinds of virtualized systems shall collectively be called "machines".
+Nomenclature: a _Virtual Machine_ shall refer to a system running on
+virtualized hardware consisting of a full OS with its own kernel. A _Container_
+shall refer to a system running on the same shared kernel of the host, but
+running a mostly complete OS with its own init system. Both kinds of
+virtualized systems shall collectively be called "machines".
-systemd provides a number of integration points with virtual machine and container managers, such as libvirt, LXC or systemd-nspawn. On one hand there are integration points of the VM/container manager towards the host OS it is running on, and on the other there integration points for container managers towards the guest OS it is managing.
+systemd provides a number of integration points with virtual machine and
+container managers, such as libvirt, LXC or systemd-nspawn. On one hand there
+are integration points of the VM/container manager towards the host OS it is
+running on, and on the other there integration points for container managers
+towards the guest OS it is managing.
-Note that this document does not cover lightweight containers for the purpose of application sandboxes, i.e. containers that do _not_ run a init system of their own.
+Note that this document does not cover lightweight containers for the purpose
+of application sandboxes, i.e. containers that do _not_ run a init system of
+their own.
## Host OS Integration
-All virtual machines and containers should be registered with the [machined](http://www.freedesktop.org/wiki/Software/systemd/machined) mini service that is part of systemd. This provides integration into the core OS at various points. For example, tools like ps, cgls, gnome-system-manager use this registration information to show machine information for running processes, as each of the VM's/container's processes can reliably attributed to a registered machine. The various systemd tools (like systemctl, journalctl, loginctl, systemd-run, ...) all support a -M switch that operates on machines registered with machined. "machinectl" may be used to execute operations on any such machine. When a machine is registered via machined its processes will automatically be placed in a systemd scope unit (that is located in the machines.slice slice) and thus appear in "systemctl" and similar commands. The scope unit name is based on the machine meta information passed to machined at registration.
-
-For more details on the APIs provided by machine consult [the bus API interface documentation](http://www.freedesktop.org/wiki/Software/systemd/machined).
+All virtual machines and containers should be registered with the
+[systemd-machined(8)](https://www.freedesktop.org/software/systemd/man/latest/systemd-machined.service.html)
+mini service that is part of systemd. This provides integration into the core
+OS at various points. For example, tools like ps, cgls, gnome-system-manager
+use this registration information to show machine information for running
+processes, as each of the VM's/container's processes can reliably attributed to
+a registered machine. The various systemd tools (like systemctl, journalctl,
+loginctl, systemd-run, ...) all support a -M switch that operates on machines
+registered with machined. "machinectl" may be used to execute operations on any
+such machine. When a machine is registered via machined its processes will
+automatically be placed in a systemd scope unit (that is located in the
+machines.slice slice) and thus appear in "systemctl" and similar commands. The
+scope unit name is based on the machine meta information passed to machined at
+registration.
+
+For more details on the APIs provided by machine consult [the bus API interface
+documentation](https://www.freedesktop.org/software/systemd/man/latest/org.freedesktop.machine1.html).
## Guest OS Integration
-As container virtualization is much less comprehensive, and the guest is less isolated from the host, there are a number of interfaces defined how the container manager can set up the environment for systemd running inside a container. These Interfaces are documented in [Container Interface of systemd](http://www.freedesktop.org/wiki/Software/systemd/ContainerInterface).
-
-VM virtualization is more comprehensive and fewer integration APIs are available. In fact there's only one: a VM manager may initialize the SMBIOS DMI field "Product UUUID" to a UUID uniquely identifying this virtual machine instance. This is read in the guest via /sys/class/dmi/id/product_uuid, and used as configuration source for /etc/machine-id if in the guest, if that file is not initialized yet. Note that this is currently only supported for kvm hosts, but may be extended to other managers as well.
+A number of interfaces are defined that permit a machine or container manager
+to set provide integration points with the payload/guest system. These
+interfaces are documented in [Container Interface of
+systemd](https://systemd.io/CONTAINER_INTERFACE) and [VM Interface of
+systemd](https://systemd.io/VM_INTERFACE).
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
<footer class="site-footer">
- <p>© systemd, 2023</p>
+ <p>© systemd, 2024</p>
<p><a href="https://github.com/systemd/systemd/tree/main/docs">Website source</a></p>
</footer>
usb:v0011p7788*
ID_MODEL_FROM_DATABASE=counterfeit flash drive
+usb:v001F*
+ ID_VENDOR_FROM_DATABASE=Walmart
+
+usb:v001Fp0B21*
+ ID_MODEL_FROM_DATABASE=AB13X Headset Adapter
+
usb:v0040*
ID_VENDOR_FROM_DATABASE=Anyware Corporation
usb:v03F0p002A*
ID_MODEL_FROM_DATABASE=LaserJet P1102
+usb:v03F0p0036*
+ ID_MODEL_FROM_DATABASE=CCID Smartcard Keyboard KUS0133
+
usb:v03F0p0053*
ID_MODEL_FROM_DATABASE=DeskJet 2620 All-in-One Printer
ID_MODEL_FROM_DATABASE=AVC-1410 GameBridge TV NTSC
usb:v03F3p2000*
- ID_MODEL_FROM_DATABASE=USBXchange
+ ID_MODEL_FROM_DATABASE=USBXchange Firmware Loader
usb:v03F3p2001*
ID_MODEL_FROM_DATABASE=USBXchange Adapter
usb:v03F3p2002*
- ID_MODEL_FROM_DATABASE=USB2-Xchange
+ ID_MODEL_FROM_DATABASE=USB2-Xchange Firmware Loader
usb:v03F3p2003*
ID_MODEL_FROM_DATABASE=USB2-Xchange Adapter
usb:v0403p6F70*
ID_MODEL_FROM_DATABASE=HB-RF-USB
+usb:v0403p7150*
+ ID_MODEL_FROM_DATABASE=FT2232x wired for MPSSE+UART
+
+usb:v0403p7151*
+ ID_MODEL_FROM_DATABASE=FT2232x wired for MPSSE+UART
+
+usb:v0403p7152*
+ ID_MODEL_FROM_DATABASE=FreeCalypso dual UART with boot control
+
usb:v0403p7BE8*
ID_MODEL_FROM_DATABASE=FT232R
usb:v0424p4060*
ID_MODEL_FROM_DATABASE=Ultra Fast Media Reader
+usb:v0424p4063*
+ ID_MODEL_FROM_DATABASE=xD/SD/MS/MMC Reader
+
usb:v0424p4064*
ID_MODEL_FROM_DATABASE=Ultra Fast Media Reader
usb:v043Ep9804*
ID_MODEL_FROM_DATABASE=DMB Receiver Control
+usb:v043Ep9A10*
+ ID_MODEL_FROM_DATABASE=34UC88-B
+
+usb:v043Ep9A11*
+ ID_MODEL_FROM_DATABASE=34UC88-B
+
usb:v043Ep9A39*
ID_MODEL_FROM_DATABASE=27UP850 - WK.AEUDCSN - External Monitor 4K
usb:v045Ep02FD*
ID_MODEL_FROM_DATABASE=Xbox One S Controller [Bluetooth]
+usb:v045Ep02FE*
+ ID_MODEL_FROM_DATABASE=Xbox Wireless Adapter for Windows
+
+usb:v045Ep0306*
+ ID_MODEL_FROM_DATABASE=Surface Pro 7 SD Card Reader
+
usb:v045Ep0400*
ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2002
usb:v045Ep0823*
ID_MODEL_FROM_DATABASE=Classic IntelliMouse
+usb:v045Ep082A*
+ ID_MODEL_FROM_DATABASE=Pro Intellimouse
+
usb:v045Ep0900*
ID_MODEL_FROM_DATABASE=Surface Dock Hub
ID_MODEL_FROM_DATABASE=MK260 Wireless Combo Receiver
usb:v046DpC52F*
- ID_MODEL_FROM_DATABASE=Unifying Receiver
+ ID_MODEL_FROM_DATABASE=Nano Receiver
usb:v046DpC531*
ID_MODEL_FROM_DATABASE=C-U0007 [Unifying Receiver]
ID_MODEL_FROM_DATABASE=Unifying Receiver
usb:v046DpC534*
- ID_MODEL_FROM_DATABASE=Unifying Receiver
+ ID_MODEL_FROM_DATABASE=Nano Receiver
usb:v046DpC537*
ID_MODEL_FROM_DATABASE=Cordless Mouse Receiver
usb:v0483p5722*
ID_MODEL_FROM_DATABASE=Bulk Demo
+usb:v0483p572A*
+ ID_MODEL_FROM_DATABASE=STM32F401 microcontroller [ARM Cortex M4] [CDC/ACM serial port]
+
usb:v0483p5730*
ID_MODEL_FROM_DATABASE=Audio Speaker
ID_MODEL_FROM_DATABASE=MediaTek Bluetooth Adapter
usb:v0489pE0D8*
- ID_MODEL_FROM_DATABASE=Bluetooth Adapter
+ ID_MODEL_FROM_DATABASE=Bluetooth 5.2 Adapter [MediaTek MT7922]
usb:v048A*
ID_VENDOR_FROM_DATABASE=S-MOS Systems, Inc.
usb:v04BFp0A28*
ID_MODEL_FROM_DATABASE=INDI AV-IN Device
+usb:v04BFp1301*
+ ID_MODEL_FROM_DATABASE=Network Controller
+
+usb:v04BFp1302*
+ ID_MODEL_FROM_DATABASE=i3 Gateway
+
+usb:v04BFp1303*
+ ID_MODEL_FROM_DATABASE=3 Micro Module
+
+usb:v04BFp1304*
+ ID_MODEL_FROM_DATABASE=i3 Module
+
+usb:v04BFp1305*
+ ID_MODEL_FROM_DATABASE=i3 Multi Sensing Module
+
usb:v04C1*
ID_VENDOR_FROM_DATABASE=U.S. Robotics (3Com)
usb:v04CAp0020*
ID_MODEL_FROM_DATABASE=USB Keyboard
+usb:v04CAp003A*
+ ID_MODEL_FROM_DATABASE=Multimedia Keyboard
+
usb:v04CAp004B*
ID_MODEL_FROM_DATABASE=Keyboard
usb:v04D9p1603*
ID_MODEL_FROM_DATABASE=Keyboard
+usb:v04D9p1605*
+ ID_MODEL_FROM_DATABASE=Keyboard
+
usb:v04D9p1702*
ID_MODEL_FROM_DATABASE=Keyboard LKS02
usb:v04F2pB76B*
ID_MODEL_FROM_DATABASE=SunplusIT Inc [HP HD Camera]
+usb:v04F2pB7B4*
+ ID_MODEL_FROM_DATABASE=Integrated Camera (1920x1080)
+
usb:v04F3*
ID_VENDOR_FROM_DATABASE=Elan Microelectronics Corp.
usb:v04FEp0006*
ID_MODEL_FROM_DATABASE=Happy Hacking Keyboard Lite2
+usb:v04FEp0020*
+ ID_MODEL_FROM_DATABASE=HHKB-Classic
+
+usb:v04FEp0021*
+ ID_MODEL_FROM_DATABASE=Happy Hacking Keyboard Professional HYBRID Type-S
+
usb:v04FF*
ID_VENDOR_FROM_DATABASE=E-CMOS Corp.
usb:v050Dp0084*
ID_MODEL_FROM_DATABASE=F8T003v2 Bluetooth
+usb:v050Dp008A*
+ ID_MODEL_FROM_DATABASE=6-in-1 Multiport Adapter
+
usb:v050Dp0102*
ID_MODEL_FROM_DATABASE=Flip KVM
usb:v054Cp0689*
ID_MODEL_FROM_DATABASE=Walkman NWZ-B173F
+usb:v054Cp068C*
+ ID_MODEL_FROM_DATABASE=UP-D711
+
usb:v054Cp06BB*
ID_MODEL_FROM_DATABASE=WALKMAN NWZ-F805
usb:v056Ap03B3*
ID_MODEL_FROM_DATABASE=DTH167 [Cintiq Pro 16] touchscreen
+usb:v056Ap03C0*
+ ID_MODEL_FROM_DATABASE=DTH271 [Cintiq Pro 27] touchscreen
+
+usb:v056Ap03C4*
+ ID_MODEL_FROM_DATABASE=DTH172 [Cintiq Pro 17]
+
usb:v056Ap03C5*
ID_MODEL_FROM_DATABASE=CTL-4100WL [Intuos BT (S)]
usb:v056Ap03C7*
ID_MODEL_FROM_DATABASE=CTL-6100WL [Intuos BT (M)]
+usb:v056Ap03CB*
+ ID_MODEL_FROM_DATABASE=DTH134 [Wacom One 13] touchscreen
+
+usb:v056Ap03CE*
+ ID_MODEL_FROM_DATABASE=DTC121 [Wacom One 12] touchscreen
+
+usb:v056Ap03D0*
+ ID_MODEL_FROM_DATABASE=DTH227 [Cintiq Pro 22]
+
usb:v056Ap03DC*
ID_MODEL_FROM_DATABASE=PTH-460 [Intuos Pro (S)] tablet
usb:v056Ap03DD*
ID_MODEL_FROM_DATABASE=PTH-460 [Intuos Pro BT (S)] tablet
+usb:v056Ap03EC*
+ ID_MODEL_FROM_DATABASE=DTH134 [DTH134] touchscreen
+
+usb:v056Ap03ED*
+ ID_MODEL_FROM_DATABASE=DTC121 [DTC121] touchscreen
+
usb:v056Ap0400*
ID_MODEL_FROM_DATABASE=PenPartner 4x5
ID_MODEL_FROM_DATABASE=FlexScan EV3237
usb:v056Dp4001*
- ID_MODEL_FROM_DATABASE=Monitor
+ ID_MODEL_FROM_DATABASE=FlexScan EV2450
usb:v056Dp4002*
- ID_MODEL_FROM_DATABASE=USB HID Monitor
+ ID_MODEL_FROM_DATABASE=FlexScan EV2455
usb:v056Dp4014*
ID_MODEL_FROM_DATABASE=FlexScan EV2750
usb:v056Dp4027*
ID_MODEL_FROM_DATABASE=FlexScan EV2456
+usb:v056Dp402B*
+ ID_MODEL_FROM_DATABASE=FlexScan EV2780
+
usb:v056Dp4036*
ID_MODEL_FROM_DATABASE=FlexScan EV2785
usb:v056Dp405B*
ID_MODEL_FROM_DATABASE=FlexScan EV2460
+usb:v056Dp405E*
+ ID_MODEL_FROM_DATABASE=FlexScan EV2495
+
usb:v056Dp405F*
ID_MODEL_FROM_DATABASE=FlexScan EV2795
usb:v056Dp4065*
ID_MODEL_FROM_DATABASE=FlexScan EV3895
+usb:v056Dp406A*
+ ID_MODEL_FROM_DATABASE=FlexScan EV2480
+
usb:v056E*
ID_VENDOR_FROM_DATABASE=Elecom Co., Ltd
usb:v059Fp1095*
ID_MODEL_FROM_DATABASE=Rugged
+usb:v059Fp1105*
+ ID_MODEL_FROM_DATABASE=Mobile Drive (RLSD: 2022)
+
usb:v059FpA601*
ID_MODEL_FROM_DATABASE=HardDrive
usb:v05E6*
ID_VENDOR_FROM_DATABASE=Keithley Instruments
+usb:v05E6p3390*
+ ID_MODEL_FROM_DATABASE=3390 Arbitrary Waveform Generator
+
usb:v05E8*
ID_VENDOR_FROM_DATABASE=ICC, Inc.
usb:v0639*
ID_VENDOR_FROM_DATABASE=Chrontel, Inc.
+usb:v0639p7213*
+ ID_MODEL_FROM_DATABASE=CH7213
+
+usb:v0639p7231*
+ ID_MODEL_FROM_DATABASE=CH7213
+
usb:v063A*
ID_VENDOR_FROM_DATABASE=Techwin Corp.
usb:v06CBp00CB*
ID_MODEL_FROM_DATABASE=Fingerprint scanner
+usb:v06CBp00FC*
+ ID_MODEL_FROM_DATABASE=Prometheus Fingerprint Reader
+
usb:v06CBp0AC3*
ID_MODEL_FROM_DATABASE=Large Touch Screen
usb:v06D3p0394*
ID_MODEL_FROM_DATABASE=CP9000D/DW Port
+usb:v06D3p0395*
+ ID_MODEL_FROM_DATABASE=CP9000DW
+
usb:v06D3p0398*
ID_MODEL_FROM_DATABASE=P93D
+usb:v06D3p039E*
+ ID_MODEL_FROM_DATABASE=CP9500DW-S
+
usb:v06D3p03A1*
ID_MODEL_FROM_DATABASE=CP9550D/DW Port
usb:v06D3p3B10*
ID_MODEL_FROM_DATABASE=P95D
+usb:v06D3p3B20*
+ ID_MODEL_FROM_DATABASE=CP9820DW Series
+
usb:v06D3p3B21*
ID_MODEL_FROM_DATABASE=CP-9810D/DW
+usb:v06D3p3B2F*
+ ID_MODEL_FROM_DATABASE=LS9820A
+
usb:v06D3p3B30*
ID_MODEL_FROM_DATABASE=CP-D70DW / CP-D707DW
usb:v07CEpC010*
ID_MODEL_FROM_DATABASE=CPB-7000
+usb:v07CEpC011*
+ ID_MODEL_FROM_DATABASE=ASK-2500
+
usb:v07CF*
ID_VENDOR_FROM_DATABASE=Casio Computer Co., Ltd
ID_MODEL_FROM_DATABASE=MOTU Audio for 64 bit
usb:v07FDp0004*
- ID_MODEL_FROM_DATABASE=MicroBook
+ ID_MODEL_FROM_DATABASE=Microbook I/II/IIc
usb:v07FDp0008*
ID_MODEL_FROM_DATABASE=M Series
+usb:v07FDp0009*
+ ID_MODEL_FROM_DATABASE=M Series (firmware update mode)
+
+usb:v07FDp000B*
+ ID_MODEL_FROM_DATABASE=M Series
+
+usb:v07FDp000D*
+ ID_MODEL_FROM_DATABASE=M Series (firmware update mode)
+
usb:v07FF*
ID_VENDOR_FROM_DATABASE=Unknown
usb:v0828*
ID_VENDOR_FROM_DATABASE=Sato Corp.
+usb:v0828pA003*
+ ID_MODEL_FROM_DATABASE=WS408 Label Printer
+
usb:v0829*
ID_VENDOR_FROM_DATABASE=DirecTV Broadband, Inc. (Telocity)
usb:v0908p04B4*
ID_MODEL_FROM_DATABASE=SCR_CCID
+usb:v0908p04B5*
+ ID_MODEL_FROM_DATABASE=Camera
+
+usb:v0908p04B6*
+ ID_MODEL_FROM_DATABASE=Cockpit Touchkeypad
+
+usb:v0908p04B7*
+ ID_MODEL_FROM_DATABASE=Cockpit Touchkeypad Bootloader
+
+usb:v0908p04B8*
+ ID_MODEL_FROM_DATABASE=MediSET USB4-W
+
+usb:v0908p04B9*
+ ID_MODEL_FROM_DATABASE=MediSET USB4-R
+
+usb:v0908p04BA*
+ ID_MODEL_FROM_DATABASE=MediSET USB4-G
+
usb:v0908p2701*
ID_MODEL_FROM_DATABASE=ShenZhen SANZHAI Technology Co.,Ltd Spy Pen VGA
usb:v090Cp1132*
ID_MODEL_FROM_DATABASE=5-in-1 Card Reader
+usb:v090Cp2000*
+ ID_MODEL_FROM_DATABASE=Disk
+
usb:v090Cp337B*
ID_MODEL_FROM_DATABASE=Silicon Motion Camera
usb:v0920*
ID_VENDOR_FROM_DATABASE=Echelon Co.
+usb:v0920p5550*
+ ID_MODEL_FROM_DATABASE=U60 FT Network Interface
+
usb:v0920p7500*
ID_MODEL_FROM_DATABASE=Network Interface
usb:v0944p012F*
ID_MODEL_FROM_DATABASE=SQ-1
+usb:v0944p0203*
+ ID_MODEL_FROM_DATABASE=KRONOS
+
usb:v0944p0F03*
ID_MODEL_FROM_DATABASE=K-Series K61P MIDI studio controller
usb:v0955p7321*
ID_MODEL_FROM_DATABASE=Switch [Tegra Erista] recovery mode
+usb:v0955p7323*
+ ID_MODEL_FROM_DATABASE=T234 [Orin NX 16GB] recovery mode
+
+usb:v0955p7423*
+ ID_MODEL_FROM_DATABASE=T234 [Orin NX 8GB] recovery mode
+
usb:v0955p7721*
ID_MODEL_FROM_DATABASE=T210 [TX1 Tegra Erista] recovery mode
usb:v0957*
ID_VENDOR_FROM_DATABASE=Agilent Technologies, Inc.
+usb:v0957p0007*
+ ID_MODEL_FROM_DATABASE=82357A GPIB Interface Firmware loader
+
+usb:v0957p0107*
+ ID_MODEL_FROM_DATABASE=82357A GPIB Interface
+
usb:v0957p0200*
ID_MODEL_FROM_DATABASE=E-Video DC-350 Camera
ID_MODEL_FROM_DATABASE=33220A Waveform Generator
usb:v0957p0518*
+ ID_MODEL_FROM_DATABASE=82357B GPIB Interface Firmware loader
+
+usb:v0957p0607*
+ ID_MODEL_FROM_DATABASE=34410A Multimeter
+
+usb:v0957p0718*
ID_MODEL_FROM_DATABASE=82357B GPIB Interface
usb:v0957p0A07*
usb:v0957p1745*
ID_MODEL_FROM_DATABASE=Test and Measurement Device (IVI)
+usb:v0957p1907*
+ ID_MODEL_FROM_DATABASE=53230A Frequency Counter
+
usb:v0957p1F01*
ID_MODEL_FROM_DATABASE=N5181A MXG Analog Signal Generator
usb:v099Ap7160*
ID_MODEL_FROM_DATABASE=Hyper Slim Keyboard
+usb:v099Ap7202*
+ ID_MODEL_FROM_DATABASE=Enermax Aurora Micro Wireless Receiver
+
usb:v099E*
ID_VENDOR_FROM_DATABASE=Trimble Navigation, Ltd
usb:v09D8p0406*
ID_MODEL_FROM_DATABASE=TWN4 MIFARE NFC
+usb:v09D8p0410*
+ ID_MODEL_FROM_DATABASE=TWN4 HID
+
+usb:v09D8p0420*
+ ID_MODEL_FROM_DATABASE=TWN4 CDC
+
usb:v09D9*
ID_VENDOR_FROM_DATABASE=KRF Tech, Ltd
usb:v09DAp002A*
ID_MODEL_FROM_DATABASE=Wireless Optical Mouse NB-30
+usb:v09DAp0103*
+ ID_MODEL_FROM_DATABASE=Oscar X-710BK Gaming Mouse
+
usb:v09DAp022B*
ID_MODEL_FROM_DATABASE=Wireless Mouse (Battery Free)
usb:v09DAp112C*
ID_MODEL_FROM_DATABASE=Bloody V5 Mouse
+usb:v09DAp2268*
+ ID_MODEL_FROM_DATABASE=Keyboard (FK11)
+
+usb:v09DAp2690*
+ ID_MODEL_FROM_DATABASE=PK-635G
+
usb:v09DAp3A60*
ID_MODEL_FROM_DATABASE=Bloody V8M Core 2 Mouse
ID_MODEL_FROM_DATABASE=F3 V-Track Gaming Mouse
usb:v09DAp9090*
- ID_MODEL_FROM_DATABASE=XL-730K / XL-750BK / XL-755BK Mice
+ ID_MODEL_FROM_DATABASE=XL-730K / XL-747H / XL-750BK / XL-755BK Mice
usb:v09DApF613*
ID_MODEL_FROM_DATABASE=Bloody V7M Mouse
+usb:v09DApF6CC*
+ ID_MODEL_FROM_DATABASE=B314 Light Strike Gaming Keyboard
+
+usb:v09DApFA44*
+ ID_MODEL_FROM_DATABASE=B930 Light Strike RGB Mechanical Gaming Keyboard
+
usb:v09DB*
ID_VENDOR_FROM_DATABASE=Measurement Computing Corp.
usb:v09E8*
ID_VENDOR_FROM_DATABASE=AKAI Professional M.I. Corp.
+usb:v09E8p0029*
+ ID_MODEL_FROM_DATABASE=APC40 mkII
+
usb:v09E8p0045*
ID_MODEL_FROM_DATABASE=MPK Mini Mk II MIDI Controller
usb:v09E8p0076*
ID_MODEL_FROM_DATABASE=LPK25 MIDI Keyboard
+usb:v09E8p007C*
+ ID_MODEL_FROM_DATABASE=MPK Mini MIDI Controller
+
usb:v09E9*
ID_VENDOR_FROM_DATABASE=Chen-Source, Inc.
usb:v0A12p1012*
ID_MODEL_FROM_DATABASE=Bluetooth Device
+usb:v0A12p1243*
+ ID_MODEL_FROM_DATABASE=CSRA64210 [TaoTronics Headset BH-22 in charging mode]
+
+usb:v0A12p4007*
+ ID_MODEL_FROM_DATABASE=Mpow HC5 Headset in charging mode - HID / Mass Storage
+
+usb:v0A12p4010*
+ ID_MODEL_FROM_DATABASE=Mpow HC5 Headset in charging mode - USB Hub
+
usb:v0A12pFFFF*
ID_MODEL_FROM_DATABASE=USB Bluetooth Device in DFU State
usb:v0A35p008A*
ID_MODEL_FROM_DATABASE=SAC Hub
+usb:v0A38*
+ ID_VENDOR_FROM_DATABASE=IRIS sa
+
usb:v0A39*
ID_VENDOR_FROM_DATABASE=Gilat Satellite Networks, Ltd
usb:v0A5Cp219B*
ID_MODEL_FROM_DATABASE=Bluetooth 2.1 Device
+usb:v0A5Cp219C*
+ ID_MODEL_FROM_DATABASE=BCM2070 Bluetooth
+
usb:v0A5Cp21B1*
ID_MODEL_FROM_DATABASE=HP Bluetooth Module
usb:v0A5Cp5804*
ID_MODEL_FROM_DATABASE=BCM5880 Secure Applications Processor with fingerprint swipe sensor
+usb:v0A5Cp5832*
+ ID_MODEL_FROM_DATABASE=BCM5880 Secure Applications Processor Smartcard reader
+
usb:v0A5Cp6300*
ID_MODEL_FROM_DATABASE=Pirelli Remote NDIS Device
usb:v20A0p4107*
ID_MODEL_FROM_DATABASE=GPF Crypto Stick V1.2
+usb:v20A0p4108*
+ ID_MODEL_FROM_DATABASE=Nitrokey Pro
+
+usb:v20A0p4109*
+ ID_MODEL_FROM_DATABASE=Nitrokey Storage
+
usb:v20A0p4123*
ID_MODEL_FROM_DATABASE=IKALOGIC SCANALOGIC 2
usb:v20A0p4223*
ID_MODEL_FROM_DATABASE=ATSAMD21 [castAR]
+usb:v20A0p4230*
+ ID_MODEL_FROM_DATABASE=Nitrokey HSM
+
+usb:v20A0p4287*
+ ID_MODEL_FROM_DATABASE=Nitrokey FIDO U2F
+
usb:v20A0p428D*
ID_MODEL_FROM_DATABASE=Electrosense wideband converter
+usb:v20A0p42B1*
+ ID_MODEL_FROM_DATABASE=Nitrokey FIDO2
+
+usb:v20A0p42B2*
+ ID_MODEL_FROM_DATABASE=Nitrokey 3A Mini/3A NFC/3C NFC
+
+usb:v20A0p42B4*
+ ID_MODEL_FROM_DATABASE=Nitrokey Pro Bootloader
+
+usb:v20A0p42DA*
+ ID_MODEL_FROM_DATABASE=MuteMe
+
+usb:v20A0p42DD*
+ ID_MODEL_FROM_DATABASE=Nitrokey 3A NFC Bootloader/3C NFC Bootloader
+
+usb:v20A0p42E8*
+ ID_MODEL_FROM_DATABASE=Nitrokey 3A Mini Bootloader
+
+usb:v20A0p42EC*
+ ID_MODEL_FROM_DATABASE=RP2040 [PicoWifi]
+
usb:v20B1*
ID_VENDOR_FROM_DATABASE=XMOS Ltd
ID_MODEL_FROM_DATABASE=WinUSB Smartcard
usb:v2581pF1D0*
- ID_MODEL_FROM_DATABASE=FIDO U2F Security Key
+ ID_MODEL_FROM_DATABASE=Nitrokey U2F
usb:v258D*
ID_VENDOR_FROM_DATABASE=Sequans Communications
evdev:name:AT Translated Set 2 keyboard:dmi:bvn*:svnPositivoTecnologiaSA:pn*:pvr*:rvnPositivoTecnologiaSA:rnK116*
KEYBOARD_KEY_76=f21 # Fn+F1 toggle touchpad
+# Positivo (N14NPE-N, N15NPE-N)
+evdev:name:AT Translated Set 2 keyboard:dmi:bvn*:svnPositivo*:pn*:pvr*:rvnPositivo*:rnN1[45]NPE-N*
+ KEYBOARD_KEY_76=f21 # Fn+F1 toggle touchpad
+ KEYBOARD_KEY_dd=search
+
# Positivo (CG15D)
evdev:name:AT Translated Set 2 keyboard:dmi:bvn*:bvr*:svnPositivoTecnologiaSA:pn*:pvr*:rvn*:rnCG15D*
# Positivo Motion (N14DP6, N14DP7, N14DP7-V2, N14DP9, N14JP6, N14KP6)
# The latest version can be obtained from
# http://www.linux-usb.org/usb.ids
#
-# Version: 2023.11.08
-# Date: 2023-11-08 20:34:02
+# Version: 2024.03.18
+# Date: 2024-03-18 20:34:02
#
# Vendors, devices and interfaces. Please keep sorted.
0004 Nebraska Furniture Mart
0011 Unknown
7788 counterfeit flash drive
+001f Walmart
+ 0b21 AB13X Headset Adapter
0040 Anyware Corporation
073d Mini Multimedia 2.4GHz Wireless Keyboard with Touch Pad
0042 DMT
0012 DeskJet 1125C Printer Port
0024 KU-0316 Keyboard
002a LaserJet P1102
+ 0036 CCID Smartcard Keyboard KUS0133
0053 DeskJet 2620 All-in-One Printer
0101 ScanJet 4100c
0102 PhotoSmart S20
008c AVC-2310 Device
0094 eHome Infrared Receiver
009b AVC-1410 GameBridge TV NTSC
- 2000 USBXchange
+ 2000 USBXchange Firmware Loader
2001 USBXchange Adapter
- 2002 USB2-Xchange
+ 2002 USB2-Xchange Firmware Loader
2003 USB2-Xchange Adapter
4000 4-port hub
adcc Composite Device Support
601f FT601 32-bit FIFO IC
6ee0 EZO Carrier Board
6f70 HB-RF-USB
+ 7150 FT2232x wired for MPSSE+UART
+ 7151 FT2232x wired for MPSSE+UART
+ 7152 FreeCalypso dual UART with boot control
7be8 FT232R
8028 Dev board JTAG (FT232H based)
8040 4 Port Hub
3fcc RME MADIface
4041 Hub and media card controller
4060 Ultra Fast Media Reader
+ 4063 xD/SD/MS/MMC Reader
4064 Ultra Fast Media Reader
4712 USB4712 high-speed hub
4713 USB4715 high-speed hub (2 ports disabled)
9800 Remote Control Receiver_iMON
9803 eHome Infrared Receiver
9804 DMB Receiver Control
+ 9a10 34UC88-B
+ 9a11 34UC88-B
9a39 27UP850 - WK.AEUDCSN - External Monitor 4K
9c01 LGE Sync
043f RadiSys Corp.
02e6 Xbox Wireless Adapter for Windows
02ea Xbox One Controller
02fd Xbox One S Controller [Bluetooth]
+ 02fe Xbox Wireless Adapter for Windows
+ 0306 Surface Pro 7 SD Card Reader
0400 Windows Powered Pocket PC 2002
0401 Windows Powered Pocket PC 2002
0402 Windows Powered Pocket PC 2002
0800 Wireless keyboard (All-in-One-Media)
0810 LifeCam HD-3000
0823 Classic IntelliMouse
+ 082a Pro Intellimouse
0900 Surface Dock Hub
0901 Surface Dock Hub
0902 Surface Dock Hub
c52b Unifying Receiver
c52d R700 Remote Presenter receiver
c52e MK260 Wireless Combo Receiver
- c52f Unifying Receiver
+ c52f Nano Receiver
c531 C-U0007 [Unifying Receiver]
c532 Unifying Receiver
- c534 Unifying Receiver
+ c534 Nano Receiver
c537 Cordless Mouse Receiver
c539 Lightspeed Receiver
c53a PowerPlay Wireless Charging System
5720 Mass Storage Device
5721 Interrupt Demo
5722 Bulk Demo
+ 572a STM32F401 microcontroller [ARM Cortex M4] [CDC/ACM serial port]
5730 Audio Speaker
5731 Microphone
5740 Virtual COM Port
e07a Broadcom BCM20702A1 Bluetooth
e0c8 MediaTek MT7921 Bluetooth
e0cd MediaTek Bluetooth Adapter
- e0d8 Bluetooth Adapter
+ e0d8 Bluetooth 5.2 Adapter [MediaTek MT7922]
048a S-MOS Systems, Inc.
048c Alps Electric Ireland, Ltd
048d Integrated Technology Express, Inc.
0320 Bluetooth Adapter
0321 Bluetooth Device
0a28 INDI AV-IN Device
+ 1301 Network Controller
+ 1302 i3 Gateway
+ 1303 3 Micro Module
+ 1304 i3 Module
+ 1305 i3 Multi Sensing Module
04c1 U.S. Robotics (3Com)
0020 56K Voice Pro
0022 56K Voice Pro
072d Revio KD410Z
04ca Lite-On Technology Corp.
0020 USB Keyboard
+ 003a Multimedia Keyboard
004b Keyboard
004f SK-9020 keyboard
008a Acer Wired Mouse Model SM-9023
1400 PS/2 keyboard + mouse controller
1503 Keyboard
1603 Keyboard
+ 1605 Keyboard
1702 Keyboard LKS02
1818 Keyboard [Diatec Filco Majestouch 2]
2011 Keyboard [Diatec Filco Majestouch 1]
b681 ThinkPad T490 Webcam
b71a Integrated IR Camera
b76b SunplusIT Inc [HP HD Camera]
+ b7b4 Integrated Camera (1920x1080)
04f3 Elan Microelectronics Corp.
000a Touchscreen
0103 ActiveJet K-2024 Multimedia Keyboard
0003 Smart Card Reader II
04fe PFU, Ltd
0006 Happy Hacking Keyboard Lite2
+ 0020 HHKB-Classic
+ 0021 Happy Hacking Keyboard Professional HYBRID Type-S
04ff E-CMOS Corp.
0500 Siam United Hi-Tech
0001 DART Keyboard Mouse
0081 F8T001v2 Bluetooth
0083 Bluetooth Device
0084 F8T003v2 Bluetooth
+ 008a 6-in-1 Multiport Adapter
0102 Flip KVM
0103 F5U103 Serial Adapter [etek]
0106 VideoBus II Adapter, Video
05c4 DualShock 4 [CUH-ZCT1x]
0643 DSC-H100 in PTP/MTP mode
0689 Walkman NWZ-B173F
+ 068c UP-D711
06bb WALKMAN NWZ-F805
06c3 RC-S380
07c3 ILCE-6000 (aka Alpha-6000) in Mass Storage mode
03ac DTH-W1620 [MobileStudio Pro 16] touchscreen
03b2 DTH167 [Cintiq Pro 16] tablet
03b3 DTH167 [Cintiq Pro 16] touchscreen
+ 03c0 DTH271 [Cintiq Pro 27] touchscreen
+ 03c4 DTH172 [Cintiq Pro 17]
03c5 CTL-4100WL [Intuos BT (S)]
03c7 CTL-6100WL [Intuos BT (M)]
+ 03cb DTH134 [Wacom One 13] touchscreen
+ 03ce DTC121 [Wacom One 12] touchscreen
+ 03d0 DTH227 [Cintiq Pro 22]
03dc PTH-460 [Intuos Pro (S)] tablet
03dd PTH-460 [Intuos Pro BT (S)] tablet
+ 03ec DTH134 [DTH134] touchscreen
+ 03ed DTC121 [DTC121] touchscreen
0400 PenPartner 4x5
4001 TPC4001
4004 TPC4004
0002 HID Monitor Controls
0003 Device Bay Controller
4000 FlexScan EV3237
- 4001 Monitor
- 4002 USB HID Monitor
+ 4001 FlexScan EV2450
+ 4002 FlexScan EV2455
4014 FlexScan EV2750
4026 FlexScan EV2451
4027 FlexScan EV2456
+ 402b FlexScan EV2780
4036 FlexScan EV2785
4037 FlexScan EV3285
4044 FlexScan EV2457
4059 FlexScan EV2760
405a FlexScan EV2360
405b FlexScan EV2460
+ 405e FlexScan EV2495
405f FlexScan EV2795
4065 FlexScan EV3895
+ 406a FlexScan EV2480
056e Elecom Co., Ltd
0002 29UO Mouse
0057 Micro Grast Pop M-PGDL
1093 Rugged
1094 Rugged THB
1095 Rugged
+ 1105 Mobile Drive (RLSD: 2022)
a601 HardDrive
a602 CD R/W
05a0 Vetronix Corp.
05e4 Red Wing Corp.
05e5 Fuji Electric Co., Ltd
05e6 Keithley Instruments
+ 3390 3390 Arbitrary Waveform Generator
05e8 ICC, Inc.
05e9 Kawasaki LSI
0008 KL5KUSB101B Ethernet [klsi]
# typo?
4004 Minolta Dimage Scan Elite II AF-2920 (2888)
0639 Chrontel, Inc.
+ 7213 CH7213
+ 7231 CH7213
063a Techwin Corp.
063b Taugagreining HF
063c Yamaichi Electronics Co., Ltd (Sakura)
00bd Prometheus MIS Touch Fingerprint Reader
00c7 TouchPad
00cb Fingerprint scanner
+ 00fc Prometheus Fingerprint Reader
0ac3 Large Touch Screen
2970 touchpad
06cc Terayon Communication Systems
038c CP900DW(ID) Port
0393 CP9500D/DW Port
0394 CP9000D/DW Port
+ 0395 CP9000DW
0398 P93D
+ 039e CP9500DW-S
03a1 CP9550D/DW Port
03a5 CP9550DW-S
03a9 CP-9600DW
03ae CP-9800DW-S
0f10 Hori/Namco FlightStick 2
3b10 P95D
+ 3b20 CP9820DW Series
3b21 CP-9810D/DW
+ 3b2f LS9820A
3b30 CP-D70DW / CP-D707DW
3b31 CP-K60DW-S
3b36 CP-D80DW
c007 DPB-4000
c009 DPB-6000
c010 CPB-7000
+ c011 ASK-2500
07cf Casio Computer Co., Ltd
1001 QV-8000SX/5700/3000EX Digicam; Exilim EX-M20
1003 Exilim EX-S500
0000 FastLane MIDI Interface
0001 MIDI Interface
0002 MOTU Audio for 64 bit
- 0004 MicroBook
+ 0004 Microbook I/II/IIc
0008 M Series
+ 0009 M Series (firmware update mode)
+ 000b M Series
+ 000d M Series (firmware update mode)
07ff Unknown
00ff Portable Hard Drive
ffff Mad Catz Gamepad
0826 Data Transit
0827 BroadLogic, Inc.
0828 Sato Corp.
+ a003 WS408 Label Printer
0829 DirecTV Broadband, Inc. (Telocity)
082d Handspring
0100 Visor
04b2 NC interface
04b3 keyboard front panel Cockpit
04b4 SCR_CCID
+ 04b5 Camera
+ 04b6 Cockpit Touchkeypad
+ 04b7 Cockpit Touchkeypad Bootloader
+ 04b8 MediSET USB4-W
+ 04b9 MediSET USB4-R
+ 04ba MediSET USB4-G
2701 ShenZhen SANZHAI Technology Co.,Ltd Spy Pen VGA
0909 Audio-Technica Corp.
001b ATR2100-USB
037c 300k Pixel Camera
1000 Flash Drive
1132 5-in-1 Card Reader
+ 2000 Disk
337b Silicon Motion Camera
3710 Silicon Motion Camera
3720 Silicon Motion Camera
4cda Fenix 6 Sapphire
4cdb Fenix 6
0920 Echelon Co.
+ 5550 U60 FT Network Interface
7500 Network Interface
0921 GoHubs, Inc.
1001 GoCOM232 Serial
010f nanoKONTROL studio controller
0117 nanoKONTROL2 MIDI Controller
012f SQ-1
+ 0203 KRONOS
0f03 K-Series K61P MIDI studio controller
0945 Pasco Scientific
0948 Kronauer music in digital
7140 T124 [Tegra K1/Logan 32-bit]
7210 SHIELD Controller
7321 Switch [Tegra Erista] recovery mode
+ 7323 T234 [Orin NX 16GB] recovery mode
+ 7423 T234 [Orin NX 8GB] recovery mode
7721 T210 [TX1 Tegra Erista] recovery mode
7820 T20 [Tegra 2] recovery mode
7c18 T186 [TX2 Tegra Parker] recovery mode
cf09 SHIELD Tablet
0956 BSquare Corp.
0957 Agilent Technologies, Inc.
+ 0007 82357A GPIB Interface Firmware loader
+ 0107 82357A GPIB Interface
0200 E-Video DC-350 Camera
0202 E-Video DC-350 Camera
0407 33220A Waveform Generator
- 0518 82357B GPIB Interface
+ 0518 82357B GPIB Interface Firmware loader
+ 0607 34410A Multimeter
+ 0718 82357B GPIB Interface
0a07 34411A Multimeter
1507 33210A Waveform Generator
1745 Test and Measurement Device (IVI)
+ 1907 53230A Frequency Counter
1f01 N5181A MXG Analog Signal Generator
2918 U2702A oscilloscope
fb18 LC Device
6330 SANWA Supply Inc. Slim Keyboard
713a WK-713 Multimedia Keyboard
7160 Hyper Slim Keyboard
+ 7202 Enermax Aurora Micro Wireless Receiver
099e Trimble Navigation, Ltd
09a3 PairGain Technologies
09a4 Contech Research, Inc.
09d8 ELATEC GmbH
0320 TWN3 Multi125
0406 TWN4 MIFARE NFC
+ 0410 TWN4 HID
+ 0420 TWN4 CDC
09d9 KRF Tech, Ltd
09da A4Tech Co., Ltd.
0006 Optical Mouse WOP-35 / Trust 450L Optical Mouse
0018 Trust Human Interface Device
001a Wireless Mouse & RXM-15 Receiver
002a Wireless Optical Mouse NB-30
+ 0103 Oscar X-710BK Gaming Mouse
022b Wireless Mouse (Battery Free)
024f RF Receiver and G6-20D Wireless Optical Mouse
0260 KV-300H Isolation Keyboard
09da Bloody V8 Mouse
1068 Bloody A90 Mouse
112c Bloody V5 Mouse
+ 2268 Keyboard (FK11)
+ 2690 PK-635G
3a60 Bloody V8M Core 2 Mouse
8090 X-718BK Oscar Optical Gaming Mouse
9033 X-718BK Optical Mouse
9066 F3 V-Track Gaming Mouse
- 9090 XL-730K / XL-750BK / XL-755BK Mice
+ 9090 XL-730K / XL-747H / XL-750BK / XL-755BK Mice
f613 Bloody V7M Mouse
+ f6cc B314 Light Strike Gaming Keyboard
+ fa44 B930 Light Strike RGB Mechanical Gaming Keyboard
09db Measurement Computing Corp.
0075 MiniLab 1008
0076 PMD-1024
09e6 Silutia, Inc.
09e7 Real 3D, Inc.
09e8 AKAI Professional M.I. Corp.
+ 0029 APC40 mkII
0045 MPK Mini Mk II MIDI Controller
0062 MPD16 MIDI Pad Controller Unit
006d EWI electronic wind instrument
0071 MPK25 MIDI Keyboard
0076 LPK25 MIDI Keyboard
+ 007c MPK Mini MIDI Controller
09e9 Chen-Source, Inc.
09eb IM Networks, Inc.
4331 iRhythm Tuner Remote
1010 Bluetooth Device
1011 Bluetooth Device
1012 Bluetooth Device
+ 1243 CSRA64210 [TaoTronics Headset BH-22 in charging mode]
+ 4007 Mpow HC5 Headset in charging mode - HID / Mass Storage
+ 4010 Mpow HC5 Headset in charging mode - USB Hub
ffff USB Bluetooth Device in DFU State
0a13 Telebyte, Inc.
0a14 Spacelabs Medical, Inc.
0a35 Radikal Technologies
002a SAC - Software Assigned Controller
008a SAC Hub
+0a38 IRIS sa
0a39 Gilat Satellite Networks, Ltd
0a3a PentaMedia Co., Ltd
0163 KN-W510U 1.0 Wireless LAN Adapter
217f BCM2045B (BDC-2.1)
2198 Bluetooth 3.0 Device
219b Bluetooth 2.1 Device
+ 219c BCM2070 Bluetooth
21b1 HP Bluetooth Module
21b4 BCM2070 Bluetooth 2.1 + EDR
21b9 BCM2070 Bluetooth 2.1 + EDR
5802 BCM5880 Secure Applications Processor with fingerprint touch sensor
5803 BCM5880 Secure Applications Processor with secure keyboard
5804 BCM5880 Secure Applications Processor with fingerprint swipe sensor
+ 5832 BCM5880 Secure Applications Processor Smartcard reader
6300 Pirelli Remote NDIS Device
6410 BCM20703A1 Bluetooth 4.1 + LE
bd11 BCM4320 802.11bg Wireless Adapter
20a0 Clay Logic
0006 flirc
4107 GPF Crypto Stick V1.2
+ 4108 Nitrokey Pro
+ 4109 Nitrokey Storage
4123 IKALOGIC SCANALOGIC 2
414a MDE SPI Interface
415a OpenPilot
41e5 BlinkStick
4211 Nitrokey Start
4223 ATSAMD21 [castAR]
+ 4230 Nitrokey HSM
+ 4287 Nitrokey FIDO U2F
428d Electrosense wideband converter
+ 42b1 Nitrokey FIDO2
+ 42b2 Nitrokey 3A Mini/3A NFC/3C NFC
+ 42b4 Nitrokey Pro Bootloader
+ 42da MuteMe
+ 42dd Nitrokey 3A NFC Bootloader/3C NFC Bootloader
+ 42e8 Nitrokey 3A Mini Bootloader
+ 42ec RP2040 [PicoWifi]
20b1 XMOS Ltd
10ad XUSB Loader
f7d1 XTAG2 - JTAG Adapter
2581 Plug-up
1807 Generic HID Smartcard
1808 WinUSB Smartcard
- f1d0 FIDO U2F Security Key
+ f1d0 Nitrokey U2F
258d Sequans Communications
259a TriQuint Semiconductor
25a7 Areson Technology Corp
<term><varname>$SYSTEMD_LOG_LEVEL</varname></term>
<listitem><para id='log-level-body'>The maximum log level of emitted messages (messages with a higher
- log level, i.e. less important ones, will be suppressed). Either one of (in order of decreasing
- importance) <constant>emerg</constant>, <constant>alert</constant>, <constant>crit</constant>,
- <constant>err</constant>, <constant>warning</constant>, <constant>notice</constant>,
- <constant>info</constant>, <constant>debug</constant>, or an integer in the range 0…7. See
+ log level, i.e. less important ones, will be suppressed). Takes a comma-separated list of values. A
+ value may be either one of (in order of decreasing importance) <constant>emerg</constant>,
+ <constant>alert</constant>, <constant>crit</constant>, <constant>err</constant>,
+ <constant>warning</constant>, <constant>notice</constant>, <constant>info</constant>,
+ <constant>debug</constant>, or an integer in the range 0…7. See
<citerefentry project='man-pages'><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry>
- for more information.</para>
- </listitem>
+ for more information. Each value may optionally be prefixed with one of <constant>console</constant>,
+ <constant>syslog</constant>, <constant>kmsg</constant> or <constant>journal</constant> followed by a
+ colon to set the maximum log level for that specific log target (e.g.
+ <constant>SYSTEMD_LOG_LEVEL=debug,console:info</constant> specifies to log at debug level except when
+ logging to the console which should be at info level). Note that the global maximum log level takes
+ priority over any per target maximum log levels.</para></listitem>
</varlistentry>
<varlistentry id='log-color'>
<para>For the latter five mechanisms the source for the key material used for unlocking the volume is
primarily configured in the third field of each <filename>/etc/crypttab</filename> line, but may also
- configured in <filename>/etc/cryptsetup-keys.d/</filename> and
+ be configured in <filename>/etc/cryptsetup-keys.d/</filename> and
<filename>/run/cryptsetup-keys.d/</filename> (see above) or in the LUKS2 JSON token header (in case of
the latter three). Use the
<citerefentry><refentrytitle>systemd-cryptenroll</refentrytitle><manvolnum>1</manvolnum></citerefentry>
is acquired by connecting to the socket and reading the key from the connection. The connection is made
from an <constant>AF_UNIX</constant> socket name in the abstract namespace, see <citerefentry
project='man-pages'><refentrytitle>unix</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
- details. The source socket name is chosen according the following format:</para>
+ details. The source socket name is chosen according to the following format:</para>
<programlisting><constant>NUL</constant> <replaceable>RANDOM</replaceable> /cryptsetup/ <replaceable>VOLUME</replaceable></programlisting>
<listitem><para>If the service opens sockets or other files on it own, and those file descriptors
shall survive a restart, the daemon should store them in the service manager via
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry> with
- <varname>FDSTORE=1</varname>..</para></listitem>
+ <varname>FDSTORE=1</varname>.</para></listitem>
<listitem><para>Instead of using the <function>syslog()</function> call to log directly to the system
syslog service, a new-style daemon may choose to simply log to standard error via
<refsect1>
<title>Description</title>
- <para><command>importctl</command> may be used to download, import export disk images via
+ <para><command>importctl</command> may be used to download, import, and export disk images via
<citerefentry><refentrytitle>systemd-importd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
<para><command>importctl</command> operates both on block-level disk images (such as DDIs) as well as
<refsect1>
<title>Commands</title>
- <para>The following commands are understood. If none is specified the default is to display journal records.</para>
+ <para>The following commands are understood. If none is specified the default is to display journal records:</para>
<variablelist>
<varlistentry>
out h send_fd);
@org.freedesktop.systemd1.Privileged("true")
ReleaseHome(in s user_name);
- InhibitSuspendHome(in s user_name,
- out h send_fd);
@org.freedesktop.systemd1.Privileged("true")
LockAllHomes();
@org.freedesktop.systemd1.Privileged("true")
<variablelist class="dbus-method" generated="True" extra-ref="ReleaseHome()"/>
- <variablelist class="dbus-method" generated="True" extra-ref="InhibitSuspendHome()"/>
-
<variablelist class="dbus-method" generated="True" extra-ref="LockAllHomes()"/>
<variablelist class="dbus-method" generated="True" extra-ref="DeactivateAllHomes()"/>
the numeric UID and GID, the real name, home directory and shell. In addition it returns a state
identifier describing the state the user's home directory is in, as well as a bus path referring to the
bus object encapsulating the user record and home directory. This object implements the
- <classname>org.freedesktop.home1.Home</classname> interface documented below.</para>
+ <classname>org.freedesktop.home1.Home</classname> interface documented below. This method, and most others
+ in this interface that take user names, will try to use the caller's home area if the specified user name is
+ an empty string.</para>
<para><function>GetHomeByUID()</function> is similar to <function>GetHomeByName()</function> but
acquires the information based on the numeric UID of the user.</para>
re-authenticate when the system comes back from suspending. It should be set by all clients that
implement a secure lock screen running outside of the user's context, that is brought up when the
system comes back from suspend and can be used to re-acquire the credentials to unlock the user's home
- directory. A home directory is locked automatically at system suspend only if all clients with open
- references to the home directory specify that they support this functionality, and no client has
- temporarily inhibited it (see <function>InhibitSuspendHome()</function> below); otherwise the directory
- remains unlocked. This method is equivalent to <function>Acquire()</function> on the
+ directory. If a home directory has at least one client with an open reference to the home directory
+ that does not support this it is not suspended automatically at system suspend, otherwise it is. This
+ method is equivalent to <function>Acquire()</function> on the
<classname>org.freedesktop.home1.Home</classname> interface.</para>
<para><function>RefHome()</function> is similar to <function>AcquireHome()</function> but takes no user
triggered deactivation is completed. This method is equivalent to <function>Release()</function> on the
<classname>org.freedesktop.home1.Home</classname> interface.</para>
- <para><function>InhibitSuspendHome()</function> temporarily inhibits automatic locking during system
- suspend for a home directory. It returns a file descriptor that inhibits this functionality for as long
- as it is open. As mentioned above, locking a home directory requires a secure lock screen running
- outside of the user context, and is likely to freeze any process that attempts to access the directory.
- Thus, locking a home directory is a trade-off: it increases security, but prevents the client from
- displaying any user content on its secure lock screen, including notifications, media controls, contact
- information for incoming phone calls, and much more. A client may use this method to implement more
- complicated automatic locking behavior for home directories, in order to solve some of these UX issues.
- For instance, the client may choose to only lock the home directory and switch to the secure lock screen
- if the device has been suspended for over 24 hours. Note that this inhibitor does not prevent clients from
- calling <function>LockHome()</function>, and in fact clients will need to call <function>LockHome()</function>
- manually as part of their custom behavior to lock the home directory. Clients should take care to ensure that
- the file descriptor is closed in the event that their custom behavior fails or is disabled. This method is
- equivalent to <function>InhibitSuspend()</function> on the <classname>org.freedesktop.home1.Home</classname>
- interface.</para>
-
<para><function>LockAllHomes()</function> locks all active home directories that only have references
- that opted into automatic locking during system suspend and have no clients inhibiting this behavior.
- This is usually invoked automatically shortly before system suspend.</para>
+ that opted into automatic suspending during system suspend. This is usually invoked automatically
+ shortly before system suspend.</para>
<para><function>DeactivateAllHomes()</function> deactivates all home areas that are currently
active. This is usually invoked automatically shortly before system shutdown.</para>
out h send_fd);
@org.freedesktop.systemd1.Privileged("true")
Release();
- InhibitSuspend(out h send_fd);
properties:
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s UserName = '...';
<variablelist class="dbus-method" generated="True" extra-ref="Release()"/>
- <variablelist class="dbus-method" generated="True" extra-ref="InhibitSuspend()"/>
-
<variablelist class="dbus-property" generated="True" extra-ref="UserName"/>
<variablelist class="dbus-property" generated="True" extra-ref="UID"/>
<function>Update()</function>, <function>UpdateEx()</function>, <function>Resize()</function>,
<function>ChangePassword()</function>, <function>Lock()</function>, <function>Unlock()</function>,
<function>Acquire()</function>, <function>Ref()</function>, <function>RefUnrestricted()</function>,
- <function>Release()</function>, <function>InhibitSuspend()</function> operate like their matching counterparts
- on the <classname>org.freedesktop.home1.Manager</classname> interface (see above). The main difference is that
- they are methods of the home directory objects, and hence carry no additional user name
- parameter. Which of the two flavors of methods to call depends on the handles to the user known on the
- client side: if only the user name is known, it's preferable to use the methods on the manager object
- since they operate with user names only. If however the home object path was already acquired some way
- it is preferable to operate on the <classname>org.freedesktop.home1.Home</classname> objects
- instead.</para>
+ <function>Release()</function>,
+ operate like their matching counterparts on the <classname>org.freedesktop.home1.Manager</classname>
+ interface (see above). The main difference is that they are methods of the home directory objects, and
+ hence carry no additional user name parameter. Which of the two flavors of methods to call depends on
+ the handles to the user known on the client side: if only the user name is known, it's preferable to use
+ the methods on the manager object since they operate with user names only. Clients can also easily operate
+ on their own home area by using the methods on the manager object with an empty string as the user name.
+ If the client has the home's object path already acquired in some way, however, it is preferable to operate
+ on the <classname>org.freedesktop.home1.Home</classname> objects instead.</para>
</refsect2>
<refsect2>
<title>History</title>
<refsect2>
<title>The Manager Object</title>
- <para><function>InhibitSuspendHome()</function>, <function>ActivateHomeIfReferenced()</function>, <function>RefHomeUnrestricted()</function>,
+ <para><function>ActivateHomeIfReferenced()</function>, <function>RefHomeUnrestricted()</function>,
<function>CreateHomeEx()</function>, and <function>UpdateHomeEx()</function> were added in version 256.</para>
</refsect2>
<refsect2>
<title>Home Objects</title>
- <para><function>InhibitSuspend()</function>, <function>ActivateIfReferenced()</function>, <function>RefUnrestricted()</function>, and
+ <para><function>ActivateIfReferenced()</function>, <function>RefUnrestricted()</function>, and
<function>UpdateEx()</function> were added in version 256.</para>
</refsect2>
</refsect1>
multiple times, in which case the order in which images are laid down follows the rules specified in
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for the <varname>ExtensionImages=</varname> directive and for the
- <citerefentry><refentrytitle>systemd-sysext</refentrytitle><manvolnum>8</manvolnum></citerefentry> and.
+ <citerefentry><refentrytitle>systemd-sysext</refentrytitle><manvolnum>8</manvolnum></citerefentry> and
<citerefentry><refentrytitle>systemd-confext</refentrytitle><manvolnum>8</manvolnum></citerefentry> tools.
The images must contain an <filename>extension-release</filename> file with metadata that matches
what is defined in the <filename>os-release</filename> of <replaceable>IMAGE</replaceable>. See:
<para>The file specified here must have a size that is a multiple of the basic block size 512 and not
be empty. If this option is used, the size allocation algorithm is slightly altered: the partition is
- created as least as big as required to fit the data in, i.e. the data size is an additional minimum
+ created at least as big as required to fit the data in, i.e. the data size is an additional minimum
size value taken into consideration for the allocation algorithm, similar to and in addition to the
<varname>SizeMin=</varname> value configured above.</para>
<literal>squashfs</literal> or the special value <literal>swap</literal>. If specified and the partition
is newly created it is formatted with the specified file system (or as swap device). The file system
UUID and label are automatically derived from the partition UUID and label. If this option is used,
- the size allocation algorithm is slightly altered: the partition is created as least as big as
+ the size allocation algorithm is slightly altered: the partition is created at least as big as
required for the minimal file system of the specified type (or 4KiB if the minimal size is not
known).</para>
['repart.d', '5', [], 'ENABLE_REPART'],
['resolvectl', '1', ['resolvconf'], 'ENABLE_RESOLVE'],
['resolved.conf', '5', ['resolved.conf.d'], 'ENABLE_RESOLVE'],
+ ['run0', '1', [], ''],
['runlevel', '8', [], 'HAVE_SYSV_COMPAT'],
['sd-bus-errors',
'3',
'sd_journal_seek_realtime_usec',
'sd_journal_seek_tail'],
''],
- ['sd_journal_stream_fd', '3', [], ''],
+ ['sd_journal_stream_fd', '3', ['sd_journal_stream_fd_with_namespace'], ''],
['sd_listen_fds',
'3',
['SD_LISTEN_FDS_START', 'sd_listen_fds_with_names'],
''],
['udev_new', '3', ['udev_ref', 'udev_unref'], ''],
['udevadm', '8', [], ''],
- ['uid0', '1', [], ''],
['ukify', '1', [], 'ENABLE_UKIFY'],
['user@.service',
'5',
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
-<refentry id="uid0"
+<refentry id="run0"
xmlns:xi="http://www.w3.org/2001/XInclude">
<refentryinfo>
- <title>uid0</title>
+ <title>run0</title>
<productname>systemd</productname>
</refentryinfo>
<refmeta>
- <refentrytitle>uid0</refentrytitle>
+ <refentrytitle>run0</refentrytitle>
<manvolnum>1</manvolnum>
</refmeta>
<refnamediv>
- <refname>uid0</refname>
+ <refname>run0</refname>
<refpurpose>Elevate privileges</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
- <command>uid0</command>
+ <command>run0</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
<arg choice="opt" rep="repeat">COMMAND</arg>
</cmdsynopsis>
<refsect1>
<title>Description</title>
- <para><command>uid0</command> may be used to temporarily and interactively acquire elevated or different
+ <para><command>run0</command> may be used to temporarily and interactively acquire elevated or different
privileges. It serves a similar purpose as <citerefentry
project='man-pages'><refentrytitle>sudo</refentrytitle><manvolnum>8</manvolnum></citerefentry>, but
operates differently in a couple of key areas:</para>
setting the <varname>NoNewPrivileges=</varname> variable in
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>).</para>
- <para>Any session invoked via <command>uid0</command> will run through the
- <literal>systemd-uid0</literal> PAM stack.</para>
+ <para>Any session invoked via <command>run0</command> will run through the
+ <literal>systemd-run0</literal> PAM stack.</para>
- <para>Note that <command>uid0</command> is implemented as an alternative multi-call invocation of
+ <para>Note that <command>run0</command> is implemented as an alternative multi-call invocation of
<citerefentry><refentrytitle>systemd-run</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para>
</refsect1>
<term><option>--slice-inherit</option></term>
<listitem><para>Make the new <filename>.service</filename> unit part of the slice the
- <command>uid0</command> itself has been invoked in. This option may be combined with
+ <command>run0</command> itself has been invoked in. This option may be combined with
<option>--slice=</option>, in which case the slice specified via <option>--slice=</option> is placed
- within the slice the <command>uid0</command> command is invoked in.</para>
+ within the slice the <command>run0</command> command is invoked in.</para>
- <para>Example: consider <command>uid0</command> being invoked in the slice
+ <para>Example: consider <command>run0</command> being invoked in the slice
<filename>foo.slice</filename>, and the <option>--slice=</option> argument is
<filename>bar</filename>. The unit will then be placed under
<filename>foo-bar.slice</filename>.</para>
<refsect1>
<title>Exit status</title>
- <para>On success, 0 is returned. If <command>uid0</command> failed to start the session or the specified command fails, a
+ <para>On success, 0 is returned. If <command>run0</command> failed to start the session or the specified command fails, a
non-zero return value will be returned.</para>
</refsect1>
<refnamediv>
<refname>sd_journal_stream_fd</refname>
+ <refname>sd_journal_stream_fd_with_namespace</refname>
<refpurpose>Create log stream file descriptor to the journal</refpurpose>
</refnamediv>
<paramdef>int <parameter>level_prefix</parameter></paramdef>
</funcprototype>
+ <funcprototype>
+ <funcdef>int <function>sd_journal_stream_fd_with_namespace</function></funcdef>
+ <paramdef>const char *<parameter>name_space</parameter></paramdef>
+ <paramdef>const char *<parameter>identifier</parameter></paramdef>
+ <paramdef>int <parameter>priority</parameter></paramdef>
+ <paramdef>int <parameter>level_prefix</parameter></paramdef>
+ </funcprototype>
+
</funcsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
- <para><function>sd_journal_stream_fd()</function> may be used to
- create a log stream file descriptor. Log messages written to this
- file descriptor as simple newline-separated text strings are
- written to the journal. This file descriptor can be used
- internally by applications or be made standard output or standard
- error of other processes executed.</para>
+ <para><function>sd_journal_stream_fd()</function> may be used to create a log stream file descriptor.
+ Log messages written to this file descriptor as simple newline-separated text strings are written
+ to the journal. This file descriptor can be used internally by applications or be made standard output
+ or standard error of other processes executed.</para>
- <para><function>sd_journal_stream_fd()</function> takes a short
- program identifier string as first argument, which will be written
- to the journal as SYSLOG_IDENTIFIER= field for each log entry
+ <para><function>sd_journal_stream_fd()</function> takes a short program identifier string as
+ first argument, which will be written to the journal as SYSLOG_IDENTIFIER= field for each log entry
(see
<citerefentry><refentrytitle>systemd.journal-fields</refentrytitle><manvolnum>7</manvolnum></citerefentry>
- for more information). The second argument shall be the default
- priority level for all messages. The priority level is one of
+ for more information). The second argument shall be the default priority level for all messages.
+ The priority level is one of
<constant>LOG_EMERG</constant>, <constant>LOG_ALERT</constant>,
<constant>LOG_CRIT</constant>, <constant>LOG_ERR</constant>,
<constant>LOG_WARNING</constant>, <constant>LOG_NOTICE</constant>,
<citerefentry><refentrytitle>sd-daemon</refentrytitle><manvolnum>3</manvolnum></citerefentry>
for more information.</para>
- <para>It is recommended that applications log UTF-8 messages only
- with this API, but this is not enforced.</para>
+ <para><function>sd_journal_stream_fd_with_namespace()</function> is similar to
+ <function>sd_journal_stream_fd()</function>, but takes an additional <parameter>name_space</parameter> parameter
+ that specifies which journal namespace to operate on. If specified as <constant>NULL</constant> the call
+ is identical to <function>sd_journal_stream_fd()</function>. For details about journal namespaces, see
+ <citerefentry><refentrytitle>systemd-journald.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
+
+ <para>It is recommended that applications log UTF-8 messages only with this API, but this is not enforced.</para>
- <para>Each invocation of <function>sd_journal_stream_fd()</function> allocates a new log stream file descriptor,
- that is not shared with prior or later invocations. The file descriptor is write-only (its reading direction is
- shut down), and <constant>O_NONBLOCK</constant> is turned off initially.</para>
+ <para>Each invocation of these functions allocates a new log stream file descriptor,
+ that is not shared with prior or later invocations. The file descriptor is write-only (its reading direction
+ is shut down), and <constant>O_NONBLOCK</constant> is turned off initially.</para>
</refsect1>
<refsect1>
<title>Return Value</title>
- <para>The call returns a valid write-only file descriptor on
- success or a negative errno-style error code.</para>
+ <para>The call returns a valid write-only file descriptor on success or a negative errno-style error code.</para>
</refsect1>
<refsect1>
<title>Signal safety</title>
- <para><function>sd_journal_stream_fd()</function> is "async signal safe" in the meaning of <citerefentry
+ <para><function>sd_journal_stream_fd()</function> and <function>sd_journal_stream_fd_with_namespace()</function>
+ are "async signal safe" in the meaning of <citerefentry
project='man-pages'><refentrytitle>signal-safety</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
</para>
</refsect1>
<refsect1>
<title>History</title>
<para><function>sd_journal_stream_fd()</function> was added in version 187.</para>
+ <para><function>sd_journal_stream_fd_with_namespace()</function> was added in version 256.</para>
</refsect1>
<refsect1>
</variablelist>
<para>The notification messages sent by services are interpreted by the service manager. Unknown
- assignments may be logged, but are otherwise ignored. Thus, it is not useful to send assignments which
- are not in this list. The service manager also sends some messages to <emphasis>its</emphasis>
- notification socket, which are then consumed by the machine or container manager.</para>
+ assignments are ignored. Thus, it is is safe (but often without effect) to send assignments which are not
+ in this list. The protocol is extensible, but care should be taken to ensure private extensions are
+ recognizable as such. Specifically, it is recommend to prefix them with <literal>X_</literal> followed by
+ some namespace identifier. The service manager also sends some messages to <emphasis>its</emphasis>
+ notification socket, which may then consumed by a supervising machine or container manager further up the
+ stack. The service manager sends a number of extension fields, for example
+ <varname>X_SYSTEMD_UNIT_ACTIVE=</varname>, for details see
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para>
</refsect1>
<refsect1>
<constant>AF_VSOCK</constant> address, which is useful for hypervisors/VMMs or other processes on the
host to receive a notification when a virtual machine has finished booting. Note that in case the
hypervisor does not support <constant>SOCK_DGRAM</constant> over <constant>AF_VSOCK</constant>,
- <constant>SOCK_SEQPACKET</constant> will be used instead. The address should be in the form:
- <literal>vsock:CID:PORT</literal>. Note that unlike other uses of vsock, the CID is mandatory and cannot
- be <literal>VMADDR_CID_ANY</literal>. Note that PID1 will send the VSOCK packets from a privileged port
- (i.e.: lower than 1024), as an attempt to address concerns that unprivileged processes in the guest might
- try to send malicious notifications to the host, driving it to make destructive decisions based on
- them.</para>
+ <constant>SOCK_SEQPACKET</constant> will be used instead. <literal>vsock-stream</literal>,
+ <literal>vsock-dgram</literal> and <literal>vsock-seqpacket</literal> can be used instead of
+ <literal>vsock</literal> to force usage of the corresponding socket type. The address should be in the
+ form: <literal>vsock:CID:PORT</literal>. Note that unlike other uses of vsock, the CID is mandatory and
+ cannot be <literal>VMADDR_CID_ANY</literal>. Note that PID1 will send the VSOCK packets from a
+ privileged port (i.e.: lower than 1024), as an attempt to address concerns that unprivileged processes in
+ the guest might try to send malicious notifications to the host, driving it to make destructive decisions
+ based on them.</para>
</refsect1>
<refsect1>
boot counting is used.</para>
<para>Internally, the service operates based on the <varname>LoaderBootCountPath</varname> EFI variable (of the
- vendor UUID <constant>4a67b082-0a4c-41cf-b6c7-440b29bb8c4</constant>), which is passed from the boot loader to the
+ vendor UUID <constant>4a67b082-0a4c-41cf-b6c7-440b29bb8c4f</constant>), which is passed from the boot loader to the
OS. It contains a file system path (relative to the EFI system partition) of the <ulink
url="https://uapi-group.org/specifications/specs/boot_loader_specification">Boot Loader Specification</ulink> compliant boot loader entry
file or unified kernel image file that was used to boot up the
similar, to extend the native firmware support.</para>
<para>Enrollment of Secure Boot variables can be performed manually or automatically if files are available
- under <filename>/loader/keys/<replaceable>NAME</replaceable>/{db,KEK,PK}.auth</filename>, <replaceable>NAME</replaceable>
+ under <filename>/loader/keys/<replaceable>NAME</replaceable>/{db,dbx,KEK,PK}.auth</filename>, <replaceable>NAME</replaceable>
being the display name for the set of variables in the menu. If one of the sets is named <filename>auto</filename>
then it might be enrolled automatically depending on whether <literal>secure-boot-enroll</literal> is set
to force or not.</para>
<refnamediv>
<refname>systemd-bsod.service</refname>
<refname>systemd-bsod</refname>
- <refpurpose>Displays boot-time emergency log message in full screen.</refpurpose>
+ <refpurpose>Displays boot-time emergency log message in full screen</refpurpose>
</refnamediv>
<refsynopsisdiv>
boolean argument.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--namespace=</option></term>
+
+ <listitem><para>Specifies the journal namespace to which the standard IO should be connected.
+ For details about journal namespaces, see
+ <citerefentry><refentrytitle>systemd-journald.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
+ </para>
+
+ <xi:include href="version-info.xml" xpointer="v256"/></listitem>
+ </varlistentry>
+
</variablelist>
</refsect1>
<refsect1>
<title>Exit status</title>
- <para>On success, 0 is returned, a non-zero failure code
- otherwise.</para>
+ <para>On success, 0 is returned, a non-zero failure code otherwise.</para>
</refsect1>
<refsect1>
<para><filename>systemd-cryptsetup</filename> is used to set up (with <command>attach</command>) and tear
down (with <command>detach</command>) access to an encrypted block device. It is primarily used via
<filename>systemd-cryptsetup@.service</filename> during early boot, but may also be be called manually.
- The positional arguments <parameter>VOLUME</parameter>, <parameter>SOURCEDEVICE</parameter>,
+ The positional arguments <parameter>VOLUME</parameter>, <parameter>SOURCE-DEVICE</parameter>,
<parameter>KEY-FILE</parameter>, and <parameter>CRYPTTAB-OPTIONS</parameter> have the same meaning as the
fields in <citerefentry><refentrytitle>crypttab</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
</para>
<para>In order to embed binary data into the credential data for <option>--set-credential=</option>,
use C-style escaping (i.e. <literal>\n</literal> to embed a newline, or <literal>\x00</literal> to
embed a <constant>NUL</constant> byte). Note that the invoking shell might already apply unescaping
- once, hence this might require double escaping!.</para>
+ once, hence this might require double escaping!</para>
<para>The
<citerefentry><refentrytitle>systemd-sysusers.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
<listitem><para>Generates/removes a <filename>.pcrlock</filename> file based on raw binary data. The
data is either read from the specified file or from STDIN (if none is specified). This requires that
- <option>--pcrs=</option> is specified. The generated pcrlock file is written to the file specified
+ <option>--pcrs=</option> is specified. The generated .pcrlock file is written to the file specified
via <option>--pcrlock=</option> or to STDOUT (if none is specified).</para>
<xi:include href="version-info.xml" xpointer="v255"/>
<varlistentry>
<term><option>--nv-index=</option></term>
- <listitem><para>Specifies to NV index to store the policy in. Honoured by
+ <listitem><para>Specifies the NV index to store the policy in. Honoured by
<command>make-policy</command>. If not specified the command will automatically pick a free NV
index.</para>
<literal>kexec</literal>, depending on the chosen action. All executables in this directory are executed
in parallel, and execution of the action is not continued before all executables finished. Note that
these executables are run <emphasis>after</emphasis> all services have been shut down, and after most
- mounts have been detached (the root file system as well as <filename>/run/</filename> and various API
+ mounts have been unmounted (the root file system as well as <filename>/run/</filename> and various API
file systems are still around though). This means any programs dropped into this directory must be
prepared to run in such a limited execution environment and not rely on external services or hierarchies
such as <filename>/var/</filename> to be around (or writable).</para>
<title>Generate a configuration extension image</title>
<para>The following creates a configuration extension DDI (confext) for an
- <filename>/etc/motd</filename> update.</para>
+ <filename>/etc/motd</filename> update:</para>
<programlisting>mkdir tree tree/etc tree/etc/extension-release.d
echo "Hello World" > tree/etc/motd
<member><citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-mount</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
- <member><citerefentry><refentrytitle>uid0</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
+ <member><citerefentry><refentrytitle>run0</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
via <varname>SurviveFinalKillSignal=yes</varname>, and also be configured to avoid being stopped on
isolate via <varname>IgnoreOnIsolate=yes</varname>. They also have to be configured to be stopped on
normal shutdown, reboot and maintenance mode. Finally, they have to be ordered after
- <constant>basic.target</constant> to ensure correct ordeering on boot. Note that in case any new or
+ <constant>basic.target</constant> to ensure correct ordering on boot. Note that in case any new or
custom units are used to isolate to, or that implement an equivalent shutdown functionality, they will
also have to be configured manually for correct ordering and conflicting. For example:</para>
<programlisting>[Unit]
-Description=My surviving service
+Description=My Surviving Service
SurviveFinalKillSignal=yes
IgnoreOnIsolate=yes
DefaultDependencies=no
After=basic.target
-Conflicts=reboot.target
-Before=reboot.target
-Conflicts=kexec.target
-Before=kexec.target
-Conflicts=poweroff.target
-Before=poweroff.target
-Conflicts=halt.target
-Before=halt.target
-Conflicts=rescue.target
-Before=rescue.target
-Conflicts=emergency.target
-Before=emergency.target
+Conflicts=reboot.target kexec.target poweroff.target halt.target rescue.target emergency.target
+Before=reboot.target kexec.target poweroff.target halt.target rescue.target emergency.target
[Service]
Type=oneshot
-ExecStart=sleep infinity
- </programlisting>
+ExecStart=sleep infinity</programlisting>
</listitem>
<listitem><para>File system mounts may remain mounted during the transition, and complex storage
exposed NVMe-TCP mass storage devices. The NQN should follow the syntax described in <ulink
url="https://nvmexpress.org/wp-content/uploads/NVM-Express-Base-Specification-2.0c-2022.10.04-Ratified.pdf">NVM
Express Base Specification 2.0c</ulink>, section 4.5 "NVMe Qualified Names". Note that the NQN
- specified here will be suffixed with a dot and the the block device name before it is exposed on the
+ specified here will be suffixed with a dot and the block device name before it is exposed on the
NVMe target. If not specified defaults to
<literal>nqn.2023-10.io.systemd:storagetm.<replaceable>ID</replaceable></literal>, where ID is
replaced by a 128bit ID derived from
but the used architecture identifiers are the same as for <varname>ConditionArchitecture=</varname>
described in <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
<varname>EXTENSION_RELOAD_MANAGER=</varname> can be set to 1 if the extension requires a service manager reload after application
- of the extension. Note that the for the reasons mentioned earlier:
+ of the extension. Note that for the reasons mentioned earlier:
<ulink url="https://systemd.io/PORTABLE_SERVICES">Portable Services</ulink> remain
the recommended way to ship system services.
<para>The services will store the public key of the SRK key pair in a PEM file in
<filename>/run/systemd/tpm2-srk-public-key.pem</filename> and
- <filename>/var/lib/systemd/tpm2-srk-public-key.pem</filename>. It will also store it in TPM2B_PUBLIC
+ <filename>/var/lib/systemd/tpm2-srk-public-key.pem</filename>. They will also store it in TPM2B_PUBLIC
format in <filename>/run/systemd/tpm2-srk-public-key.tpm2_public</filename> and
<filename>/var/lib/systemd/tpm2-srk-public-key.tpm2b_public</filename>.</para>
<refnamediv>
<refname>systemd-vmspawn</refname>
- <refpurpose>Spawn an OS in a virtual machine.</refpurpose>
+ <refpurpose>Spawn an OS in a virtual machine</refpurpose>
</refnamediv>
<refsynopsisdiv>
<xi:include href="version-info.xml" xpointer="v256"/>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><option>--pass-ssh-key=</option><replaceable>BOOL</replaceable></term>
+
+ <listitem><para>By default an SSH key is generated to allow <command>systemd-vmspawn</command> to open
+ a D-Bus connection to the VM's systemd bus. Setting this to "no" will disable SSH key generation.</para>
+
+ <para>The generated keys are ephemeral. That is they are valid only for the current invocation of <command>systemd-vmspawn</command>,
+ and are typically not persisted.</para>
+
+ <xi:include href="version-info.xml" xpointer="v256"/>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--ssh-key-type=</option><replaceable>TYPE</replaceable></term>
+
+ <listitem><para>Configures the type of SSH key to generate, see
+ <citerefentry><refentrytitle>ssh-keygen</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ for more information.</para>
+
+ <para>By default <literal>ed25519</literal> keys are generated, however <literal>rsa</literal> keys
+ may also be useful if the VM has a particularly old version of <command>sshd</command></para>.
+
+ <xi:include href="version-info.xml" xpointer="v256"/>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect2>
<para>In order to embed binary data into the credential data for <option>--set-credential=</option>,
use C-style escaping (i.e. <literal>\n</literal> to embed a newline, or <literal>\x00</literal> to
embed a <constant>NUL</constant> byte). Note that the invoking shell might already apply unescaping
- once, hence this might require double escaping!.</para>
+ once, hence this might require double escaping!</para>
<xi:include href="version-info.xml" xpointer="v255"/></listitem>
</varlistentry>
<xi:include href="version-info.xml" xpointer="v236"/>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>SubType=</varname></term>
+ <listitem>
+ <para>A subtype of the network service as defined in the section 7.1 of <ulink
+ url="https://tools.ietf.org/html/rfc6763">RFC 6763</ulink>, e.g. <literal>_printer</literal>.
+ </para>
+
+ <xi:include href="version-info.xml" xpointer="v256"/>
+ </listitem>
+ </varlistentry>
<varlistentry>
<term><varname>Port=</varname></term>
<listitem>
<literal>ipv4</literal>, <literal>ipv6</literal>, <literal>both</literal>, or
<literal>no</literal>. Defaults to <literal>no</literal>.</para>
<para>Note. Any positive boolean values such as <literal>yes</literal> or
- <literal>true</literal> are now deprecated. Please use one of the values in the above.</para>
+ <literal>true</literal> are now deprecated. Please use one of the values above.</para>
<xi:include href="version-info.xml" xpointer="v219"/>
</listitem>
Address=192.168.0.2/24
[DHCPServer]
ServerAddress=192.168.0.1/24</programlisting>
- are equivalent to the following.
+ are equivalent to the following:
<programlisting>[Network]
DHCPServer=yes
Address=192.168.0.2/24
<listitem><para>Takes a timespan. Configures the retransmit time, used by clients to retransmit Neighbor
Solicitation messages on address resolution and the Neighbor Unreachability Detection algorithm.
- An integer the default unit of seconds, in the range 0…4294967295 msec. Defaults to 0.</para>
+ An integer, the default unit is seconds, in the range 0…4294967295 msec. Defaults to 0.</para>
<xi:include href="version-info.xml" xpointer="v255"/>
</listitem>
<varlistentry>
<term><varname>HomeAgent=</varname></term>
- <listitem><para>Takes a boolean. Specifies that IPv6 router advertisements which indicates to hosts that
- the router acts as a Home Agent and includes a Home Agent Option. Defaults to false. See
+ <listitem><para>Takes a boolean. Specifies that IPv6 router advertisements which indicate to hosts that
+ the router acts as a Home Agent and includes a Home Agent option. Defaults to false. See
<ulink url="https://tools.ietf.org/html/rfc6275">RFC 6275</ulink> for further details.</para>
<xi:include href="version-info.xml" xpointer="v255"/>
<varlistentry>
<term><varname>HomeAgentLifetimeSec=</varname></term>
- <listitem><para>Takes a timespan. Specifies the lifetime of the Home Agent. An integer the default unit of seconds,
+ <listitem><para>Takes a timespan. Specifies the lifetime of the Home Agent. An integer, the default unit is seconds,
in the range 1…65535. Defaults to the value set to <varname>RouterLifetimeSec=</varname>.</para>
<xi:include href="version-info.xml" xpointer="v255"/>
<term><filename>250-firmware-code-early.pcrlock</filename></term>
<listitem><para>Firmware code measurements, as recorded to PCR 0 and 2, up to the separator
- measurement (see <filename>400-secureboot-separator.pcrlock.</filename> below). May be generated via
+ measurement (see <filename>400-secureboot-separator.pcrlock</filename> below). May be generated via
<command>systemd-pcrlock lock-firmware-code</command>.</para>
<xi:include href="version-info.xml" xpointer="v255"/></listitem>
<term><filename>250-firmware-config-early.pcrlock</filename></term>
<listitem><para>Firmware configuration measurements, as recorded to PCR 1 and 3, up to the separator
- measurement (see <filename>400-secureboot-separator.pcrlock.</filename> below). May be generated via
+ measurement (see <filename>400-secureboot-separator.pcrlock</filename> below). May be generated via
<command>systemd-pcrlock lock-firmware-config</command>.</para>
<xi:include href="version-info.xml" xpointer="v255"/></listitem>
<term><filename>550-firmware-code-late.pcrlock</filename></term>
<listitem><para>Firmware code measurements, as recorded to PCR 0 and 2, after the separator
- measurement (see <filename>400-secureboot-separator.pcrlock.</filename> above). May be generated via
+ measurement (see <filename>400-secureboot-separator.pcrlock</filename> above). May be generated via
<command>systemd-pcrlock lock-firmware-code</command>.</para>
<xi:include href="version-info.xml" xpointer="v255"/></listitem>
<term><filename>550-firmware-config-late.pcrlock</filename></term>
<listitem><para>Firmware configuration measurements, as recorded to PCR 1 and 3, after the separator
- measurement (see <filename>400-secureboot-separator.pcrlock.</filename> above). May be generated via
+ measurement (see <filename>400-secureboot-separator.pcrlock</filename> above). May be generated via
<command>systemd-pcrlock lock-firmware-config</command>.</para>
<xi:include href="version-info.xml" xpointer="v255"/></listitem>
<term><filename>700-action-efi-exit-boot-services.pcrlock</filename></term>
<listitem><para>The EFI action generated when <function>ExitBootServices()</function> is generated,
- i.e. the UEFI environment is left and the OS takes over. Covers the PCR 5 measurement. Statically
+ i.e. when the UEFI environment is left and the OS takes over. Covers the PCR 5 measurement. Statically
defined.</para>
<xi:include href="version-info.xml" xpointer="v255"/></listitem>
<row>
<entry><literal>:</literal></entry>
- <entry>If the executable path is prefixed with <literal>:</literal>, environment variable substitution (as described by the "Command Lines" section below) is not applied.</entry>
+ <entry>If the executable path is prefixed with <literal>:</literal>, environment variable substitution (as described below this table) is not applied.</entry>
</row>
<row>
<replaceable>x</replaceable> on a port <replaceable>y</replaceable> address in the
<constant>AF_VSOCK</constant> family. The CID is a unique 32-bit integer identifier in
<constant>AF_VSOCK</constant> analogous to an IP address. Specifying the CID is optional, and may be
- set to the empty string.</para>
+ set to the empty string. <literal>vsock</literal> may be replaced with
+ <literal>vsock-stream</literal>, <literal>vsock-dgram</literal> or <literal>vsock-seqpacket</literal>
+ to force usage of the corresponding socket type.</para>
<para>Note that <constant>SOCK_SEQPACKET</constant> (i.e.
<varname>ListenSequentialPacket=</varname>) is only available
<filename>sockets.target</filename>,
<filename>soft-reboot.target</filename>,
<filename>sound.target</filename>,
+ <filename>ssh-access.target</filename>,
<filename>storage-target-mode.target</filename>,
<filename>suspend.target</filename>,
<filename>swap.target</filename>,
the <literal>$portmap</literal> facility.</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><filename>ssh-access.target</filename></term>
+ <listitem>
+ <para>Service and socket units that provide remote SSH secure shell access to the local system
+ should pull in this unit and order themselves before this unit. It's supposed to act as a
+ milestone indicating if and when SSH access into the system is available. It should only become
+ active when an SSH port is bound for remote clients (i.e. if SSH is used as a local privilege
+ escalation mechanism, it should <emphasis>not</emphasis> involve this target unit), regardless of
+ the protocol choices, i.e. regardless if IPv4, IPv6 or <constant>AF_VSOCK</constant> is
+ used.</para>
+ <xi:include href="version-info.xml" xpointer="v256"/>
+ </listitem>
+ </varlistentry>
<varlistentry>
<term><filename>time-set.target</filename></term>
<listitem>
<refsect1>
<title>Signals</title>
+ <para>The service listens to various UNIX process signals that can be used to request various actions
+ asynchronously. The signal handling is enabled very early during boot, before any further processes are
+ invoked. However, a supervising container manager or similar that intends to request these operations via
+ this mechanism must take into consideration that this functionality is not available during the earliest
+ initialization phase. An <function>sd_notify()</function> notification message carrying the
+ <varname>X_SYSTEMD_SIGNALS_LEVEL=2</varname> field is emitted once the signal handlers are enabled, see
+ below. This may be used to schedule submission of these signals correctly.</para>
+
<variablelist>
<varlistentry>
<term><constant>SIGTERM</constant></term>
<varlistentry>
<term><varname>$NOTIFY_SOCKET</varname></term>
- <listitem><para>Set by systemd for supervised processes for
- status and start-up completion notification. See
- <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>
- for more information.</para></listitem>
+ <listitem><para>Set by service manager for its services for status and readiness notifications. Also
+ consumed by service manager for notifying supervising container managers or service managers up the
+ stack about its own progress. See
+ <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry> and the
+ relevant section below for more information.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
- <title>System credentials</title>
+ <title>System Credentials</title>
<para>During initialization the service manager will import credentials from various sources into the
system's set of credentials, which can then be propagated into services and consumed by
<term><varname>vmm.notify_socket</varname></term>
<listitem>
<para>Contains a <constant>AF_VSOCK</constant> or <constant>AF_UNIX</constant> address where to
- send a <constant>READY=1</constant> notification datagram when the system has finished booting. See
- <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry> for
- more information. Note that in case the hypervisor does not support <constant>SOCK_DGRAM</constant>
- over <constant>AF_VSOCK</constant>, <constant>SOCK_SEQPACKET</constant> will be tried instead. The
- credential payload for <constant>AF_VSOCK</constant> should be in the form
- <literal>vsock:CID:PORT</literal>.</para>
-
- <para>This feature is useful for hypervisors/VMMs or other processes on the host to receive a
+ send a <constant>READY=1</constant> notification message when the service manager has completed
+ booting. See
+ <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry> and
+ the next section for more information. Note that in case the hypervisor does not support
+ <constant>SOCK_DGRAM</constant> over <constant>AF_VSOCK</constant>,
+ <constant>SOCK_SEQPACKET</constant> will be tried instead. The credential payload for
+ <constant>AF_VSOCK</constant> should be a string in the form
+ <literal>vsock:CID:PORT</literal>. <literal>vsock-stream</literal>, <literal>vsock-dgram</literal>
+ and <literal>vsock-seqpacket</literal> can be used instead of <literal>vsock</literal> to force
+ usage of the corresponding socket type.</para>
+
+ <para>This feature is useful for machine managers or other processes on the host to receive a
notification via VSOCK when a virtual machine has finished booting.</para>
<xi:include href="version-info.xml" xpointer="v254"/>
</listitem>
</varlistentry>
</variablelist>
+
+ <para>For a list of system credentials various other components of systemd consume, see
+ <citerefentry><refentrytitle>systemd.system-credentials</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Readiness Protocol</title>
+
+ <para>The service manager implements a readiness notification protocol both between the manager and its
+ services (i.e. down the stack), and between the manager and a potential supervisor further up the stack
+ (the latter could be a machine or container manager, or in case of a per-user service manager the system
+ service manager instance). The basic protocol (and the suggested API for it) is described in
+ <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
+
+ <para>The notification socket the service manager (including PID 1) uses for reporting readiness to its
+ own supervisor is set via the usual <varname>$NOTIFY_SOCKET</varname> environment variable (see
+ above). Since this is directly settable only for container managers and for the per-user instance of the
+ service manager, an additional mechanism to configure this is available, in particular intended for use
+ in VM environments: the <varname>vmm.notify_socket</varname> system credential (see above) may be set to
+ a suitable socket (typically an <constant>AF_VSOCK</constant> one) via SMBIOS Type 11 vendor strings. For
+ details see above.</para>
+
+ <para>The notification protocol from the service manager up the stack towards a supervisor supports a
+ number of extension fields that allow a supervisor to learn about specific properties of the system and
+ track its boot progress. Specifically the following fields are sent:</para>
+
+ <itemizedlist>
+ <listitem><para>An <varname>X_SYSTEMD_HOSTNAME=…</varname> message will be sent out once the initial
+ hostname for the system has been determined. Note that during later runtime the hostname might be
+ changed again programmatically, and (currently) no further notifications are sent out in that case.</para>
+
+ <xi:include href="version-info.xml" xpointer="v256"/></listitem>
+
+ <listitem><para>An <varname>X_SYSTEMD_MACHINE_ID=…</varname> message will be sent out once the machine
+ ID of the system has been determined. See
+ <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
+ details.</para>
+
+ <xi:include href="version-info.xml" xpointer="v256"/></listitem>
+
+ <listitem><para>An <varname>X_SYSTEMD_SIGNALS_LEVEL=…</varname> message will be sent out once the
+ service manager installed the various UNIX process signal handlers described above. The field's value
+ is an unsigned integer formatted as decimal string, and indicates the supported UNIX process signal
+ feature level of the service manager. Currently, only a single feature level is defined:</para>
+
+ <itemizedlist>
+ <listitem><para><varname>X_SYSTEMD_SIGNALS_LEVEL=2</varname> covers the various UNIX process signals
+ documented above – which are a superset of those supported by the historical SysV init
+ system.</para></listitem>
+ </itemizedlist>
+
+ <para>Signals sent to PID 1 before this message is sent might not be handled correctly yet. A consumer
+ of these messages should parse the value as an unsigned integer indication the level of support. For
+ now only the mentioned level 2 is defined, but later on additional levels might be defined with higher
+ integers, that will implement a superset of the currently defined behaviour.</para>
+
+ <xi:include href="version-info.xml" xpointer="v256"/></listitem>
+
+ <listitem><para><varname>X_SYSTEMD_UNIT_ACTIVE=…</varname> and
+ <varname>X_SYSTEMD_UNIT_INACTIVE=…</varname> messages will be sent out for each target unit as it
+ becomes active or stops being active. This is useful to track boot progress and functionality. For
+ example, once the <filename>ssh-access.target</filename> unit is reported started SSH access is
+ typically available, see
+ <citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
+ details.</para>
+
+ <xi:include href="version-info.xml" xpointer="v256"/></listitem>
+ </itemizedlist>
+
+ <para>Note that these extension fields are sent in addition to the regular <literal>READY=1</literal> and
+ <literal>RELOADING=1</literal> notifications.</para>
</refsect1>
<refsect1>
<arg choice="plain">call</arg>
<arg choice="plain"><replaceable>ADDRESS</replaceable></arg>
<arg choice="plain"><replaceable>METHOD</replaceable></arg>
- <arg choice="opt"><replaceable>PARAMETERS</replaceable></arg>
+ <arg choice="opt"><replaceable>ARGUMENTS</replaceable></arg>
</cmdsynopsis>
<cmdsynopsis>
<term><command>info</command> <replaceable>ADDRESS</replaceable></term>
<listitem><para>Show brief information about the specified service, including vendor name and list of
- implemented interfaces. Expects a service address in the formats described above.</para>
+ implemented interfaces. Expects a service address in one of the formats described above.</para>
<xi:include href="version-info.xml" xpointer="v255"/></listitem>
</varlistentry>
<term><command>list-interfaces</command> <replaceable>ADDRESS</replaceable></term>
<listitem><para>Show list of interfaces implemented by the specified service. Expects a service
- address in the formats described above.</para>
+ address in one of the formats described above.</para>
<xi:include href="version-info.xml" xpointer="v255"/></listitem>
</varlistentry>
<term><command>introspect</command> <replaceable>ADDRESS</replaceable> <replaceable>INTERFACE</replaceable></term>
<listitem><para>Show interface definition of the specified interface provided by the specified
- service. Expects a service address in the formats described above and a Varlink interface
+ service. Expects a service address in one of the formats described above and a Varlink interface
name.</para>
<xi:include href="version-info.xml" xpointer="v255"/></listitem>
<varlistentry>
<term><option>uuid=<replaceable>UUID</replaceable></option></term>
- <listitem><para>Use the provided <replaceable>UUID</replaceable> for format command instead of generating new one. The <replaceable>UUID</replaceable> must be
+ <listitem><para>Use the provided <replaceable>UUID</replaceable> instead of generating new one. The <replaceable>UUID</replaceable> must be
provided in standard <acronym>UUID</acronym> format, e.g. <literal>12345678-1234-1234-1234-123456789abc</literal>.</para>
<xi:include href="version-info.xml" xpointer="v254"/></listitem>
<term><option>fec-device=<replaceable>PATH</replaceable></option></term>
<listitem><para>Use forward error correction (<acronym>FEC</acronym>) to recover from corruption if hash verification fails. Use
- encoding data from the specified device. The fec device argument can be block device or file image. For format,
- if fec device path doesn't exist, it will be created as file. Note: block sizes for data and hash devices must
+ encoding data from the specified device. The fec device argument can be block device or file image.
+ If fec device path doesn't exist, it will be created as file. Note: block sizes for data and hash devices must
match. Also, if the verity data_device is encrypted the fec_device should be too.</para>
<xi:include href="version-info.xml" xpointer="v254"/></listitem>
#####################################################################
# Try to install the git pre-commit hook
-add_git_hook_sh = find_program('tools/add-git-hook.sh', required : false)
-if add_git_hook_sh.found()
- git_hook = run_command(add_git_hook_sh, check : false)
+git_setup_sh = find_program('tools/git-setup.sh', required : false)
+if git_setup_sh.found()
+ git_hook = run_command(git_setup_sh, check : false)
if git_hook.returncode() == 0
message(git_hook.stdout().strip())
endif
error('POSIX caps headers not found')
endif
foreach header : ['crypt.h',
+ 'linux/ioprio.h',
'linux/memfd.h',
+ 'linux/time_types.h',
'linux/vm_sockets.h',
'sys/auxv.h',
+ 'sys/sdt.h',
'threads.h',
'valgrind/memcheck.h',
'valgrind/valgrind.h',
- 'linux/time_types.h',
- 'sys/sdt.h',
]
conf.set10('HAVE_' + header.underscorify().to_upper(),
enforcing=0
systemd.early_core_pattern=/core
systemd.firstboot=no
+ systemd.setenv=SYSTEMD_ENABLE_LOG_CONTEXT=yes
+ SYSTEMD_ENABLE_LOG_CONTEXT=yes
kexec-tools
kmod
less
+ man
mtools
nano
nftables
# tmpfs during the build script so these changes don't end up in the image itself.
tee --append /etc/makepkg.conf >/dev/null <<EOF
CFLAGS="$CFLAGS -Og"
-OPTIONS=(!strip docs !libtool !staticlibs emptydirs !zipman purge debug !lto)
+OPTIONS=(!strip docs !libtool !staticlibs emptydirs !zipman purge !debug !lto)
EOF
# Linting the PKGBUILD takes multiple seconds every build so avoid that by nuking all the linting functions.
TS="${SOURCE_DATE_EPOCH:-$(date +%s)}"
fi
+sed --in-place "pkg/$PKG_SUBDIR/PKGBUILD" \
+ --expression "s/^_tag=.*/_tag=$(cat meson.version)/" \
+ --expression "s/^pkgrel=.*/pkgrel=$(date "+%Y%m%d%H%M%S" --date "@$TS")/"
+
# We get around makepkg's root check by setting EUID to something else.
# shellcheck disable=SC2046
env --chdir="pkg/$PKG_SUBDIR" \
BUILDDIR="$PWD/pkg/$PKG_SUBDIR" \
PKGDEST="$PACKAGEDIR" \
PKGEXT=".pkg.tar" \
- PKGVER="$(cat meson.version)" \
- PKGREL="$(date "+%Y%m%d%H%M%S" --date "@$TS")" \
MESON_EXTRA_CONFIGURE_OPTIONS="-D mode=developer -D b_sanitize=${SANITIZERS:-none}"
libasan
libcap-ng-utils
libubsan
+ man-db
netcat
openssh-clients
openssh-server
libcap-ng-utils
libtss2-rc0
libtss2-tcti-device0
+ man-db
netcat-openbsd
openssh-client
openssh-server
# See https://github.com/openSUSE/suse-module-tools/pull/71
rm -f "$BUILDROOT/usr/lib/modprobe.d/60-blacklist_fs-erofs.conf"
-mkosi-install systemd udev
+mkosi-install systemd udev systemd-experimental
openssh-clients
openssh-server
pam
+ python3-pefile
quota
rpm-build
rsync
-Subproject commit 733045c8f6b0acf2f0cfaac207500483a678f4d2
+Subproject commit 4d1ecb083589270e9137c8bd3838e6b73bfdbff7
-Subproject commit 5451923e3e7f5d6cc54f78a8b1d08317a42b4109
+Subproject commit 3b4728136724b960f453de26e59ee39061575a8f
-Subproject commit 2822a03dded26b9453bddbba7c6a152de8204aec
+Subproject commit 2e32a339a10caad9392a7049bccfd1c4cd7c24cc
-Subproject commit 37aca188c2ef606319217b30ff8b0c66df6c60f1
+Subproject commit af49127b4b18ee276af099c2144760c353c39646
+pkg/debian
src/basic/parse-util.c
src/boot/efi/addon.c
src/boot/efi/boot.c
comps="default nonetwork strict trusted"
;;
--copy)
- comps="copy symlink auto"
+ comps="copy symlink auto mixed"
;;
--host|-H)
comps=$(compgen -A hostname)
local -A OPTS=(
[STANDALONE]='-h --help --version'
- [ARG]='-t --identifier -p --priority --stderr-priority --level-prefix'
+ [ARG]='-t --identifier -p --priority --stderr-priority --level-prefix --namespace'
)
_init_completion || return
--level-prefix)
comps='yes no'
;;
+ --namespace)
+ comps=$(journalctl --list-namespaces --output=cat 2>/dev/null)
+ ;;
esac
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
return 0
{-t+,--identifier=}'[Set syslog identifier.]:syslog identifier:' \
{-p+,--priority=}'[Set priority value.]:value:({0..7})' \
'--level-prefix=[Control whether level prefix shall be parsed.]:boolean:(1 0)' \
+ '--namespace=[Connect to specified journal namespace.]:journal namespace:' \
':Message'
;;
systemd-cgls)
'test-builtin:test a built-in command'
'verify:verify udev rules files'
'wait:wait for devices or device symlinks being created'
- 'lock:lock a block device and run a comand'
+ 'lock:lock a block device and run a command'
)
if ((CURRENT == 1)); then
uint64_t *ret_badness,
char **ret_description) {
- _cleanup_free_ char *d = NULL;
+ const char *d;
uint64_t b;
+ int r;
assert(ret_badness);
assert(ret_description);
if (streq_ptr(info->user, NOBODY_USER_NAME)) {
- d = strdup("Service runs under as '" NOBODY_USER_NAME "' user, which should not be used for services");
+ d = "Service runs under as '" NOBODY_USER_NAME "' user, which should not be used for services";
b = 9;
} else if (info->dynamic_user && !STR_IN_SET(info->user, "0", "root")) {
- d = strdup("Service runs under a transient non-root user identity");
+ d = "Service runs under a transient non-root user identity";
b = 0;
} else if (info->user && !STR_IN_SET(info->user, "0", "root", "")) {
- d = strdup("Service runs under a static non-root user identity");
+ d = "Service runs under a static non-root user identity";
b = 0;
} else {
*ret_badness = 10;
return 0;
}
- if (!d)
- return log_oom();
+ r = strdup_to(ret_description, d);
+ if (r < 0)
+ return r;
*ret_badness = b;
- *ret_description = TAKE_PTR(d);
-
return 0;
}
const char *description;
uint64_t badness;
- char *copy;
int r;
assert(ret_badness);
description = "Service has no access to home directories";
}
- copy = strdup(description);
- if (!copy)
- return log_oom();
+ r = strdup_to(ret_description, description);
+ if (r < 0)
+ return r;
*ret_badness = badness;
- *ret_description = copy;
-
return 0;
}
const char *description;
uint64_t badness;
- char *copy;
int r;
assert(ret_badness);
description = "Service has limited write access to the OS file hierarchy";
}
- copy = strdup(description);
- if (!copy)
- return log_oom();
+ r = strdup_to(ret_description, description);
+ if (r < 0)
+ return r;
*ret_badness = badness;
- *ret_description = copy;
-
return 0;
}
uint64_t *ret_badness,
char **ret_description) {
- char *copy = NULL;
const char *d;
uint64_t b;
+ int r;
assert(ret_badness);
assert(ret_description);
b = 0;
}
- copy = strdup(d);
- if (!copy)
- return log_oom();
+ r = strdup_to(ret_description, d);
+ if (r < 0)
+ return r;
*ret_badness = b;
- *ret_description = copy;
-
return 0;
}
uint64_t *ret_badness,
char **ret_description) {
- char *d;
+ const char *d;
uint64_t b;
+ int r;
assert(ret_badness);
assert(ret_description);
if (set_isempty(info->system_call_architectures)) {
b = 10;
- d = strdup("Service may execute system calls with all ABIs");
+ d = "Service may execute system calls with all ABIs";
} else if (set_contains(info->system_call_architectures, "native") &&
set_size(info->system_call_architectures) == 1) {
b = 0;
- d = strdup("Service may execute system calls only with native ABI");
+ d = "Service may execute system calls only with native ABI";
} else {
b = 8;
- d = strdup("Service may execute system calls with multiple ABIs");
+ d = "Service may execute system calls with multiple ABIs";
}
- if (!d)
- return log_oom();
+ r = strdup_to(ret_description, d);
+ if (r < 0)
+ return r;
*ret_badness = b;
- *ret_description = d;
-
return 0;
}
assert(a->parameter < _SYSCALL_FILTER_SET_MAX);
const SyscallFilterSet *f = syscall_filter_sets + a->parameter;
- _cleanup_free_ char *d = NULL;
+ char *d;
uint64_t b;
int r;
if (!info->system_call_filter_allow_list && set_isempty(info->system_call_filter)) {
- r = free_and_strdup(&d, "Service does not filter system calls");
+ r = strdup_to(&d, "Service does not filter system calls");
b = 10;
} else {
bool bad;
if (r < 0)
return log_oom();
+ *ret_description = d;
*ret_badness = b;
- *ret_description = TAKE_PTR(d);
return 0;
}
uint64_t *ret_badness,
char **ret_description) {
- char *d = NULL;
+ const char *d;
uint64_t b;
+ int r;
assert(info);
assert(ret_badness);
assert(ret_description);
if (info->ip_filters_custom_ingress || info->ip_filters_custom_egress) {
- d = strdup("Service defines custom ingress/egress IP filters with BPF programs");
+ d = "Service defines custom ingress/egress IP filters with BPF programs";
b = 0;
} else if (!info->ip_address_deny_all) {
- d = strdup("Service does not define an IP address allow list");
+ d = "Service does not define an IP address allow list";
b = 10;
} else if (info->ip_address_allow_other) {
- d = strdup("Service defines IP address allow list with non-localhost entries");
+ d = "Service defines IP address allow list with non-localhost entries";
b = 5;
} else if (info->ip_address_allow_localhost) {
- d = strdup("Service defines IP address allow list with only localhost entries");
+ d = "Service defines IP address allow list with only localhost entries";
b = 2;
} else {
- d = strdup("Service blocks all IP address ranges");
+ d = "Service blocks all IP address ranges";
b = 0;
}
- if (!d)
- return log_oom();
+ r = strdup_to(ret_description, d);
+ if (r < 0)
+ return r;
*ret_badness = b;
- *ret_description = d;
-
return 0;
}
uint64_t *ret_badness,
char **ret_description) {
- char *d = NULL;
+ char *d;
uint64_t b;
assert(info);
for (;;) {
UnitInfo info;
- char *copy = NULL;
r = bus_parse_unit_info(reply, &info);
if (r < 0)
if (!GREEDY_REALLOC(list, n + 2))
return log_oom();
- copy = strdup(info.id);
- if (!copy)
- return log_oom();
+ r = strdup_to(&list[n], info.id);
+ if (r < 0)
+ return r;
- list[n++] = copy;
- list[n] = NULL;
+ list[++n] = NULL;
}
strv_sort(list);
return r;
for (const char *p = content;;) {
- _cleanup_free_ char *line = NULL, *key = NULL, *val = NULL;
+ _cleanup_free_ char *line = NULL, *key = NULL;
const char *q;
r = extract_first_word(&p, &line, "\n", 0);
if (!streq(key, event))
continue;
- val = strdup(q);
- if (!val)
- return -ENOMEM;
-
- *ret = TAKE_PTR(val);
- return 0;
+ return strdup_to(ret, q);
}
}
assert(ret);
FOREACH_DIRENT_ALL(de, d, return -errno) {
- char *b;
-
if (de->d_type != DT_DIR)
continue;
if (dot_or_dot_dot(de->d_name))
continue;
- b = strdup(de->d_name);
- if (!b)
- return -ENOMEM;
-
- *ret = b;
- return 1;
+ return strdup_to_full(ret, de->d_name);
}
*ret = NULL;
if (r < 0)
return r;
- if (c == raw)
+ if (c == raw) {
*ret_cgroup = TAKE_PTR(raw);
- else {
- char *n;
-
- n = strdup(c);
- if (!n)
- return -ENOMEM;
-
- *ret_cgroup = n;
+ return 0;
}
- return 0;
+ return strdup_to(ret_cgroup, c);
}
int cg_path_decode_unit(const char *cgroup, char **ret_unit) {
- char *c, *s;
- size_t n;
-
assert(cgroup);
assert(ret_unit);
- n = strcspn(cgroup, "/");
+ size_t n = strcspn(cgroup, "/");
if (n < 3)
return -ENXIO;
- c = strndupa_safe(cgroup, n);
+ char *c = strndupa_safe(cgroup, n);
c = cg_unescape(c);
if (!unit_name_is_valid(c, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
return -ENXIO;
- s = strdup(c);
- if (!s)
- return -ENOMEM;
-
- *ret_unit = s;
- return 0;
+ return strdup_to(ret_unit, c);
}
static bool valid_slice_name(const char *p, size_t n) {
if (!session_id_valid(start))
return -ENXIO;
- if (ret_session) {
- char *rr;
-
- rr = strdup(start);
- if (!rr)
- return -ENOMEM;
-
- *ret_session = rr;
- }
+ if (!ret_session)
+ return 0;
- return 0;
+ return strdup_to(ret_session, start);
}
int cg_pid_get_session(pid_t pid, char **ret_session) {
assert(p);
assert(ret_slice);
- /* Finds the right-most slice unit from the beginning, but
- * stops before we come to the first non-slice unit. */
+ /* Finds the right-most slice unit from the beginning, but stops before we come to
+ * the first non-slice unit. */
for (;;) {
- size_t n;
-
- p += strspn(p, "/");
+ const char *s;
+ int n;
- n = strcspn(p, "/");
- if (!valid_slice_name(p, n)) {
-
- if (!e) {
- char *s;
-
- s = strdup(SPECIAL_ROOT_SLICE);
- if (!s)
- return -ENOMEM;
+ n = path_find_first_component(&p, /* accept_dot_dot = */ false, &s);
+ if (n < 0)
+ return n;
+ if (!valid_slice_name(s, n))
+ break;
- *ret_slice = s;
- return 0;
- }
+ e = s;
+ }
- return cg_path_decode_unit(e, ret_slice);
- }
+ if (e)
+ return cg_path_decode_unit(e, ret_slice);
- e = p;
- p += n;
- }
+ return strdup_to(ret_slice, SPECIAL_ROOT_SLICE);
}
int cg_pid_get_slice(pid_t pid, char **ret_slice) {
assert(unit);
assert(ret);
- if (streq(unit, SPECIAL_ROOT_SLICE)) {
- char *x;
-
- x = strdup("");
- if (!x)
- return -ENOMEM;
- *ret = x;
- return 0;
- }
+ if (streq(unit, SPECIAL_ROOT_SLICE))
+ return strdup_to(ret, "");
if (!unit_name_is_valid(unit, UNIT_NAME_PLAIN))
return -EINVAL;
return r;
}
- char *fname = strdup(".");
- if (!fname)
- return -ENOMEM;
-
- *ret = fname;
- return 0;
+ return strdup_to(ret, ".");
}
int chase_and_open(const char *path, const char *root, ChaseFlags chase_flags, int open_flags, char **ret_path) {
}
int device_path_make_inaccessible(mode_t mode, char **ret) {
- char *s;
+ const char *s;
assert(ret);
if (S_ISCHR(mode))
- s = strdup("/run/systemd/inaccessible/chr");
+ s = "/run/systemd/inaccessible/chr";
else if (S_ISBLK(mode))
- s = strdup("/run/systemd/inaccessible/blk");
+ s = "/run/systemd/inaccessible/blk";
else
return -ENODEV;
- if (!s)
- return -ENOMEM;
- *ret = s;
- return 0;
+ return strdup_to(ret, s);
}
int device_path_make_canonical(mode_t mode, dev_t devnum, char **ret) {
/* For testing purposes it is sometimes useful to be able to override this */
e = secure_getenv("SYSTEMD_EFI_OPTIONS");
- if (e) {
- char *m;
-
- m = strdup(e);
- if (!m)
- return -ENOMEM;
-
- *ret = m;
- return 0;
- }
+ if (e)
+ return strdup_to(ret, e);
r = read_one_line_file(EFIVAR_CACHE_PATH(EFI_SYSTEMD_VARIABLE(SystemdOptions)), ret);
if (r == -ENOENT)
int read_stripped_line(FILE *f, size_t limit, char **ret) {
_cleanup_free_ char *s = NULL;
- int r;
+ int r, k;
assert(f);
return r;
if (ret) {
- const char *p;
-
- p = strstrip(s);
+ const char *p = strstrip(s);
if (p == s)
*ret = TAKE_PTR(s);
else {
- char *copy;
-
- copy = strdup(p);
- if (!copy)
- return -ENOMEM;
-
- *ret = copy;
+ k = strdup_to(ret, p);
+ if (k < 0)
+ return k;
}
}
- return r;
+ return r > 0; /* Return 1 if something was read. */
}
int safe_fgetc(FILE *f, char *ret) {
}
int format_ifname_full_alloc(int ifindex, FormatIfnameFlag flag, char **ret) {
- char buf[IF_NAMESIZE], *copy;
+ char buf[IF_NAMESIZE];
int r;
assert(ret);
if (r < 0)
return r;
- copy = strdup(buf);
- if (!copy)
- return -ENOMEM;
-
- *ret = copy;
- return 0;
+ return strdup_to(ret, buf);
}
char *format_bytes_full(char *buf, size_t l, uint64_t t, FormatBytesFlag flag) {
return TAKE_FD(fd);
}
+
+int link_fd(int fd, int newdirfd, const char *newpath) {
+ int r;
+
+ assert(fd >= 0);
+ assert(newdirfd >= 0 || newdirfd == AT_FDCWD);
+ assert(newpath);
+
+ /* Try linking via /proc/self/fd/ first. */
+ r = RET_NERRNO(linkat(AT_FDCWD, FORMAT_PROC_FD_PATH(fd), newdirfd, newpath, AT_SYMLINK_FOLLOW));
+ if (r != -ENOENT)
+ return r;
+
+ /* Fall back to symlinking via AT_EMPTY_PATH as fallback (this requires CAP_DAC_READ_SEARCH and a
+ * more recent kernel, but does not require /proc/ mounted) */
+ if (proc_mounted() != 0)
+ return r;
+
+ return RET_NERRNO(linkat(fd, "", newdirfd, newpath, AT_EMPTY_PATH));
+}
+
+int linkat_replace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) {
+ _cleanup_close_ int old_fd = -EBADF;
+ int r;
+
+ assert(olddirfd >= 0 || olddirfd == AT_FDCWD);
+ assert(newdirfd >= 0 || newdirfd == AT_FDCWD);
+ assert(!isempty(newpath)); /* source path is optional, but the target path is not */
+
+ /* Like linkat() but replaces the target if needed. Is a NOP if source and target already share the
+ * same inode. */
+
+ if (olddirfd == AT_FDCWD && isempty(oldpath)) /* Refuse operating on the cwd (which is a dir, and dirs can't be hardlinked) */
+ return -EISDIR;
+
+ if (path_implies_directory(oldpath)) /* Refuse these definite directories early */
+ return -EISDIR;
+
+ if (path_implies_directory(newpath))
+ return -EISDIR;
+
+ /* First, try to link this directly */
+ if (oldpath)
+ r = RET_NERRNO(linkat(olddirfd, oldpath, newdirfd, newpath, 0));
+ else
+ r = link_fd(olddirfd, newdirfd, newpath);
+ if (r >= 0)
+ return 0;
+ if (r != -EEXIST)
+ return r;
+
+ old_fd = xopenat(olddirfd, oldpath, O_PATH|O_CLOEXEC);
+ if (old_fd < 0)
+ return old_fd;
+
+ struct stat old_st;
+ if (fstat(old_fd, &old_st) < 0)
+ return -errno;
+
+ if (S_ISDIR(old_st.st_mode)) /* Don't bother if we are operating on a directory */
+ return -EISDIR;
+
+ struct stat new_st;
+ if (fstatat(newdirfd, newpath, &new_st, AT_SYMLINK_NOFOLLOW) < 0)
+ return -errno;
+
+ if (S_ISDIR(new_st.st_mode)) /* Refuse replacing directories */
+ return -EEXIST;
+
+ if (stat_inode_same(&old_st, &new_st)) /* Already the same inode? Then shortcut this */
+ return 0;
+
+ _cleanup_free_ char *tmp_path = NULL;
+ r = tempfn_random(newpath, /* extra= */ NULL, &tmp_path);
+ if (r < 0)
+ return r;
+
+ r = link_fd(old_fd, newdirfd, tmp_path);
+ if (r < 0) {
+ if (!ERRNO_IS_PRIVILEGE(r))
+ return r;
+
+ /* If that didn't work due to permissions then go via the path of the dentry */
+ r = RET_NERRNO(linkat(olddirfd, oldpath, newdirfd, tmp_path, 0));
+ if (r < 0)
+ return r;
+ }
+
+ r = RET_NERRNO(renameat(newdirfd, tmp_path, newdirfd, newpath));
+ if (r < 0) {
+ (void) unlinkat(newdirfd, tmp_path, /* flags= */ 0);
+ return r;
+ }
+
+ return 0;
+}
static inline int xopenat_lock(int dir_fd, const char *path, int open_flags, LockType locktype, int operation) {
return xopenat_lock_full(dir_fd, path, open_flags, 0, 0, locktype, operation);
}
+
+int link_fd(int fd, int newdirfd, const char *newpath);
+
+int linkat_replace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath);
return label_ops->post(dir_fd, path);
}
+
+void label_ops_reset(void) {
+ label_ops = NULL;
+}
int label_ops_pre(int dir_fd, const char *path, mode_t mode);
int label_ops_post(int dir_fd, const char *path);
+void label_ops_reset(void);
static LogTarget log_target = LOG_TARGET_CONSOLE;
static int log_max_level = LOG_INFO;
+static int log_target_max_level[] = {
+ [LOG_TARGET_CONSOLE] = INT_MAX,
+ [LOG_TARGET_KMSG] = INT_MAX,
+ [LOG_TARGET_SYSLOG] = INT_MAX,
+ [LOG_TARGET_JOURNAL] = INT_MAX,
+};
static int log_facility = LOG_DAEMON;
static bool ratelimit_kmsg = true;
if (console_fd < 0)
return 0;
+ if (LOG_PRI(level) > log_target_max_level[LOG_TARGET_CONSOLE])
+ return 0;
+
if (log_target == LOG_TARGET_CONSOLE_PREFIXED) {
xsprintf(prefix, "<%i>", level);
iovec[n++] = IOVEC_MAKE_STRING(prefix);
if (syslog_fd < 0)
return 0;
+ if (LOG_PRI(level) > log_target_max_level[LOG_TARGET_SYSLOG])
+ return 0;
+
xsprintf(header_priority, "<%i>", level);
t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC);
if (kmsg_fd < 0)
return 0;
+ if (LOG_PRI(level) > log_target_max_level[LOG_TARGET_KMSG])
+ return 0;
+
if (ratelimit_kmsg && !ratelimit_below(&ratelimit)) {
if (ratelimit_num_dropped(&ratelimit) > 1)
return 0;
if (journal_fd < 0)
return 0;
+ if (LOG_PRI(level) > log_target_max_level[LOG_TARGET_JOURNAL])
+ return 0;
+
iovec_len = MIN(6 + _log_context_num_fields * 2, IOVEC_MAX);
iovec = newa(struct iovec, iovec_len);
PROTECT_ERRNO;
log_assert(LOG_DEBUG, text, file, line, func,
- "Assertion '%s' failed at %s:%u, function %s(). Ignoring.");
+ "Assertion '%s' failed at %s:%u, function %s(), ignoring.");
}
int log_oom_internal(int level, const char *file, int line, const char *func) {
int log_set_max_level_from_string(const char *e) {
int r;
- r = log_level_from_string(e);
+ for (;;) {
+ _cleanup_free_ char *word = NULL, *prefix = NULL;
+ LogTarget target;
+ const char *colon;
+
+ r = extract_first_word(&e, &word, ",", 0);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ colon = strchr(word, ':');
+ if (!colon) {
+ r = log_level_from_string(word);
+ if (r < 0)
+ return r;
+
+ log_set_max_level(r);
+ continue;
+ }
+
+ prefix = strndup(word, colon - word);
+ if (!prefix)
+ return -ENOMEM;
+
+ target = log_target_from_string(prefix);
+ if (target < 0)
+ return target;
+
+ if (target >= _LOG_TARGET_SINGLE_MAX)
+ return -EINVAL;
+
+ r = log_level_from_string(colon + 1);
+ if (r < 0)
+ return r;
+
+ log_target_max_level[target] = r;
+ }
+
+ return 0;
+}
+
+int log_max_levels_to_string(int level, char **ret) {
+ _cleanup_free_ char *s = NULL;
+ int r;
+
+ assert(ret);
+
+ r = log_level_to_string_alloc(level, &s);
if (r < 0)
return r;
- log_set_max_level(r);
+ for (LogTarget target = 0; target < _LOG_TARGET_SINGLE_MAX; target++) {
+ _cleanup_free_ char *l = NULL;
+
+ if (log_target_max_level[target] == INT_MAX)
+ continue;
+
+ r = log_level_to_string_alloc(log_target_max_level[target], &l);
+ if (r < 0)
+ return r;
+
+ r = strextendf_with_separator(&s, ",", "%s:%s", log_target_to_string(target), l);
+ if (r < 0)
+ return r;
+ }
+
+ *ret = TAKE_PTR(s);
return 0;
}
return 0;
if (log_set_target_from_string(value) < 0)
- log_warning("Failed to parse log target '%s'. Ignoring.", value);
+ log_warning("Failed to parse log target '%s', ignoring.", value);
} else if (proc_cmdline_key_streq(key, "systemd.log_level")) {
return 0;
if (log_set_max_level_from_string(value) < 0)
- log_warning("Failed to parse log level '%s'. Ignoring.", value);
+ log_warning("Failed to parse log level setting '%s', ignoring.", value);
} else if (proc_cmdline_key_streq(key, "systemd.log_color")) {
if (log_show_color_from_string(value ?: "1") < 0)
- log_warning("Failed to parse log color setting '%s'. Ignoring.", value);
+ log_warning("Failed to parse log color setting '%s', ignoring.", value);
} else if (proc_cmdline_key_streq(key, "systemd.log_location")) {
if (log_show_location_from_string(value ?: "1") < 0)
- log_warning("Failed to parse log location setting '%s'. Ignoring.", value);
+ log_warning("Failed to parse log location setting '%s', ignoring.", value);
} else if (proc_cmdline_key_streq(key, "systemd.log_tid")) {
if (log_show_tid_from_string(value ?: "1") < 0)
- log_warning("Failed to parse log tid setting '%s'. Ignoring.", value);
+ log_warning("Failed to parse log tid setting '%s', ignoring.", value);
} else if (proc_cmdline_key_streq(key, "systemd.log_time")) {
if (log_show_time_from_string(value ?: "1") < 0)
- log_warning("Failed to parse log time setting '%s'. Ignoring.", value);
+ log_warning("Failed to parse log time setting '%s', ignoring.", value);
} else if (proc_cmdline_key_streq(key, "systemd.log_ratelimit_kmsg")) {
if (log_set_ratelimit_kmsg_from_string(value ?: "1") < 0)
- log_warning("Failed to parse log ratelimit kmsg boolean '%s'. Ignoring.", value);
+ log_warning("Failed to parse log ratelimit kmsg boolean '%s', ignoring.", value);
}
return 0;
e = getenv("SYSTEMD_LOG_TARGET");
if (e && log_set_target_from_string(e) < 0)
- log_warning("Failed to parse log target '%s'. Ignoring.", e);
+ log_warning("Failed to parse log target '%s', ignoring.", e);
e = getenv("SYSTEMD_LOG_LEVEL");
if (e && log_set_max_level_from_string(e) < 0)
- log_warning("Failed to parse log level '%s'. Ignoring.", e);
+ log_warning("Failed to parse log level '%s', ignoring.", e);
e = getenv("SYSTEMD_LOG_COLOR");
if (e && log_show_color_from_string(e) < 0)
- log_warning("Failed to parse log color '%s'. Ignoring.", e);
+ log_warning("Failed to parse log color '%s', ignoring.", e);
e = getenv("SYSTEMD_LOG_LOCATION");
if (e && log_show_location_from_string(e) < 0)
- log_warning("Failed to parse log location '%s'. Ignoring.", e);
+ log_warning("Failed to parse log location '%s', ignoring.", e);
e = getenv("SYSTEMD_LOG_TIME");
if (e && log_show_time_from_string(e) < 0)
- log_warning("Failed to parse log time '%s'. Ignoring.", e);
+ log_warning("Failed to parse log time '%s', ignoring.", e);
e = getenv("SYSTEMD_LOG_TID");
if (e && log_show_tid_from_string(e) < 0)
- log_warning("Failed to parse log tid '%s'. Ignoring.", e);
+ log_warning("Failed to parse log tid '%s', ignoring.", e);
e = getenv("SYSTEMD_LOG_RATELIMIT_KMSG");
if (e && log_set_ratelimit_kmsg_from_string(e) < 0)
- log_warning("Failed to parse log ratelimit kmsg boolean '%s'. Ignoring.", e);
+ log_warning("Failed to parse log ratelimit kmsg boolean '%s', ignoring.", e);
}
void log_parse_environment(void) {
typedef enum LogTarget{
LOG_TARGET_CONSOLE,
- LOG_TARGET_CONSOLE_PREFIXED,
LOG_TARGET_KMSG,
LOG_TARGET_JOURNAL,
- LOG_TARGET_JOURNAL_OR_KMSG,
LOG_TARGET_SYSLOG,
+ LOG_TARGET_CONSOLE_PREFIXED,
+ LOG_TARGET_JOURNAL_OR_KMSG,
LOG_TARGET_SYSLOG_OR_KMSG,
LOG_TARGET_AUTO, /* console if stderr is not journal, JOURNAL_OR_KMSG otherwise */
LOG_TARGET_NULL,
- _LOG_TARGET_MAX,
+ _LOG_TARGET_SINGLE_MAX = LOG_TARGET_SYSLOG + 1,
+ _LOG_TARGET_MAX = LOG_TARGET_NULL + 1,
_LOG_TARGET_INVALID = -EINVAL,
} LogTarget;
void log_set_max_level(int level);
int log_set_max_level_from_string(const char *e);
int log_get_max_level(void) _pure_;
+int log_max_levels_to_string(int level, char **ret);
void log_set_facility(int facility);
((long)(_current_ - _entries_) < (long)(ELEMENTSOF(_entries_) - 1)) && ({ entry = *_current_; true; }); \
_current_++)
+#define DECIMAL_STR_FMT(x) _Generic((x), \
+ char: "%c", \
+ bool: "%d", \
+ unsigned char: "%d", \
+ short: "%hd", \
+ unsigned short: "%hu", \
+ int: "%d", \
+ unsigned: "%u", \
+ long: "%ld", \
+ unsigned long: "%lu", \
+ long long: "%lld", \
+ unsigned long long: "%llu")
+
#include "log.h"
#include <linux/audit.h>
#if HAVE_AUDIT
-#include <libaudit.h>
+# include <libaudit.h>
#endif
#ifndef AUDIT_SERVICE_START
-#define AUDIT_SERVICE_START 1130 /* Service (daemon) start */
+# define AUDIT_SERVICE_START 1130 /* Service (daemon) start */
+#else
+assert_cc(AUDIT_SERVICE_START == 1130);
#endif
#ifndef AUDIT_SERVICE_STOP
-#define AUDIT_SERVICE_STOP 1131 /* Service (daemon) stop */
+# define AUDIT_SERVICE_STOP 1131 /* Service (daemon) stop */
+#else
+assert_cc(AUDIT_SERVICE_STOP == 1131);
#endif
#ifndef MAX_AUDIT_MESSAGE_LENGTH
-#define MAX_AUDIT_MESSAGE_LENGTH 8970
+# define MAX_AUDIT_MESSAGE_LENGTH 8970
+#else
+assert_cc(MAX_AUDIT_MESSAGE_LENGTH == 8970);
#endif
+/* Note: we check for AUDIT_NLGRP_MAX because it's a define, but we actually
+ * need AUDIT_NLGRP_READLOG which is an enum. */
#ifndef AUDIT_NLGRP_MAX
-#define AUDIT_NLGRP_READLOG 1
+# define AUDIT_NLGRP_READLOG 1
+#else
+assert_cc(AUDIT_NLGRP_READLOG == 1);
#endif
/* 3a101b8de0d39403b2c7e5c23fd0b005668acf48 (3.16) */
#ifndef CAP_AUDIT_READ
# define CAP_AUDIT_READ 37
+#else
+assert_cc(CAP_AUDIT_READ == 37);
#endif
/* 980737282232b752bb14dab96d77665c15889c36 (5.8) */
#ifndef CAP_PERFMON
# define CAP_PERFMON 38
+#else
+assert_cc(CAP_PERFMON == 38);
#endif
/* a17b53c4a4b55ec322c132b6670743612229ee9c (5.8) */
#ifndef CAP_BPF
# define CAP_BPF 39
+#else
+assert_cc(CAP_BPF == 39);
#endif
/* 124ea650d3072b005457faed69909221c2905a1f (5.9) */
#ifndef CAP_CHECKPOINT_RESTORE
# define CAP_CHECKPOINT_RESTORE 40
+#else
+assert_cc(CAP_CHECKPOINT_RESTORE == 40);
#endif
#define SYSTEMD_CAP_LAST_CAP CAP_CHECKPOINT_RESTORE
# undef CAP_LAST_CAP
# endif
#endif
+
#ifndef CAP_LAST_CAP
# define CAP_LAST_CAP SYSTEMD_CAP_LAST_CAP
#endif
#pragma once
#ifndef DRM_IOCTL_SET_MASTER
-#define DRM_IOCTL_SET_MASTER _IO('d', 0x1e)
+# define DRM_IOCTL_SET_MASTER _IO('d', 0x1e)
#endif
#ifndef DRM_IOCTL_DROP_MASTER
-#define DRM_IOCTL_DROP_MASTER _IO('d', 0x1f)
+# define DRM_IOCTL_DROP_MASTER _IO('d', 0x1f)
#endif
#include <linux/types.h>
+#include "macro.h"
+
/* linux/fs.h */
#ifndef RENAME_NOREPLACE /* 0a7c3937a1f23f8cb5fc77ae01661e9968a51d0c (3.15) */
#define RENAME_NOREPLACE (1 << 0)
/* linux/fs.h or sys/mount.h */
#ifndef MS_MOVE
-#define MS_MOVE 8192
+# define MS_MOVE 8192
+#else
+assert_cc(MS_MOVE == 8192);
#endif
#ifndef MS_REC
-#define MS_REC 16384
+# define MS_REC 16384
+#else
+assert_cc(MS_REC == 16384);
#endif
#ifndef MS_PRIVATE
-#define MS_PRIVATE (1<<18)
+# define MS_PRIVATE (1<<18)
+#else
+assert_cc(MS_PRIVATE == (1<<18));
#endif
#ifndef MS_SLAVE
-#define MS_SLAVE (1<<19)
+# define MS_SLAVE (1<<19)
+#else
+assert_cc(MS_SLAVE == (1<<19));
#endif
#ifndef MS_SHARED
-#define MS_SHARED (1<<20)
+# define MS_SHARED (1<<20)
+#else
+assert_cc(MS_SHARED == (1<<20));
#endif
#ifndef MS_RELATIME
-#define MS_RELATIME (1<<21)
+# define MS_RELATIME (1<<21)
+#else
+assert_cc(MS_RELATIME == (1<<21));
#endif
#ifndef MS_KERNMOUNT
-#define MS_KERNMOUNT (1<<22)
+# define MS_KERNMOUNT (1<<22)
+#else
+assert_cc(MS_KERNMOUNT == (1<<22));
#endif
#ifndef MS_I_VERSION
-#define MS_I_VERSION (1<<23)
+# define MS_I_VERSION (1<<23)
+#else
+assert_cc(MS_I_VERSION == (1<<23));
#endif
#ifndef MS_STRICTATIME
-#define MS_STRICTATIME (1<<24)
+# define MS_STRICTATIME (1<<24)
+#else
+assert_cc(MS_STRICTATIME == (1 << 24));
#endif
#ifndef MS_LAZYTIME
-#define MS_LAZYTIME (1<<25)
+# define MS_LAZYTIME (1<<25)
+#else
+assert_cc(MS_LAZYTIME == (1<<25));
#endif
/* Not exposed yet. Defined at fs/ext4/ext4.h */
#endif
#ifndef FS_PROJINHERIT_FL
-#define FS_PROJINHERIT_FL 0x20000000
+# define FS_PROJINHERIT_FL 0x20000000
+#else
+assert_cc(FS_PROJINHERIT_FL == 0x20000000);
#endif
/* linux/fscrypt.h */
#ifndef FS_KEY_DESCRIPTOR_SIZE
-#define FS_KEY_DESCRIPTOR_SIZE 8
+# define FS_KEY_DESCRIPTOR_SIZE 8
+#else
+assert_cc(FS_KEY_DESCRIPTOR_SIZE == 8);
#endif
#include <linux/input.h>
#include <linux/types.h>
+#include "macro.h"
+
/* linux@c7dc65737c9a607d3e6f8478659876074ad129b8 (3.12) */
#ifndef EVIOCREVOKE
-#define EVIOCREVOKE _IOW('E', 0x91, int)
+# define EVIOCREVOKE _IOW('E', 0x91, int)
#endif
/* linux@06a16293f71927f756dcf37558a79c0b05a91641 (4.4) */
__u64 codes_ptr;
};
-#define EVIOCGMASK _IOR('E', 0x92, struct input_mask)
-#define EVIOCSMASK _IOW('E', 0x93, struct input_mask)
+# define EVIOCGMASK _IOR('E', 0x92, struct input_mask)
+# define EVIOCSMASK _IOW('E', 0x93, struct input_mask)
#endif
/* linux@7611392fe8ff95ecae528b01a815ae3d72ca6b95 (3.17) */
#ifndef INPUT_PROP_POINTING_STICK
-#define INPUT_PROP_POINTING_STICK 0x05
+# define INPUT_PROP_POINTING_STICK 0x05
+#else
+assert_cc(INPUT_PROP_POINTING_STICK == 0x05);
#endif
/* linux@500d4160abe9a2e88b12e319c13ae3ebd1e18108 (4.0) */
#ifndef INPUT_PROP_ACCELEROMETER
-#define INPUT_PROP_ACCELEROMETER 0x06
+# define INPUT_PROP_ACCELEROMETER 0x06
+#else
+assert_cc(INPUT_PROP_ACCELEROMETER == 0x06);
#endif
/* linux@d09bbfd2a8408a995419dff0d2ba906013cf4cc9 (3.11) */
#ifndef BTN_DPAD_UP
-#define BTN_DPAD_UP 0x220
-#define BTN_DPAD_DOWN 0x221
-#define BTN_DPAD_LEFT 0x222
-#define BTN_DPAD_RIGHT 0x223
+# define BTN_DPAD_UP 0x220
+# define BTN_DPAD_DOWN 0x221
+# define BTN_DPAD_LEFT 0x222
+# define BTN_DPAD_RIGHT 0x223
+#else
+assert_cc(BTN_DPAD_UP == 0x220);
+assert_cc(BTN_DPAD_DOWN == 0x221);
+assert_cc(BTN_DPAD_LEFT == 0x222);
+assert_cc(BTN_DPAD_RIGHT == 0x223);
#endif
/* linux@358f24704f2f016af7d504b357cdf32606091d07 (3.13) */
#ifndef KEY_ALS_TOGGLE
-#define KEY_ALS_TOGGLE 0x230
+# fine KEY_ALS_TOGGLE 0x230
+#else
+assert_cc(KEY_ALS_TOGGLE == 0x230);
#endif
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
-#include <sched.h>
+#if HAVE_LINUX_IOPRIO_H
+# include <linux/ioprio.h>
+#endif
+
+#include "macro.h"
/* Match values uses by the kernel internally, as no public header seems to exist. */
#ifndef IOPRIO_N_CLASSES
# define IOPRIO_N_CLASSES 8
+#else
+assert_cc(IOPRIO_N_CLASSES == 8);
#endif
#ifndef IOPRIO_BE_NR
# define IOPRIO_BE_NR 8
+#else
+assert_cc(IOPRIO_BE_NR == 8);
#endif
#ifndef IOPRIO_CLASS_NONE
# define IOPRIO_CLASS_NONE 0
+#else
+assert_cc(IOPRIO_CLASS_NONE == 0);
#endif
#ifndef IOPRIO_CLASS_RT
# define IOPRIO_CLASS_RT 1
+#else
+assert_cc(IOPRIO_CLASS_RT == 1);
#endif
#ifndef IOPRIO_CLASS_BE
# define IOPRIO_CLASS_BE 2
+#else
+assert_cc(IOPRIO_CLASS_BE == 2);
#endif
#ifndef IOPRIO_CLASS_IDLE
# define IOPRIO_CLASS_IDLE 3
+#else
+assert_cc(IOPRIO_CLASS_IDLE == 3);
#endif
#ifndef IOPRIO_WHO_PROCESS
# define IOPRIO_WHO_PROCESS 1
+#else
+assert_cc(IOPRIO_WHO_PROCESS == 1);
#endif
+
#ifndef IOPRIO_WHO_PGRP
# define IOPRIO_WHO_PGRP 2
+#else
+assert_cc(IOPRIO_WHO_PGRP == 2);
#endif
+
#ifndef IOPRIO_WHO_USER
# define IOPRIO_WHO_USER 3
+#else
+assert_cc(IOPRIO_WHO_USER == 3);
#endif
#ifndef IOPRIO_BITS
# define IOPRIO_BITS 16
+#else
+assert_cc(IOPRIO_BITS == 16);
#endif
+
#ifndef IOPRIO_N_CLASSES
# define IOPRIO_N_CLASSES 8
+#else
+assert_cc(IOPRIO_N_CLASSES == 8);
#endif
+
#ifndef IOPRIO_CLASS_SHIFT
# define IOPRIO_CLASS_SHIFT 13
+#else
+assert_cc(IOPRIO_CLASS_SHIFT == 13);
#endif
static inline int ioprio_prio_class(int value) {
#include <inttypes.h>
#include <linux/keyctl.h>
+#include "macro.h"
+
#ifndef KEYCTL_JOIN_SESSION_KEYRING
-#define KEYCTL_JOIN_SESSION_KEYRING 1
+# define KEYCTL_JOIN_SESSION_KEYRING 1
+#else
+assert_cc(KEYCTL_JOIN_SESSION_KEYRING == 1);
#endif
#ifndef KEYCTL_CHOWN
-#define KEYCTL_CHOWN 4
+# define KEYCTL_CHOWN 4
+#else
+assert_cc(KEYCTL_CHOWN == 4);
#endif
#ifndef KEYCTL_SETPERM
-#define KEYCTL_SETPERM 5
+# define KEYCTL_SETPERM 5
+#else
+assert_cc(KEYCTL_SETPERM == 5);
#endif
#ifndef KEYCTL_DESCRIBE
-#define KEYCTL_DESCRIBE 6
+# define KEYCTL_DESCRIBE 6
+#else
+assert_cc(KEYCTL_DESCRIBE == 6);
#endif
#ifndef KEYCTL_LINK
-#define KEYCTL_LINK 8
+# define KEYCTL_LINK 8
+#else
+assert_cc(KEYCTL_LINK == 8);
#endif
#ifndef KEYCTL_READ
-#define KEYCTL_READ 11
+# define KEYCTL_READ 11
+#else
+assert_cc(KEYCTL_READ == 11);
#endif
#ifndef KEYCTL_SET_TIMEOUT
-#define KEYCTL_SET_TIMEOUT 15
+# define KEYCTL_SET_TIMEOUT 15
+#else
+assert_cc(KEYCTL_SET_TIMEOUT == 15);
#endif
#ifndef KEY_SPEC_USER_KEYRING
-#define KEY_SPEC_USER_KEYRING -4
+# define KEY_SPEC_USER_KEYRING -4
+#else
+assert_cc(KEY_SPEC_USER_KEYRING == -4);
#endif
#ifndef KEY_SPEC_SESSION_KEYRING
-#define KEY_SPEC_SESSION_KEYRING -3
+# define KEY_SPEC_SESSION_KEYRING -3
+#else
+assert_cc(KEY_SPEC_SESSION_KEYRING == -3);
#endif
/* From linux/key.h */
typedef int32_t key_serial_t;
-#define KEY_POS_VIEW 0x01000000
-#define KEY_POS_READ 0x02000000
-#define KEY_POS_WRITE 0x04000000
-#define KEY_POS_SEARCH 0x08000000
-#define KEY_POS_LINK 0x10000000
-#define KEY_POS_SETATTR 0x20000000
-#define KEY_POS_ALL 0x3f000000
-
-#define KEY_USR_VIEW 0x00010000
-#define KEY_USR_READ 0x00020000
-#define KEY_USR_WRITE 0x00040000
-#define KEY_USR_SEARCH 0x00080000
-#define KEY_USR_LINK 0x00100000
-#define KEY_USR_SETATTR 0x00200000
-#define KEY_USR_ALL 0x003f0000
-
-#define KEY_GRP_VIEW 0x00000100
-#define KEY_GRP_READ 0x00000200
-#define KEY_GRP_WRITE 0x00000400
-#define KEY_GRP_SEARCH 0x00000800
-#define KEY_GRP_LINK 0x00001000
-#define KEY_GRP_SETATTR 0x00002000
-#define KEY_GRP_ALL 0x00003f00
-
-#define KEY_OTH_VIEW 0x00000001
-#define KEY_OTH_READ 0x00000002
-#define KEY_OTH_WRITE 0x00000004
-#define KEY_OTH_SEARCH 0x00000008
-#define KEY_OTH_LINK 0x00000010
-#define KEY_OTH_SETATTR 0x00000020
-#define KEY_OTH_ALL 0x0000003f
+# define KEY_POS_VIEW 0x01000000
+# define KEY_POS_READ 0x02000000
+# define KEY_POS_WRITE 0x04000000
+# define KEY_POS_SEARCH 0x08000000
+# define KEY_POS_LINK 0x10000000
+# define KEY_POS_SETATTR 0x20000000
+# define KEY_POS_ALL 0x3f000000
+
+# define KEY_USR_VIEW 0x00010000
+# define KEY_USR_READ 0x00020000
+# define KEY_USR_WRITE 0x00040000
+# define KEY_USR_SEARCH 0x00080000
+# define KEY_USR_LINK 0x00100000
+# define KEY_USR_SETATTR 0x00200000
+# define KEY_USR_ALL 0x003f0000
+
+# define KEY_GRP_VIEW 0x00000100
+# define KEY_GRP_READ 0x00000200
+# define KEY_GRP_WRITE 0x00000400
+# define KEY_GRP_SEARCH 0x00000800
+# define KEY_GRP_LINK 0x00001000
+# define KEY_GRP_SETATTR 0x00002000
+# define KEY_GRP_ALL 0x00003f00
+
+# define KEY_OTH_VIEW 0x00000001
+# define KEY_OTH_READ 0x00000002
+# define KEY_OTH_WRITE 0x00000004
+# define KEY_OTH_SEARCH 0x00000008
+# define KEY_OTH_LINK 0x00000010
+# define KEY_OTH_SETATTR 0x00000020
+# define KEY_OTH_ALL 0x0000003f
+#else
+assert_cc(KEY_OTH_ALL == 0x0000003f);
#endif
#include <linux/loop.h>
+#include "macro.h"
+
#ifndef LOOP_CONFIGURE
struct loop_config {
__u32 fd;
__u64 __reserved[8];
};
-#define LOOP_CONFIGURE 0x4C0A
+# define LOOP_CONFIGURE 0x4C0A
+#else
+assert_cc(LOOP_CONFIGURE == 0x4C0A);
#endif
#ifndef LO_FLAGS_DIRECT_IO
-#define LO_FLAGS_DIRECT_IO 16
-#define LOOP_SET_DIRECT_IO 0x4C08
+# define LO_FLAGS_DIRECT_IO 16
+# define LOOP_SET_DIRECT_IO 0x4C08
+#else
+assert_cc(LO_FLAGS_DIRECT_IO == 16);
+assert_cc(LO_FLAGS_DIRECT_IO == 0x4C08);
#endif
#ifndef LOOP_SET_STATUS_SETTABLE_FLAGS
-#define LOOP_SET_STATUS_SETTABLE_FLAGS (LO_FLAGS_AUTOCLEAR | LO_FLAGS_PARTSCAN | LO_FLAGS_DIRECT_IO)
+# define LOOP_SET_STATUS_SETTABLE_FLAGS (LO_FLAGS_AUTOCLEAR | LO_FLAGS_PARTSCAN | LO_FLAGS_DIRECT_IO)
#endif
/* 62aa81d7c4c24b90fdb61da70ac0dbbc414f9939 (4.13) */
#ifndef OCFS2_SUPER_MAGIC
-#define OCFS2_SUPER_MAGIC 0x7461636f
+# define OCFS2_SUPER_MAGIC 0x7461636f
+#else
+assert_cc(OCFS2_SUPER_MAGIC == 0x7461636f);
#endif
/* 67e9c74b8a873408c27ac9a8e4c1d1c8d72c93ff (4.5) */
#ifndef CGROUP2_SUPER_MAGIC
-#define CGROUP2_SUPER_MAGIC 0x63677270
+# define CGROUP2_SUPER_MAGIC 0x63677270
+#else
+assert_cc(CGROUP2_SUPER_MAGIC == 0x63677270);
#endif
/* 4282d60689d4f21b40692029080440cc58e8a17d (4.1) */
#ifndef TRACEFS_MAGIC
-#define TRACEFS_MAGIC 0x74726163
+# define TRACEFS_MAGIC 0x74726163
+#else
+assert_cc(TRACEFS_MAGIC == 0x74726163);
#endif
/* e149ed2b805fefdccf7ccdfc19eca22fdd4514ac (3.19) */
#ifndef NSFS_MAGIC
-#define NSFS_MAGIC 0x6e736673
+# define NSFS_MAGIC 0x6e736673
+#else
+assert_cc(NSFS_MAGIC == 0x6e736673);
#endif
/* b2197755b2633e164a439682fb05a9b5ea48f706 (4.4) */
#ifndef BPF_FS_MAGIC
-#define BPF_FS_MAGIC 0xcafe4a11
+# define BPF_FS_MAGIC 0xcafe4a11
+#else
+assert_cc(BPF_FS_MAGIC == 0xcafe4a11);
#endif
/* Not exposed yet (4.20). Defined at ipc/mqueue.c */
#ifndef MQUEUE_MAGIC
-#define MQUEUE_MAGIC 0x19800202
+# define MQUEUE_MAGIC 0x19800202
+#else
+assert_cc(MQUEUE_MAGIC == 0x19800202);
#endif
/* Not exposed yet (as of Linux 5.4). Defined in fs/xfs/libxfs/xfs_format.h */
#ifndef XFS_SB_MAGIC
-#define XFS_SB_MAGIC 0x58465342
+# define XFS_SB_MAGIC 0x58465342
+#else
+assert_cc(XFS_SB_MAGIC == 0x58465342);
#endif
/* dea2903719283c156b53741126228c4a1b40440f (5.17) */
#ifndef CIFS_SUPER_MAGIC
-#define CIFS_SUPER_MAGIC 0xFF534D42
+# define CIFS_SUPER_MAGIC 0xFF534D42
+#else
+assert_cc(CIFS_SUPER_MAGIC == 0xFF534D42);
#endif
/* dea2903719283c156b53741126228c4a1b40440f (5.17) */
#ifndef SMB2_SUPER_MAGIC
-#define SMB2_SUPER_MAGIC 0xFE534D42
+# define SMB2_SUPER_MAGIC 0xFE534D42
+#else
+assert_cc(SMB2_SUPER_MAGIC == 0xFE534D42);
#endif
/* 257f871993474e2bde6c497b54022c362cf398e1 (4.5) */
#ifndef OVERLAYFS_SUPER_MAGIC
-#define OVERLAYFS_SUPER_MAGIC 0x794c7630
+# define OVERLAYFS_SUPER_MAGIC 0x794c7630
+#else
+assert_cc(OVERLAYFS_SUPER_MAGIC == 0x794c7630);
#endif
/* 2a28900be20640fcd1e548b1e3bad79e8221fcf9 (4.7) */
#ifndef UDF_SUPER_MAGIC
-#define UDF_SUPER_MAGIC 0x15013346
+# define UDF_SUPER_MAGIC 0x15013346
+#else
+assert_cc(UDF_SUPER_MAGIC == 0x15013346);
#endif
/* b1123ea6d3b3da25af5c8a9d843bd07ab63213f4 (4.8) */
#ifndef BALLOON_KVM_MAGIC
-#define BALLOON_KVM_MAGIC 0x13661366
+# define BALLOON_KVM_MAGIC 0x13661366
+#else
+assert_cc(BALLOON_KVM_MAGIC == 0x13661366);
#endif
/* 48b4800a1c6af2cdda344ea4e2c843dcc1f6afc9 (4.8) */
#ifndef ZSMALLOC_MAGIC
-#define ZSMALLOC_MAGIC 0x58295829
+# define ZSMALLOC_MAGIC 0x58295829
+#else
+assert_cc(ZSMALLOC_MAGIC == 0x58295829);
#endif
/* 3bc52c45bac26bf7ed1dc8d287ad1aeaed1250b6 (4.9) */
#ifndef DAXFS_MAGIC
-#define DAXFS_MAGIC 0x64646178
+# define DAXFS_MAGIC 0x64646178
+#else
+assert_cc(DAXFS_MAGIC == 0x64646178);
#endif
/* 5ff193fbde20df5d80fec367cea3e7856c057320 (4.10) */
#ifndef RDTGROUP_SUPER_MAGIC
-#define RDTGROUP_SUPER_MAGIC 0x7655821
+# define RDTGROUP_SUPER_MAGIC 0x7655821
+#else
+assert_cc(RDTGROUP_SUPER_MAGIC == 0x7655821);
#endif
/* a481f4d917835cad86701fc0d1e620c74bb5cd5f (4.13) */
#ifndef AAFS_MAGIC
-#define AAFS_MAGIC 0x5a3c69f0
+# define AAFS_MAGIC 0x5a3c69f0
+#else
+assert_cc(AAFS_MAGIC == 0x5a3c69f0);
#endif
/* f044c8847bb61eff5e1e95b6f6bb950e7f4a73a4 (4.15) */
#ifndef AFS_FS_MAGIC
-#define AFS_FS_MAGIC 0x6b414653
+# define AFS_FS_MAGIC 0x6b414653
+#else
+assert_cc(AFS_FS_MAGIC == 0x6b414653);
#endif
/* dddde68b8f06dd83486124b8d245e7bfb15c185d (4.20) */
#ifndef XFS_SUPER_MAGIC
-#define XFS_SUPER_MAGIC 0x58465342
+# define XFS_SUPER_MAGIC 0x58465342
+#else
+assert_cc(XFS_SUPER_MAGIC == 0x58465342);
#endif
/* 3ad20fe393b31025bebfc2d76964561f65df48aa (5.0) */
#ifndef BINDERFS_SUPER_MAGIC
-#define BINDERFS_SUPER_MAGIC 0x6c6f6f70
+# define BINDERFS_SUPER_MAGIC 0x6c6f6f70
+#else
+assert_cc(BINDERFS_SUPER_MAGIC == 0x6c6f6f70);
#endif
/* ed63bb1d1f8469586006a9ca63c42344401aa2ab (5.3) */
#ifndef DMA_BUF_MAGIC
-#define DMA_BUF_MAGIC 0x444d4142
+# define DMA_BUF_MAGIC 0x444d4142
+#else
+assert_cc(DMA_BUF_MAGIC == 0x444d4142);
#endif
/* ea8157ab2ae5e914dd427e5cfab533b6da3819cd (5.3) */
#ifndef Z3FOLD_MAGIC
-#define Z3FOLD_MAGIC 0x33
+# define Z3FOLD_MAGIC 0x33
+#else
+assert_cc(Z3FOLD_MAGIC == 0x33);
#endif
/* 47e4937a4a7ca4184fd282791dfee76c6799966a (5.4) */
#ifndef EROFS_SUPER_MAGIC_V1
-#define EROFS_SUPER_MAGIC_V1 0xe0f5e1e2
+# define EROFS_SUPER_MAGIC_V1 0xe0f5e1e2
+#else
+assert_cc(EROFS_SUPER_MAGIC_V1 == 0xe0f5e1e2);
#endif
/* fe030c9b85e6783bc52fe86449c0a4b8aa16c753 (5.5) */
#ifndef PPC_CMM_MAGIC
-#define PPC_CMM_MAGIC 0xc7571590
+# define PPC_CMM_MAGIC 0xc7571590
+#else
+assert_cc(PPC_CMM_MAGIC == 0xc7571590);
#endif
/* 8dcc1a9d90c10fa4143e5c17821082e5e60e46a1 (5.6) */
#ifndef ZONEFS_MAGIC
-#define ZONEFS_MAGIC 0x5a4f4653
+# define ZONEFS_MAGIC 0x5a4f4653
+#else
+assert_cc(ZONEFS_MAGIC == 0x5a4f4653);
#endif
/* 3234ac664a870e6ea69ae3a57d824cd7edbeacc5 (5.8) */
#ifndef DEVMEM_MAGIC
-#define DEVMEM_MAGIC 0x454d444d
+# define DEVMEM_MAGIC 0x454d444d
+#else
+assert_cc(DEVMEM_MAGIC == 0x454d444d);
#endif
/* cb12fd8e0dabb9a1c8aef55a6a41e2c255fcdf4b (6.8) */
#ifndef PID_FS_MAGIC
-#define PID_FS_MAGIC 0x50494446
+# define PID_FS_MAGIC 0x50494446
+#else
+assert_cc(PID_FS_MAGIC == 0x50494446);
#endif
/* Not in mainline but included in Ubuntu */
#ifndef SHIFTFS_MAGIC
-#define SHIFTFS_MAGIC 0x6a656a62
+# define SHIFTFS_MAGIC 0x6a656a62
+#else
+assert_cc(SHIFTFS_MAGIC == 0x6a656a62);
#endif
/* 1507f51255c9ff07d75909a84e7c0d7f3c4b2f49 (5.14) */
#ifndef SECRETMEM_MAGIC
-#define SECRETMEM_MAGIC 0x5345434d
+# define SECRETMEM_MAGIC 0x5345434d
+#else
+assert_cc(SECRETMEM_MAGIC == 0x5345434d);
#endif
/* Not exposed yet. Defined at fs/fuse/inode.c */
#ifndef FUSE_SUPER_MAGIC
-#define FUSE_SUPER_MAGIC 0x65735546
+# define FUSE_SUPER_MAGIC 0x65735546
+#else
+assert_cc(FUSE_SUPER_MAGIC == 0x65735546);
#endif
/* Not exposed yet. Defined at fs/fuse/control.c */
#ifndef FUSE_CTL_SUPER_MAGIC
-#define FUSE_CTL_SUPER_MAGIC 0x65735543
+# define FUSE_CTL_SUPER_MAGIC 0x65735543
+#else
+assert_cc(FUSE_CTL_SUPER_MAGIC == 0x65735543);
#endif
/* Not exposed yet. Defined at fs/ceph/super.h */
#ifndef CEPH_SUPER_MAGIC
-#define CEPH_SUPER_MAGIC 0x00c36400
+# define CEPH_SUPER_MAGIC 0x00c36400
+#else
+assert_cc(CEPH_SUPER_MAGIC == 0x00c36400);
#endif
/* Not exposed yet. Defined at fs/orangefs/orangefs-kernel.h */
#ifndef ORANGEFS_DEVREQ_MAGIC
-#define ORANGEFS_DEVREQ_MAGIC 0x20030529
+# define ORANGEFS_DEVREQ_MAGIC 0x20030529
+#else
+assert_cc(ORANGEFS_DEVREQ_MAGIC == 0x20030529);
#endif
/* linux/gfs2_ondisk.h */
#ifndef GFS2_MAGIC
-#define GFS2_MAGIC 0x01161970
+# define GFS2_MAGIC 0x01161970
+#else
+assert_cc(GFS2_MAGIC == 0x01161970);
#endif
/* Not exposed yet. Defined at fs/configfs/mount.c */
#ifndef CONFIGFS_MAGIC
-#define CONFIGFS_MAGIC 0x62656570
+# define CONFIGFS_MAGIC 0x62656570
+#else
+assert_cc(CONFIGFS_MAGIC == 0x62656570);
#endif
/* Not exposed yet. Defined at fs/vboxsf/super.c */
#ifndef VBOXSF_SUPER_MAGIC
-#define VBOXSF_SUPER_MAGIC 0x786f4256
+# define VBOXSF_SUPER_MAGIC 0x786f4256
+#else
+assert_cc(VBOXSF_SUPER_MAGIC == 0x786f4256);
#endif
/* Not exposed yet. Defined at fs/exfat/exfat_fs.h */
#ifndef EXFAT_SUPER_MAGIC
-#define EXFAT_SUPER_MAGIC 0x2011BAB0UL
+# define EXFAT_SUPER_MAGIC 0x2011BAB0UL
+#else
+assert_cc(EXFAT_SUPER_MAGIC == 0x2011BAB0UL);
#endif
/* Not exposed yet, internally actually called RPCAUTH_GSSMAGIC. Defined in net/sunrpc/rpc_pipe.c */
#ifndef RPC_PIPEFS_SUPER_MAGIC
-#define RPC_PIPEFS_SUPER_MAGIC 0x67596969
+# define RPC_PIPEFS_SUPER_MAGIC 0x67596969
+#else
+assert_cc(RPC_PIPEFS_SUPER_MAGIC == 0x67596969);
#endif
/* Not exposed yet, defined at fs/ntfs/ntfs.h */
#ifndef NTFS_SB_MAGIC
-#define NTFS_SB_MAGIC 0x5346544e
+# define NTFS_SB_MAGIC 0x5346544e
+#else
+assert_cc(NTFS_SB_MAGIC == 0x5346544e);
#endif
/* Not exposed yet, encoded literally in fs/ntfs3/super.c. */
#ifndef NTFS3_SUPER_MAGIC
-#define NTFS3_SUPER_MAGIC 0x7366746e
+# define NTFS3_SUPER_MAGIC 0x7366746e
+#else
+assert_cc(NTFS3_SUPER_MAGIC == 0x7366746e);
#endif
#include <sys/mman.h>
+#include "macro.h"
+
#ifndef MFD_ALLOW_SEALING
-#define MFD_ALLOW_SEALING 0x0002U
+# define MFD_ALLOW_SEALING 0x0002U
+#else
+assert_cc(MFD_ALLOW_SEALING == 0x0002U);
#endif
#ifndef MFD_CLOEXEC
-#define MFD_CLOEXEC 0x0001U
+# define MFD_CLOEXEC 0x0001U
+#else
+assert_cc(MFD_CLOEXEC == 0x0001U);
#endif
#ifndef MFD_NOEXEC_SEAL
-#define MFD_NOEXEC_SEAL 0x0008U
+# define MFD_NOEXEC_SEAL 0x0008U
+#else
+assert_cc(MFD_NOEXEC_SEAL == 0x0008U);
#endif
#ifndef MFD_EXEC
-#define MFD_EXEC 0x0010U
+# define MFD_EXEC 0x0010U
+#else
+assert_cc(MFD_EXEC == 0x0010U);
#endif
#include <sys/mount.h>
+#include "macro.h"
+
/* dab741e0e02bd3c4f5e2e97be74b39df2523fc6e (5.10) */
#ifndef MS_NOSYMFOLLOW
-#define MS_NOSYMFOLLOW 256
+# define MS_NOSYMFOLLOW 256
+#else
+assert_cc(MS_NOSYMFOLLOW == 256);
#endif
#include <linux/prctl.h>
+#include "macro.h"
+
/* 58319057b7847667f0c9585b9de0e8932b0fdb08 (4.3) */
#ifndef PR_CAP_AMBIENT
#define PR_CAP_AMBIENT 47
/* b507808ebce23561d4ff8c2aa1fb949fe402bc61 (6.3) */
#ifndef PR_SET_MDWE
-#define PR_SET_MDWE 65
+# define PR_SET_MDWE 65
+#else
+assert_cc(PR_SET_MDWE == 65);
#endif
+
#ifndef PR_MDWE_REFUSE_EXEC_GAIN
-#define PR_MDWE_REFUSE_EXEC_GAIN 1
+# define PR_MDWE_REFUSE_EXEC_GAIN 1
+#else
+assert_cc(PR_MDWE_REFUSE_EXEC_GAIN == 1);
#endif
#ifndef PR_SET_MEMORY_MERGE
-#define PR_SET_MEMORY_MERGE 67
+# define PR_SET_MEMORY_MERGE 67
+#else
+assert_cc(PR_SET_MEMORY_MERGE == 67);
#endif
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
+#include "macro.h"
+
#if USE_SYS_RANDOM_H
# include <sys/random.h>
#else
#endif
#ifndef GRND_NONBLOCK
-#define GRND_NONBLOCK 0x0001
+# define GRND_NONBLOCK 0x0001
+#else
+assert_cc(GRND_NONBLOCK == 0x0001);
#endif
#ifndef GRND_RANDOM
-#define GRND_RANDOM 0x0002
+# define GRND_RANDOM 0x0002
+#else
+assert_cc(GRND_RANDOM == 0x0002);
#endif
#ifndef GRND_INSECURE
-#define GRND_INSECURE 0x0004
+# define GRND_INSECURE 0x0004
+#else
+assert_cc(GRND_INSECURE == 0x0004);
#endif
#include <sys/resource.h>
+#include "macro.h"
+
#ifndef RLIMIT_RTTIME
-#define RLIMIT_RTTIME 15
+# define RLIMIT_RTTIME 15
+#else
+assert_cc(RLIMIT_RTTIME == 15);
#endif
/* If RLIMIT_RTTIME is not defined, then we cannot use RLIMIT_NLIMITS as is */
#include <sched.h>
+#include "macro.h"
+
#ifndef CLONE_NEWCGROUP
-#define CLONE_NEWCGROUP 0x02000000
+# define CLONE_NEWCGROUP 0x02000000
+#else
+assert_cc(CLONE_NEWCGROUP == 0x02000000);
#endif
/* 769071ac9f20b6a447410c7eaa55d1a5233ef40c (5.8) */
#ifndef CLONE_NEWTIME
-#define CLONE_NEWTIME 0x00000080
+# define CLONE_NEWTIME 0x00000080
+#else
+assert_cc(CLONE_NEWTIME == 0x00000080);
#endif
/* Not exposed yet. Defined at include/linux/sched.h */
#ifndef PF_KTHREAD
-#define PF_KTHREAD 0x00200000
+# define PF_KTHREAD 0x00200000
+#else
+assert_cc(PF_KTHREAD == 0x00200000);
#endif
-/* The maximum thread/process name length including trailing NUL byte. This mimics the kernel definition of the same
- * name, which we need in userspace at various places but is not defined in userspace currently, neither under this
- * name nor any other. */
-/* Not exposed yet. Defined at include/linux/sched.h */
+/* The maximum thread/process name length including trailing NUL byte. This mimics the kernel definition of
+ * the same name, which we need in userspace at various places but is not defined in userspace currently,
+ * neither under this name nor any other.
+ *
+ * Not exposed yet. Defined at include/linux/sched.h */
#ifndef TASK_COMM_LEN
-#define TASK_COMM_LEN 16
+# define TASK_COMM_LEN 16
+#else
+assert_cc(TASK_COMM_LEN == 16);
#endif
#include <sys/timerfd.h>
+#include "macro.h"
+
#ifndef TFD_TIMER_CANCEL_ON_SET
-#define TFD_TIMER_CANCEL_ON_SET (1 << 1)
+# define TFD_TIMER_CANCEL_ON_SET (1 << 1)
+#else
+assert_cc(TFD_TIMER_CANCEL_ON_SET == (1 << 1));
#endif
#include <uchar.h>
#if !HAVE_CHAR32_T
-#define char32_t uint32_t
+# define char32_t uint32_t
#endif
#if !HAVE_CHAR16_T
-#define char16_t uint16_t
+# define char16_t uint16_t
#endif
#include <sys/wait.h>
+#include "macro.h"
+
#ifndef P_PIDFD
-#define P_PIDFD 3
+# define P_PIDFD 3
+#else
+assert_cc(P_PIDFD == 3);
#endif
#include "string-util.h"
#include "strv.h"
+const char* nulstr_get(const char *nulstr, const char *needle) {
+ if (!nulstr)
+ return NULL;
+
+ NULSTR_FOREACH(i, nulstr)
+ if (streq(i, needle))
+ return i;
+
+ return NULL;
+}
+
char** strv_parse_nulstr_full(const char *s, size_t l, bool drop_trailing_nuls) {
+ _cleanup_strv_free_ char **v = NULL;
+ size_t c = 0, i = 0;
+
/* l is the length of the input data, which will be split at NULs into elements of the resulting
* strv. Hence, the number of items in the resulting strv will be equal to one plus the number of NUL
* bytes in the l bytes starting at s, unless s[l-1] is NUL, in which case the final empty string is
* Note that contrary to a normal nulstr which cannot contain empty strings, because the input data
* is terminated by any two consequent NUL bytes, this parser accepts empty strings in s. */
- _cleanup_strv_free_ char **v = NULL;
- size_t c = 0, i = 0;
-
assert(s || l <= 0);
if (drop_trailing_nuls)
if (!v)
return NULL;
- for (const char *p = s; p < s + l; ) {
+ for (const char *p = s; p < s + l;) {
const char *e;
e = memchr(p, 0, s + l - p);
v[i] = memdup_suffix0(p, e ? e - p : s + l - p);
if (!v[i])
return NULL;
-
i++;
if (!e)
}
int strv_make_nulstr(char * const *l, char **ret, size_t *ret_size) {
+ _cleanup_free_ char *m = NULL;
+ size_t n = 0;
+
/* Builds a nulstr and returns it together with the size. An extra NUL byte will be appended (⚠️ but
* not included in the size! ⚠️). This is done so that the nulstr can be used both in
* strv_parse_nulstr() and in NULSTR_FOREACH()/strv_split_nulstr() contexts, i.e. with and without a
* NUL bytes (which it will, if not empty). To ensure that this assumption *always* holds, we'll
* return a buffer with two NUL bytes in that case, but return a size of zero. */
- _cleanup_free_ char *m = NULL;
- size_t n = 0;
-
assert(ret);
STRV_FOREACH(i, l) {
size_t z;
- z = strlen(*i);
+ z = strlen(*i) + 1;
- if (!GREEDY_REALLOC(m, n + z + 2))
+ if (!GREEDY_REALLOC(m, n + z + 1)) /* One extra NUL at the end as marker */
return -ENOMEM;
- memcpy(m + n, *i, z + 1);
- n += z + 1;
+ memcpy(m + n, *i, z);
+ n += z;
}
if (!m) {
n = 0;
} else
- /* Make sure there is a second extra NUL at the end of resulting nulstr (not counted in return size) */
+ /* Extra NUL is not counted in size returned */
m[n] = '\0';
*ret = TAKE_PTR(m);
return strv_make_nulstr(strv, ret, ret_size);
}
-
-const char* nulstr_get(const char *nulstr, const char *needle) {
- if (!nulstr)
- return NULL;
-
- NULSTR_FOREACH(i, nulstr)
- if (streq(i, needle))
- return i;
-
- return NULL;
-}
for (typeof(*(l)) *(i) = (l), *(j) = strchr((i), 0)+1; (i) && *(i); (i) = strchr((j), 0)+1, (j) = *(i) ? strchr((i), 0)+1 : (i))
const char* nulstr_get(const char *nulstr, const char *needle);
-
static inline bool nulstr_contains(const char *nulstr, const char *needle) {
return nulstr_get(nulstr, needle);
}
return strv_parse_nulstr_full(s, l, false);
}
char** strv_split_nulstr(const char *s);
-int strv_make_nulstr(char * const *l, char **p, size_t *n);
-int set_make_nulstr(Set *s, char **ret, size_t *ret_size);
-
static inline int strv_from_nulstr(char ***ret, const char *nulstr) {
char **t;
*ret = t;
return 0;
}
+
+int strv_make_nulstr(char * const *l, char **p, size_t *n);
+int set_make_nulstr(Set *s, char **ret, size_t *ret_size);
}
int runtime_directory(char **ret, RuntimeScope scope, const char *suffix) {
- _cleanup_free_ char *d = NULL;
int r;
assert(ret);
* Return value indicates whether the suffix was applied or not */
const char *e = secure_getenv("RUNTIME_DIRECTORY");
- if (e) {
- d = strdup(e);
- if (!d)
- return -ENOMEM;
-
- *ret = TAKE_PTR(d);
- return false;
- }
+ if (e)
+ return strdup_to(ret, e);
if (scope == RUNTIME_SCOPE_USER) {
- r = xdg_user_runtime_dir(&d, suffix);
+ r = xdg_user_runtime_dir(ret, suffix);
if (r < 0)
return r;
} else {
- d = path_join("/run", suffix);
+ char *d = path_join("/run", suffix);
if (!d)
return -ENOMEM;
+ *ret = d;
}
- *ret = TAKE_PTR(d);
return true;
}
}
int path_extract_directory(const char *path, char **ret) {
- _cleanup_free_ char *a = NULL;
const char *c, *next = NULL;
int r;
if (*path != '/') /* filename only */
return -EDESTADDRREQ;
- a = strdup("/");
- if (!a)
- return -ENOMEM;
- *ret = TAKE_PTR(a);
- return 0;
+ return strdup_to(ret, "/");
}
- a = strndup(path, next - path);
+ _cleanup_free_ char *a = strndup(path, next - path);
if (!a)
return -ENOMEM;
return path[2] == 0;
}
+bool path_implies_directory(const char *path) {
+
+ /* Sometimes, if we look at a path we already know it must refer to a directory, because it is
+ * suffixed with a slash, or its last component is "." or ".." */
+
+ if (!path)
+ return false;
+
+ if (dot_or_dot_dot(path))
+ return true;
+
+ return ENDSWITH_SET(path, "/", "/.", "/..");
+}
+
bool empty_or_root(const char *path) {
/* For operations relative to some root directory, returns true if the specified root directory is
#define path_extend(x, ...) path_extend_internal(x, __VA_ARGS__, POINTER_MAX)
#define path_join(...) path_extend_internal(NULL, __VA_ARGS__, POINTER_MAX)
+static inline char* skip_leading_slash(const char *p) {
+ return skip_leading_chars(p, "/");
+}
+
typedef enum PathSimplifyFlags {
PATH_SIMPLIFY_KEEP_TRAILING_SLASH = 1 << 0,
} PathSimplifyFlags;
bool dot_or_dot_dot(const char *path);
+bool path_implies_directory(const char *path);
+
static inline const char *skip_dev_prefix(const char *p) {
const char *e;
/* For testing purposes it is sometimes useful to be able to override what we consider /proc/cmdline to be */
e = secure_getenv("SYSTEMD_PROC_CMDLINE");
- if (e) {
- char *m;
-
- m = strdup(e);
- if (!m)
- return -ENOMEM;
-
- *ret = m;
- return 0;
- }
+ if (e)
+ return strdup_to(ret, e);
if (detect_container() > 0)
return pid_get_cmdline(1, SIZE_MAX, 0, ret);
int getenv_for_pid(pid_t pid, const char *field, char **ret) {
_cleanup_fclose_ FILE *f = NULL;
- char *value = NULL;
const char *path;
size_t sum = 0;
int r;
assert(field);
assert(ret);
- if (pid == 0 || pid == getpid_cached()) {
- const char *e;
-
- e = getenv(field);
- if (!e) {
- *ret = NULL;
- return 0;
- }
-
- value = strdup(e);
- if (!value)
- return -ENOMEM;
-
- *ret = value;
- return 1;
- }
+ if (pid == 0 || pid == getpid_cached())
+ return strdup_to_full(ret, getenv(field));
if (!pid_is_valid(pid))
return -EINVAL;
sum += r;
match = startswith(line, field);
- if (match && *match == '=') {
- value = strdup(match + 1);
- if (!value)
- return -ENOMEM;
-
- *ret = value;
- return 1;
- }
+ if (match && *match == '=')
+ return strdup_to_full(ret, match + 1);
}
*ret = NULL;
assert(sa);
assert(salen >= sizeof(sa->sa.sa_family));
+ assert(ret);
switch (sa->sa.sa_family) {
assert(sa);
assert(salen > sizeof(sa_family_t));
+ assert(ret);
r = getnameinfo(sa, salen, host, sizeof(host), /* service= */ NULL, /* service_len= */ 0, IDN_FLAGS);
if (r != 0) {
return sockaddr_pretty(sa, salen, /* translate_ipv6= */ true, /* include_port= */ true, ret);
}
- if (ret) {
- char *copy = strdup(host);
- if (!copy)
- return -ENOMEM;
-
- *ret = copy;
- }
-
- return 0;
+ return strdup_to(ret, host);
}
static const char* const netlink_family_table[] = {
return null_or_empty(&st);
}
-static int fd_is_read_only_fs(int fd) {
+int fd_is_read_only_fs(int fd) {
struct statvfs st;
assert(fd >= 0);
return null_or_empty_path_with_root(fn, NULL);
}
+int fd_is_read_only_fs(int fd);
int path_is_read_only_fs(const char *path);
int inode_same_at(int fda, const char *filea, int fdb, const char *fileb, int flags);
return 1;
}
+int strdup_to_full(char **ret, const char *src) {
+ if (!src) {
+ if (ret)
+ *ret = NULL;
+
+ return 0;
+ } else {
+ if (ret) {
+ char *t = strdup(src);
+ if (!t)
+ return -ENOMEM;
+ *ret = t;
+ }
+
+ return 1;
+ }
+};
+
bool string_is_safe(const char *p) {
if (!p)
return false;
return -ENOMEM;
*ret = m;
- return !isempty(q + 1); /* more coming? */
- } else {
- if (p == s)
- *ret = NULL; /* Just use the input string */
- else {
- char *m;
-
- m = strdup(p);
- if (!m)
- return -ENOMEM;
-
- *ret = m;
- }
-
- return 0; /* The end */
- }
+ return !isempty(q + 1); /* More coming? */
+ } else
+ /* Tell the caller to use the input string if equal */
+ return strdup_to(ret, p != s ? p : NULL);
}
- if (!q) {
- char *m;
-
+ if (!q)
/* No more lines, return empty line */
-
- m = strdup("");
- if (!m)
- return -ENOMEM;
-
- *ret = m;
- return 0; /* The end */
- }
+ return strdup_to(ret, "");
p = q + 1;
c++;
}
int free_and_strndup(char **p, const char *s, size_t l);
+int strdup_to_full(char **ret, const char *src);
+static inline int strdup_to(char **ret, const char *src) {
+ int r = strdup_to_full(ASSERT_PTR(ret), src);
+ return r < 0 ? r : 0; /* Suppress return value of 1. */
+}
+
bool string_is_safe(const char *p) _pure_;
DISABLE_WARNING_STRINGOP_TRUNCATION;
ssize_t strlevenshtein(const char *x, const char *y);
-static inline int strdup_or_null(const char *s, char **ret) {
- char *c;
-
- assert(ret);
-
- /* This is a lot like strdup(), but is happy with NULL strings, and does not treat that as error, but
- * copies the NULL value. */
-
- if (!s) {
- *ret = NULL;
- return 0;
- }
-
- c = strdup(s);
- if (!c)
- return -ENOMEM;
-
- *ret = c;
- return 1;
-}
-
char *strrstr(const char *haystack, const char *needle);
tty = active;
}
- if (tty == active)
- *ret = TAKE_PTR(active);
- else {
- char *tmp;
-
- tmp = strdup(tty);
- if (!tmp)
- return -ENOMEM;
-
- *ret = tmp;
- }
+ if (tty != active)
+ return strdup_to(ret, tty);
+ *ret = TAKE_PTR(active);
return 0;
}
}
int getttyname_malloc(int fd, char **ret) {
- char path[PATH_MAX], *c; /* PATH_MAX is counted *with* the trailing NUL byte */
+ char path[PATH_MAX]; /* PATH_MAX is counted *with* the trailing NUL byte */
int r;
assert(fd >= 0);
if (r > 0)
return -r;
- c = strdup(skip_dev_prefix(path));
- if (!c)
- return -ENOMEM;
-
- *ret = c;
- return 0;
+ return strdup_to(ret, skip_dev_prefix(path));
}
int getttyname_harder(int fd, char **ret) {
return -EINVAL;
if (ret) {
- _cleanup_free_ char *b = NULL;
-
- b = strdup(w);
- if (!b)
- return -ENOMEM;
-
- *ret = TAKE_PTR(b);
+ r = strdup_to(ret, w);
+ if (r < 0)
+ return r;
}
if (ret_devnr)
}
static inline const char *ansi_underline(void) {
- return underline_enabled() ? ANSI_UNDERLINE : ANSI_NORMAL;
+ return underline_enabled() ? ANSI_UNDERLINE : "";
}
static inline const char *ansi_add_underline(void) {
int get_timezone(char **ret) {
_cleanup_free_ char *t = NULL;
- const char *e;
- char *z;
int r;
assert(ret);
r = readlink_malloc("/etc/localtime", &t);
- if (r == -ENOENT) {
+ if (r == -ENOENT)
/* If the symlink does not exist, assume "UTC", like glibc does */
- z = strdup("UTC");
- if (!z)
- return -ENOMEM;
-
- *ret = z;
- return 0;
- }
+ return strdup_to(ret, "UTC");
if (r < 0)
- return r; /* returns EINVAL if not a symlink */
+ return r; /* Return EINVAL if not a symlink */
- e = PATH_STARTSWITH_SET(t, "/usr/share/zoneinfo/", "../usr/share/zoneinfo/");
+ const char *e = PATH_STARTSWITH_SET(t, "/usr/share/zoneinfo/", "../usr/share/zoneinfo/");
if (!e)
return -EINVAL;
-
if (!timezone_is_valid(e, LOG_DEBUG))
return -EINVAL;
- z = strdup(e);
- if (!z)
- return -ENOMEM;
-
- *ret = z;
- return 0;
+ return strdup_to(ret, e);
}
time_t mktime_or_timegm(struct tm *tm, bool utc) {
return 0;
}
-static int link_fd(int fd, int newdirfd, const char *newpath) {
- int r;
-
- assert(fd >= 0);
- assert(newdirfd >= 0 || newdirfd == AT_FDCWD);
- assert(newpath);
-
- /* Try symlinking via /proc/fd/ first. */
- r = RET_NERRNO(linkat(AT_FDCWD, FORMAT_PROC_FD_PATH(fd), newdirfd, newpath, AT_SYMLINK_FOLLOW));
- if (r != -ENOENT)
- return r;
-
- /* Fall back to symlinking via AT_EMPTY_PATH as fallback (this requires CAP_DAC_READ_SEARCH and a
- * more recent kernel, but does not require /proc/ mounted) */
- if (proc_mounted() != 0)
- return r;
-
- return RET_NERRNO(linkat(fd, "", newdirfd, newpath, AT_EMPTY_PATH));
-}
-
int link_tmpfile_at(int fd, int dir_fd, const char *path, const char *target, LinkTmpfileFlags flags) {
- _cleanup_free_ char *tmp = NULL;
int r;
assert(fd >= 0);
r = RET_NERRNO(renameat(dir_fd, path, dir_fd, target));
else
r = rename_noreplace(dir_fd, path, dir_fd, target);
- if (r < 0)
- return r;
} else {
-
- r = link_fd(fd, dir_fd, target);
- if (r != -EEXIST || !FLAGS_SET(flags, LINK_TMPFILE_REPLACE))
- return r;
-
- /* So the target already exists and we were asked to replace it. That sucks a bit, since the kernel's
- * linkat() logic does not allow that. We work-around this by linking the file to a random name
- * first, and then renaming that to the final name. This reintroduces the race O_TMPFILE kinda is
- * trying to fix, but at least the vulnerability window (i.e. where the file is linked into the file
- * system under a temporary name) is very short. */
-
- r = tempfn_random(target, NULL, &tmp);
- if (r < 0)
- return r;
-
- if (link_fd(fd, dir_fd, tmp) < 0)
- return -EEXIST; /* propagate original error */
-
- r = RET_NERRNO(renameat(dir_fd, tmp, dir_fd, target));
- if (r < 0) {
- (void) unlinkat(dir_fd, tmp, 0);
- return r;
- }
+ if (FLAGS_SET(flags, LINK_TMPFILE_REPLACE))
+ r = linkat_replace(fd, /* oldpath= */ NULL, dir_fd, target);
+ else
+ r = link_fd(fd, dir_fd, target);
}
+ if (r < 0)
+ return r;
if (FLAGS_SET(flags, LINK_TMPFILE_SYNC)) {
r = fsync_full(fd);
return 1;
good:
- s = strdup(name);
- if (!s)
- return -ENOMEM;
-
- *ret = TAKE_PTR(s);
- return 0;
+ return strdup_to(ret, name);
}
int slice_build_parent_slice(const char *slice, char **ret) {
- _cleanup_free_ char *s = NULL;
- char *dash;
- int r;
-
assert(slice);
assert(ret);
return 0;
}
- s = strdup(slice);
+ _cleanup_free_ char *s = strdup(slice);
if (!s)
return -ENOMEM;
- dash = strrchr(s, '-');
- if (dash)
- strcpy(dash, ".slice");
- else {
- r = free_and_strdup(&s, SPECIAL_ROOT_SLICE);
- if (r < 0)
- return r;
- }
+ char *dash = strrchr(s, '-');
+ if (!dash)
+ return strdup_to_full(ret, SPECIAL_ROOT_SLICE);
+
+ /* We know that s ended with .slice before truncation, so we have enough space. */
+ strcpy(dash, ".slice");
*ret = TAKE_PTR(s);
return 1;
return 0;
}
-static const char *skip_slash(const char *path) {
- assert(path);
- assert(path[0] == '/');
-
- return path + 1;
-}
-
static int verb_status(int argc, char *argv[], void *userdata) {
_cleanup_free_ char *path = NULL, *prefix = NULL, *suffix = NULL, *good = NULL, *bad = NULL;
uint64_t left, done;
return log_error_errno(errno, "Failed to open $BOOT partition '%s': %m", *p);
}
- if (faccessat(fd, skip_slash(path), F_OK, 0) >= 0) {
+ if (faccessat(fd, skip_leading_slash(path), F_OK, 0) >= 0) {
puts("indeterminate");
return 0;
}
if (errno != ENOENT)
return log_error_errno(errno, "Failed to check if '%s' exists: %m", path);
- if (faccessat(fd, skip_slash(good), F_OK, 0) >= 0) {
+ if (faccessat(fd, skip_leading_slash(good), F_OK, 0) >= 0) {
puts("good");
return 0;
}
if (errno != ENOENT)
return log_error_errno(errno, "Failed to check if '%s' exists: %m", good);
- if (faccessat(fd, skip_slash(bad), F_OK, 0) >= 0) {
+ if (faccessat(fd, skip_leading_slash(bad), F_OK, 0) >= 0) {
puts("bad");
return 0;
}
if (fd < 0)
return log_error_errno(errno, "Failed to open $BOOT partition '%s': %m", *p);
- r = rename_noreplace(fd, skip_slash(source1), fd, skip_slash(target));
+ r = rename_noreplace(fd, skip_leading_slash(source1), fd, skip_leading_slash(target));
if (r == -EEXIST)
goto exists;
if (r == -ENOENT) {
- r = rename_noreplace(fd, skip_slash(source2), fd, skip_slash(target));
+ r = rename_noreplace(fd, skip_leading_slash(source2), fd, skip_leading_slash(target));
if (r == -EEXIST)
goto exists;
if (r == -ENOENT) {
- if (faccessat(fd, skip_slash(target), F_OK, 0) >= 0) /* Hmm, if we can't find either source file, maybe the destination already exists? */
+ if (faccessat(fd, skip_leading_slash(target), F_OK, 0) >= 0) /* Hmm, if we can't find either source file, maybe the destination already exists? */
goto exists;
if (errno != ENOENT)
log_debug("Successfully renamed '%s' to '%s'.", source1, target);
/* First, fsync() the directory these files are located in */
- r = fsync_parent_at(fd, skip_slash(target));
+ r = fsync_parent_at(fd, skip_leading_slash(target));
if (r < 0)
log_debug_errno(errno, "Failed to synchronize image directory, ignoring: %m");
GUID_DEF(0x8be4df61, 0x93ca, 0x11d2, 0xaa, 0x0d, 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c)
#define EFI_IMAGE_SECURITY_DATABASE_GUID \
GUID_DEF(0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f)
+#define EFI_CUSTOM_MODE_ENABLE_GUID \
+ GUID_DEF(0xc076ec0c, 0x7028, 0x4399, 0xa0, 0x72, 0x71, 0xee, 0x5c, 0x44, 0x8b, 0x9f)
#define EVT_TIMER 0x80000000U
#define EVT_RUNTIME 0x40000000U
return decode_secure_boot_mode(secure, audit, deployed, setup);
}
+/*
+ * Custom mode allows to change secure boot certificate databases db, dbx, KEK and PK without the variable
+ * updates being signed. When enrolling certificates to an unconfigured system (no PK present yet) writing
+ * db, dbx and KEK updates without signature works fine even in standard mode. Writing PK updates without
+ * signature requires custom mode in any case.
+ *
+ * Enabling custom mode works only if a user is physically present. Note that OVMF has a dummy
+ * implementation for the user presence check (there is no useful way to implement a presence check for a
+ * virtual machine).
+ *
+ * FYI: Your firmware setup utility might offers the option to enroll certificates from *.crt files
+ * (DER-encoded x509 certificates) on the ESP; that uses custom mode too. Your firmware setup might also
+ * offer the option to switch the system into custom mode for the next boot.
+ */
+static bool custom_mode_enabled(void) {
+ bool enabled = false;
+
+ (void) efivar_get_boolean_u8(MAKE_GUID_PTR(EFI_CUSTOM_MODE_ENABLE),
+ u"CustomMode", &enabled);
+ return enabled;
+}
+
+static EFI_STATUS set_custom_mode(bool enable) {
+ static char16_t name[] = u"CustomMode";
+ static uint32_t attr =
+ EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS;
+ uint8_t mode = enable
+ ? 1 /* CUSTOM_SECURE_BOOT_MODE */
+ : 0; /* STANDARD_SECURE_BOOT_MODE */
+
+ return RT->SetVariable(name, MAKE_GUID_PTR(EFI_CUSTOM_MODE_ENABLE),
+ attr, sizeof(mode), &mode);
+}
+
EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path, bool force) {
assert(root_dir);
assert(path);
+ bool need_custom_mode = false;
EFI_STATUS err;
clear_screen(COLOR_NORMAL);
const char16_t *name;
const char16_t *filename;
const EFI_GUID vendor;
+ bool required;
char *buffer;
size_t size;
} sb_vars[] = {
- { u"db", u"db.auth", EFI_IMAGE_SECURITY_DATABASE_GUID, NULL, 0 },
- { u"KEK", u"KEK.auth", EFI_GLOBAL_VARIABLE, NULL, 0 },
- { u"PK", u"PK.auth", EFI_GLOBAL_VARIABLE, NULL, 0 },
+ { u"db", u"db.auth", EFI_IMAGE_SECURITY_DATABASE_GUID, true, NULL, 0 },
+ { u"dbx", u"dbx.auth", EFI_IMAGE_SECURITY_DATABASE_GUID, false, NULL, 0 },
+ { u"KEK", u"KEK.auth", EFI_GLOBAL_VARIABLE, true, NULL, 0 },
+ { u"PK", u"PK.auth", EFI_GLOBAL_VARIABLE, true, NULL, 0 },
};
/* Make sure all keys files exist before we start enrolling them by loading them from the disk first. */
for (size_t i = 0; i < ELEMENTSOF(sb_vars); i++) {
err = file_read(dir, sb_vars[i].filename, 0, 0, &sb_vars[i].buffer, &sb_vars[i].size);
- if (err != EFI_SUCCESS) {
+ if (err != EFI_SUCCESS && sb_vars[i].required) {
log_error_status(err, "Failed reading file %ls\\%ls: %m", path, sb_vars[i].filename);
goto out_deallocate;
}
+ if (streq16(sb_vars[i].name, u"PK") && sb_vars[i].size > 20) {
+ assert(sb_vars[i].buffer);
+ /*
+ * The buffer should be EFI_TIME (16 bytes), followed by
+ * EFI_VARIABLE_AUTHENTICATION_2 header. First header field is the size. If the
+ * size covers only the header itself (8 bytes) plus the signature type guid (16
+ * bytes), leaving no space for an actual signature, we can conclude that no
+ * signature is present.
+ */
+ uint32_t *sigsize = (uint32_t*)(sb_vars[i].buffer + 16);
+ if (*sigsize <= 24) {
+ printf("PK is not signed (need custom mode).\n");
+ need_custom_mode = true;
+ }
+ }
+ }
+
+ if (need_custom_mode && !custom_mode_enabled()) {
+ err = set_custom_mode(/* enable */ true);
+ if (err != EFI_SUCCESS) {
+ log_error_status(err, "Failed to enable custom mode: %m");
+ goto out_deallocate;
+ }
+ printf("Custom mode enabled.\n");
}
for (size_t i = 0; i < ELEMENTSOF(sb_vars); i++) {
EFI_VARIABLE_RUNTIME_ACCESS |
EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
+ if (sb_vars[i].size == 0)
+ continue;
err = efivar_set_raw(&sb_vars[i].vendor, sb_vars[i].name, sb_vars[i].buffer, sb_vars[i].size, sb_vars_opts);
if (err != EFI_SUCCESS) {
log_error_status(err, "Failed to write %ls secure boot variable: %m", sb_vars[i].name);
static int automount_send_ready(Automount *a, Set *tokens, int status);
static void automount_init(Unit *u) {
- Automount *a = AUTOMOUNT(u);
+ Automount *a = ASSERT_PTR(AUTOMOUNT(u));
- assert(a);
- assert(u);
assert(u->load_state == UNIT_STUB);
a->pipe_fd = -EBADF;
}
static void automount_done(Unit *u) {
- Automount *a = AUTOMOUNT(u);
-
- assert(a);
+ Automount *a = ASSERT_PTR(AUTOMOUNT(u));
unmount_autofs(a);
}
static int automount_load(Unit *u) {
- Automount *a = AUTOMOUNT(u);
+ Automount *a = ASSERT_PTR(AUTOMOUNT(u));
int r;
- assert(u);
assert(u->load_state == UNIT_STUB);
/* Load a .automount file */
static void automount_set_state(Automount *a, AutomountState state) {
AutomountState old_state;
+
assert(a);
if (a->state != state)
}
static int automount_coldplug(Unit *u) {
- Automount *a = AUTOMOUNT(u);
+ Automount *a = ASSERT_PTR(AUTOMOUNT(u));
int r;
- assert(a);
assert(a->state == AUTOMOUNT_DEAD);
if (a->deserialized_state == a->state)
}
static void automount_dump(Unit *u, FILE *f, const char *prefix) {
- Automount *a = AUTOMOUNT(u);
-
- assert(a);
+ Automount *a = ASSERT_PTR(AUTOMOUNT(u));
fprintf(f,
"%sAutomount State: %s\n"
r = 0;
/* Autofs thankfully does not hand out 0 as a token */
- while ((token = PTR_TO_UINT(set_steal_first(tokens)))) {
- int k;
-
+ while ((token = PTR_TO_UINT(set_steal_first(tokens))))
/* Autofs fun fact:
*
- * if you pass a positive status code here, kernels
- * prior to 4.12 will freeze! Yay! */
-
- k = autofs_send_ready(UNIT(a)->manager->dev_autofs_fd,
- ioctl_fd,
- token,
- status);
- if (k < 0)
- r = k;
- }
+ * if you pass a positive status code here, kernels prior to 4.12 will freeze! Yay! */
+ RET_GATHER(r, autofs_send_ready(UNIT(a)->manager->dev_autofs_fd,
+ ioctl_fd,
+ token,
+ status));
return r;
}
static void automount_trigger_notify(Unit *u, Unit *other) {
- Automount *a = AUTOMOUNT(u);
+ Automount *a = ASSERT_PTR(AUTOMOUNT(u));
int r;
- assert(a);
assert(other);
/* Filter out invocations with bogus state */
}
static int automount_dispatch_expire(sd_event_source *source, usec_t usec, void *userdata) {
+ Automount *a = ASSERT_PTR(AUTOMOUNT(userdata));
_cleanup_close_ int ioctl_fd = -EBADF;
- Automount *a = AUTOMOUNT(userdata);
int r;
- assert(a);
assert(source == a->expire_event_source);
ioctl_fd = open_ioctl_fd(UNIT(a)->manager->dev_autofs_fd, a->where, a->dev_id);
}
static int automount_start(Unit *u) {
- Automount *a = AUTOMOUNT(u);
+ Automount *a = ASSERT_PTR(AUTOMOUNT(u));
int r;
- assert(a);
assert(IN_SET(a->state, AUTOMOUNT_DEAD, AUTOMOUNT_FAILED));
if (path_is_mount_point(a->where) > 0)
}
static int automount_stop(Unit *u) {
- Automount *a = AUTOMOUNT(u);
+ Automount *a = ASSERT_PTR(AUTOMOUNT(u));
- assert(a);
assert(IN_SET(a->state, AUTOMOUNT_WAITING, AUTOMOUNT_RUNNING));
automount_enter_dead(a, AUTOMOUNT_SUCCESS);
}
static int automount_serialize(Unit *u, FILE *f, FDSet *fds) {
- Automount *a = AUTOMOUNT(u);
+ Automount *a = ASSERT_PTR(AUTOMOUNT(u));
void *p;
int r;
- assert(a);
assert(f);
assert(fds);
}
static int automount_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Automount *a = AUTOMOUNT(u);
+ Automount *a = ASSERT_PTR(AUTOMOUNT(u));
int r;
- assert(a);
assert(fds);
if (streq(key, "state")) {
}
static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, void *userdata) {
+ Automount *a = ASSERT_PTR(AUTOMOUNT(userdata));
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
union autofs_v5_packet_union packet;
- Automount *a = AUTOMOUNT(userdata);
Unit *trigger;
int r;
- assert(a);
assert(fd == a->pipe_fd);
if (events & (EPOLLHUP|EPOLLERR)) {
}
static void automount_reset_failed(Unit *u) {
- Automount *a = AUTOMOUNT(u);
-
- assert(a);
+ Automount *a = ASSERT_PTR(AUTOMOUNT(u));
if (a->state == AUTOMOUNT_FAILED)
automount_set_state(a, AUTOMOUNT_DEAD);
}
static int automount_can_start(Unit *u) {
- Automount *a = AUTOMOUNT(u);
+ Automount *a = ASSERT_PTR(AUTOMOUNT(u));
int r;
- assert(a);
-
r = unit_test_start_limit(u);
if (r < 0) {
automount_enter_dead(a, AUTOMOUNT_FAILURE_START_LIMIT_HIT);
}
static void device_init(Unit *u) {
- Device *d = DEVICE(u);
+ Device *d = ASSERT_PTR(DEVICE(u));
- assert(d);
- assert(UNIT(d)->load_state == UNIT_STUB);
+ assert(u->load_state == UNIT_STUB);
/* In contrast to all other unit types we timeout jobs waiting
* for devices by default. This is because they otherwise wait
}
static void device_done(Unit *u) {
- Device *d = DEVICE(u);
-
- assert(d);
+ Device *d = ASSERT_PTR(DEVICE(u));
device_unset_sysfs(d);
d->deserialized_sysfs = mfree(d->deserialized_sysfs);
}
static int device_coldplug(Unit *u) {
- Device *d = DEVICE(u);
+ Device *d = ASSERT_PTR(DEVICE(u));
- assert(d);
assert(d->state == DEVICE_DEAD);
/* First, let's put the deserialized state and found mask into effect, if we have it. */
}
static void device_catchup(Unit *u) {
- Device *d = DEVICE(u);
-
- assert(d);
+ Device *d = ASSERT_PTR(DEVICE(u));
/* Second, let's update the state with the enumerated state */
device_update_found_one(d, d->enumerated_found, DEVICE_FOUND_MASK);
}
static int device_serialize(Unit *u, FILE *f, FDSet *fds) {
+ Device *d = ASSERT_PTR(DEVICE(u));
_cleanup_free_ char *s = NULL;
- Device *d = DEVICE(u);
- assert(d);
- assert(u);
assert(f);
assert(fds);
}
static int device_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Device *d = DEVICE(u);
+ Device *d = ASSERT_PTR(DEVICE(u));
int r;
- assert(d);
- assert(u);
assert(key);
assert(value);
assert(fds);
}
static void device_dump(Unit *u, FILE *f, const char *prefix) {
- Device *d = DEVICE(u);
+ Device *d = ASSERT_PTR(DEVICE(u));
_cleanup_free_ char *s = NULL;
- assert(d);
+ assert(f);
+ assert(prefix);
(void) device_found_to_string_many(d->found, &s);
}
static UnitActiveState device_active_state(Unit *u) {
- assert(u);
+ Device *d = ASSERT_PTR(DEVICE(u));
- return state_translation_table[DEVICE(u)->state];
+ return state_translation_table[d->state];
}
static const char *device_sub_state_to_string(Unit *u) {
- assert(u);
+ Device *d = ASSERT_PTR(DEVICE(u));
- return device_state_to_string(DEVICE(u)->state);
+ return device_state_to_string(d->state);
}
static int device_update_description(Unit *u, sd_device *dev, const char *path) {
}
static int device_add_udev_wants(Unit *u, sd_device *dev) {
+ Device *d = ASSERT_PTR(DEVICE(u));
_cleanup_strv_free_ char **added = NULL;
const char *wants, *property;
- Device *d = DEVICE(u);
int r;
- assert(d);
assert(dev);
property = MANAGER_IS_USER(u->manager) ? "SYSTEMD_USER_WANTS" : "SYSTEMD_WANTS";
/* Let's upgrade Requires= to BindsTo= on us. (Used when SYSTEMD_MOUNT_DEVICE_BOUND is set) */
+ assert(u);
+
HASHMAP_FOREACH_KEY(v, other, unit_get_dependencies(u, UNIT_REQUIRED_BY)) {
if (other->type != UNIT_MOUNT)
continue;
unit_add_to_load_queue(u);
}
- if (!DEVICE(u)->path) {
- DEVICE(u)->path = strdup(path);
- if (!DEVICE(u)->path)
+ Device *d = ASSERT_PTR(DEVICE(u));
+
+ if (!d->path) {
+ d->path = strdup(path);
+ if (!d->path)
return log_oom();
}
/* If this was created via some dependency and has not actually been seen yet ->sysfs will not be
* initialized. Hence initialize it if necessary. */
if (sysfs) {
- r = device_set_sysfs(DEVICE(u), sysfs);
+ r = device_set_sysfs(d, sysfs);
if (r < 0)
return log_unit_error_errno(u, r, "Failed to set sysfs path %s: %m", sysfs);
* by systemd before the device appears on its radar. In this case the device unit is partially
* initialized and includes the deps on the mount unit but at that time the "bind mounts" flag wasn't
* present. Fix this up now. */
- if (dev && device_is_bound_by_mounts(DEVICE(u), dev))
+ if (dev && device_is_bound_by_mounts(d, dev))
device_upgrade_mount_deps(u);
if (units) {
- r = set_ensure_put(units, NULL, DEVICE(u));
+ r = set_ensure_put(units, NULL, d);
if (r < 0)
return log_unit_error_errno(u, r, "Failed to store unit: %m");
}
}
static Unit *device_following(Unit *u) {
- Device *d = DEVICE(u);
- Device *first = NULL;
-
- assert(d);
+ Device *d = ASSERT_PTR(DEVICE(u)), *first = NULL;
if (startswith(u->id, "sys-"))
return NULL;
return UNIT(first);
}
-static int device_following_set(Unit *u, Set **_set) {
- Device *d = DEVICE(u);
+static int device_following_set(Unit *u, Set **ret) {
+ Device *d = ASSERT_PTR(DEVICE(u));
_cleanup_set_free_ Set *set = NULL;
int r;
- assert(d);
- assert(_set);
+ assert(ret);
if (LIST_JUST_US(same_sysfs, d)) {
- *_set = NULL;
+ *ret = NULL;
return 0;
}
return r;
}
- *_set = TAKE_PTR(set);
+ *ret = TAKE_PTR(set);
return 1;
}
#include "hexdecoct.h"
#include "io-util.h"
#include "iovec-util.h"
+#include "journal-send.h"
#include "missing_ioprio.h"
#include "missing_prctl.h"
#include "missing_securebits.h"
const char *j;
int r;
- j = log_namespace ?
- strjoina("/run/systemd/journal.", log_namespace, "/stdout") :
- "/run/systemd/journal/stdout";
+ assert(fd >= 0);
+
+ j = journal_stream_path(log_namespace);
+ if (!j)
+ return -EINVAL;
if (gid_is_valid(gid)) {
oldgid = getgid();
PidRef *ret) {
char serialization_fd_number[DECIMAL_STR_MAX(int) + 1];
- _cleanup_free_ char *subcgroup_path = NULL, *log_level = NULL, *executor_path = NULL;
+ _cleanup_free_ char *subcgroup_path = NULL, *max_log_levels = NULL, *executor_path = NULL;
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
_cleanup_fdset_free_ FDSet *fdset = NULL;
_cleanup_fclose_ FILE *f = NULL;
/* If LogLevelMax= is specified, then let's use the specified log level at the beginning of the
* executor process. To achieve that the specified log level is passed as an argument, rather than
* the one for the manager process. */
- r = log_level_to_string_alloc(context->log_level_max >= 0 ? context->log_level_max : log_get_max_level(), &log_level);
+ r = log_max_levels_to_string(context->log_level_max >= 0 ? context->log_level_max : log_get_max_level(), &max_log_levels);
if (r < 0)
- return log_unit_error_errno(unit, r, "Failed to convert log level to string: %m");
+ return log_unit_error_errno(unit, r, "Failed to convert max log levels to string: %m");
r = fd_get_path(unit->manager->executor_fd, &executor_path);
if (r < 0)
FORMAT_PROC_FD_PATH(unit->manager->executor_fd),
STRV_MAKE(executor_path,
"--deserialize", serialization_fd_number,
- "--log-level", log_level,
+ "--log-level", max_log_levels,
"--log-target", log_target_to_string(manager_get_executor_log_target(unit->manager))),
environ,
cg_unified() > 0 ? subcgroup_path : NULL,
[MANAGER_KEXEC] = "kexec",
};
- char log_level[STRLEN("--log-level=") + DECIMAL_STR_MAX(int)],
- timeout[STRLEN("--timeout=") + DECIMAL_STR_MAX(usec_t) + STRLEN("us")],
+ char timeout[STRLEN("--timeout=") + DECIMAL_STR_MAX(usec_t) + STRLEN("us")],
exit_code[STRLEN("--exit-code=") + DECIMAL_STR_MAX(uint8_t)];
_cleanup_strv_free_ char **env_block = NULL;
+ _cleanup_free_ char *max_log_levels = NULL;
usec_t watchdog_timer = 0;
int r;
assert(objective >= 0 && objective < _MANAGER_OBJECTIVE_MAX);
assert(table[objective]);
- xsprintf(log_level, "--log-level=%d", log_get_max_level());
xsprintf(timeout, "--timeout=%" PRI_USEC "us", arg_defaults.timeout_stop_usec);
- const char* command_line[10] = {
+ const char* command_line[11] = {
SYSTEMD_SHUTDOWN_BINARY_PATH,
table[objective],
- log_level,
timeout,
/* Note that the last position is a terminator and must contain NULL. */
};
- size_t pos = 4;
+ size_t pos = 3;
assert(command_line[pos-1]);
assert(!command_line[pos]);
+ (void) log_max_levels_to_string(log_get_max_level(), &max_log_levels);
+
+ if (max_log_levels) {
+ command_line[pos++] = "--log-level";
+ command_line[pos++] = max_log_levels;
+ }
+
switch (log_get_target()) {
case LOG_TARGET_KMSG:
#endif
if (r < 0)
- (void) sd_notifyf(0, "ERRNO=%i", -r);
+ (void) sd_notifyf(/* unset_environment= */ false,
+ "ERRNO=%i", -r);
/* Try to invoke the shutdown binary unless we already failed.
* If we failed above, we want to freeze after finishing cleanup. */
/* This is primarily useful when running systemd in a VM, as it provides the user running the VM with
* a mechanism to pick up systemd's exit status in the VM. */
- (void) sd_notifyf(0, "EXIT_STATUS=%i", retval);
+ (void) sd_notifyf(/* unset_environment= */ false,
+ "EXIT_STATUS=%i", retval);
watchdog_free_device();
arg_watchdog_device = mfree(arg_watchdog_device);
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);
+ (void) sd_notifyf(/* unset_environment= */ 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;
}
if (MANAGER_IS_TEST_RUN(m))
return 0;
- /* Enable that we get SIGINT on control-alt-del. In containers
- * this will fail with EPERM (older) or EINVAL (newer), so
- * ignore that. */
+ /* Enable that we get SIGINT on control-alt-del. In containers this will fail with EPERM (older) or
+ * EINVAL (newer), so ignore that. */
if (reboot(RB_DISABLE_CAD) < 0 && !IN_SET(errno, EPERM, EINVAL))
- log_warning_errno(errno, "Failed to enable ctrl-alt-del handling: %m");
+ log_warning_errno(errno, "Failed to enable ctrl-alt-del handling, ignoring: %m");
fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
- if (fd < 0) {
- /* Support systems without virtual console */
- if (fd != -ENOENT)
- log_warning_errno(errno, "Failed to open /dev/tty0: %m");
- } else {
+ if (fd < 0)
+ /* Support systems without virtual console (ENOENT) gracefully */
+ log_full_errno(fd == -ENOENT ? LOG_DEBUG : LOG_WARNING, fd, "Failed to open /dev/tty0, ignoring: %m");
+ else {
/* Enable that we get SIGWINCH on kbrequest */
if (ioctl(fd, KDSIGACCEPT, SIGWINCH) < 0)
- log_warning_errno(errno, "Failed to enable kbrequest handling: %m");
+ log_warning_errno(errno, "Failed to enable kbrequest handling, ignoring: %m");
}
return 0;
if (r < 0)
return r;
+ /* Report to supervisor that we now process the above signals. We report this as level "2", to
+ * indicate that we support more than sysvinit's signals (of course, sysvinit never sent this
+ * message, but conceptually it makes sense to consider level "1" to be equivalent to sysvinit's
+ * signal handling). Also, by setting this to "2" people looking for this hopefully won't
+ * misunderstand this as a boolean concept. Signal level 2 shall refer to the signals PID 1
+ * understands at the time of release of systemd v256, i.e. including basic SIGRTMIN+18 handling for
+ * memory pressure and stuff. When more signals are hooked up (or more SIGRTMIN+18 multiplex
+ * operations added, this level should be increased). */
+ (void) sd_notify(/* unset_environment= */ false,
+ "X_SYSTEMD_SIGNALS_LEVEL=2");
+
if (MANAGER_IS_SYSTEM(m))
return enable_special_signals(m);
log_info("Activating special unit %s...", s);
- sd_notifyf(false,
- "STATUS=Activating special unit %s...", s);
+ (void) sd_notifyf(/* unset_environment= */ false,
+ "STATUS=Activating special unit %s...", s);
m->status_ready = false;
}
const char *msg;
int audit_fd, r;
+ assert(m);
+ assert(u);
+
if (!MANAGER_IS_SYSTEM(m))
return;
- audit_fd = get_audit_fd();
- if (audit_fd < 0)
+ /* Don't generate audit events if the service was already started and we're just deserializing */
+ if (MANAGER_IS_RELOADING(m))
return;
- /* Don't generate audit events if the service was already
- * started and we're just deserializing */
- if (MANAGER_IS_RELOADING(m))
+ audit_fd = get_audit_fd();
+ if (audit_fd < 0)
return;
r = unit_name_to_prefix_and_instance(u->id, &p);
log_warning_errno(errno, "Failed to send audit message, ignoring: %m");
}
#endif
-
}
void manager_send_unit_plymouth(Manager *m, Unit *u) {
_cleanup_free_ char *message = NULL;
int c, r;
- /* Don't generate plymouth events if the service was already
- * started and we're just deserializing */
- if (MANAGER_IS_RELOADING(m))
- return;
+ assert(m);
+ assert(u);
if (!MANAGER_IS_SYSTEM(m))
return;
+ /* Don't generate plymouth events if the service was already started and we're just deserializing */
+ if (MANAGER_IS_RELOADING(m))
+ return;
+
if (detect_container() > 0)
return;
"Failed to communicate with plymouth: %m");
}
+void manager_send_unit_supervisor(Manager *m, Unit *u, bool active) {
+ assert(m);
+ assert(u);
+
+ /* Notify a "supervisor" process about our progress, i.e. a container manager, hypervisor, or
+ * surrounding service manager. */
+
+ if (MANAGER_IS_RELOADING(m))
+ return;
+
+ if (!UNIT_VTABLE(u)->notify_supervisor)
+ return;
+
+ if (in_initrd()) /* Only send these once we left the initrd */
+ return;
+
+ (void) sd_notifyf(/* unset_environment= */ false,
+ active ? "X_SYSTEMD_UNIT_ACTIVE=%s" : "X_SYSTEMD_UNIT_INACTIVE=%s",
+ u->id);
+}
+
usec_t manager_get_watchdog(Manager *m, WatchdogType t) {
assert(m);
log_taint_string(m);
}
-static void user_manager_send_ready(Manager *m) {
+static void manager_send_ready_user_scope(Manager *m) {
int r;
assert(m);
if (!MANAGER_IS_USER(m) || m->ready_sent)
return;
- r = sd_notify(false,
+ r = sd_notify(/* unset_environment= */ false,
"READY=1\n"
"STATUS=Reached " SPECIAL_BASIC_TARGET ".");
if (r < 0)
m->status_ready = false;
}
-static void manager_send_ready(Manager *m) {
+static void manager_send_ready_system_scope(Manager *m) {
int r;
+ assert(m);
+
+ if (!MANAGER_IS_SYSTEM(m))
+ return;
+
+ /* Skip the notification if nothing changed. */
if (m->ready_sent && m->status_ready)
- /* Skip the notification if nothing changed. */
return;
- r = sd_notify(false,
+ r = sd_notify(/* unset_environment= */ false,
"READY=1\n"
"STATUS=Ready.");
if (r < 0)
return;
/* For user managers, send out READY=1 as soon as we reach basic.target */
- user_manager_send_ready(m);
+ manager_send_ready_user_scope(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);
+ manager_send_ready_system_scope(m);
/* Notify Type=idle units that we are done now */
manager_close_idle_pipe(m);
assert(m);
/* Let whoever invoked us know that we are now reloading */
- (void) sd_notifyf(/* unset= */ false,
+ (void) sd_notifyf(/* unset_environment= */ false,
"RELOADING=1\n"
"MONOTONIC_USEC=" USEC_FMT "\n", now(CLOCK_MONOTONIC));
void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success);
void manager_send_unit_plymouth(Manager *m, Unit *u);
+void manager_send_unit_supervisor(Manager *m, Unit *u, bool active);
bool manager_unit_inactive_or_pending(Manager *m, const char *name);
}
static void mount_init(Unit *u) {
- Mount *m = MOUNT(u);
+ Mount *m = ASSERT_PTR(MOUNT(u));
- assert(m);
- assert(u);
assert(u->load_state == UNIT_STUB);
m->timeout_usec = u->manager->defaults.timeout_start_usec;
}
static void mount_done(Unit *u) {
- Mount *m = MOUNT(u);
-
- assert(m);
+ Mount *m = ASSERT_PTR(MOUNT(u));
m->where = mfree(m->where);
MountParameters *p;
int r, q, w;
+ assert(m);
+
p = &m->parameters_proc_self_mountinfo;
r = free_and_strdup(&p->what, what);
}
static bool mount_is_extrinsic(Unit *u) {
+ Mount *m = ASSERT_PTR(MOUNT(u));
MountParameters *p;
- Mount *m = MOUNT(u);
- assert(m);
/* Returns true for all units that are "magic" and should be excluded from the usual
* start-up and shutdown dependencies. We call them "extrinsic" here, as they are generally
}
static int mount_add_extras(Mount *m) {
- Unit *u = UNIT(m);
+ Unit *u = UNIT(ASSERT_PTR(m));
int r;
- assert(m);
-
/* Note: this call might be called after we already have been loaded once (and even when it has already been
* activated), in case data from /proc/self/mountinfo has changed. This means all code here needs to be ready
* to run with an already set up unit. */
}
static void mount_load_root_mount(Unit *u) {
- assert(u);
+ Mount *m = ASSERT_PTR(MOUNT(u));
if (!unit_has_name(u, SPECIAL_ROOT_MOUNT))
return;
u->default_dependencies = false;
/* The stdio/kmsg bridge socket is on /, in order to avoid a dep loop, don't use kmsg logging for -.mount */
- MOUNT(u)->exec_context.std_output = EXEC_OUTPUT_NULL;
- MOUNT(u)->exec_context.std_input = EXEC_INPUT_NULL;
+ m->exec_context.std_output = EXEC_OUTPUT_NULL;
+ m->exec_context.std_input = EXEC_INPUT_NULL;
if (!u->description)
u->description = strdup("Root Mount");
}
static int mount_load(Unit *u) {
- Mount *m = MOUNT(u);
- int r, q = 0;
+ Mount *m = ASSERT_PTR(MOUNT(u));
+ int r;
- assert(m);
- assert(u);
assert(u->load_state == UNIT_STUB);
mount_load_root_mount(u);
- bool fragment_optional = m->from_proc_self_mountinfo || u->perpetual;
- r = unit_load_fragment_and_dropin(u, !fragment_optional);
+ bool from_kernel = m->from_proc_self_mountinfo || u->perpetual;
+
+ r = unit_load_fragment_and_dropin(u, /* fragment_required = */ !from_kernel);
/* Add in some extras. Note we do this in all cases (even if we failed to load the unit) when announced by the
* kernel, because we need some things to be set up no matter what when the kernel establishes a mount and thus
* we need to update the state in our unit to track it. After all, consider that we don't allow changing the
* 'slice' field for a unit once it is active. */
- if (u->load_state == UNIT_LOADED || m->from_proc_self_mountinfo || u->perpetual)
- q = mount_add_extras(m);
+ if (u->load_state == UNIT_LOADED || from_kernel)
+ RET_GATHER(r, mount_add_extras(m));
if (r < 0)
return r;
- if (q < 0)
- return q;
+
if (u->load_state != UNIT_LOADED)
return 0;
static void mount_set_state(Mount *m, MountState state) {
MountState old_state;
+
assert(m);
if (m->state != state)
}
static int mount_coldplug(Unit *u) {
- Mount *m = MOUNT(u);
+ Mount *m = ASSERT_PTR(MOUNT(u));
int r;
- assert(m);
assert(m->state == MOUNT_DEAD);
if (m->deserialized_state == m->state)
}
static void mount_catchup(Unit *u) {
- Mount *m = MOUNT(ASSERT_PTR(u));
-
- assert(m);
+ Mount *m = ASSERT_PTR(MOUNT(u));
/* Adjust the deserialized state. See comments in mount_process_proc_self_mountinfo(). */
if (m->from_proc_self_mountinfo)
}
static void mount_dump(Unit *u, FILE *f, const char *prefix) {
- Mount *m = MOUNT(u);
+ Mount *m = ASSERT_PTR(MOUNT(u));
MountParameters *p;
- assert(m);
assert(f);
p = get_mount_parameters(m);
}
static int mount_spawn(Mount *m, ExecCommand *c, PidRef *ret_pid) {
-
_cleanup_(exec_params_shallow_clear) ExecParameters exec_params = EXEC_PARAMETERS_INIT(
EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN);
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
}
static void mount_enter_mounting(Mount *m) {
- int r;
MountParameters *p;
bool source_is_dir = true;
+ int r;
assert(m);
}
static void mount_enter_remounting(Mount *m) {
- int r;
MountParameters *p;
+ int r;
assert(m);
}
static int mount_start(Unit *u) {
- Mount *m = MOUNT(u);
+ Mount *m = ASSERT_PTR(MOUNT(u));
int r;
- assert(m);
-
/* We cannot fulfill this request right now, try again later
* please! */
if (IN_SET(m->state,
}
static int mount_stop(Unit *u) {
- Mount *m = MOUNT(u);
-
- assert(m);
+ Mount *m = ASSERT_PTR(MOUNT(u));
/* When we directly call umount() for a path, then the state of the corresponding mount unit may be
* outdated. Let's re-read mountinfo now and update the state. */
}
static int mount_reload(Unit *u) {
- Mount *m = MOUNT(u);
+ Mount *m = ASSERT_PTR(MOUNT(u));
- assert(m);
assert(m->state == MOUNT_MOUNTED);
mount_enter_remounting(m);
}
static int mount_serialize(Unit *u, FILE *f, FDSet *fds) {
- Mount *m = MOUNT(u);
+ Mount *m = ASSERT_PTR(MOUNT(u));
- assert(m);
assert(f);
assert(fds);
}
static int mount_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Mount *m = MOUNT(u);
+ Mount *m = ASSERT_PTR(MOUNT(u));
int r;
- assert(m);
- assert(u);
assert(key);
assert(value);
assert(fds);
}
static UnitActiveState mount_active_state(Unit *u) {
- assert(u);
+ Mount *m = ASSERT_PTR(MOUNT(u));
- return state_translation_table[MOUNT(u)->state];
+ return state_translation_table[m->state];
}
static const char *mount_sub_state_to_string(Unit *u) {
- assert(u);
+ Mount *m = ASSERT_PTR(MOUNT(u));
- return mount_state_to_string(MOUNT(u)->state);
+ return mount_state_to_string(m->state);
}
static bool mount_may_gc(Unit *u) {
- Mount *m = MOUNT(u);
-
- assert(m);
+ Mount *m = ASSERT_PTR(MOUNT(u));
if (m->from_proc_self_mountinfo)
return false;
}
static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
- Mount *m = MOUNT(u);
+ Mount *m = ASSERT_PTR(MOUNT(u));
MountResult f;
- assert(m);
assert(pid >= 0);
if (pid != m->control_pid.pid)
}
static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
- Mount *m = MOUNT(userdata);
+ Mount *m = ASSERT_PTR(MOUNT(userdata));
- assert(m);
assert(m->timer_event_source == source);
switch (m->state) {
Unit **ret) {
_cleanup_(unit_freep) Unit *u = NULL;
+ Mount *mnt;
int r;
assert(m);
if (r < 0)
return r;
+ mnt = ASSERT_PTR(MOUNT(u));
+
r = free_and_strdup(&u->source_path, "/proc/self/mountinfo");
if (r < 0)
return r;
- r = free_and_strdup(&MOUNT(u)->where, where);
+ r = free_and_strdup(&mnt->where, where);
if (r < 0)
return r;
- r = update_parameters_proc_self_mountinfo(MOUNT(u), what, options, fstype);
+ r = update_parameters_proc_self_mountinfo(mnt, what, options, fstype);
if (r < 0)
return r;
/* This unit was generated because /proc/self/mountinfo reported it. Remember this, so that by the
* time we load the unit file for it (and thus add in extra deps right after) we know what source to
* attributes the deps to. */
- MOUNT(u)->from_proc_self_mountinfo = true;
+ mnt->from_proc_self_mountinfo = true;
- r = mount_add_non_exec_dependencies(MOUNT(u));
+ r = mount_add_non_exec_dependencies(mnt);
if (r < 0)
return r;
const char *fstype,
MountProcFlags *ret_flags) {
+ Mount *m = ASSERT_PTR(MOUNT(u));
int r;
assert(u);
+ assert(where);
assert(ret_flags);
- if (!MOUNT(u)->where) {
- MOUNT(u)->where = strdup(where);
- if (!MOUNT(u)->where)
+ if (!m->where) {
+ m->where = strdup(where);
+ if (!m->where)
return -ENOMEM;
}
* for the current unit. Note that the flags field is reset on each iteration of reading
* /proc/self/mountinfo, hence we know for sure anything already set here is from the current
* iteration and thus worthy of taking into account. */
- MountProcFlags flags =
- MOUNT(u)->proc_flags | MOUNT_PROC_IS_MOUNTED;
+ MountProcFlags flags = m->proc_flags | MOUNT_PROC_IS_MOUNTED;
- r = update_parameters_proc_self_mountinfo(MOUNT(u), what, options, fstype);
+ r = update_parameters_proc_self_mountinfo(m, what, options, fstype);
if (r < 0)
return r;
if (r > 0)
* from the serialized state), and need to catch up. Since we know that the MOUNT_MOUNTING state is
* reached when we wait for the mount to appear we hence can assume that if we are in it, we are
* actually seeing it established for the first time. */
- if (!MOUNT(u)->from_proc_self_mountinfo || MOUNT(u)->state == MOUNT_MOUNTING)
+ if (!m->from_proc_self_mountinfo || m->state == MOUNT_MOUNTING)
flags |= MOUNT_PROC_JUST_MOUNTED;
- MOUNT(u)->from_proc_self_mountinfo = true;
+ m->from_proc_self_mountinfo = true;
if (IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_BAD_SETTING, UNIT_ERROR)) {
/* The unit was previously not found or otherwise not loaded. Now that the unit shows up in
if (FLAGS_SET(flags, MOUNT_PROC_JUST_CHANGED)) {
/* If things changed, then make sure that all deps are regenerated. Let's
* first remove all automatic deps, and then add in the new ones. */
- r = mount_add_non_exec_dependencies(MOUNT(u));
+ r = mount_add_non_exec_dependencies(m);
if (r < 0)
return r;
}
}
static int mount_get_timeout(Unit *u, usec_t *timeout) {
- Mount *m = MOUNT(u);
+ Mount *m = ASSERT_PTR(MOUNT(u));
usec_t t;
int r;
- assert(m);
- assert(u);
-
if (!m->timer_event_source)
return 0;
}
static int mount_can_clean(Unit *u, ExecCleanMask *ret) {
- Mount *m = MOUNT(u);
-
- assert(m);
+ Mount *m = ASSERT_PTR(MOUNT(u));
return exec_context_get_clean_mask(&m->exec_context, ret);
}
static int mount_can_start(Unit *u) {
- Mount *m = MOUNT(u);
+ Mount *m = ASSERT_PTR(MOUNT(u));
int r;
- assert(m);
-
r = unit_test_start_limit(u);
if (r < 0) {
mount_enter_dead(m, MOUNT_FAILURE_START_LIMIT_HIT);
static void path_spec_mkdir(PathSpec *s, mode_t mode) {
int r;
+ assert(s);
+
if (IN_SET(s->type, PATH_EXISTS, PATH_EXISTS_GLOB))
return;
static void path_spec_dump(PathSpec *s, FILE *f, const char *prefix) {
const char *type;
+ assert(s);
+ assert(f);
+ assert(prefix);
+
assert_se(type = path_type_to_string(s->type));
fprintf(f, "%s%s: %s\n", prefix, type, s->path);
}
}
static void path_init(Unit *u) {
- Path *p = PATH(u);
+ Path *p = ASSERT_PTR(PATH(u));
- assert(u);
assert(u->load_state == UNIT_STUB);
p->directory_mode = 0755;
}
static void path_done(Unit *u) {
- Path *p = PATH(u);
-
- assert(p);
+ Path *p = ASSERT_PTR(PATH(u));
p->trigger_notify_event_source = sd_event_source_disable_unref(p->trigger_notify_event_source);
path_free_specs(p);
}
static int path_load(Unit *u) {
- Path *p = PATH(u);
+ Path *p = ASSERT_PTR(PATH(u));
int r;
- assert(u);
assert(u->load_state == UNIT_STUB);
r = unit_load_fragment_and_dropin(u, true);
}
static void path_dump(Unit *u, FILE *f, const char *prefix) {
- Path *p = PATH(u);
+ Path *p = ASSERT_PTR(PATH(u));
Unit *trigger;
- assert(p);
assert(f);
+ assert(prefix);
trigger = UNIT_TRIGGER(u);
static void path_set_state(Path *p, PathState state) {
PathState old_state;
+
assert(p);
if (p->state != state)
static void path_enter_waiting(Path *p, bool initial, bool from_trigger_notify);
static int path_coldplug(Unit *u) {
- Path *p = PATH(u);
+ Path *p = ASSERT_PTR(PATH(u));
- assert(p);
assert(p->state == PATH_DEAD);
if (p->deserialized_state != p->state) {
}
static int path_start(Unit *u) {
- Path *p = PATH(u);
+ Path *p = ASSERT_PTR(PATH(u));
int r;
- assert(p);
assert(IN_SET(p->state, PATH_DEAD, PATH_FAILED));
r = unit_test_trigger_loaded(u);
}
static int path_stop(Unit *u) {
- Path *p = PATH(u);
+ Path *p = ASSERT_PTR(PATH(u));
- assert(p);
assert(IN_SET(p->state, PATH_WAITING, PATH_RUNNING));
path_enter_dead(p, PATH_SUCCESS);
}
static int path_serialize(Unit *u, FILE *f, FDSet *fds) {
- Path *p = PATH(u);
+ Path *p = ASSERT_PTR(PATH(u));
- assert(u);
assert(f);
assert(fds);
}
static int path_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Path *p = PATH(u);
+ Path *p = ASSERT_PTR(PATH(u));
- assert(u);
assert(key);
assert(value);
assert(fds);
}
static UnitActiveState path_active_state(Unit *u) {
- assert(u);
+ Path *p = ASSERT_PTR(PATH(u));
- return state_translation_table[PATH(u)->state];
+ return state_translation_table[p->state];
}
static const char *path_sub_state_to_string(Unit *u) {
- assert(u);
+ Path *p = ASSERT_PTR(PATH(u));
- return path_state_to_string(PATH(u)->state);
+ return path_state_to_string(p->state);
}
static int path_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
- PathSpec *s = userdata, *found = NULL;
- Path *p;
+ PathSpec *s = ASSERT_PTR(userdata), *found = NULL;
+ Path *p = ASSERT_PTR(PATH(s->unit));
int changed;
- assert(s);
- assert(s->unit);
assert(fd >= 0);
- p = PATH(s->unit);
-
if (!IN_SET(p->state, PATH_WAITING, PATH_RUNNING))
return 0;
}
static void path_trigger_notify_impl(Unit *u, Unit *other, bool on_defer) {
- Path *p = PATH(u);
+ Path *p = ASSERT_PTR(PATH(u));
int r;
- assert(u);
assert(other);
/* Invoked whenever the unit we trigger changes state or gains or loses a job */
}
static void path_reset_failed(Unit *u) {
- Path *p = PATH(u);
-
- assert(p);
+ Path *p = ASSERT_PTR(PATH(u));
if (p->state == PATH_FAILED)
path_set_state(p, PATH_DEAD);
}
static int path_can_start(Unit *u) {
- Path *p = PATH(u);
+ Path *p = ASSERT_PTR(PATH(u));
int r;
- assert(p);
-
r = unit_test_start_limit(u);
if (r < 0) {
path_enter_dead(p, PATH_FAILURE_START_LIMIT_HIT);
}
static int activation_details_path_append_env(ActivationDetails *details, char ***strv) {
- ActivationDetailsPath *p = ACTIVATION_DETAILS_PATH(details);
+ ActivationDetailsPath *p = ASSERT_PTR(ACTIVATION_DETAILS_PATH(details));
char *s;
int r;
- assert(details);
assert(strv);
- assert(p);
if (isempty(p->trigger_path_filename))
return 0;
}
static int activation_details_path_append_pair(ActivationDetails *details, char ***strv) {
- ActivationDetailsPath *p = ACTIVATION_DETAILS_PATH(details);
+ ActivationDetailsPath *p = ASSERT_PTR(ACTIVATION_DETAILS_PATH(details));
int r;
- assert(details);
assert(strv);
- assert(p);
if (isempty(p->trigger_path_filename))
return 0;
static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata);
static void scope_init(Unit *u) {
- Scope *s = SCOPE(u);
+ Scope *s = ASSERT_PTR(SCOPE(u));
- assert(u);
assert(u->load_state == UNIT_STUB);
s->runtime_max_usec = USEC_INFINITY;
}
static void scope_done(Unit *u) {
- Scope *s = SCOPE(u);
-
- assert(u);
+ Scope *s = ASSERT_PTR(SCOPE(u));
s->controller = mfree(s->controller);
s->controller_track = sd_bus_track_unref(s->controller_track);
static void scope_set_state(Scope *s, ScopeState state) {
ScopeState old_state;
+
assert(s);
if (s->state != state)
}
static int scope_load(Unit *u) {
- Scope *s = SCOPE(u);
+ Scope *s = ASSERT_PTR(SCOPE(u));
int r;
- assert(s);
assert(u->load_state == UNIT_STUB);
if (!u->transient && !MANAGER_IS_RELOADING(u->manager))
}
static int scope_coldplug(Unit *u) {
- Scope *s = SCOPE(u);
+ Scope *s = ASSERT_PTR(SCOPE(u));
int r;
- assert(s);
assert(s->state == SCOPE_DEAD);
if (s->deserialized_state == s->state)
}
static void scope_dump(Unit *u, FILE *f, const char *prefix) {
- Scope *s = SCOPE(u);
+ Scope *s = ASSERT_PTR(SCOPE(u));
- assert(s);
assert(f);
+ assert(prefix);
fprintf(f,
"%sScope State: %s\n"
prefix, FORMAT_TIMESPAN(s->runtime_rand_extra_usec, USEC_PER_SEC),
prefix, oom_policy_to_string(s->oom_policy));
- cgroup_context_dump(UNIT(s), f, prefix);
+ cgroup_context_dump(u, f, prefix);
kill_context_dump(&s->kill_context, f, prefix);
}
}
static int scope_enter_start_chown(Scope *s) {
+ Unit *u = UNIT(ASSERT_PTR(s));
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
- Unit *u = UNIT(s);
int r;
- assert(s);
assert(s->user);
if (!s->cgroup_runtime)
}
static int scope_enter_running(Scope *s) {
- Unit *u = UNIT(s);
+ Unit *u = UNIT(ASSERT_PTR(s));
int r;
- assert(s);
-
(void) bus_scope_track_controller(s);
r = unit_acquire_invocation_id(u);
}
static int scope_start(Unit *u) {
- Scope *s = SCOPE(u);
-
- assert(s);
+ Scope *s = ASSERT_PTR(SCOPE(u));
if (unit_has_name(u, SPECIAL_INIT_SCOPE))
return -EPERM;
}
static int scope_stop(Unit *u) {
- Scope *s = SCOPE(u);
-
- assert(s);
+ Scope *s = ASSERT_PTR(SCOPE(u));
if (IN_SET(s->state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
return 0;
}
static void scope_reset_failed(Unit *u) {
- Scope *s = SCOPE(u);
-
- assert(s);
+ Scope *s = ASSERT_PTR(SCOPE(u));
if (s->state == SCOPE_FAILED)
scope_set_state(s, SCOPE_DEAD);
}
static int scope_get_timeout(Unit *u, usec_t *timeout) {
- Scope *s = SCOPE(u);
+ Scope *s = ASSERT_PTR(SCOPE(u));
usec_t t;
int r;
}
static int scope_serialize(Unit *u, FILE *f, FDSet *fds) {
- Scope *s = SCOPE(u);
+ Scope *s = ASSERT_PTR(SCOPE(u));
PidRef *pid;
- assert(s);
assert(f);
assert(fds);
}
static int scope_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Scope *s = SCOPE(u);
+ Scope *s = ASSERT_PTR(SCOPE(u));
int r;
- assert(u);
assert(key);
assert(value);
assert(fds);
}
static void scope_notify_cgroup_empty_event(Unit *u) {
- Scope *s = SCOPE(u);
- assert(u);
+ Scope *s = ASSERT_PTR(SCOPE(u));
log_unit_debug(u, "cgroup is empty");
}
static void scope_notify_cgroup_oom_event(Unit *u, bool managed_oom) {
- Scope *s = SCOPE(u);
+ Scope *s = ASSERT_PTR(SCOPE(u));
if (managed_oom)
log_unit_debug(u, "Process(es) of control group were killed by systemd-oomd.");
}
static void scope_sigchld_event(Unit *u, pid_t pid, int code, int status) {
- Scope *s = SCOPE(u);
-
- assert(s);
+ Scope *s = ASSERT_PTR(SCOPE(u));
if (s->state == SCOPE_START_CHOWN) {
if (!is_clean_exit(code, status, EXIT_CLEAN_COMMAND, NULL))
}
static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
- Scope *s = SCOPE(userdata);
+ Scope *s = ASSERT_PTR(SCOPE(userdata));
- assert(s);
assert(s->timer_event_source == source);
switch (s->state) {
}
static UnitActiveState scope_active_state(Unit *u) {
- assert(u);
+ Scope *s = ASSERT_PTR(SCOPE(u));
- return state_translation_table[SCOPE(u)->state];
+ return state_translation_table[s->state];
}
static const char *scope_sub_state_to_string(Unit *u) {
- assert(u);
+ Scope *s = ASSERT_PTR(SCOPE(u));
- return scope_state_to_string(SCOPE(u)->state);
+ return scope_state_to_string(s->state);
}
static void scope_enumerate_perpetual(Manager *m) {
}
static void service_unwatch_pid_file(Service *s) {
+ assert(s);
+
if (!s->pid_file_pathspec)
return;
}
static void service_done(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
+ Service *s = ASSERT_PTR(SERVICE(u));
open_file_free_many(&s->open_files);
}
static int service_load(Unit *u) {
- Service *s = SERVICE(u);
+ Service *s = ASSERT_PTR(SERVICE(u));
int r;
r = unit_load_fragment_and_dropin(u, true);
}
static void service_dump(Unit *u, FILE *f, const char *prefix) {
- Service *s = SERVICE(u);
+ Service *s = ASSERT_PTR(SERVICE(u));
const char *prefix2;
- assert(s);
-
prefix = strempty(prefix);
prefix2 = strjoina(prefix, "\t");
static bool service_good(Service *s) {
int main_pid_ok;
+
assert(s);
if (s->type == SERVICE_DBUS && !s->bus_name_good)
static void service_enter_start_post(Service *s) {
int r;
+
assert(s);
service_unwatch_control_pid(s);
}
static int service_stop(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
+ Service *s = ASSERT_PTR(SERVICE(u));
/* Don't create restart jobs from manual stops. */
s->forbid_restart = true;
}
static int service_reload(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
+ Service *s = ASSERT_PTR(SERVICE(u));
assert(IN_SET(s->state, SERVICE_RUNNING, SERVICE_EXITED));
}
static bool service_can_reload(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
+ Service *s = ASSERT_PTR(SERVICE(u));
return s->exec_command[SERVICE_EXEC_RELOAD] ||
s->type == SERVICE_NOTIFY_RELOAD;
}
static int service_serialize_exec_command(Unit *u, FILE *f, const ExecCommand *command) {
+ Service *s = ASSERT_PTR(SERVICE(u));
_cleanup_free_ char *args = NULL, *p = NULL;
- Service *s = SERVICE(u);
const char *type, *key;
ServiceExecCommand id;
size_t length = 0;
unsigned idx;
- assert(s);
assert(f);
if (!command)
}
static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
- Service *s = SERVICE(u);
+ Service *s = ASSERT_PTR(SERVICE(u));
int r;
- assert(u);
assert(f);
assert(fds);
const char *key,
const char *value) {
- Service *s = SERVICE(u);
- int r;
- unsigned idx = 0, i;
- bool control, found = false, last = false;
- ServiceExecCommand id = _SERVICE_EXEC_COMMAND_INVALID;
+ Service *s = ASSERT_PTR(SERVICE(u));
ExecCommand *command = NULL;
+ ServiceExecCommand id = _SERVICE_EXEC_COMMAND_INVALID;
_cleanup_free_ char *path = NULL;
_cleanup_strv_free_ char **argv = NULL;
+ unsigned idx = 0, i;
+ bool control, found = false, last = false;
+ int r;
enum ExecCommandState {
STATE_EXEC_COMMAND_TYPE,
_STATE_EXEC_COMMAND_INVALID = -EINVAL,
} state;
- assert(s);
assert(key);
assert(value);
}
static int service_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Service *s = SERVICE(u);
+ Service *s = ASSERT_PTR(SERVICE(u));
int r;
- assert(u);
assert(key);
assert(value);
assert(fds);
}
static UnitActiveState service_active_state(Unit *u) {
+ Service *s = ASSERT_PTR(SERVICE(u));
const UnitActiveState *table;
- assert(u);
-
- table = SERVICE(u)->type == SERVICE_IDLE ? state_translation_table_idle : state_translation_table;
+ table = s->type == SERVICE_IDLE ? state_translation_table_idle : state_translation_table;
- return table[SERVICE(u)->state];
+ return table[s->state];
}
static const char *service_sub_state_to_string(Unit *u) {
}
static bool service_may_gc(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
+ Service *s = ASSERT_PTR(SERVICE(u));
/* Never clean up services that still have a process around, even if the service is formally dead. Note that
* unit_may_gc() already checked our cgroup for us, we just check our two additional PIDs, too, in case they
static int service_retry_pid_file(Service *s) {
int r;
+ assert(s);
assert(s->pid_file);
assert(IN_SET(s->state, SERVICE_START, SERVICE_START_POST));
static int service_watch_pid_file(Service *s) {
int r;
+ assert(s);
+
log_unit_debug(UNIT(s), "Setting watch for PID file %s", s->pid_file_pathspec->path);
r = path_spec_watch(s->pid_file_pathspec, service_dispatch_inotify_io);
static int service_demand_pid_file(Service *s) {
_cleanup_free_ PathSpec *ps = NULL;
+ assert(s);
assert(s->pid_file);
assert(!s->pid_file_pathspec);
static int service_dispatch_inotify_io(sd_event_source *source, int fd, uint32_t events, void *userdata) {
PathSpec *p = ASSERT_PTR(userdata);
- Service *s;
-
- s = SERVICE(p->unit);
+ Service *s = ASSERT_PTR(SERVICE(p->unit));
- assert(s);
assert(fd >= 0);
assert(IN_SET(s->state, SERVICE_START, SERVICE_START_POST));
assert(s->pid_file_pathspec);
}
static int service_dispatch_exec_io(sd_event_source *source, int fd, uint32_t events, void *userdata) {
- Service *s = SERVICE(userdata);
-
- assert(s);
+ Service *s = ASSERT_PTR(SERVICE(userdata));
log_unit_debug(UNIT(s), "got exec-fd event");
}
static void service_notify_cgroup_empty_event(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(u);
+ Service *s = ASSERT_PTR(SERVICE(u));
log_unit_debug(u, "Control group is empty.");
}
static void service_notify_cgroup_oom_event(Unit *u, bool managed_oom) {
- Service *s = SERVICE(u);
+ Service *s = ASSERT_PTR(SERVICE(u));
if (managed_oom)
log_unit_debug(u, "Process(es) of control group were killed by systemd-oomd.");
}
static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
+ Service *s = ASSERT_PTR(SERVICE(u));
bool notify_dbus = true;
- Service *s = SERVICE(u);
ServiceResult f;
ExitClean clean_mode;
int r;
- assert(s);
assert(pid >= 0);
/* Oneshot services and non-SERVICE_EXEC_START commands should not be
}
static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
- Service *s = SERVICE(userdata);
+ Service *s = ASSERT_PTR(SERVICE(userdata));
- assert(s);
assert(source == s->timer_event_source);
switch (s->state) {
}
static int service_dispatch_watchdog(sd_event_source *source, usec_t usec, void *userdata) {
- Service *s = SERVICE(userdata);
+ Service *s = ASSERT_PTR(SERVICE(userdata));
usec_t watchdog_usec;
- assert(s);
assert(source == s->watchdog_event_source);
watchdog_usec = service_get_watchdog_usec(s);
}
static void service_force_watchdog(Service *s) {
+ assert(s);
+
if (!UNIT(s)->manager->service_watchdogs)
return;
}
static int service_get_timeout(Unit *u, usec_t *timeout) {
- Service *s = SERVICE(u);
+ Service *s = ASSERT_PTR(SERVICE(u));
uint64_t t;
int r;
+ assert(timeout);
+
if (!s->timer_event_source)
return 0;
}
static usec_t service_get_timeout_start_usec(Unit *u) {
- Service *s = SERVICE(ASSERT_PTR(u));
+ Service *s = ASSERT_PTR(SERVICE(u));
return s->timeout_start_usec;
}
}
static int bus_name_pid_lookup_callback(sd_bus_message *reply, void *userdata, sd_bus_error *ret_error) {
+ Service *s = ASSERT_PTR(SERVICE(userdata));
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
const sd_bus_error *e;
- Unit *u = ASSERT_PTR(userdata);
uint32_t pid;
- Service *s;
int r;
assert(reply);
- s = SERVICE(u);
s->bus_name_pid_lookup_slot = sd_bus_slot_unref(s->bus_name_pid_lookup_slot);
if (!s->bus_name || !pick_up_pid_from_bus_name(s))
return 1;
}
- log_unit_debug(u, "D-Bus name %s is now owned by process " PID_FMT, s->bus_name, pidref.pid);
+ log_unit_debug(UNIT(s), "D-Bus name %s is now owned by process " PID_FMT, s->bus_name, pidref.pid);
(void) service_set_main_pidref(s, &pidref);
(void) unit_watch_pidref(UNIT(s), &s->main_pid, /* exclusive= */ false);
}
static void service_bus_name_owner_change(Unit *u, const char *new_owner) {
-
- Service *s = SERVICE(u);
+ Service *s = ASSERT_PTR(SERVICE(u));
int r;
- assert(s);
-
if (new_owner)
log_unit_debug(u, "D-Bus name %s now owned by %s", s->bus_name, new_owner);
else
}
static void service_reset_failed(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
+ Service *s = ASSERT_PTR(SERVICE(u));
if (s->state == SERVICE_FAILED)
service_set_state(s, service_determine_dead_state(s));
}
static bool service_needs_console(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
+ Service *s = ASSERT_PTR(SERVICE(u));
/* We provide our own implementation of this here, instead of relying of the generic implementation
* unit_needs_console() provides, since we want to return false if we are in SERVICE_EXITED state. */
}
static int service_exit_status(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(u);
+ Service *s = ASSERT_PTR(SERVICE(u));
if (s->main_exec_status.pid <= 0 ||
!dual_timestamp_is_set(&s->main_exec_status.exit_timestamp))
}
static const char* service_status_text(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
+ Service *s = ASSERT_PTR(SERVICE(u));
return s->status_text;
}
static int service_clean(Unit *u, ExecCleanMask mask) {
+ Service *s = ASSERT_PTR(SERVICE(u));
_cleanup_strv_free_ char **l = NULL;
bool may_clean_fdstore = false;
- Service *s = SERVICE(u);
int r;
- assert(s);
assert(mask != 0);
if (!IN_SET(s->state, SERVICE_DEAD, SERVICE_DEAD_RESOURCES_PINNED))
}
static int service_can_clean(Unit *u, ExecCleanMask *ret) {
- Service *s = SERVICE(u);
+ Service *s = ASSERT_PTR(SERVICE(u));
ExecCleanMask mask = 0;
int r;
- assert(s);
assert(ret);
r = exec_context_get_clean_mask(&s->exec_context, &mask);
return 0;
}
-static const char *service_finished_job(Unit *u, JobType t, JobResult result) {
+static const char* service_finished_job(Unit *u, JobType t, JobResult result) {
+ Service *s = ASSERT_PTR(SERVICE(u));
+
if (t == JOB_START &&
result == JOB_DONE &&
- SERVICE(u)->type == SERVICE_ONESHOT)
+ s->type == SERVICE_ONESHOT)
return "Finished %s.";
/* Fall back to generic */
}
static int service_can_start(Unit *u) {
- Service *s = SERVICE(u);
+ Service *s = ASSERT_PTR(SERVICE(u));
int r;
- assert(s);
-
/* Make sure we don't enter a busy loop of some kind. */
r = unit_test_start_limit(u);
if (r < 0) {
}
static void service_release_resources(Unit *u) {
- Service *s = SERVICE(ASSERT_PTR(u));
+ Service *s = ASSERT_PTR(SERVICE(u));
/* Invoked by the unit state engine, whenever it realizes that unit is dead and there's no job
* anymore for it, and it hence is a good idea to release resources */
/* Returns the SELinux label used for execution of the main service binary */
- if (s->exec_context.selinux_context) { /* Prefer the explicitly configured label if there is one */
- char *con = strdup(s->exec_context.selinux_context);
- if (!con)
- return -ENOMEM;
-
- *ret = con;
- return 0;
- }
+ if (s->exec_context.selinux_context)
+ /* Prefer the explicitly configured label if there is one */
+ return strdup_to(ret, s->exec_context.selinux_context);
if (s->exec_context.root_image ||
s->exec_context.n_extension_images > 0 ||
static void slice_set_state(Slice *t, SliceState state) {
SliceState old_state;
+
assert(t);
if (t->state != state)
}
static int slice_add_parent_slice(Slice *s) {
- Unit *u = UNIT(s);
+ Unit *u = UNIT(ASSERT_PTR(s));
_cleanup_free_ char *a = NULL;
int r;
- assert(s);
-
if (UNIT_GET_SLICE(u))
return 0;
}
static int slice_load(Unit *u) {
- Slice *s = SLICE(u);
+ Slice *s = ASSERT_PTR(SLICE(u));
int r;
- assert(s);
assert(u->load_state == UNIT_STUB);
r = slice_load_root_slice(u);
}
static int slice_coldplug(Unit *u) {
- Slice *t = SLICE(u);
+ Slice *s = ASSERT_PTR(SLICE(u));
- assert(t);
- assert(t->state == SLICE_DEAD);
+ assert(s->state == SLICE_DEAD);
- if (t->deserialized_state != t->state)
- slice_set_state(t, t->deserialized_state);
+ if (s->deserialized_state != s->state)
+ slice_set_state(s, s->deserialized_state);
return 0;
}
static void slice_dump(Unit *u, FILE *f, const char *prefix) {
- Slice *t = SLICE(u);
+ Slice *s = ASSERT_PTR(SLICE(u));
- assert(t);
+ assert(s);
assert(f);
+ assert(prefix);
fprintf(f,
"%sSlice State: %s\n",
- prefix, slice_state_to_string(t->state));
+ prefix, slice_state_to_string(s->state));
- cgroup_context_dump(UNIT(t), f, prefix);
+ cgroup_context_dump(u, f, prefix);
}
static int slice_start(Unit *u) {
- Slice *t = SLICE(u);
+ Slice *s = ASSERT_PTR(SLICE(u));
int r;
- assert(t);
- assert(t->state == SLICE_DEAD);
+ assert(s->state == SLICE_DEAD);
r = unit_acquire_invocation_id(u);
if (r < 0)
(void) unit_realize_cgroup(u);
(void) unit_reset_accounting(u);
- slice_set_state(t, SLICE_ACTIVE);
+ slice_set_state(s, SLICE_ACTIVE);
return 1;
}
static int slice_stop(Unit *u) {
- Slice *t = SLICE(u);
+ Slice *s = ASSERT_PTR(SLICE(u));
- assert(t);
- assert(t->state == SLICE_ACTIVE);
+ assert(s->state == SLICE_ACTIVE);
/* We do not need to destroy the cgroup explicitly,
* unit_notify() will do that for us anyway. */
- slice_set_state(t, SLICE_DEAD);
+ slice_set_state(s, SLICE_DEAD);
return 1;
}
static int slice_serialize(Unit *u, FILE *f, FDSet *fds) {
- Slice *s = SLICE(u);
+ Slice *s = ASSERT_PTR(SLICE(u));
- assert(s);
assert(f);
assert(fds);
}
static int slice_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Slice *s = SLICE(u);
+ Slice *s = ASSERT_PTR(SLICE(u));
- assert(u);
assert(key);
assert(value);
assert(fds);
state = slice_state_from_string(value);
if (state < 0)
- log_debug("Failed to parse state value %s", value);
+ log_unit_debug(u, "Failed to parse state: %s", value);
else
s->deserialized_state = state;
} else
- log_debug("Unknown serialization key '%s'", key);
+ log_unit_debug(u, "Unknown serialization key: %s", key);
return 0;
}
static UnitActiveState slice_active_state(Unit *u) {
- assert(u);
+ Slice *s = ASSERT_PTR(SLICE(u));
- return state_translation_table[SLICE(u)->state];
+ return state_translation_table[s->state];
}
static const char *slice_sub_state_to_string(Unit *u) {
- assert(u);
+ Slice *s = ASSERT_PTR(SLICE(u));
- return slice_state_to_string(SLICE(u)->state);
+ return slice_state_to_string(s->state);
}
static int slice_make_perpetual(Manager *m, const char *name, Unit **ret) {
}
static void socket_done(Unit *u) {
- Socket *s = SOCKET(u);
+ Socket *s = ASSERT_PTR(SOCKET(u));
SocketPeer *p;
- assert(s);
-
socket_free_ports(s);
while ((p = set_steal_first(s->peers_by_address)))
static int socket_add_default_dependencies(Socket *s) {
int r;
+
assert(s);
if (!UNIT(s)->default_dependencies)
static bool socket_has_exec(Socket *s) {
unsigned i;
+
assert(s);
for (i = 0; i < _SOCKET_EXEC_COMMAND_MAX; i++)
}
static int socket_add_extras(Socket *s) {
- Unit *u = UNIT(s);
+ Unit *u = UNIT(ASSERT_PTR(s));
int r;
- assert(s);
-
/* Pick defaults for the trigger limit, if nothing was explicitly configured. We pick a relatively high limit
* in Accept=yes mode, and a lower limit for Accept=no. Reason: in Accept=yes mode we are invoking accept()
* ourselves before the trigger limit can hit, thus incoming connections are taken off the socket queue quickly
DEFINE_PRIVATE_HASH_OPS(peer_address_hash_ops, SocketPeer, peer_address_hash_func, peer_address_compare_func);
static int socket_load(Unit *u) {
- Socket *s = SOCKET(u);
+ Socket *s = ASSERT_PTR(SOCKET(u));
int r;
- assert(u);
assert(u->load_state == UNIT_STUB);
r = unit_load_fragment_and_dropin(u, true);
}, *i;
int r;
- assert(fd >= 0);
assert(s);
+ assert(fd >= 0);
assert(ret);
if (getpeername(fd, &key.peer.sa, &key.peer_salen) < 0)
}
static void socket_dump(Unit *u, FILE *f, const char *prefix) {
- Socket *s = SOCKET(u);
+ Socket *s = ASSERT_PTR(SOCKET(u));
const char *prefix2, *str;
- assert(s);
assert(f);
prefix = strempty(prefix);
static int usbffs_write_descs(int fd, Service *s) {
int r;
+ assert(fd >= 0);
+ assert(s);
+
if (!s->usb_function_descriptors || !s->usb_function_strings)
return -EINVAL;
* instance name.
*/
+ assert(s);
+ assert(ret);
+
if (UNIT_ISSET(s->service)) {
*ret = UNIT_DEREF(s->service);
return 0;
static void socket_set_state(Socket *s, SocketState state) {
SocketState old_state;
+
assert(s);
if (s->state != state)
}
static int socket_coldplug(Unit *u) {
- Socket *s = SOCKET(u);
+ Socket *s = ASSERT_PTR(SOCKET(u));
int r;
- assert(s);
assert(s->state == SOCKET_DEAD);
if (s->deserialized_state == s->state)
}
static int socket_spawn(Socket *s, ExecCommand *c, PidRef *ret_pid) {
-
_cleanup_(exec_params_shallow_clear) ExecParameters exec_params = EXEC_PARAMETERS_INIT(
EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN);
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
static void socket_enter_stop_post(Socket *s, SocketResult f) {
int r;
+
assert(s);
if (s->result == SOCKET_SUCCESS)
static void socket_enter_stop_pre(Socket *s, SocketResult f) {
int r;
+
assert(s);
if (s->result == SOCKET_SUCCESS)
static void socket_enter_listening(Socket *s) {
int r;
+
assert(s);
if (!s->accept && s->flush_pending) {
static void socket_enter_start_post(Socket *s) {
int r;
+
assert(s);
socket_unwatch_control_pid(s);
static void socket_enter_start_pre(Socket *s) {
int r;
+
assert(s);
socket_unwatch_control_pid(s);
/* Note that this call takes possession of the connection fd passed. It either has to assign it
* somewhere or close it. */
_cleanup_close_ int cfd = cfd_in;
-
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
}
static int socket_start(Unit *u) {
- Socket *s = SOCKET(u);
+ Socket *s = ASSERT_PTR(SOCKET(u));
int r;
- assert(s);
-
/* We cannot fulfill this request right now, try again later
* please! */
if (IN_SET(s->state,
}
static int socket_stop(Unit *u) {
- Socket *s = SOCKET(u);
-
- assert(s);
+ Socket *s = ASSERT_PTR(SOCKET(u));
/* Already on it */
if (IN_SET(s->state,
}
static int socket_serialize(Unit *u, FILE *f, FDSet *fds) {
- Socket *s = SOCKET(u);
+ Socket *s = ASSERT_PTR(SOCKET(u));
int r;
- assert(u);
assert(f);
assert(fds);
}
static int socket_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Socket *s = SOCKET(u);
+ Socket *s = ASSERT_PTR(SOCKET(u));
int r;
- assert(u);
assert(key);
assert(value);
}
static void socket_distribute_fds(Unit *u, FDSet *fds) {
- Socket *s = SOCKET(u);
-
- assert(u);
+ Socket *s = ASSERT_PTR(SOCKET(u));
LIST_FOREACH(port, p, s->ports) {
int fd;
}
static UnitActiveState socket_active_state(Unit *u) {
- assert(u);
+ Socket *s = ASSERT_PTR(SOCKET(u));
- return state_translation_table[SOCKET(u)->state];
+ return state_translation_table[s->state];
}
static const char *socket_sub_state_to_string(Unit *u) {
- assert(u);
+ Socket *s = ASSERT_PTR(SOCKET(u));
- return socket_state_to_string(SOCKET(u)->state);
+ return socket_state_to_string(s->state);
}
int socket_port_to_address(const SocketPort *p, char **ret) {
}
const char* socket_port_type_to_string(SocketPort *p) {
-
assert(p);
switch (p->type) {
}
static bool socket_may_gc(Unit *u) {
- Socket *s = SOCKET(u);
-
- assert(u);
+ Socket *s = ASSERT_PTR(SOCKET(u));
return s->n_connections == 0;
}
}
static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) {
- Socket *s = SOCKET(u);
+ Socket *s = ASSERT_PTR(SOCKET(u));
SocketResult f;
- assert(s);
assert(pid >= 0);
if (pid != s->control_pid.pid)
}
static int socket_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
- Socket *s = SOCKET(userdata);
+ Socket *s = ASSERT_PTR(SOCKET(userdata));
- assert(s);
assert(s->timer_event_source == source);
switch (s->state) {
}
static void socket_trigger_notify(Unit *u, Unit *other) {
- Socket *s = SOCKET(u);
+ Socket *s = ASSERT_PTR(SOCKET(u));
- assert(u);
assert(other);
/* Filter out invocations with bogus state */
}
static int socket_get_timeout(Unit *u, usec_t *timeout) {
- Socket *s = SOCKET(u);
+ Socket *s = ASSERT_PTR(SOCKET(u));
usec_t t;
int r;
}
static int socket_clean(Unit *u, ExecCleanMask mask) {
+ Socket *s = ASSERT_PTR(SOCKET(u));
_cleanup_strv_free_ char **l = NULL;
- Socket *s = SOCKET(u);
int r;
- assert(s);
assert(mask != 0);
if (s->state != SOCKET_DEAD)
}
static int socket_can_clean(Unit *u, ExecCleanMask *ret) {
- Socket *s = SOCKET(u);
-
- assert(s);
+ Socket *s = ASSERT_PTR(SOCKET(u));
return exec_context_get_clean_mask(&s->exec_context, ret);
}
static int socket_can_start(Unit *u) {
- Socket *s = SOCKET(u);
+ Socket *s = ASSERT_PTR(SOCKET(u));
int r;
- assert(s);
-
r = unit_test_start_limit(u);
if (r < 0) {
socket_enter_dead(s, SOCKET_FAILURE_START_LIMIT_HIT);
}
static bool swap_may_gc(Unit *u) {
- Swap *s = SWAP(u);
-
- assert(s);
+ Swap *s = ASSERT_PTR(SWAP(u));
if (s->from_proc_swaps)
return false;
}
static void swap_init(Unit *u) {
- Swap *s = SWAP(u);
+ Swap *s = ASSERT_PTR(SWAP(u));
- assert(s);
- assert(UNIT(s)->load_state == UNIT_STUB);
+ assert(u->load_state == UNIT_STUB);
s->timeout_usec = u->manager->defaults.timeout_start_usec;
}
static void swap_done(Unit *u) {
- Swap *s = SWAP(u);
-
- assert(s);
+ Swap *s = ASSERT_PTR(SWAP(u));
swap_unset_proc_swaps(s);
swap_set_devnode(s, NULL);
_cleanup_free_ char *e = NULL;
int r;
+ assert(s);
assert(UNIT(s)->load_state == UNIT_LOADED);
r = unit_name_from_path(s->what, ".swap", &e);
}
static int swap_load(Unit *u) {
- Swap *s = SWAP(u);
- int r, q = 0;
+ Swap *s = ASSERT_PTR(SWAP(u));
+ int r;
- assert(s);
assert(u->load_state == UNIT_STUB);
/* Load a .swap file */
- bool fragment_optional = s->from_proc_swaps;
- r = unit_load_fragment_and_dropin(u, !fragment_optional);
+ r = unit_load_fragment_and_dropin(u, /* fragment_required = */ !s->from_proc_swaps);
/* Add in some extras, and do so either when we successfully loaded something or when /proc/swaps is
* already active. */
if (u->load_state == UNIT_LOADED || s->from_proc_swaps)
- q = swap_add_extras(s);
+ RET_GATHER(r, swap_add_extras(s));
if (r < 0)
return r;
- if (q < 0)
- return q;
+
if (u->load_state != UNIT_LOADED)
return 0;
int priority,
bool set_flags) {
+ _cleanup_(unit_freep) Unit *new = NULL;
_cleanup_free_ char *e = NULL;
- bool delete = false;
- Unit *u = NULL;
+ Unit *u;
+ Swap *s;
int r;
- SwapParameters *p;
assert(m);
assert(what);
r = unit_name_from_path(what, ".swap", &e);
if (r < 0)
- return log_unit_error_errno(u, r, "Failed to generate unit name from path: %m");
+ return log_error_errno(r, "Failed to generate unit name from path: %m");
u = manager_get_unit(m, e);
- if (u &&
- SWAP(u)->from_proc_swaps &&
- !path_equal(SWAP(u)->parameters_proc_swaps.what, what_proc_swaps))
- return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
- "Swap %s appeared twice with different device paths %s and %s",
- e, SWAP(u)->parameters_proc_swaps.what, what_proc_swaps);
+ if (u) {
+ s = ASSERT_PTR(SWAP(u));
+
+ if (s->from_proc_swaps &&
+ !path_equal(s->parameters_proc_swaps.what, what_proc_swaps))
+ return log_unit_error_errno(u, SYNTHETIC_ERRNO(EEXIST),
+ "Swap appeared twice with different device paths %s and %s, refusing.",
+ s->parameters_proc_swaps.what, what_proc_swaps);
+ } else {
+ r = unit_new_for_name(m, sizeof(Swap), e, &new);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to load swap unit '%s': %m", e);
- if (!u) {
- delete = true;
+ u = new;
+ s = ASSERT_PTR(SWAP(u));
- r = unit_new_for_name(m, sizeof(Swap), e, &u);
- if (r < 0) {
- log_unit_warning_errno(u, r, "Failed to load swap unit: %m");
- goto fail;
- }
-
- SWAP(u)->what = strdup(what);
- if (!SWAP(u)->what) {
- r = log_oom();
- goto fail;
- }
+ s->what = strdup(what);
+ if (!s->what)
+ return log_oom();
unit_add_to_load_queue(u);
- } else
- delete = false;
+ }
- p = &SWAP(u)->parameters_proc_swaps;
+ SwapParameters *p = &s->parameters_proc_swaps;
if (!p->what) {
p->what = strdup(what_proc_swaps);
- if (!p->what) {
- r = log_oom();
- goto fail;
- }
+ if (!p->what)
+ return log_oom();
}
- /* The unit is definitely around now, mark it as loaded if it was previously referenced but could not be
- * loaded. After all we can load it now, from the data in /proc/swaps. */
+ /* The unit is definitely around now, mark it as loaded if it was previously referenced but
+ * could not be loaded. After all we can load it now, from the data in /proc/swaps. */
if (IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_BAD_SETTING, UNIT_ERROR)) {
u->load_state = UNIT_LOADED;
u->load_error = 0;
}
if (set_flags) {
- SWAP(u)->is_active = true;
- SWAP(u)->just_activated = !SWAP(u)->from_proc_swaps;
+ s->is_active = true;
+ s->just_activated = !s->from_proc_swaps;
}
- SWAP(u)->from_proc_swaps = true;
+ s->from_proc_swaps = true;
p->priority = priority;
p->priority_set = true;
unit_add_to_dbus_queue(u);
return 0;
-
-fail:
- if (delete)
- unit_free(u);
-
- return r;
}
static void swap_process_new(Manager *m, const char *device, int prio, bool set_flags) {
}
static int swap_coldplug(Unit *u) {
- Swap *s = SWAP(u);
+ Swap *s = ASSERT_PTR(SWAP(u));
SwapState new_state = SWAP_DEAD;
int r;
- assert(s);
assert(s->state == SWAP_DEAD);
if (s->deserialized_state != s->state)
}
static void swap_dump(Unit *u, FILE *f, const char *prefix) {
- Swap *s = SWAP(u);
+ Swap *s = ASSERT_PTR(SWAP(u));
SwapParameters *p;
- assert(s);
assert(f);
if (s->from_proc_swaps)
}
static int swap_spawn(Swap *s, ExecCommand *c, PidRef *ret_pid) {
-
_cleanup_(exec_params_shallow_clear) ExecParameters exec_params = EXEC_PARAMETERS_INIT(
EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN);
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
}
static int swap_stop(Unit *u) {
- Swap *s = SWAP(u);
-
- assert(s);
+ Swap *s = ASSERT_PTR(SWAP(u));
switch (s->state) {
}
static int swap_serialize(Unit *u, FILE *f, FDSet *fds) {
- Swap *s = SWAP(u);
+ Swap *s = ASSERT_PTR(SWAP(u));
- assert(s);
assert(f);
assert(fds);
}
static int swap_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Swap *s = SWAP(u);
+ Swap *s = ASSERT_PTR(SWAP(u));
- assert(s);
assert(fds);
if (streq(key, "state")) {
}
static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) {
- Swap *s = SWAP(u);
+ Swap *s = ASSERT_PTR(SWAP(u));
SwapResult f;
- assert(s);
assert(pid >= 0);
if (pid != s->control_pid.pid)
}
static int swap_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
- Swap *s = SWAP(userdata);
+ Swap *s = ASSERT_PTR(SWAP(userdata));
- assert(s);
assert(s->timer_event_source == source);
switch (s->state) {
return swap_process_proc_swaps(m);
}
-static Unit *swap_following(Unit *u) {
- Swap *s = SWAP(u);
+static Unit* swap_following(Unit *u) {
+ Swap *s = ASSERT_PTR(SWAP(u));
Swap *first = NULL;
- assert(s);
-
/* If the user configured the swap through /etc/fstab or
* a device unit, follow that. */
return UNIT(first);
}
-static int swap_following_set(Unit *u, Set **_set) {
- Swap *s = SWAP(u);
+static int swap_following_set(Unit *u, Set **ret) {
+ Swap *s = ASSERT_PTR(SWAP(u));
_cleanup_set_free_ Set *set = NULL;
int r;
- assert(s);
- assert(_set);
+ assert(ret);
if (LIST_JUST_US(same_devnode, s)) {
- *_set = NULL;
+ *ret = NULL;
return 0;
}
return r;
}
- *_set = TAKE_PTR(set);
+ *ret = TAKE_PTR(set);
return 1;
}
int swap_process_device_remove(Manager *m, sd_device *dev) {
const char *dn;
- int r;
Swap *s;
+ int r;
r = sd_device_get_devname(dev, &dn);
if (r < 0)
return 0;
- while ((s = hashmap_get(m->swaps_by_devnode, dn))) {
- int q;
-
- q = swap_set_devnode(s, NULL);
- if (q < 0)
- r = q;
- }
+ r = 0;
+ while ((s = hashmap_get(m->swaps_by_devnode, dn)))
+ RET_GATHER(r, swap_set_devnode(s, NULL));
return r;
}
static void swap_reset_failed(Unit *u) {
- Swap *s = SWAP(u);
-
- assert(s);
+ Swap *s = ASSERT_PTR(SWAP(u));
if (s->state == SWAP_FAILED)
swap_set_state(s, SWAP_DEAD);
}
static int swap_get_timeout(Unit *u, usec_t *timeout) {
- Swap *s = SWAP(u);
+ Swap *s = ASSERT_PTR(SWAP(u));
usec_t t;
int r;
- assert(s);
- assert(u);
-
if (!s->timer_event_source)
return 0;
}
static int swap_clean(Unit *u, ExecCleanMask mask) {
+ Swap *s = ASSERT_PTR(SWAP(u));
_cleanup_strv_free_ char **l = NULL;
- Swap *s = SWAP(u);
int r;
- assert(s);
assert(mask != 0);
if (s->state != SWAP_DEAD)
}
static int swap_can_clean(Unit *u, ExecCleanMask *ret) {
- Swap *s = SWAP(u);
-
- assert(s);
+ Swap *s = ASSERT_PTR(SWAP(u));
return exec_context_get_clean_mask(&s->exec_context, ret);
}
static int swap_can_start(Unit *u) {
- Swap *s = SWAP(u);
+ Swap *s = ASSERT_PTR(SWAP(u));
int r;
- assert(s);
-
r = unit_test_start_limit(u);
if (r < 0) {
swap_enter_dead(s, SWAP_FAILURE_START_LIMIT_HIT);
}
static int target_load(Unit *u) {
- Target *t = TARGET(u);
+ Target *t = ASSERT_PTR(TARGET(u));
int r;
- assert(t);
-
r = unit_load_fragment_and_dropin(u, true);
if (r < 0)
return r;
}
static int target_coldplug(Unit *u) {
- Target *t = TARGET(u);
+ Target *t = ASSERT_PTR(TARGET(u));
- assert(t);
assert(t->state == TARGET_DEAD);
if (t->deserialized_state != t->state)
}
static void target_dump(Unit *u, FILE *f, const char *prefix) {
- Target *t = TARGET(u);
+ Target *t = ASSERT_PTR(TARGET(u));
- assert(t);
assert(f);
+ assert(prefix);
fprintf(f,
"%sTarget State: %s\n",
}
static int target_start(Unit *u) {
- Target *t = TARGET(u);
+ Target *t = ASSERT_PTR(TARGET(u));
int r;
- assert(t);
assert(t->state == TARGET_DEAD);
r = unit_acquire_invocation_id(u);
}
static int target_stop(Unit *u) {
- Target *t = TARGET(u);
+ Target *t = ASSERT_PTR(TARGET(u));
- assert(t);
assert(t->state == TARGET_ACTIVE);
target_set_state(t, TARGET_DEAD);
}
static int target_serialize(Unit *u, FILE *f, FDSet *fds) {
- Target *s = TARGET(u);
+ Target *t = ASSERT_PTR(TARGET(u));
- assert(s);
assert(f);
assert(fds);
- (void) serialize_item(f, "state", target_state_to_string(s->state));
+ (void) serialize_item(f, "state", target_state_to_string(t->state));
return 0;
}
static int target_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Target *s = TARGET(u);
+ Target *t = ASSERT_PTR(TARGET(u));
- assert(s);
- assert(u);
assert(key);
assert(value);
assert(fds);
state = target_state_from_string(value);
if (state < 0)
- log_debug("Failed to parse state value %s", value);
+ log_unit_debug(u, "Failed to parse state: %s", value);
else
- s->deserialized_state = state;
+ t->deserialized_state = state;
} else
- log_debug("Unknown serialization key '%s'", key);
+ log_unit_debug(u, "Unknown serialization key: %s", key);
return 0;
}
static UnitActiveState target_active_state(Unit *u) {
- assert(u);
+ Target *t = ASSERT_PTR(TARGET(u));
- return state_translation_table[TARGET(u)->state];
+ return state_translation_table[t->state];
}
static const char *target_sub_state_to_string(Unit *u) {
- assert(u);
+ Target *t = ASSERT_PTR(TARGET(u));
- return target_state_to_string(TARGET(u)->state);
+ return target_state_to_string(t->state);
}
const UnitVTable target_vtable = {
[JOB_DONE] = "Stopped target %s.",
},
},
+
+ .notify_supervisor = true,
};
static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata);
static void timer_init(Unit *u) {
- Timer *t = TIMER(u);
+ Timer *t = ASSERT_PTR(TIMER(u));
- assert(u);
assert(u->load_state == UNIT_STUB);
t->next_elapse_monotonic_or_boottime = USEC_INFINITY;
}
static void timer_done(Unit *u) {
- Timer *t = TIMER(u);
-
- assert(t);
+ Timer *t = ASSERT_PTR(TIMER(u));
timer_free_values(t);
}
static int timer_load(Unit *u) {
- Timer *t = TIMER(u);
+ Timer *t = ASSERT_PTR(TIMER(u));
int r;
- assert(u);
assert(u->load_state == UNIT_STUB);
r = unit_load_fragment_and_dropin(u, true);
}
static void timer_dump(Unit *u, FILE *f, const char *prefix) {
- Timer *t = TIMER(u);
+ Timer *t = ASSERT_PTR(TIMER(u));
Unit *trigger;
+ assert(f);
+ assert(prefix);
+
trigger = UNIT_TRIGGER(u);
fprintf(f,
static void timer_set_state(Timer *t, TimerState state) {
TimerState old_state;
+
assert(t);
if (t->state != state)
static void timer_enter_waiting(Timer *t, bool time_change);
static int timer_coldplug(Unit *u) {
- Timer *t = TIMER(u);
+ Timer *t = ASSERT_PTR(TIMER(u));
- assert(t);
assert(t->state == TIMER_DEAD);
if (t->deserialized_state == t->state)
}
static int timer_start(Unit *u) {
- Timer *t = TIMER(u);
+ Timer *t = ASSERT_PTR(TIMER(u));
int r;
- assert(t);
assert(IN_SET(t->state, TIMER_DEAD, TIMER_FAILED));
r = unit_test_trigger_loaded(u);
}
static int timer_stop(Unit *u) {
- Timer *t = TIMER(u);
+ Timer *t = ASSERT_PTR(TIMER(u));
- assert(t);
assert(IN_SET(t->state, TIMER_WAITING, TIMER_RUNNING, TIMER_ELAPSED));
timer_enter_dead(t, TIMER_SUCCESS);
}
static int timer_serialize(Unit *u, FILE *f, FDSet *fds) {
- Timer *t = TIMER(u);
+ Timer *t = ASSERT_PTR(TIMER(u));
- assert(u);
assert(f);
assert(fds);
}
static int timer_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Timer *t = TIMER(u);
+ Timer *t = ASSERT_PTR(TIMER(u));
- assert(u);
assert(key);
assert(value);
assert(fds);
}
static UnitActiveState timer_active_state(Unit *u) {
- assert(u);
+ Timer *t = ASSERT_PTR(TIMER(u));
- return state_translation_table[TIMER(u)->state];
+ return state_translation_table[t->state];
}
static const char *timer_sub_state_to_string(Unit *u) {
- assert(u);
+ Timer *t = ASSERT_PTR(TIMER(u));
- return timer_state_to_string(TIMER(u)->state);
+ return timer_state_to_string(t->state);
}
static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata) {
- Timer *t = TIMER(userdata);
-
- assert(t);
+ Timer *t = ASSERT_PTR(TIMER(userdata));
if (t->state != TIMER_WAITING)
return 0;
}
static void timer_trigger_notify(Unit *u, Unit *other) {
- Timer *t = TIMER(u);
+ Timer *t = ASSERT_PTR(TIMER(u));
- assert(u);
assert(other);
/* Filter out invocations with bogus state */
}
static void timer_reset_failed(Unit *u) {
- Timer *t = TIMER(u);
-
- assert(t);
+ Timer *t = ASSERT_PTR(TIMER(u));
if (t->state == TIMER_FAILED)
timer_set_state(t, TIMER_DEAD);
}
static void timer_time_change(Unit *u) {
- Timer *t = TIMER(u);
+ Timer *t = ASSERT_PTR(TIMER(u));
usec_t ts;
- assert(u);
-
if (t->state != TIMER_WAITING)
return;
}
static void timer_timezone_change(Unit *u) {
- Timer *t = TIMER(u);
-
- assert(u);
+ Timer *t = ASSERT_PTR(TIMER(u));
if (t->state != TIMER_WAITING)
return;
}
static int timer_clean(Unit *u, ExecCleanMask mask) {
- Timer *t = TIMER(u);
+ Timer *t = ASSERT_PTR(TIMER(u));
int r;
- assert(t);
assert(mask != 0);
if (t->state != TIMER_DEAD)
}
static int timer_can_clean(Unit *u, ExecCleanMask *ret) {
- Timer *t = TIMER(u);
+ Timer *t = ASSERT_PTR(TIMER(u));
- assert(t);
assert(ret);
*ret = t->persistent ? EXEC_CLEAN_STATE : 0;
}
static int timer_can_start(Unit *u) {
- Timer *t = TIMER(u);
+ Timer *t = ASSERT_PTR(TIMER(u));
int r;
- assert(t);
-
r = unit_test_start_limit(u);
if (r < 0) {
timer_enter_dead(t, TIMER_FAILURE_START_LIMIT_HIT);
}
static void activation_details_timer_serialize(ActivationDetails *details, FILE *f) {
- ActivationDetailsTimer *t = ACTIVATION_DETAILS_TIMER(details);
+ ActivationDetailsTimer *t = ASSERT_PTR(ACTIVATION_DETAILS_TIMER(details));
- assert(details);
assert(f);
assert(t);
}
static int activation_details_timer_append_env(ActivationDetails *details, char ***strv) {
- ActivationDetailsTimer *t = ACTIVATION_DETAILS_TIMER(details);
+ ActivationDetailsTimer *t = ASSERT_PTR(ACTIVATION_DETAILS_TIMER(details));
int r;
- assert(details);
assert(strv);
assert(t);
}
static int activation_details_timer_append_pair(ActivationDetails *details, char ***strv) {
- ActivationDetailsTimer *t = ACTIVATION_DETAILS_TIMER(details);
+ ActivationDetailsTimer *t = ASSERT_PTR(ACTIVATION_DETAILS_TIMER(details));
int r;
- assert(details);
assert(strv);
assert(t);
bad_specifier(u, specifier);
- if (crt && crt->cgroup_path) {
- char *n;
-
- n = strdup(crt->cgroup_path);
- if (!n)
- return -ENOMEM;
-
- *ret = n;
- return 0;
- }
+ if (crt && crt->cgroup_path)
+ return strdup_to(ret, crt->cgroup_path);
return unit_default_cgroup_path(u, ret);
}
static int specifier_cgroup_root(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
const Unit *u = ASSERT_PTR(userdata);
- char *n;
bad_specifier(u, specifier);
- n = strdup(u->manager->cgroup_root);
- if (!n)
- return -ENOMEM;
-
- *ret = n;
- return 0;
+ return strdup_to(ret, u->manager->cgroup_root);
}
static int specifier_cgroup_slice(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
const Unit *u = ASSERT_PTR(userdata), *slice;
- char *n;
bad_specifier(u, specifier);
CGroupRuntime *crt = unit_get_cgroup_runtime(slice);
if (crt && crt->cgroup_path)
- n = strdup(crt->cgroup_path);
- else
- return unit_default_cgroup_path(slice, ret);
- } else
- n = strdup(u->manager->cgroup_root);
- if (!n)
- return -ENOMEM;
+ return strdup_to(ret, crt->cgroup_path);
- *ret = n;
- return 0;
+ return unit_default_cgroup_path(slice, ret);
+ }
+
+ return strdup_to(ret, u->manager->cgroup_root);
}
static int specifier_special_directory(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
const Unit *u = ASSERT_PTR(userdata);
- char *n;
- n = strdup(u->manager->prefix[PTR_TO_UINT(data)]);
- if (!n)
- return -ENOMEM;
-
- *ret = n;
- return 0;
+ return strdup_to(ret, u->manager->prefix[PTR_TO_UINT(data)]);
}
static int specifier_credentials_dir(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
unit_emit_audit_start(u);
manager_send_unit_plymouth(m, u);
+ manager_send_unit_supervisor(m, u, /* active= */ true);
}
if (UNIT_IS_INACTIVE_OR_FAILED(ns) && !UNIT_IS_INACTIVE_OR_FAILED(os)) {
/* This unit just stopped/failed. */
unit_emit_audit_stop(u, ns);
+ manager_send_unit_supervisor(m, u, /* active= */ false);
unit_log_resources(u);
}
p->runtime_scope = u->manager->runtime_scope;
- r = strdup_or_null(manager_get_confirm_spawn(u->manager), &p->confirm_spawn);
+ r = strdup_to(&p->confirm_spawn, manager_get_confirm_spawn(u->manager));
if (r < 0)
return r;
/* If true, we'll notify plymouth about this unit */
bool notify_plymouth;
+ /* If true, we'll notify a surrounding VMM/container manager about this unit becoming available */
+ bool notify_supervisor;
+
/* The audit events to generate on start + stop (or 0 if none shall be generated) */
int audit_start_message_type;
int audit_stop_message_type;
c = hashmap_get(h, UID_TO_PTR(uid));
if (c) {
-
if (t < c->oldest_mtime) {
- char *n;
-
- n = strdup(de->d_name);
- if (!n)
- return log_oom();
-
- free_and_replace(c->oldest_file, n);
+ r = free_and_strdup_warn(&c->oldest_file, de->d_name);
+ if (r < 0)
+ return r;
c->oldest_mtime = t;
}
-
} else {
_cleanup_(vacuum_candidate_freep) VacuumCandidate *n = NULL;
if (!n)
return log_oom();
- n->oldest_file = strdup(de->d_name);
- if (!n->oldest_file)
- return log_oom();
-
+ r = free_and_strdup_warn(&n->oldest_file, de->d_name);
+ if (r < 0)
+ return r;
n->oldest_mtime = t;
r = hashmap_put(h, UID_TO_PTR(uid), n);
assert(where);
assert(ret_options);
- if (!(*flags & (MOUNT_NOAUTO|MOUNT_NOFAIL|MOUNT_AUTOMOUNT))) {
- r = strdup_or_null(options, ret_options);
- if (r < 0)
- return r;
-
- return 0;
- }
+ if (!(*flags & (MOUNT_NOAUTO|MOUNT_NOFAIL|MOUNT_AUTOMOUNT)))
+ return strdup_to(ret_options, options);
log_debug("Mount '%s' is mandatory, ignoring 'noauto', 'nofail', and 'x-systemd.automount' options.",
where);
return 1;
}
-int bus_home_method_update_record(
+int bus_home_update_record(
Home *h,
sd_bus_message *message,
UserRecord *hr,
return r;
}
- return bus_home_method_update_record(h, message, hr, blobs, flags, error);
+ return bus_home_update_record(h, message, hr, blobs, flags, error);
}
int bus_home_method_resize(
return r;
/* This operation might not be something we can executed immediately, hence queue it */
- fd = home_create_fifo(h, please_suspend ? HOME_FIFO_PLEASE_SUSPEND : HOME_FIFO_DONT_SUSPEND);
+ fd = home_create_fifo(h, please_suspend);
if (fd < 0)
return sd_bus_reply_method_errnof(message, fd, "Failed to allocate FIFO for %s: %m", h->user_name);
}
}
- fd = home_create_fifo(h, please_suspend ? HOME_FIFO_PLEASE_SUSPEND : HOME_FIFO_DONT_SUSPEND);
+ fd = home_create_fifo(h, please_suspend);
if (fd < 0)
return sd_bus_reply_method_errnof(message, fd, "Failed to allocate FIFO for %s: %m", h->user_name);
return 1;
}
-int bus_home_method_inhibit_suspend(
- sd_bus_message *message,
- void *userdata,
- sd_bus_error *error) {
-
- _cleanup_close_ int fd = -EBADF;
- Home *h = ASSERT_PTR(userdata);
- HomeState state;
- int r;
-
- r = home_verify_polkit_async(
- h,
- message,
- "org.freedesktop.home1.inhibit-suspend",
- h->uid,
- error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* Will call us back */
-
- state = home_get_state(h);
- switch (state) {
- case HOME_ABSENT:
- return sd_bus_error_setf(error, BUS_ERROR_HOME_ABSENT, "Home %s is currently missing or not plugged in.", h->user_name);
- case HOME_UNFIXATED:
- case HOME_INACTIVE:
- case HOME_DIRTY:
- return sd_bus_error_setf(error, BUS_ERROR_HOME_NOT_ACTIVE, "Home %s not active.", h->user_name);
- case HOME_LOCKED:
- return sd_bus_error_setf(error, BUS_ERROR_HOME_LOCKED, "Home %s is currently locked.", h->user_name);
- default:
- if (HOME_STATE_IS_ACTIVE(state))
- break;
-
- return sd_bus_error_setf(error, BUS_ERROR_HOME_BUSY, "An operation on home %s is currently being executed.", h->user_name);
- }
-
- fd = home_create_fifo(h, HOME_FIFO_INHIBIT_SUSPEND);
- if (fd < 0)
- return sd_bus_reply_method_errnof(message, fd, "Failed to allocate FIFO for %s: %m", h->user_name);
-
- return sd_bus_reply_method_return(message, "h", fd);
-}
-
/* We map a uid_t as uint32_t bus property, let's ensure this is safe. */
assert_cc(sizeof(uid_t) == sizeof(uint32_t));
bus_home_method_ref,
0),
SD_BUS_METHOD("Release", NULL, NULL, bus_home_method_release, 0),
- SD_BUS_METHOD_WITH_ARGS("InhibitSuspend",
- SD_BUS_NO_ARGS,
- SD_BUS_RESULT("h", send_fd),
- bus_home_method_inhibit_suspend,
- SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END
};
int bus_home_method_fixate(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_home_method_authenticate(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_home_method_update(sd_bus_message *message, void *userdata, sd_bus_error *error);
-int bus_home_method_update_record(Home *home, sd_bus_message *message, UserRecord *hr, Hashmap *blobs, uint64_t flags, sd_bus_error *error);
int bus_home_method_resize(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_home_method_change_password(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_home_method_lock(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_home_method_acquire(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_home_method_ref(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_home_method_release(sd_bus_message *message, void *userdata, sd_bus_error *error);
-int bus_home_method_inhibit_suspend(sd_bus_message *message, void *userdata, sd_bus_error *error);
+
+int bus_home_update_record(Home *home, sd_bus_message *message, UserRecord *hr, Hashmap *blobs, uint64_t flags, sd_bus_error *error);
extern const BusObjectImplementation home_object;
h->ref_event_source_please_suspend = sd_event_source_disable_unref(h->ref_event_source_please_suspend);
h->ref_event_source_dont_suspend = sd_event_source_disable_unref(h->ref_event_source_dont_suspend);
- h->inhibit_suspend_event_source = sd_event_source_disable_unref(h->inhibit_suspend_event_source);
h->pending_operations = ordered_set_free(h->pending_operations);
h->pending_event_source = sd_event_source_disable_unref(h->pending_event_source);
if (h->ref_event_source_dont_suspend == s)
h->ref_event_source_dont_suspend = sd_event_source_disable_unref(h->ref_event_source_dont_suspend);
- if (h->inhibit_suspend_event_source == s)
- h->inhibit_suspend_event_source = sd_event_source_disable_unref(h->inhibit_suspend_event_source);
-
if (home_is_referenced(h))
return 0;
return 0;
}
-int home_create_fifo(Home *h, HomeFifoType type) {
- static const struct {
- const char *suffix;
- const char *description;
- size_t event_source;
- } table[_HOME_FIFO_TYPE_MAX] = {
- [HOME_FIFO_PLEASE_SUSPEND] = {
- .suffix = ".please-suspend",
- .description = "acquire-ref",
- .event_source = offsetof(Home, ref_event_source_please_suspend),
- },
- [HOME_FIFO_DONT_SUSPEND] = {
- .suffix = ".dont-suspend",
- .description = "acquire-ref-dont-suspend",
- .event_source = offsetof(Home, ref_event_source_dont_suspend),
- },
- [HOME_FIFO_INHIBIT_SUSPEND] = {
- .suffix = ".inhibit-suspend",
- .description = "inhibit-suspend",
- .event_source = offsetof(Home, inhibit_suspend_event_source),
- },
- };
-
+int home_create_fifo(Home *h, bool please_suspend) {
_cleanup_close_ int ret_fd = -EBADF;
- sd_event_source **evt;
- const char *fn;
+ sd_event_source **ss;
+ const char *fn, *suffix;
int r;
assert(h);
- assert(type >= 0 && type < _HOME_FIFO_TYPE_MAX);
- evt = (sd_event_source**) ((uint8_t*) h + table[type].event_source);
+ if (please_suspend) {
+ suffix = ".please-suspend";
+ ss = &h->ref_event_source_please_suspend;
+ } else {
+ suffix = ".dont-suspend";
+ ss = &h->ref_event_source_dont_suspend;
+ }
- fn = strjoina("/run/systemd/home/", h->user_name, table[type].suffix);
+ fn = strjoina("/run/systemd/home/", h->user_name, suffix);
- if (!*evt) {
+ if (!*ss) {
_cleanup_close_ int ref_fd = -EBADF;
(void) mkdir("/run/systemd/home/", 0755);
if (ref_fd < 0)
return log_error_errno(errno, "Failed to open FIFO %s for reading: %m", fn);
- r = sd_event_add_io(h->manager->event, evt, ref_fd, 0, on_home_ref_eof, h);
+ r = sd_event_add_io(h->manager->event, ss, ref_fd, 0, on_home_ref_eof, h);
if (r < 0)
return log_error_errno(r, "Failed to allocate reference FIFO event source: %m");
- (void) sd_event_source_set_description(*evt, table[type].description);
+ (void) sd_event_source_set_description(*ss, "acquire-ref");
- r = sd_event_source_set_priority(*evt, SD_EVENT_PRIORITY_IDLE-1);
+ /* We need to notice dropped refs before we process new bus requests (which
+ * might try to obtain new refs) */
+ r = sd_event_source_set_priority(*ss, SD_EVENT_PRIORITY_NORMAL-10);
if (r < 0)
return r;
- r = sd_event_source_set_io_fd_own(*evt, true);
+ r = sd_event_source_set_io_fd_own(*ss, true);
if (r < 0)
return log_error_errno(r, "Failed to pass ownership of FIFO event fd to event source: %m");
+
TAKE_FD(ref_fd);
}
bool home_shall_suspend(Home *h) {
assert(h);
- /* We lock the home area on suspend if... */
- return h->ref_event_source_please_suspend && /* at least one client supports suspend, and... */
- !h->ref_event_source_dont_suspend && /* no clients lack support for suspend, and... */
- !h->inhibit_suspend_event_source; /* no client is temporarily inhibiting suspend */
+ /* Suspend if there's at least one client referencing this home directory that wants a suspend and none who does not. */
+ return h->ref_event_source_please_suspend && !h->ref_event_source_dont_suspend;
}
static int home_dispatch_release(Home *h, Operation *o) {
static int home_get_image_path_seat(Home *h, char **ret) {
_cleanup_(sd_device_unrefp) sd_device *d = NULL;
- _cleanup_free_ char *c = NULL;
const char *ip, *seat;
struct stat st;
int r;
else if (r < 0)
return r;
- c = strdup(seat);
- if (!c)
- return -ENOMEM;
-
- *ret = TAKE_PTR(c);
- return 0;
+ return strdup_to(ret, seat);
}
int home_auto_login(Home *h, char ***ret_seats) {
bool unregister_on_failure;
/* The reading side of a FIFO stored in /run/systemd/home/, the writing side being used for reference
- * counting. The references dropped to zero as soon as we see EOF. This concept exists thrice: once
- * for clients that are fine if we lock the home directory on system suspend, once for clients
- * that are not ok with that, and once for clients that are usually ok with it but temporarily
- * want to opt-out so that they can implement more advanced behavior on their own. This allows
- * us to determine for each home whether there are any clients that don't support suspend at this
- * moment. */
+ * counting. The references dropped to zero as soon as we see EOF. This concept exists twice: once
+ * for clients that are fine if we suspend the home directory on system suspend, and once for clients
+ * that are not ok with that. This allows us to determine for each home whether there are any clients
+ * that support unsuspend. */
sd_event_source *ref_event_source_please_suspend;
sd_event_source *ref_event_source_dont_suspend;
- /* This is distinct from ref_event_source_dont_suspend because it can be obtained from unprivileged
- * code, and thus we don't count it as a reference on the home area. */
- sd_event_source *inhibit_suspend_event_source;
/* Any pending operations we still need to execute. These are for operations we want to queue if we
* can't execute them right-away. */
int home_augment_status(Home *h, UserRecordLoadFlags flags, UserRecord **ret);
-typedef enum {
- HOME_FIFO_PLEASE_SUSPEND,
- HOME_FIFO_DONT_SUSPEND,
- HOME_FIFO_INHIBIT_SUSPEND,
- _HOME_FIFO_TYPE_MAX,
- _HOME_FIFO_TYPE_INVALID = -EINVAL,
-} HomeFifoType;
-int home_create_fifo(Home *h, HomeFifoType mode);
-
+int home_create_fifo(Home *h, bool please_suspend);
int home_schedule_operation(Home *h, Operation *o, sd_bus_error *error);
int home_auto_login(Home *h, char ***ret_seats);
if (!h)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_HOME, "No home for user %s known", hr->user_name);
- return bus_home_method_update_record(h, message, hr, blobs, flags, error);
+ return bus_home_update_record(h, message, hr, blobs, flags, error);
}
static int method_resize_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
return generic_home_method(userdata, message, bus_home_method_release, error);
}
-static int method_inhibit_suspend_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return generic_home_method(userdata, message, bus_home_method_inhibit_suspend, error);
-}
-
static int method_lock_all_homes(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(operation_unrefp) Operation *o = NULL;
bool waiting = false;
method_release_home,
0),
- SD_BUS_METHOD_WITH_ARGS("InhibitSuspendHome",
- SD_BUS_ARGS("s", user_name),
- SD_BUS_RESULT("h", send_fd),
- method_inhibit_suspend_home,
- SD_BUS_VTABLE_UNPRIVILEGED),
-
/* An operation that acts on all homes that allow it */
SD_BUS_METHOD("LockAllHomes", NULL, NULL, method_lock_all_homes, 0),
SD_BUS_METHOD("DeactivateAllHomes", NULL, NULL, method_deactivate_all_homes, 0),
if (r < 0)
return log_error_errno(r, "Failed to request name: %m");
- r = sd_bus_attach_event(m->bus, m->event, 0);
+ r = sd_bus_attach_event(m->bus, m->event, SD_EVENT_PRIORITY_NORMAL);
if (r < 0)
return log_error_errno(r, "Failed to attach bus to event loop: %m");
sd_id128_t *ret_uuid) {
_cleanup_(blkid_free_probep) blkid_probe b = NULL;
- _cleanup_free_ char *s = NULL;
const char *fstype = NULL, *uuid = NULL;
sd_id128_t id;
int r;
if (r < 0)
return r;
- s = strdup(fstype);
- if (!s)
- return -ENOMEM;
-
- *ret_fstype = TAKE_PTR(s);
+ r = strdup_to(ret_fstype, fstype);
+ if (r < 0)
+ return r;
*ret_uuid = id;
-
return 0;
}
send_interface="org.freedesktop.home1.Manager"
send_member="ReleaseHome"/>
- <allow send_destination="org.freedesktop.home1"
- send_interface="org.freedesktop.home1.Manager"
- send_member="InhibitSuspendHome"/>
-
<allow send_destination="org.freedesktop.home1"
send_interface="org.freedesktop.home1.Manager"
send_member="LockAllHomes"/>
send_interface="org.freedesktop.home1.Home"
send_member="Release"/>
- <allow send_destination="org.freedesktop.home1"
- send_interface="org.freedesktop.home1.Home"
- send_member="InhibitSuspend"/>
-
<allow receive_sender="org.freedesktop.home1"/>
</policy>
</defaults>
</action>
- <action id="org.freedesktop.home1.inhibit-suspend">
- <description gettext-domain="systemd">Inhibit automatic lock of a home area</description>
- <message gettext-domain="systemd">Authentication is required to inhibit automatic lock of a user's home area.</message>
- <defaults>
- <allow_any>auth_admin_keep</allow_any>
- <allow_inactive>auth_admin_keep</allow_inactive>
- <allow_active>auth_admin_keep</allow_active>
- </defaults>
- </action>
-
<action id="org.freedesktop.home1.activate-home">
<description gettext-domain="systemd">Activate a home area</description>
<message gettext-domain="systemd">Authentication is required to activate a user's home area.</message>
static int get_dmi_data(const char *database_key, const char *regular_key, char **ret) {
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
- _cleanup_free_ char *b = NULL;
const char *s = NULL;
int r;
if (!s && regular_key)
(void) sd_device_get_property_value(device, regular_key, &s);
- if (!ret)
- return !!s;
-
- if (s) {
- b = strdup(s);
- if (!b)
- return -ENOMEM;
- }
-
- *ret = TAKE_PTR(b);
- return !!s;
+ return strdup_to_full(ret, s);
}
static int get_hardware_vendor(char **ret) {
(void) sd_device_get_sysattr_value(device, sysattr, &s);
- bool empty = isempty(s);
-
- if (ret) {
- if (empty)
- *ret = NULL;
- else {
- _cleanup_free_ char *b = NULL;
-
- b = strdup(s);
- if (!b)
- return -ENOMEM;
-
- *ret = TAKE_PTR(b);
- }
- }
-
- return !empty;
+ return strdup_to_full(ret, empty_to_null(s));
}
static int get_hardware_serial(char **ret) {
#include "terminal-util.h"
static const char *arg_identifier = NULL;
+static const char *arg_namespace = NULL;
static int arg_priority = LOG_INFO;
static int arg_stderr_priority = -1;
static bool arg_level_prefix = true;
" -p --priority=PRIORITY Set priority value (0..7)\n"
" --stderr-priority=PRIORITY Set priority value (0..7) used for stderr\n"
" --level-prefix=BOOL Control whether level prefix shall be parsed\n"
+ " --namespace=NAMESPACE Connect to specified journal namespace\n"
"\nSee the %s for details.\n",
program_invocation_short_name,
ansi_highlight(),
enum {
ARG_VERSION = 0x100,
ARG_STDERR_PRIORITY,
- ARG_LEVEL_PREFIX
+ ARG_LEVEL_PREFIX,
+ ARG_NAMESPACE,
};
static const struct option options[] = {
{ "priority", required_argument, NULL, 'p' },
{ "stderr-priority", required_argument, NULL, ARG_STDERR_PRIORITY },
{ "level-prefix", required_argument, NULL, ARG_LEVEL_PREFIX },
+ { "namespace", required_argument, NULL, ARG_NAMESPACE },
{}
};
return version();
case 't':
- if (isempty(optarg))
- arg_identifier = NULL;
- else
- arg_identifier = optarg;
+ arg_identifier = empty_to_null(optarg);
break;
case 'p':
return r;
break;
+ case ARG_NAMESPACE:
+ arg_namespace = empty_to_null(optarg);
+ break;
+
case '?':
return -EINVAL;
if (r <= 0)
return r;
- outfd = sd_journal_stream_fd(arg_identifier, arg_priority, arg_level_prefix);
+ outfd = sd_journal_stream_fd_with_namespace(arg_namespace, arg_identifier, arg_priority, arg_level_prefix);
if (outfd < 0)
return log_error_errno(outfd, "Failed to create stream fd: %m");
if (arg_stderr_priority >= 0 && arg_stderr_priority != arg_priority) {
- errfd = sd_journal_stream_fd(arg_identifier, arg_stderr_priority, arg_level_prefix);
+ errfd = sd_journal_stream_fd_with_namespace(arg_namespace, arg_identifier, arg_stderr_priority, arg_level_prefix);
if (errfd < 0)
return log_error_errno(errfd, "Failed to create stream fd: %m");
}
typedef struct Context {
sd_journal *journal;
+ bool has_cursor;
bool need_seek;
bool since_seeked;
bool ellipsized;
break;
}
- if (arg_until_set && !arg_reverse && (arg_lines < 0 || arg_since_set)) {
- /* If --lines= is set, we usually rely on the n_shown to tell us
- * when to stop. However, if --since= is set too, we may end up
- * having less than --lines= to output. In this case let's also
- * check if the entry is in range. */
+ if (arg_until_set && !arg_reverse && (arg_lines < 0 || arg_since_set || c->has_cursor)) {
+ /* If --lines= is set, we usually rely on the n_shown to tell us when to stop.
+ * However, if --since= or one of the cursor argument is set too, we may end up
+ * having less than --lines= to output. In this case let's also check if the entry
+ * is in range. */
usec_t usec;
Context c = {
.journal = j,
+ .has_cursor = cursor,
.need_seek = need_seek,
.since_seeked = since_seeked,
};
ENTRY_DIR_ABS="$3"
KERNEL_IMAGE="$4"
-[ "$KERNEL_INSTALL_LAYOUT" = "uki" ] || exit 0
-
ENTRY_TOKEN="$KERNEL_INSTALL_ENTRY_TOKEN"
BOOT_ROOT="$KERNEL_INSTALL_BOOT_ROOT"
;;
esac
+[ "$KERNEL_INSTALL_LAYOUT" = "uki" ] || exit 0
+
if ! [ -d "$UKI_DIR" ]; then
[ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "creating $UKI_DIR"
mkdir -p "$UKI_DIR"
return copy.rfd;
}
- r = strdup_or_null(source->layout_other, ©.layout_other);
+ r = strdup_to(©.layout_other, source->layout_other);
if (r < 0)
return r;
- r = strdup_or_null(source->conf_root, ©.conf_root);
+ r = strdup_to(©.conf_root, source->conf_root);
if (r < 0)
return r;
- r = strdup_or_null(source->boot_root, ©.boot_root);
+ r = strdup_to(©.boot_root, source->boot_root);
if (r < 0)
return r;
- r = strdup_or_null(source->entry_token, ©.entry_token);
+ r = strdup_to(©.entry_token, source->entry_token);
if (r < 0)
return r;
- r = strdup_or_null(source->entry_dir, ©.entry_dir);
+ r = strdup_to(©.entry_dir, source->entry_dir);
if (r < 0)
return r;
- r = strdup_or_null(source->version, ©.version);
+ r = strdup_to(©.version, source->version);
if (r < 0)
return r;
- r = strdup_or_null(source->kernel, ©.kernel);
+ r = strdup_to(©.kernel, source->kernel);
if (r < 0)
return r;
r = strv_copy_unless_empty(source->initrds, ©.initrds);
if (r < 0)
return r;
- r = strdup_or_null(source->initrd_generator, ©.initrd_generator);
+ r = strdup_to(©.initrd_generator, source->initrd_generator);
if (r < 0)
return r;
- r = strdup_or_null(source->uki_generator, ©.uki_generator);
+ r = strdup_to(©.uki_generator, source->uki_generator);
if (r < 0)
return r;
- r = strdup_or_null(source->staging_area, ©.staging_area);
+ r = strdup_to(©.staging_area, source->staging_area);
if (r < 0)
return r;
r = strv_copy_unless_empty(source->plugins, ©.plugins);
char *agent_circuit_id;
char *agent_remote_id;
+ int lease_dir_fd;
char *lease_file;
};
int dhcp_server_save_leases(sd_dhcp_server *server);
int dhcp_server_load_leases(sd_dhcp_server *server);
+int dhcp_server_leases_file_get_server_address(
+ int dir_fd,
+ const char *path,
+ struct in_addr *ret_address,
+ uint8_t *ret_prefixlen);
_cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL;
struct in_addr address = { .s_addr = htobe32(UINT32_C(10) << 24 | UINT32_C(1))};
_cleanup_free_ uint8_t *duped = NULL;
- _cleanup_free_ char *lease_file = NULL;
+ _cleanup_close_ int dir_fd = -EBADF;
if (size < sizeof(DHCPMessage))
return 0;
assert_se(duped = memdup(data, size));
- assert_se(mkdtemp_malloc(NULL, &tmpdir) >= 0);
- assert_se(lease_file = path_join(tmpdir, "leases"));
+ dir_fd = mkdtemp_open(NULL, 0, &tmpdir);
+ assert_se(dir_fd >= 0);
assert_se(sd_dhcp_server_new(&server, 1) >= 0);
assert_se(sd_dhcp_server_attach_event(server, NULL, 0) >= 0);
- assert_se(sd_dhcp_server_set_lease_file(server, lease_file) >= 0);
+ assert_se(sd_dhcp_server_set_lease_file(server, dir_fd, "leases") >= 0);
server->fd = open("/dev/null", O_RDWR|O_CLOEXEC|O_NOCTTY);
assert_se(server->fd >= 0);
assert_se(sd_dhcp_server_configure_pool(server, &address, 24, 0, 0) >= 0);
int dhcp_server_save_leases(sd_dhcp_server *server) {
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
- _cleanup_(unlink_and_freep) char *temp_path = NULL;
+ _cleanup_free_ char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
sd_id128_t boot_id;
int r;
if (r < 0)
return r;
- r = json_build(&v, JSON_BUILD_OBJECT(JSON_BUILD_PAIR_ID128("BootID", boot_id)));
+ r = json_build(&v, JSON_BUILD_OBJECT(
+ JSON_BUILD_PAIR_ID128("BootID", boot_id),
+ JSON_BUILD_PAIR_IN4_ADDR("Address", &(struct in_addr) { .s_addr = server->address }),
+ JSON_BUILD_PAIR_UNSIGNED("PrefixLength",
+ in4_addr_netmask_to_prefixlen(&(struct in_addr) { .s_addr = server->netmask }))));
if (r < 0)
return r;
if (r < 0)
return r;
- r = mkdir_parents(server->lease_file, 0755);
+ r = mkdirat_parents(server->lease_dir_fd, server->lease_file, 0755);
if (r < 0)
return r;
- r = fopen_temporary(server->lease_file, &f, &temp_path);
+ r = fopen_temporary_at(server->lease_dir_fd, server->lease_file, &f, &temp_path);
if (r < 0)
return r;
r = json_variant_dump(v, JSON_FORMAT_NEWLINE | JSON_FORMAT_FLUSH, f, /* prefix = */ NULL);
if (r < 0)
- return r;
+ goto failure;
- r = conservative_rename(temp_path, server->lease_file);
+ r = conservative_renameat(server->lease_dir_fd, temp_path, server->lease_dir_fd, server->lease_file);
if (r < 0)
- return r;
+ goto failure;
- temp_path = mfree(temp_path);
return 0;
+
+failure:
+ (void) unlinkat(server->lease_dir_fd, temp_path, /* flags = */ 0);
+ return r;
}
static int json_dispatch_dhcp_lease(sd_dhcp_server *server, JsonVariant *v, bool use_boottime) {
typedef struct SavedInfo {
sd_id128_t boot_id;
+ struct in_addr address;
+ uint8_t prefixlen;
JsonVariant *leases;
} SavedInfo;
-static int dhcp_server_dispatch_leases(sd_dhcp_server *server, JsonVariant *v) {
- static const JsonDispatch dispatch_table[] = {
- { "BootID", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(SavedInfo, boot_id), JSON_MANDATORY },
- { "Leases", JSON_VARIANT_ARRAY, json_dispatch_variant_noref, offsetof(SavedInfo, leases), JSON_MANDATORY },
- {}
- };
+static void saved_info_done(SavedInfo *info) {
+ if (!info)
+ return;
- SavedInfo info = {};
- sd_id128_t boot_id;
+ json_variant_unref(info->leases);
+}
+
+static int load_leases_file(int dir_fd, const char *path, SavedInfo *ret) {
+ _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
int r;
- r = json_dispatch(v, dispatch_table, JSON_ALLOW_EXTENSIONS, &info);
- if (r < 0)
- return r;
+ assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
+ assert(path);
+ assert(ret);
- r = sd_id128_get_boot(&boot_id);
+ r = json_parse_file_at(
+ /* f = */ NULL,
+ dir_fd,
+ path,
+ /* flags = */ 0,
+ &v,
+ /* ret_line = */ NULL,
+ /* ret_column = */ NULL);
if (r < 0)
return r;
- JsonVariant *i;
- JSON_VARIANT_ARRAY_FOREACH(i, info.leases)
- RET_GATHER(r, json_dispatch_dhcp_lease(server, i, /* use_boottime = */ sd_id128_equal(info.boot_id, boot_id)));
+ static const JsonDispatch dispatch_lease_file_table[] = {
+ { "BootID", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(SavedInfo, boot_id), JSON_MANDATORY },
+ { "Address", JSON_VARIANT_ARRAY, json_dispatch_in_addr, offsetof(SavedInfo, address), JSON_MANDATORY },
+ { "PrefixLength", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint8, offsetof(SavedInfo, prefixlen), JSON_MANDATORY },
+ { "Leases", JSON_VARIANT_ARRAY, json_dispatch_variant, offsetof(SavedInfo, leases), JSON_MANDATORY },
+ {}
+ };
- return r;
+ return json_dispatch(v, dispatch_lease_file_table, JSON_ALLOW_EXTENSIONS, ret);
}
int dhcp_server_load_leases(sd_dhcp_server *server) {
- _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
+ _cleanup_(saved_info_done) SavedInfo info = {};
+ sd_id128_t boot_id;
size_t n, m;
int r;
if (!server->lease_file)
return 0;
- r = json_parse_file(
- /* f = */ NULL,
- server->lease_file,
- /* flags = */ 0,
- &v,
- /* ret_line = */ NULL,
- /* ret_column = */ NULL);
+ r = load_leases_file(server->lease_dir_fd, server->lease_file, &info);
if (r == -ENOENT)
return 0;
if (r < 0)
return r;
+ r = sd_id128_get_boot(&boot_id);
+ if (r < 0)
+ return r;
+
n = hashmap_size(server->bound_leases_by_client_id);
- r = dhcp_server_dispatch_leases(server, v);
+ JsonVariant *i;
+ JSON_VARIANT_ARRAY_FOREACH(i, info.leases)
+ RET_GATHER(r, json_dispatch_dhcp_lease(server, i, /* use_boottime = */ sd_id128_equal(info.boot_id, boot_id)));
m = hashmap_size(server->bound_leases_by_client_id);
assert(m >= n);
return r;
}
+
+int dhcp_server_leases_file_get_server_address(
+ int dir_fd,
+ const char *path,
+ struct in_addr *ret_address,
+ uint8_t *ret_prefixlen) {
+
+ _cleanup_(saved_info_done) SavedInfo info = {};
+ int r;
+
+ if (!ret_address && !ret_prefixlen)
+ return 0;
+
+ r = load_leases_file(dir_fd, path, &info);
+ if (r < 0)
+ return r;
+
+ if (ret_address)
+ *ret_address = info.address;
+ if (ret_prefixlen)
+ *ret_prefixlen = info.prefixlen;
+ return 0;
+}
free(server->agent_circuit_id);
free(server->agent_remote_id);
+ safe_close(server->lease_dir_fd);
free(server->lease_file);
free(server->ifname);
.default_lease_time = DHCP_DEFAULT_LEASE_TIME_USEC,
.max_lease_time = DHCP_MAX_LEASE_TIME_USEC,
.rapid_commit = true,
+ .lease_dir_fd = -EBADF,
};
*ret = TAKE_PTR(server);
return 0;
}
-int sd_dhcp_server_set_lease_file(sd_dhcp_server *server, const char *path) {
+int sd_dhcp_server_set_lease_file(sd_dhcp_server *server, int dir_fd, const char *path) {
+ int r;
+
assert_return(server, -EINVAL);
assert_return(!sd_dhcp_server_is_running(server), -EBUSY);
- if (path && !path_is_safe(path))
+ if (!path) {
+ /* When NULL, clear the previous assignment. */
+ server->lease_file = mfree(server->lease_file);
+ server->lease_dir_fd = safe_close(server->lease_dir_fd);
+ return 0;
+ }
+
+ if (!path_is_safe(path))
return -EINVAL;
- return free_and_strdup(&server->lease_file, path);
+ if (dir_fd < 0 && dir_fd != AT_FDCWD)
+ return -EBADF;
+
+ _cleanup_close_ int fd = -EBADF;
+ fd = fd_reopen(dir_fd, O_CLOEXEC | O_DIRECTORY | O_PATH);
+ if (fd < 0)
+ return fd;
+
+ r = free_and_strdup(&server->lease_file, path);
+ if (r < 0)
+ return r;
+
+ server->lease_dir_fd = TAKE_FD(fd);
+ return 0;
}
global:
sd_bus_creds_get_pidfd_dup;
sd_bus_creds_new_from_pidfd;
+ sd_journal_stream_fd_with_namespace;
} LIBSYSTEMD_255;
int devname_from_devnum(mode_t mode, dev_t devnum, char **ret) {
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
- _cleanup_free_ char *s = NULL;
const char *devname;
int r;
if (r < 0)
return r;
- s = strdup(devname);
- if (!s)
- return -ENOMEM;
-
- *ret = TAKE_PTR(s);
- return 0;
+ return strdup_to(ret, devname);
}
-int device_open_from_devnum(mode_t mode, dev_t devnum, int flags, char **ret) {
+int device_open_from_devnum(mode_t mode, dev_t devnum, int flags, char **ret_devname) {
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
_cleanup_close_ int fd = -EBADF;
int r;
if (fd < 0)
return fd;
- if (ret) {
+ if (ret_devname) {
const char *devname;
- char *s;
r = sd_device_get_devname(dev, &devname);
if (r < 0)
return r;
- s = strdup(devname);
- if (!s)
- return -ENOMEM;
-
- *ret = s;
+ r = strdup_to(ret_devname, devname);
+ if (r < 0)
+ return r;
}
return TAKE_FD(fd);
assert(st);
return devname_from_devnum(st->st_mode, st->st_rdev, ret);
}
-int device_open_from_devnum(mode_t mode, dev_t devnum, int flags, char **ret);
+int device_open_from_devnum(mode_t mode, dev_t devnum, int flags, char **ret_devname);
char** device_make_log_fields(sd_device *device);
const char* deflang,
char **ret) {
- size_t c;
- char *z;
-
- c = strlen(t);
+ size_t c = strlen(t);
if (c < 2)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"[%s:%u] Language too short.", filename, line);
log_warning("[%s:%u] language differs from default for file", filename, line);
}
- z = strdup(t);
- if (!z)
- return -ENOMEM;
-
- *ret = z;
- return 0;
+ return strdup_to(ret, t);
}
int catalog_import_file(OrderedHashmap *h, const char *path) {
le64toh(f->offset);
}
-int catalog_get(const char* database, sd_id128_t id, char **_text) {
+int catalog_get(const char* database, sd_id128_t id, char **ret_text) {
_cleanup_close_ int fd = -EBADF;
void *p = NULL;
- struct stat st = {};
- char *text = NULL;
+ struct stat st;
int r;
const char *s;
- assert(_text);
+ assert(ret_text);
r = open_mmap(database, &fd, &st, &p);
if (r < 0)
goto finish;
}
- text = strdup(s);
- if (!text) {
- r = -ENOMEM;
- goto finish;
- }
-
- *_text = text;
- r = 0;
-
+ r = strdup_to(ret_text, s);
finish:
(void) munmap(p, st.st_size);
int catalog_import_file(OrderedHashmap *h, const char *path);
int catalog_update(const char* database, const char* root, const char* const* dirs);
-int catalog_get(const char* database, sd_id128_t id, char **data);
+int catalog_get(const char* database, sd_id128_t id, char **ret_text);
int catalog_list(FILE *f, const char* database, bool oneline);
int catalog_list_items(FILE *f, const char* database, bool oneline, char **items);
int catalog_file_lang(const char *filename, char **lang);
return fill_iovec_perror_and_send(message, 0, iovec);
}
-_public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
+_public_ int sd_journal_stream_fd_with_namespace(
+ const char *name_space,
+ const char *identifier,
+ int priority,
+ int level_prefix) {
+
_cleanup_close_ int fd = -EBADF;
- char *header;
- size_t l;
+ const char *path;
int r;
assert_return(priority >= 0, -EINVAL);
assert_return(priority <= 7, -EINVAL);
+ path = journal_stream_path(name_space);
+ if (!path)
+ return -EINVAL;
+
fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
if (fd < 0)
return -errno;
- r = connect_unix_path(fd, AT_FDCWD, "/run/systemd/journal/stdout");
+ r = connect_unix_path(fd, AT_FDCWD, path);
if (r < 0)
return r;
identifier = strempty(identifier);
+ char *header;
+ size_t l;
+
l = strlen(identifier);
header = newa(char, l + 1 + 1 + 2 + 2 + 2 + 2 + 2);
return TAKE_FD(fd);
}
+_public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
+ return sd_journal_stream_fd_with_namespace(NULL, identifier, priority, level_prefix);
+}
+
_public_ int sd_journal_print_with_location(int priority, const char *file, const char *line, const char *func, const char *format, ...) {
int r;
va_list ap;
#pragma once
#include <stdbool.h>
+#include <stddef.h>
+
+#include "syslog-util.h"
int journal_fd_nonblock(bool nonblock);
void close_journal_fd(void);
+
+/* We declare sd_journal_stream_fd() as async-signal-safe. So instead of strjoin(), which calls malloc()
+ * internally, use a macro + alloca(). */
+#define journal_stream_path(log_namespace) \
+ ({ \
+ const char *_ns = (log_namespace), *_ret; \
+ if (!_ns) \
+ _ret = "/run/systemd/journal/stdout"; \
+ else if (log_namespace_name_valid(_ns)) \
+ _ret = strjoina("/run/systemd/journal.", _ns, "/stdout"); \
+ else \
+ _ret = NULL; \
+ _ret; \
+ })
j->has_persistent_files = true;
}
-static const char *skip_slash(const char *p) {
-
- if (!p)
- return NULL;
-
- while (*p == '/')
- p++;
-
- return p;
-}
-
static int add_any_file(
sd_journal *j,
int fd,
/* If there's a top-level fd defined make the path relative, explicitly, since otherwise
* openat() ignores the first argument. */
- fd = our_fd = openat(j->toplevel_fd, skip_slash(path), O_RDONLY|O_CLOEXEC|O_NONBLOCK);
+ fd = our_fd = openat(j->toplevel_fd, skip_leading_slash(path), O_RDONLY|O_CLOEXEC|O_NONBLOCK);
else
fd = our_fd = open(path, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
if (fd < 0) {
else
/* Open the specified directory relative to the toplevel fd. Enforce that the path specified is
* relative, by dropping the initial slash */
- d = xopendirat(j->toplevel_fd, skip_slash(path), 0);
+ d = xopendirat(j->toplevel_fd, skip_leading_slash(path), 0);
if (!d)
return -errno;
}
int find_converted_keymap(const X11Context *xc, char **ret) {
- _cleanup_free_ char *n = NULL;
+ _cleanup_free_ char *n = NULL, *p = NULL, *pz = NULL;
+ _cleanup_strv_free_ char **keymap_dirs = NULL;
+ int r;
assert(xc);
assert(!isempty(xc->layout));
if (!n)
return -ENOMEM;
- NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) {
- _cleanup_free_ char *p = NULL, *pz = NULL;
+ p = strjoin("xkb/", n, ".map");
+ pz = strjoin("xkb/", n, ".map.gz");
+ if (!p || !pz)
+ return -ENOMEM;
+
+ r = keymap_directories(&keymap_dirs);
+ if (r < 0)
+ return r;
+
+ STRV_FOREACH(dir, keymap_dirs) {
+ _cleanup_close_ int dir_fd = -EBADF;
bool uncompressed;
- p = strjoin(dir, "xkb/", n, ".map");
- pz = strjoin(dir, "xkb/", n, ".map.gz");
- if (!p || !pz)
- return -ENOMEM;
+ dir_fd = open(*dir, O_CLOEXEC | O_DIRECTORY | O_PATH);
+ if (dir_fd < 0) {
+ if (errno != ENOENT)
+ log_debug_errno(errno, "Failed to open %s, ignoring: %m", *dir);
+ continue;
+ }
- uncompressed = access(p, F_OK) == 0;
- if (uncompressed || access(pz, F_OK) == 0) {
- log_debug("Found converted keymap %s at %s", n, uncompressed ? p : pz);
+ uncompressed = faccessat(dir_fd, p, F_OK, 0) >= 0;
+ if (uncompressed || faccessat(dir_fd, pz, F_OK, 0) >= 0) {
+ log_debug("Found converted keymap %s at %s/%s", n, *dir, uncompressed ? p : pz);
*ret = TAKE_PTR(n);
return 1;
}
if (new_locale[p])
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Locale variable %s set twice, refusing.", name);
- new_locale[p] = strdup(e);
- if (!new_locale[p])
- return -ENOMEM;
-
- return 0;
+ return strdup_to(&new_locale[p], e);
}
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Locale assignment %s not valid, refusing.", assignment);
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
- _cleanup_free_ char *p = NULL;
const char *path;
int r;
if (r < 0)
return bus_log_parse_error(r);
- p = strdup(path);
- if (!p)
- return log_oom();
-
- *ret = TAKE_PTR(p);
- return 0;
+ return strdup_to(ret, path);
}
static int show_session(int argc, char *argv[], void *userdata) {
user->gc_mode = USER_GC_BY_PIN;
if (!isempty(tty)) {
- session->tty = strdup(tty);
- if (!session->tty) {
- r = -ENOMEM;
+ r = strdup_to(&session->tty, tty);
+ if (r < 0)
goto fail;
- }
session->tty_validity = TTY_FROM_PAM;
}
if (!isempty(display)) {
- session->display = strdup(display);
- if (!session->display) {
- r = -ENOMEM;
+ r = strdup_to(&session->display, display);
+ if (r < 0)
goto fail;
- }
}
if (!isempty(remote_user)) {
- session->remote_user = strdup(remote_user);
- if (!session->remote_user) {
- r = -ENOMEM;
+ r = strdup_to(&session->remote_user, remote_user);
+ if (r < 0)
goto fail;
- }
}
if (!isempty(remote_host)) {
- session->remote_host = strdup(remote_host);
- if (!session->remote_host) {
- r = -ENOMEM;
+ r = strdup_to(&session->remote_host, remote_host);
+ if (r < 0)
goto fail;
- }
}
if (!isempty(service)) {
- session->service = strdup(service);
- if (!session->service) {
- r = -ENOMEM;
+ r = strdup_to(&session->service, service);
+ if (r < 0)
goto fail;
- }
}
if (!isempty(desktop)) {
- session->desktop = strdup(desktop);
- if (!session->desktop) {
- r = -ENOMEM;
+ r = strdup_to(&session->desktop, desktop);
+ if (r < 0)
goto fail;
- }
}
if (seat) {
if (sd->device->seat != sd->session->seat)
return -EPERM;
- sd->node = strdup(node);
- if (!sd->node)
- return -ENOMEM;
-
- return 0;
+ return strdup_to(&sd->node, node);
}
int session_device_new(Session *s, dev_t dev, bool open_device, SessionDevice **ret) {
static int call_get_os_release(sd_bus *bus, const char *method, const char *name, const char *query, ...) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
- const char *k, *v, **query_res = NULL;
- size_t count = 0, awaited_args = 0;
va_list ap;
int r;
assert(bus);
+ assert(method);
assert(name);
assert(query);
- NULSTR_FOREACH(iter, query)
- awaited_args++;
- query_res = newa0(const char *, awaited_args);
-
r = bus_call_method(bus, bus_machine_mgr, method, &error, &reply, "s", name);
if (r < 0)
return log_debug_errno(r, "Failed to call '%s()': %s", method, bus_error_message(&error, r));
if (r < 0)
return bus_log_parse_error(r);
+ const char **res;
+ size_t n_fields = 0;
+
+ NULSTR_FOREACH(i, query)
+ n_fields++;
+
+ res = newa0(const char*, n_fields);
+
+ const char *k, *v;
while ((r = sd_bus_message_read(reply, "{ss}", &k, &v)) > 0) {
- count = 0;
- NULSTR_FOREACH(iter, query) {
- if (streq(k, iter)) {
- query_res[count] = v;
+ size_t c = 0;
+ NULSTR_FOREACH(i, query) {
+ if (streq(i, k)) {
+ res[c] = v;
break;
}
- count++;
+ c++;
}
}
if (r < 0)
if (r < 0)
return bus_log_parse_error(r);
+ r = 0;
+
va_start(ap, query);
- for (count = 0; count < awaited_args; count++) {
- char *val, **out;
-
- out = va_arg(ap, char **);
- assert(out);
- if (query_res[count]) {
- val = strdup(query_res[count]);
- if (!val) {
- va_end(ap);
- return -ENOMEM;
- }
- *out = val;
- }
+ FOREACH_ARRAY(i, res, n_fields) {
+ r = strdup_to(va_arg(ap, char**), *i);
+ if (r < 0)
+ break;
}
va_end(ap);
- return 0;
+ return r;
}
static int call_get_addresses(
addresses = strdup(prefix);
if (!addresses)
return log_oom();
- prefix = "";
r = sd_bus_message_enter_container(reply, 'a', "(iay)");
if (r < 0)
return bus_log_parse_error(r);
+ prefix = "";
while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
int family;
const void *a;
STATIC_DESTRUCTOR_REGISTER(arg_drop_in, freep);
static int varlink_connect_networkd(Varlink **ret_varlink) {
- _cleanup_(varlink_unrefp) Varlink *vl = NULL;
+ _cleanup_(varlink_flush_close_unrefp) Varlink *vl = NULL;
JsonVariant *reply;
uint64_t id;
int r;
if (r < 0)
return log_error_errno(r, "Failed to connect to network service /run/systemd/netif/io.systemd.Network: %m");
+ (void) varlink_set_description(vl, "varlink-network");
+
+ r = varlink_set_allow_fd_passing_output(vl, true);
+ if (r < 0)
+ return log_error_errno(r, "Failed to allow passing file descriptor through varlink: %m");
+
r = varlink_call_and_log(vl, "io.systemd.Network.GetNamespaceId", /* parameters= */ NULL, &reply);
if (r < 0)
return r;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
_cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
- _cleanup_(varlink_unrefp) Varlink *vl = NULL;
+ _cleanup_(varlink_flush_close_unrefp) Varlink *vl = NULL;
_cleanup_(link_info_array_freep) LinkInfo *links = NULL;
int r, c;
}
static int link_lldp_status(int argc, char *argv[], void *userdata) {
- _cleanup_(varlink_unrefp) Varlink *vl = NULL;
+ _cleanup_(varlink_flush_close_unrefp) Varlink *vl = NULL;
_cleanup_(table_unrefp) Table *table = NULL;
JsonVariant *reply;
uint64_t all = 0;
}
static int verb_persistent_storage(int argc, char *argv[], void *userdata) {
- _cleanup_(varlink_unrefp) Varlink *vl = NULL;
+ _cleanup_(varlink_flush_close_unrefp) Varlink *vl = NULL;
bool ready;
int r;
if (r < 0)
return r;
+ if (ready) {
+ _cleanup_close_ int fd = -EBADF;
+
+ fd = open("/var/lib/systemd/network/", O_CLOEXEC | O_DIRECTORY);
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to open /var/lib/systemd/network/: %m");
+
+ r = varlink_push_fd(vl, fd);
+ if (r < 0)
+ return log_error_errno(r, "Failed to push file descriptor of /var/lib/systemd/network/ into varlink: %m");
+
+ TAKE_FD(fd);
+ }
+
return varlink_callb_and_log(vl, "io.systemd.Network.SetPersistentStorage", /* reply = */ NULL,
JSON_BUILD_OBJECT(JSON_BUILD_PAIR_BOOLEAN("Ready", ready)));
}
dest->nft_set_context.n_sets = 0;
if (src->family == AF_INET) {
- r = strdup_or_null(src->label, &dest->label);
+ r = strdup_to(&dest->label, src->label);
if (r < 0)
return r;
}
- r = strdup_or_null(src->netlabel, &dest->netlabel);
+ r = strdup_to(&dest->netlabel, src->netlabel);
if (r < 0)
return r;
address->source = NETWORK_CONFIG_SOURCE_FOREIGN;
}
-static int address_acquire(Link *link, const Address *original, Address **ret) {
- _cleanup_(address_unrefp) Address *na = NULL;
- union in_addr_union in_addr;
- int r;
-
- assert(link);
- assert(original);
- assert(ret);
-
- /* Something useful was configured? just use it */
- if (in_addr_is_set(original->family, &original->in_addr))
- return address_dup(original, ret);
-
- /* The address is configured to be 0.0.0.0 or [::] by the user?
- * Then let's acquire something more useful from the pool. */
- r = address_pool_acquire(link->manager, original->family, original->prefixlen, &in_addr);
- if (r < 0)
- return r;
- if (r == 0)
- return -EBUSY;
-
- /* Pick first address in range for ourselves. */
- if (original->family == AF_INET)
- in_addr.in.s_addr = in_addr.in.s_addr | htobe32(1);
- else if (original->family == AF_INET6)
- in_addr.in6.s6_addr[15] |= 1;
-
- r = address_dup(original, &na);
- if (r < 0)
- return r;
-
- na->in_addr = in_addr;
-
- *ret = TAKE_PTR(na);
- return 0;
-}
-
int address_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, const char *error_msg) {
int r;
return request_call_netlink_async(link->manager->rtnl, m, req);
}
-static bool address_is_ready_to_configure(Link *link, const Address *address) {
+static int address_acquire(Link *link, const Address *address, union in_addr_union *ret) {
+ union in_addr_union a;
+ int r;
+
assert(link);
assert(address);
+ assert(ret);
- if (!link_is_ready_to_configure(link, false))
- return false;
+ r = address_pool_acquire(link->manager, address->family, address->prefixlen, &a);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -EBUSY;
- if (!ipv4acd_bound(link, address))
- return false;
+ /* Pick first address in range for ourselves. */
+ if (address->family == AF_INET)
+ a.in.s_addr |= htobe32(1);
+ else if (address->family == AF_INET6)
+ a.in6.s6_addr[15] |= 1;
+ else
+ assert_not_reached();
- /* Refuse adding more than the limit */
- if (set_size(link->addresses) >= ADDRESSES_PER_LINK_MAX)
- return false;
+ *ret = a;
+ return 0;
+}
- return true;
+static int address_requeue_request(Request *req, Link *link, const Address *address) {
+ int r;
+
+ assert(req);
+ assert(link);
+ assert(link->manager);
+ assert(link->network);
+ assert(address);
+
+ /* Something useful was configured? just use it */
+ if (in_addr_is_set(address->family, &address->in_addr))
+ return 0;
+
+ /* The address is configured to be 0.0.0.0 or [::] by the user?
+ * Then let's acquire something more useful. */
+ union in_addr_union a;
+ r = address_acquire(link, address, &a);
+ if (r < 0)
+ return r;
+
+ _cleanup_(address_unrefp) Address *tmp = NULL;
+ r = address_dup(address, &tmp);
+ if (r < 0)
+ return r;
+
+ tmp->in_addr = a;
+
+ r = link_requeue_request(link, req, tmp, NULL);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -EEXIST; /* Already queued?? Strange... */
+
+ TAKE_PTR(tmp);
+ return 1; /* A new request is queued. it is not necessary to process this request anymore. */
}
static int address_process_request(Request *req, Link *link, Address *address) {
assert(link);
assert(address);
- if (!address_is_ready_to_configure(link, address))
+ if (!link_is_ready_to_configure(link, false))
+ return 0;
+
+ /* Refuse adding more than the limit */
+ if (set_size(link->addresses) >= ADDRESSES_PER_LINK_MAX)
+ return 0;
+
+ r = address_requeue_request(req, link, address);
+ if (r == -EBUSY)
+ return 0;
+ if (r != 0)
+ return r;
+
+ address_set_broadcast(address, link);
+
+ r = ipv4acd_configure(link, address);
+ if (r < 0)
+ return r;
+
+ if (!ipv4acd_bound(link, address))
return 0;
address_set_cinfo(link->manager, address, &c);
/* The requested address is outdated. Let's ignore the request. */
return 0;
- if (address_get(link, address, &existing) < 0) {
- if (address_get_request(link, address, NULL) >= 0)
- return 0; /* already requested, skipping. */
+ if (address_get_request(link, address, NULL) >= 0)
+ return 0; /* already requested, skipping. */
- r = address_acquire(link, address, &tmp);
- if (r < 0)
- return log_link_warning_errno(link, r, "Failed to acquire an address from pool: %m");
-
- } else {
- r = address_dup(address, &tmp);
- if (r < 0)
- return log_oom();
+ r = address_dup(address, &tmp);
+ if (r < 0)
+ return log_oom();
+ if (address_get(link, address, &existing) >= 0) {
/* Copy already assigned address when it is requested as a null address. */
if (address_is_static_null(address))
tmp->in_addr = existing->in_addr;
tmp->state = existing->state;
}
- address_set_broadcast(tmp, link);
-
- r = ipv4acd_configure(link, tmp);
- if (r < 0)
- return r;
-
log_address_debug(tmp, "Requesting", link);
r = link_queue_request_safe(link, REQUEST_TYPE_ADDRESS,
tmp,
return 0;
}
-static int link_start_dhcp4_server(Link *link) {
+int link_start_dhcp4_server(Link *link) {
int r;
assert(link);
if (!link_has_carrier(link))
return 0;
+ if (sd_dhcp_server_is_running(link->dhcp_server))
+ return 0; /* already started. */
+
/* TODO: Maybe, also check the system time is synced. If the system does not have RTC battery, then
* the realtime clock in not usable in the early boot stage, and all saved leases may be wrongly
* handled as expired and dropped. */
- if (!sd_dhcp_server_is_in_relay_mode(link->dhcp_server) &&
- !link->manager->persistent_storage_is_ready)
- return 0;
+ if (!sd_dhcp_server_is_in_relay_mode(link->dhcp_server)) {
+
+ if (link->manager->persistent_storage_fd < 0)
+ return 0; /* persistent storage is not ready. */
+
+ _cleanup_free_ char *lease_file = path_join("dhcp-server-lease", link->ifname);
+ if (!lease_file)
+ return -ENOMEM;
+
+ r = sd_dhcp_server_set_lease_file(link->dhcp_server, link->manager->persistent_storage_fd, lease_file);
+ if (r < 0)
+ return r;
+ }
r = sd_dhcp_server_start(link->dhcp_server);
if (r < 0)
if (sd_dhcp_server_is_in_relay_mode(link->dhcp_server))
continue;
- if (start)
- r = link_start_dhcp4_server(link);
- else
- r = sd_dhcp_server_stop(link->dhcp_server);
+ /* Even if 'start' is true, first we need to stop the server. Otherwise, we cannot (re)set
+ * the lease file in link_start_dhcp4_server(). */
+ r = sd_dhcp_server_stop(link->dhcp_server);
if (r < 0)
- log_link_debug_errno(link, r, "Failed to %s DHCP server, ignoring: %m",
- start ? "start" : "stop");
+ log_link_debug_errno(link, r, "Failed to stop DHCP server, ignoring: %m");
+
+ if (!start)
+ continue;
+
+ r = link_start_dhcp4_server(link);
+ if (r < 0)
+ log_link_debug_errno(link, r, "Failed to start DHCP server, ignoring: %m");
}
}
return log_link_error_errno(link, r, "Failed to set DHCPv4 static lease for DHCP server: %m");
}
- if (!sd_dhcp_server_is_in_relay_mode(link->dhcp_server)) {
- _cleanup_free_ char *lease_file = path_join("/var/lib/systemd/network/dhcp-server-lease/", link->ifname);
- if (!lease_file)
- return log_oom();
-
- r = sd_dhcp_server_set_lease_file(link->dhcp_server, lease_file);
- if (r < 0)
- log_link_warning_errno(link, r, "Failed to load DHCPv4 server leases, ignoring: %m");
- }
-
r = link_start_dhcp4_server(link);
if (r < 0)
return log_link_error_errno(link, r, "Could not start DHCPv4 server instance: %m");
int link_request_dhcp_server(Link *link);
+int link_start_dhcp4_server(Link *link);
void manager_toggle_dhcp4_server_state(Manager *manager, bool start);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_relay_agent_suboption);
log_link_debug(link, "Acquiring IPv4 link-local address.");
}
- if (link->dhcp_server) {
- r = sd_dhcp_server_start(link->dhcp_server);
- if (r < 0)
- return log_link_warning_errno(link, r, "Could not start DHCP server: %m");
- }
+ r = link_start_dhcp4_server(link);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Could not start DHCP server: %m");
r = ipv4acd_start(link);
if (r < 0)
#include <unistd.h>
#include "bus-polkit.h"
-#include "fs-util.h"
+#include "fd-util.h"
#include "lldp-rx-internal.h"
#include "networkd-dhcp-server.h"
#include "networkd-manager-varlink.h"
return r;
if (ready) {
- r = path_is_read_only_fs("/var/lib/systemd/network/");
+ struct stat st, st_prev;
+ int fd;
+
+ fd = varlink_peek_fd(vlink, 0);
+ if (fd < 0)
+ return log_warning_errno(fd, "Failed to peek file descriptor of the persistent storage: %m");
+
+ r = fd_verify_safe_flags_full(fd, O_DIRECTORY);
+ if (r == -EREMOTEIO)
+ return log_warning_errno(r, "Passed persistent storage fd has unexpected flags, refusing.");
+ if (r < 0)
+ return log_warning_errno(r, "Failed to verify flags of passed persistent storage fd: %m");
+
+ r = fd_is_read_only_fs(fd);
if (r < 0)
- return log_warning_errno(r, "Failed to check if /var/lib/systemd/network/ is writable: %m");
+ return log_warning_errno(r, "Failed to check if the persistent storage is writable: %m");
if (r > 0) {
- log_warning("The directory /var/lib/systemd/network/ is read-only.");
+ log_warning("The persistent storage is on read-only filesystem.");
return varlink_error(vlink, "io.systemd.Network.StorageReadOnly", NULL);
}
+
+ if (fstat(fd, &st) < 0)
+ return log_warning_errno(r, "Failed to stat the passed persistent storage fd: %m");
+
+ r = stat_verify_directory(&st);
+ if (r < 0)
+ return log_warning_errno(r, "The passed persistent storage fd is not a directory, refusing: %m");
+
+ if (manager->persistent_storage_fd >= 0 &&
+ fstat(manager->persistent_storage_fd, &st_prev) >= 0 &&
+ stat_inode_same(&st, &st_prev))
+ return varlink_reply(vlink, NULL);
+
+ } else {
+ if (manager->persistent_storage_fd < 0)
+ return varlink_reply(vlink, NULL);
}
r = varlink_verify_polkit_async(
if (r <= 0)
return r;
- manager->persistent_storage_is_ready = ready;
-
if (ready) {
- r = touch("/run/systemd/netif/persistent-storage-ready");
- if (r < 0)
- log_debug_errno(r, "Failed to create /run/systemd/netif/persistent-storage-ready, ignoring: %m");
- } else {
- if (unlink("/run/systemd/netif/persistent-storage-ready") < 0 && errno != ENOENT)
- log_debug_errno(errno, "Failed to remove /run/systemd/netif/persistent-storage-ready, ignoring: %m");
- }
+ _cleanup_close_ int fd = -EBADF;
+
+ fd = varlink_take_fd(vlink, 0);
+ if (fd < 0)
+ return log_warning_errno(fd, "Failed to take file descriptor of the persistent storage: %m");
+
+ close_and_replace(manager->persistent_storage_fd, fd);
+ } else
+ manager->persistent_storage_fd = safe_close(manager->persistent_storage_fd);
manager_toggle_dhcp4_server_state(manager, ready);
return varlink_reply(vlink, NULL);
}
+static int on_connect(VarlinkServer *s, Varlink *vlink, void *userdata) {
+ int r;
+
+ assert(vlink);
+
+ r = varlink_set_allow_fd_passing_input(vlink, true);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to allow receiving file descriptor through varlink: %m");
+
+ return 0;
+}
+
int manager_connect_varlink(Manager *m) {
_cleanup_(varlink_server_unrefp) VarlinkServer *s = NULL;
int r;
varlink_server_set_userdata(s, m);
+ (void) varlink_server_set_description(s, "varlink-api-network");
+
r = varlink_server_add_interface(s, &vl_interface_io_systemd_Network);
if (r < 0)
return log_error_errno(r, "Failed to add Network interface to varlink server: %m");
if (r < 0)
return log_error_errno(r, "Failed to attach varlink connection to event loop: %m");
+ r = varlink_server_bind_connect(s, on_connect);
+ if (r < 0)
+ return log_error_errno(r, "Failed to set on-connect callback for varlink: %m");
+
m->varlink_server = TAKE_PTR(s);
return 0;
}
#include "device-private.h"
#include "device-util.h"
#include "dns-domain.h"
+#include "env-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "firewall-util.h"
return 0;
}
-static bool persistent_storage_is_ready(void) {
+static int persistent_storage_open(void) {
+ _cleanup_close_ int fd = -EBADF;
int r;
- if (access("/run/systemd/netif/persistent-storage-ready", F_OK) < 0) {
- if (errno != ENOENT)
- log_debug_errno(errno, "Failed to check if /run/systemd/netif/persistent-storage-ready exists, assuming not: %m");
- return false;
- }
+ r = getenv_bool("SYSTEMD_NETWORK_PERSISTENT_STORAGE_READY");
+ if (r < 0 && r != -ENXIO)
+ return log_debug_errno(r, "Failed to parse $SYSTEMD_NETWORK_PERSISTENT_STORAGE_READY environment variable, ignoring: %m");
+ if (r <= 0)
+ return -EBADF;
- r = path_is_read_only_fs("/var/lib/systemd/network/");
- if (r == 0)
- return true;
- if (r < 0)
- log_debug_errno(r, "Failed to check if /var/lib/systemd/network/ is writable: %m");
- else
- log_debug("The directory /var/lib/systemd/network/ is read-only.");
+ fd = open("/var/lib/systemd/network/", O_CLOEXEC | O_DIRECTORY | O_PATH);
+ if (fd < 0)
+ return log_debug_errno(errno, "Failed to open /var/lib/systemd/network/, ignoring: %m");
- if (unlink("/run/systemd/netif/persistent-storage-ready") < 0 && errno != ENOENT)
- log_debug_errno(errno, "Failed to remove /run/systemd/netif/persistent-storage-ready, ignoring: %m");
+ r = fd_is_read_only_fs(fd);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to check if /var/lib/systemd/network/ is writable: %m");
+ if (r > 0)
+ return log_debug_errno(SYNTHETIC_ERRNO(EROFS), "The directory /var/lib/systemd/network/ is on read-only filesystem.");
- return false;
+ return TAKE_FD(fd);
}
int manager_new(Manager **ret, bool test_mode) {
.keep_configuration = _KEEP_CONFIGURATION_INVALID,
.ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO,
.test_mode = test_mode,
- .persistent_storage_is_ready = persistent_storage_is_ready(),
.speed_meter_interval_usec = SPEED_METER_DEFAULT_TIME_INTERVAL,
.online_state = _LINK_ONLINE_STATE_INVALID,
.manage_foreign_routes = true,
.manage_foreign_rules = true,
.manage_foreign_nexthops = true,
.ethtool_fd = -EBADF,
+ .persistent_storage_fd = persistent_storage_open(),
.dhcp_duid.type = DUID_TYPE_EN,
.dhcp6_duid.type = DUID_TYPE_EN,
.duid_product_uuid.type = DUID_TYPE_UUID,
free(m->dynamic_hostname);
safe_close(m->ethtool_fd);
+ safe_close(m->persistent_storage_fd);
m->fw_ctx = fw_ctx_free(m->fw_ctx);
sd_device_monitor *device_monitor;
Hashmap *polkit_registry;
int ethtool_fd;
+ int persistent_storage_fd;
KeepConfiguration keep_configuration;
IPv6PrivacyExtensions ipv6_privacy_extensions;
bool manage_foreign_routes;
bool manage_foreign_rules;
bool manage_foreign_nexthops;
- bool persistent_storage_is_ready;
Set *dirty_links;
Set *new_wlan_ifindices;
process, counter, netlink_handler, ret);
}
+int link_requeue_request(Link *link, Request *req, void *userdata, Request **ret) {
+ assert(link);
+ assert(req);
+
+ return link_queue_request_full(
+ link,
+ req->type,
+ userdata,
+ req->free_func,
+ req->hash_func,
+ req->compare_func,
+ req->process,
+ req->counter,
+ req->netlink_handler,
+ ret);
+}
+
int manager_process_requests(Manager *manager) {
Request *req;
int r;
request_netlink_handler_t netlink_handler,
Request **ret);
+int link_requeue_request(Link *link, Request *req, void *userdata, Request **ret);
+
static inline int link_queue_request(
Link *link,
RequestType type,
} else
dest->metrics_set = NULL;
- return strdup_or_null(src->tcp_congestion_control_algo, &dest->tcp_congestion_control_algo);
+ return strdup_to(&dest->tcp_congestion_control_algo, src->tcp_congestion_control_algo);
}
void route_metric_hash_func(const RouteMetric *metric, struct siphash *state) {
/* unset pointer copied in the above. */
dest->ifname = NULL;
- return strdup_or_null(src->ifindex > 0 ? NULL : src->ifname, &dest->ifname);
+ return strdup_to(&dest->ifname, src->ifindex > 0 ? NULL : src->ifname);
}
static int route_nexthop_dup(const RouteNextHop *src, RouteNextHop **ret) {
request_detach(req);
/* Request the route with the adjusted Route object combined with the same other parameters. */
- r = link_queue_request_full(link,
- req->type,
- tmp,
- req->free_func,
- req->hash_func,
- req->compare_func,
- req->process,
- req->counter,
- req->netlink_handler,
- NULL);
+ r = link_requeue_request(link, req, tmp, NULL);
if (r < 0)
return r;
if (r == 0)
if (dissected_image) {
/* Now we know the uid shift, let's now mount everything else that might be in the image. */
- r = dissected_image_mount(
+ r = dissected_image_mount_and_warn(
dissected_image,
directory,
arg_uid_shift,
determine_dissect_image_flags()|
DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY|
(idmap ? DISSECT_IMAGE_MOUNT_IDMAPPED : 0));
- if (r == -EUCLEAN)
- return log_error_errno(r, "File system check for image failed: %m");
if (r < 0)
- return log_error_errno(r, "Failed to mount image file system: %m");
+ return r;
}
if (arg_unified_cgroup_hierarchy == CGROUP_UNIFIED_UNKNOWN) {
if (!tags)
return log_oom();
+ if (DEBUG_LOGGING) {
+ _cleanup_free_ char *joined = strv_join(tags, " ");
+
+ if (joined) {
+ _cleanup_free_ char *j = cescape(joined);
+ free_and_replace(joined, j);
+ }
+
+ log_debug("Got sd_notify() message: %s", strnull(joined));
+ }
+
if (strv_contains(tags, "READY=1")) {
r = sd_notify(false, "READY=1\n");
if (r < 0)
if (r == -ENOMEM)
return r; /* Treat oom as a hard error */
if (r < 0) {
- if (ret == 0)
- ret = r;
+ RET_GATHER(ret, r);
continue; /* Try to find something else to kill */
}
dump_until = MAX(dump_until, i + 1);
- char *selected = strdup(sorted[i]->path);
- if (!selected)
- return -ENOMEM;
- *ret_selected = selected;
+
ret = r;
+ r = strdup_to(ret_selected, sorted[i]->path);
+ if (r < 0)
+ return r;
break;
}
if (r == -ENOMEM)
return r; /* Treat oom as a hard error */
if (r < 0) {
- if (ret == 0)
- ret = r;
+ RET_GATHER(ret, r);
continue; /* Try to find something else to kill */
}
dump_until = MAX(dump_until, i + 1);
- char *selected = strdup(sorted[i]->path);
- if (!selected)
- return -ENOMEM;
- *ret_selected = selected;
+
ret = r;
+ r = strdup_to(ret_selected, sorted[i]->path);
+ if (r < 0)
+ return r;
break;
}
return log_debug_errno(r, "Error converting pgscan value to uint64_t: %m");
}
- ctx->path = strdup(empty_to_root(path));
- if (!ctx->path)
- return -ENOMEM;
+ r = strdup_to(&ctx->path, empty_to_root(path));
+ if (r < 0)
+ return r;
*ret = TAKE_PTR(ctx);
return 0;
if (r < 0)
return r;
- /* Make sure we only write the partition bar once, even if we're writing the partition table twice to
- * communicate roothashes. */
+ /* Only write the partition bar once, even if we're writing the partition table twice to communicate
+ * roothashes. */
if (FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF) && !late) {
putc('\n', stdout);
if (PARTITION_EXISTS(p)) /* Never format existing partitions */
return 0;
- /* Minimized partitions will use the copy blocks logic so let's make sure to skip those here. */
+ /* Minimized partitions will use the copy blocks logic so skip those here. */
if (p->copy_blocks_fd >= 0)
return 0;
if (!p->format)
continue;
- /* Minimized partitions will use the copy blocks logic so let's make sure to skip those here. */
+ /* Minimized partitions will use the copy blocks logic so skip those here. */
if (p->copy_blocks_fd >= 0)
continue;
assert(p->new_size != UINT64_MAX);
assert(p->new_size >= (p->encrypt != ENCRYPT_OFF ? LUKS2_METADATA_KEEP_FREE : 0));
- /* If we're doing encryption, we make sure we keep free space at the end which is required
+ /* If we're doing encryption, keep free space at the end which is required
* for cryptsetup's offline encryption. */
r = partition_target_prepare(context, p,
p->new_size - (p->encrypt != ENCRYPT_OFF ? LUKS2_METADATA_KEEP_FREE : 0),
return r;
/* The mkfs binary we invoked might have removed our temporary file when we're not operating
- * on a loop device, so let's make sure we open the file again to make sure our file
- * descriptor points to any potential new file. */
+ * on a loop device, so open the file again to make sure our file descriptor points to actual
+ * new file. */
if (t->fd >= 0 && t->path && !t->loop) {
safe_close(t->fd);
const char *verb,
const char *message_id,
const char *image_path,
+ const char *profile,
OrderedHashmap *extension_images,
char **extension_image_paths,
PortableFlags flags) {
LOG_CONTEXT_PUSH_STRV(extension_base_names);
log_struct(LOG_INFO,
- LOG_MESSAGE("Successfully %s%s '%s%s%s'",
+ LOG_MESSAGE("Successfully %s%s '%s%s%s%s%s'",
verb,
FLAGS_SET(flags, PORTABLE_RUNTIME) ? " ephemeral" : "",
image_path,
isempty(extensions_joined) ? "" : "' and its extension(s) '",
- strempty(extensions_joined)),
+ strempty(extensions_joined),
+ isempty(profile) ? "" : "' using profile '",
+ strempty(profile)),
message_id,
"PORTABLE_ROOT=%s", strna(root_base_name));
}
"attached",
"MESSAGE_ID=" SD_MESSAGE_PORTABLE_ATTACHED_STR,
image->path,
+ profile,
extension_images,
/* extension_image_paths= */ NULL,
flags);
"detached",
"MESSAGE_ID=" SD_MESSAGE_PORTABLE_DETACHED_STR,
name_or_path,
+ /* profile= */ NULL,
/* extension_images= */ NULL,
extension_image_paths,
flags);
" -M --machine=CONTAINER Operate on local container\n"
" -q --quiet Suppress informational messages\n"
" -p --profile=PROFILE Pick security profile for portable service\n"
- " --copy=copy|auto|symlink Prefer copying or symlinks if possible\n"
+ " --copy=copy|auto|symlink|mixed\n"
+ " Pick copying or symlinking of resources\n"
" --runtime Attach portable service until next reboot only\n"
" --no-reload Don't reload the system and service manager\n"
" --cat When inspecting include unit and os-release file\n"
return 0;
}
+int config_parse_dnssd_service_subtype(
+ 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) {
+
+ DnssdService *s = ASSERT_PTR(userdata);
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (isempty(rvalue)) {
+ s->subtype = mfree(s->subtype);
+ return 0;
+ }
+
+ if (!dns_subtype_name_is_valid(rvalue)) {
+ log_syntax(unit, LOG_WARNING, filename, line, 0, "Service subtype is invalid. Ignoring.");
+ return 0;
+ }
+
+ return free_and_strdup_warn(&s->subtype, rvalue);
+}
+
int config_parse_dnssd_txt(
const char *unit,
const char *filename,
CONFIG_PARSER_PROTOTYPE(config_parse_search_domains);
CONFIG_PARSER_PROTOTYPE(config_parse_dns_stub_listener_mode);
CONFIG_PARSER_PROTOTYPE(config_parse_dnssd_service_name);
+CONFIG_PARSER_PROTOTYPE(config_parse_dnssd_service_subtype);
CONFIG_PARSER_PROTOTYPE(config_parse_dnssd_service_type);
CONFIG_PARSER_PROTOTYPE(config_parse_dnssd_txt);
CONFIG_PARSER_PROTOTYPE(config_parse_dns_stub_listener_extra);
}
}
+static void dns_query_candidate_abandon(DnsQueryCandidate *c) {
+ DnsTransaction *t;
+
+ assert(c);
+
+ /* Abandon all the DnsTransactions attached to this query */
+
+ while ((t = set_steal_first(c->transactions))) {
+ t->wait_for_answer = true;
+ set_remove(t->notify_query_candidates, c);
+ set_remove(t->notify_query_candidates_done, c);
+ dns_transaction_gc(t);
+ }
+}
+
static DnsQueryCandidate* dns_query_candidate_unlink(DnsQueryCandidate *c) {
assert(c);
dns_query_candidate_stop(c);
}
+static void dns_query_abandon(DnsQuery *q) {
+ assert(q);
+
+ /* Thankfully transactions have their own timeouts */
+ event_source_disable(q->timeout_event_source);
+
+ LIST_FOREACH(candidates_by_query, c, q->candidates)
+ dns_query_candidate_abandon(c);
+}
+
static void dns_query_unlink_candidates(DnsQuery *q) {
assert(q);
(void) manager_monitor_send(q->manager, q);
- dns_query_stop(q);
+ dns_query_abandon(q);
if (q->complete)
q->complete(q);
}
dns_name_endswith(dns_resource_key_name(key), "_udp.local");
}
+bool dns_resource_key_is_dnssd_two_label_ptr(const DnsResourceKey *key) {
+ assert(key);
+
+ /* Check if this is a PTR resource key used in Service Instance
+ * Enumeration as described in RFC6763 § 4.1, excluding selective
+ * service names described in RFC6763 § 7.1. */
+
+ if (key->type != DNS_TYPE_PTR)
+ return false;
+
+ const char *name = dns_resource_key_name(key);
+ if (dns_name_parent(&name) <= 0)
+ return false;
+
+ return dns_name_equal(name, "_tcp.local") || dns_name_equal(name, "_udp.local");
+}
+
int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b) {
int r;
const char* dns_resource_key_name(const DnsResourceKey *key);
bool dns_resource_key_is_address(const DnsResourceKey *key);
bool dns_resource_key_is_dnssd_ptr(const DnsResourceKey *key);
+bool dns_resource_key_is_dnssd_two_label_ptr(const DnsResourceKey *key);
int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b);
int dns_resource_key_match_rr(const DnsResourceKey *key, DnsResourceRecord *rr, const char *search_domain);
int dns_resource_key_match_cname_or_dname(const DnsResourceKey *key, const DnsResourceKey *cname, const char *search_domain);
continue;
}
- /* Collect service types for _services._dns-sd._udp.local RRs in a set */
+ /* Collect service types for _services._dns-sd._udp.local RRs in a set. Only two-label names
+ * (not selective names) are considered according to RFC6763 § 9. */
if (!scope->announced &&
- dns_resource_key_is_dnssd_ptr(z->rr->key)) {
+ dns_resource_key_is_dnssd_two_label_ptr(z->rr->key)) {
if (!set_contains(types, dns_resource_key_name(z->rr->key))) {
r = set_ensure_put(&types, &dns_name_hash_ops, dns_resource_key_name(z->rr->key));
if (r < 0)
if (r < 0)
log_warning_errno(r, "Failed to add PTR record to MDNS zone: %m");
+ if (service->sub_ptr_rr) {
+ r = dns_zone_put(&scope->zone, scope, service->sub_ptr_rr, false);
+ if (r < 0)
+ log_warning_errno(r, "Failed to add selective PTR record to MDNS zone: %m");
+ }
+
r = dns_zone_put(&scope->zone, scope, service->srv_rr, true);
if (r < 0)
log_warning_errno(r, "Failed to add SRV record to MDNS zone: %m");
HASHMAP_FOREACH(service, scope->manager->dnssd_services) {
dns_zone_remove_rr(&scope->zone, service->ptr_rr);
+ dns_zone_remove_rr(&scope->zone, service->sub_ptr_rr);
dns_zone_remove_rr(&scope->zone, service->srv_rr);
LIST_FOREACH(items, txt_data, service->txt_data_items)
dns_zone_remove_rr(&scope->zone, txt_data->rr);
if (t->block_gc > 0)
return t;
+ if (t->wait_for_answer && IN_SET(t->state, DNS_TRANSACTION_PENDING, DNS_TRANSACTION_VALIDATING))
+ return t;
+
if (set_isempty(t->notify_query_candidates) &&
set_isempty(t->notify_query_candidates_done) &&
set_isempty(t->notify_zone_items) &&
return 1;
}
-static int dns_transaction_request_dnssec_rr(DnsTransaction *t, DnsResourceKey *key) {
+static int dns_transaction_request_dnssec_rr_full(DnsTransaction *t, DnsResourceKey *key, DnsTransaction **ret) {
_cleanup_(dns_answer_unrefp) DnsAnswer *a = NULL;
DnsTransaction *aux;
int r;
r = dns_transaction_go(aux);
if (r < 0)
return r;
+ if (ret)
+ *ret = aux;
}
return 1;
}
+static int dns_transaction_request_dnssec_rr(DnsTransaction *t, DnsResourceKey *key) {
+ assert(t);
+ assert(key);
+ return dns_transaction_request_dnssec_rr_full(t, key, NULL);
+}
+
static int dns_transaction_negative_trust_anchor_lookup(DnsTransaction *t, const char *name) {
int r;
int dns_transaction_request_dnssec_keys(DnsTransaction *t) {
DnsResourceRecord *rr;
+ /* Have we already requested a record that would be sufficient to validate an insecure delegation? */
+ bool chased_insecure = false;
int r;
assert(t);
* - For RRSIG we get the matching DNSKEY
* - For DNSKEY we get the matching DS
* - For unsigned SOA/NS we get the matching DS
- * - For unsigned CNAME/DNAME/DS we get the parent SOA RR
- * - For other unsigned RRs we get the matching SOA RR
+ * - For unsigned CNAME/DNAME/DS we get the parent DS RR
+ * - For other unsigned RRs we get the matching DS RR
* - For SOA/NS queries with no matching response RR, and no NSEC/NSEC3, the DS RR
- * - For DS queries with no matching response RRs, and no NSEC/NSEC3, the parent's SOA RR
- * - For other queries with no matching response RRs, and no NSEC/NSEC3, the SOA RR
+ * - For DS queries with no matching response RRs, and no NSEC/NSEC3, the parent's DS RR
+ * - For other queries with no matching response RRs, and no NSEC/NSEC3, the DS RR
*/
if (FLAGS_SET(t->query_flags, SD_RESOLVED_NO_VALIDATE) || t->scope->dnssec_mode == DNSSEC_NO)
case DNS_TYPE_RRSIG: {
/* For each RRSIG we request the matching DNSKEY */
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *dnskey = NULL;
+ DnsTransaction *aux = NULL;
/* If this RRSIG is about a DNSKEY RR and the
* signer is the same as the owner, then we
log_debug("Requesting DNSKEY to validate transaction %" PRIu16" (%s, RRSIG with key tag: %" PRIu16 ").",
t->id, dns_resource_key_name(rr->key), rr->rrsig.key_tag);
- r = dns_transaction_request_dnssec_rr(t, dnskey);
+ r = dns_transaction_request_dnssec_rr_full(t, dnskey, &aux);
if (r < 0)
return r;
+
+ /* If we are requesting a DNSKEY, we can anticipate that we will want the matching DS
+ * in the near future. Let's request it in advance so we don't have to wait in the
+ * common case. */
+ if (aux) {
+ _cleanup_(dns_resource_key_unrefp) DnsResourceKey *ds =
+ dns_resource_key_new(rr->key->class, DNS_TYPE_DS, dns_resource_key_name(dnskey));
+ r = dns_transaction_request_dnssec_rr(t, ds);
+ if (r < 0)
+ return r;
+ }
break;
}
if (r > 0)
continue;
+ chased_insecure = true;
ds = dns_resource_key_new(rr->key->class, DNS_TYPE_DS, dns_resource_key_name(rr->key));
if (!ds)
return -ENOMEM;
case DNS_TYPE_DS:
case DNS_TYPE_CNAME:
case DNS_TYPE_DNAME: {
- _cleanup_(dns_resource_key_unrefp) DnsResourceKey *soa = NULL;
+ _cleanup_(dns_resource_key_unrefp) DnsResourceKey *ds = NULL;
const char *name;
/* CNAMEs and DNAMEs cannot be located at a
- * zone apex, hence ask for the parent SOA for
+ * zone apex, hence ask for the parent DS for
* unsigned CNAME/DNAME RRs, maybe that's the
* apex. But do all that only if this is
* actually a response to our original
if (r == 0)
continue;
- soa = dns_resource_key_new(rr->key->class, DNS_TYPE_SOA, name);
- if (!soa)
+ ds = dns_resource_key_new(rr->key->class, DNS_TYPE_DS, name);
+ if (!ds)
return -ENOMEM;
- log_debug("Requesting parent SOA to validate transaction %" PRIu16 " (%s, unsigned CNAME/DNAME/DS RRset).",
+ log_debug("Requesting parent DS to validate transaction %" PRIu16 " (%s, unsigned CNAME/DNAME/DS RRset).",
t->id, dns_resource_key_name(rr->key));
- r = dns_transaction_request_dnssec_rr(t, soa);
+ r = dns_transaction_request_dnssec_rr(t, ds);
if (r < 0)
return r;
}
default: {
- _cleanup_(dns_resource_key_unrefp) DnsResourceKey *soa = NULL;
+ _cleanup_(dns_resource_key_unrefp) DnsResourceKey *ds = NULL;
/* For other unsigned RRsets (including
* NSEC/NSEC3!), look for proof the zone is
- * unsigned, by requesting the SOA RR of the
+ * unsigned, by requesting the DS RR of the
* zone. However, do so only if they are
* directly relevant to our original
* question. */
if (r > 0)
continue;
- soa = dns_resource_key_new(rr->key->class, DNS_TYPE_SOA, dns_resource_key_name(rr->key));
- if (!soa)
+ ds = dns_resource_key_new(rr->key->class, DNS_TYPE_DS, dns_resource_key_name(rr->key));
+ if (!ds)
return -ENOMEM;
- log_debug("Requesting SOA to validate transaction %" PRIu16 " (%s, unsigned non-SOA/NS RRset <%s>).",
+ log_debug("Requesting DS to validate transaction %" PRIu16 " (%s, unsigned non-SOA/NS RRset <%s>).",
t->id, dns_resource_key_name(rr->key), dns_resource_record_to_string(rr));
- r = dns_transaction_request_dnssec_rr(t, soa);
+ r = dns_transaction_request_dnssec_rr(t, ds);
if (r < 0)
return r;
break;
if (r < 0)
return r;
if (r > 0) {
- const char *name, *signed_status;
- uint16_t type = 0;
-
- name = dns_resource_key_name(dns_transaction_key(t));
- signed_status = dns_answer_contains_nsec_or_nsec3(t->answer) ? "signed" : "unsigned";
+ const char *name = dns_resource_key_name(dns_transaction_key(t));
+ bool was_signed = dns_answer_contains_nsec_or_nsec3(t->answer);
- /* If this was a SOA or NS request, then check if there's a DS RR for the same domain. Note that this
- * could also be used as indication that we are not at a zone apex, but in real world setups there are
- * too many broken DNS servers (Hello, incapdns.net!) where non-terminal zones return NXDOMAIN even
- * though they have further children. If this was a DS request, then it's signed when the parent zone
- * is signed, hence ask the parent SOA in that case. If this was any other RR then ask for the SOA RR,
- * to see if that is signed. */
-
- if (dns_transaction_key(t)->type == DNS_TYPE_DS) {
- r = dns_name_parent(&name);
- if (r > 0) {
- type = DNS_TYPE_SOA;
- log_debug("Requesting parent SOA (%s %s) to validate transaction %" PRIu16 " (%s, %s empty DS response).",
- special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), name, t->id,
- dns_resource_key_name(dns_transaction_key(t)), signed_status);
- } else
+ /* If the response is empty, seek the DS for this name, just in case we're at a zone cut
+ * already, unless we just requested the DS, in which case we have to ask the parent to make
+ * progress.
+ *
+ * If this was an SOA or NS request, we could also skip to the parent, but in real world
+ * setups there are too many broken DNS servers (Hello, incapdns.net!) where non-terminal
+ * zones return NXDOMAIN even though they have further children. */
+
+ if (chased_insecure || was_signed)
+ /* In this case we already requested what we need above. */
+ name = NULL;
+ else if (dns_transaction_key(t)->type == DNS_TYPE_DS)
+ /* If the DS response is empty, we'll walk up the dns labels requesting DS until we
+ * find a referral to the SOA or hit it anyway and get a positive DS response. */
+ if (dns_name_parent(&name) <= 0)
name = NULL;
- } else if (IN_SET(dns_transaction_key(t)->type, DNS_TYPE_SOA, DNS_TYPE_NS)) {
-
- type = DNS_TYPE_DS;
- log_debug("Requesting DS (%s %s) to validate transaction %" PRIu16 " (%s, %s empty SOA/NS response).",
- special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), name, t->id, name, signed_status);
-
- } else {
- type = DNS_TYPE_SOA;
- log_debug("Requesting SOA (%s %s) to validate transaction %" PRIu16 " (%s, %s empty non-SOA/NS/DS response).",
- special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), name, t->id, name, signed_status);
- }
-
if (name) {
- _cleanup_(dns_resource_key_unrefp) DnsResourceKey *soa = NULL;
+ _cleanup_(dns_resource_key_unrefp) DnsResourceKey *ds = NULL;
+
+ log_debug("Requesting DS (%s %s) to validate transaction %" PRIu16 " (%s empty response).",
+ special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), name, t->id,
+ dns_resource_key_name(dns_transaction_key(t)));
- soa = dns_resource_key_new(dns_transaction_key(t)->class, type, name);
- if (!soa)
+ ds = dns_resource_key_new(dns_transaction_key(t)->class, DNS_TYPE_DS, name);
+ if (!ds)
return -ENOMEM;
- r = dns_transaction_request_dnssec_rr(t, soa);
+ r = dns_transaction_request_dnssec_rr(t, ds);
if (r < 0)
return r;
}
DnsTransaction *dt;
/* For SOA or NS RRs we look for a matching DS transaction */
-
SET_FOREACH(dt, t->dnssec_transactions) {
if (dns_transaction_key(dt)->class != rr->key->class)
if (dns_transaction_key(dt)->type != DNS_TYPE_DS)
continue;
- r = dns_name_equal(dns_resource_key_name(dns_transaction_key(dt)), dns_resource_key_name(rr->key));
+ r = dns_name_endswith(dns_resource_key_name(rr->key), dns_resource_key_name(dns_transaction_key(dt)));
if (r < 0)
return r;
if (r == 0)
DnsTransaction *dt;
/*
- * CNAME/DNAME RRs cannot be located at a zone apex, hence look directly for the parent SOA.
+ * CNAME/DNAME RRs cannot be located at a zone apex, hence look directly for the parent DS.
*
- * DS RRs are signed if the parent is signed, hence also look at the parent SOA
+ * DS RRs are signed if the parent is signed, hence also look at the parent DS
*/
SET_FOREACH(dt, t->dnssec_transactions) {
if (dns_transaction_key(dt)->class != rr->key->class)
continue;
- if (dns_transaction_key(dt)->type != DNS_TYPE_SOA)
+ if (dns_transaction_key(dt)->type != DNS_TYPE_DS)
continue;
if (!parent) {
}
}
- r = dns_name_equal(dns_resource_key_name(dns_transaction_key(dt)), parent);
+ r = dns_name_endswith(parent, dns_resource_key_name(dns_transaction_key(dt)));
if (r < 0)
return r;
if (r == 0)
default: {
DnsTransaction *dt;
- /* Any other kind of RR (including DNSKEY/NSEC/NSEC3). Let's see if our SOA lookup was authenticated */
+ /* Any other kind of RR (including DNSKEY/NSEC/NSEC3). Let's see if our DS lookup was authenticated */
SET_FOREACH(dt, t->dnssec_transactions) {
-
if (dns_transaction_key(dt)->class != rr->key->class)
continue;
- if (dns_transaction_key(dt)->type != DNS_TYPE_SOA)
+ if (dns_transaction_key(dt)->type != DNS_TYPE_DS)
continue;
- r = dns_name_equal(dns_resource_key_name(dns_transaction_key(dt)), dns_resource_key_name(rr->key));
+ r = dns_name_endswith(dns_resource_key_name(rr->key), dns_resource_key_name(dns_transaction_key(dt)));
if (r < 0)
return r;
if (r == 0)
continue;
- /* We found the transaction that was supposed to find the SOA RR for us. It was
- * successful, but found no RR for us. This means we are not at a zone cut. In this
- * case, we require authentication if the SOA lookup was authenticated too. */
- return FLAGS_SET(dt->answer_query_flags, SD_RESOLVED_AUTHENTICATED);
+ if (!FLAGS_SET(dt->answer_query_flags, SD_RESOLVED_AUTHENTICATED))
+ return false;
+
+ /* We expect this to be signed when the DS record exists, and don't expect it to be
+ * signed when the DS record is proven not to exist. */
+ return dns_answer_match_key(dt->answer, dns_transaction_key(dt), NULL);
}
return true;
char key_str[DNS_RESOURCE_KEY_STRING_MAX];
DnsTransaction *dt;
const char *name;
- uint16_t type = 0;
int r;
assert(t);
name = dns_resource_key_name(dns_transaction_key(t));
- if (dns_transaction_key(t)->type == DNS_TYPE_DS) {
-
- /* We got a negative reply for this DS lookup? DS RRs are signed when their parent zone is signed,
- * hence check the parent SOA in this case. */
-
+ if (IN_SET(dns_transaction_key(t)->type, DNS_TYPE_DS, DNS_TYPE_CNAME, DNS_TYPE_DNAME)) {
+ /* We got a negative reply for this DS/CNAME/DNAME lookup? Check the parent in this case to
+ * see if this answer should have been signed. */
r = dns_name_parent(&name);
if (r < 0)
return r;
if (r == 0)
return true;
+ }
- type = DNS_TYPE_SOA;
-
- } else if (IN_SET(dns_transaction_key(t)->type, DNS_TYPE_SOA, DNS_TYPE_NS))
- /* We got a negative reply for this SOA/NS lookup? If so, check if there's a DS RR for this */
- type = DNS_TYPE_DS;
- else
- /* For all other negative replies, check for the SOA lookup */
- type = DNS_TYPE_SOA;
-
- /* For all other RRs we check the SOA on the same level to see
+ /* For all other RRs we check the DS on the same level to see
* if it's signed. */
SET_FOREACH(dt, t->dnssec_transactions) {
-
if (dns_transaction_key(dt)->class != dns_transaction_key(t)->class)
continue;
- if (dns_transaction_key(dt)->type != type)
+ if (dns_transaction_key(dt)->type != DNS_TYPE_DS)
continue;
- r = dns_name_equal(dns_resource_key_name(dns_transaction_key(dt)), name);
+ r = dns_name_endswith(name, dns_resource_key_name(dns_transaction_key(dt)));
if (r < 0)
return r;
if (r == 0)
continue;
- return FLAGS_SET(dt->answer_query_flags, SD_RESOLVED_AUTHENTICATED);
+ if (!FLAGS_SET(dt->answer_query_flags, SD_RESOLVED_AUTHENTICATED))
+ return false;
+
+ /* We expect this to be signed when the DS record exists, and don't expect it to be signed
+ * when the DS record is proven not to exist. */
+ return dns_answer_match_key(dt->answer, dns_transaction_key(dt), NULL);
}
/* If in doubt, require NSEC/NSEC3 */
unsigned block_gc;
+ /* Set when we're willing to let this transaction live beyond it's usefulness for the original query,
+ * for caching purposes. This blocks gc while there is still a chance we might still receive an
+ * answer. */
+ bool wait_for_answer;
+
LIST_FIELDS(DnsTransaction, transactions_by_scope);
LIST_FIELDS(DnsTransaction, transactions_by_stream);
LIST_FIELDS(DnsTransaction, transactions_by_key);
log_warning_errno(r, "Failed to send goodbye messages in IPv4 scope: %m");
dns_zone_remove_rr(&l->mdns_ipv4_scope->zone, s->ptr_rr);
+ dns_zone_remove_rr(&l->mdns_ipv4_scope->zone, s->sub_ptr_rr);
dns_zone_remove_rr(&l->mdns_ipv4_scope->zone, s->srv_rr);
LIST_FOREACH(items, txt_data, s->txt_data_items)
dns_zone_remove_rr(&l->mdns_ipv4_scope->zone, txt_data->rr);
log_warning_errno(r, "Failed to send goodbye messages in IPv6 scope: %m");
dns_zone_remove_rr(&l->mdns_ipv6_scope->zone, s->ptr_rr);
+ dns_zone_remove_rr(&l->mdns_ipv6_scope->zone, s->sub_ptr_rr);
dns_zone_remove_rr(&l->mdns_ipv6_scope->zone, s->srv_rr);
LIST_FOREACH(items, txt_data, s->txt_data_items)
dns_zone_remove_rr(&l->mdns_ipv6_scope->zone, txt_data->rr);
%struct-type
%includes
%%
-Service.Name, config_parse_dnssd_service_name, 0, 0
-Service.Type, config_parse_dnssd_service_type, 0, 0
-Service.Port, config_parse_ip_port, 0, offsetof(DnssdService, port)
-Service.Priority, config_parse_uint16, 0, offsetof(DnssdService, priority)
-Service.Weight, config_parse_uint16, 0, offsetof(DnssdService, weight)
-Service.TxtText, config_parse_dnssd_txt, DNS_TXT_ITEM_TEXT, 0
-Service.TxtData, config_parse_dnssd_txt, DNS_TXT_ITEM_DATA, 0
+Service.Name, config_parse_dnssd_service_name, 0, 0
+Service.Type, config_parse_dnssd_service_type, 0, 0
+Service.SubType, config_parse_dnssd_service_subtype, 0, 0
+Service.Port, config_parse_ip_port, 0, offsetof(DnssdService, port)
+Service.Priority, config_parse_uint16, 0, offsetof(DnssdService, priority)
+Service.Weight, config_parse_uint16, 0, offsetof(DnssdService, weight)
+Service.TxtText, config_parse_dnssd_txt, DNS_TXT_ITEM_TEXT, 0
+Service.TxtData, config_parse_dnssd_txt, DNS_TXT_ITEM_DATA, 0
hashmap_remove(service->manager->dnssd_services, service->name);
dns_resource_record_unref(service->ptr_rr);
+ dns_resource_record_unref(service->sub_ptr_rr);
dns_resource_record_unref(service->srv_rr);
dnssd_txtdata_free_all(service->txt_data_items);
free(service->filename);
free(service->name);
free(service->type);
+ free(service->subtype);
free(service->name_template);
return mfree(service);
static int specifier_dnssd_hostname(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
const Manager *m = ASSERT_PTR(userdata);
- char *n;
assert(m->llmnr_hostname);
- n = strdup(m->llmnr_hostname);
- if (!n)
- return -ENOMEM;
-
- *ret = n;
- return 0;
+ return strdup_to(ret, m->llmnr_hostname);
}
int dnssd_render_instance_name(Manager *m, DnssdService *s, char **ret) {
}
int dnssd_update_rrs(DnssdService *s) {
- _cleanup_free_ char *n = NULL, *service_name = NULL, *full_name = NULL;
+ _cleanup_free_ char *n = NULL, *service_name = NULL, *full_name = NULL, *sub_name = NULL, *selective_name = NULL;
int r;
assert(s);
assert(s->manager);
s->ptr_rr = dns_resource_record_unref(s->ptr_rr);
+ s->sub_ptr_rr = dns_resource_record_unref(s->sub_ptr_rr);
s->srv_rr = dns_resource_record_unref(s->srv_rr);
LIST_FOREACH(items, txt_data, s->txt_data_items)
txt_data->rr = dns_resource_record_unref(txt_data->rr);
r = dns_name_concat(n, service_name, 0, &full_name);
if (r < 0)
return r;
+ if (s->subtype) {
+ r = dns_name_concat("_sub", service_name, 0, &sub_name);
+ if (r < 0)
+ return r;
+ r = dns_name_concat(s->subtype, sub_name, 0, &selective_name);
+ if (r < 0)
+ return r;
+ }
LIST_FOREACH(items, txt_data, s->txt_data_items) {
txt_data->rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_TXT,
if (!s->ptr_rr->ptr.name)
goto oom;
+ if (selective_name) {
+ s->sub_ptr_rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_PTR, selective_name);
+ if (!s->sub_ptr_rr)
+ goto oom;
+
+ s->sub_ptr_rr->ttl = MDNS_DEFAULT_TTL;
+ s->sub_ptr_rr->ptr.name = strdup(full_name);
+ if (!s->sub_ptr_rr->ptr.name)
+ goto oom;
+ }
+
s->srv_rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_SRV,
full_name);
if (!s->srv_rr)
LIST_FOREACH(items, txt_data, s->txt_data_items)
txt_data->rr = dns_resource_record_unref(txt_data->rr);
s->ptr_rr = dns_resource_record_unref(s->ptr_rr);
+ s->sub_ptr_rr = dns_resource_record_unref(s->sub_ptr_rr);
s->srv_rr = dns_resource_record_unref(s->srv_rr);
return -ENOMEM;
}
char *name;
char *name_template;
char *type;
+ char *subtype;
uint16_t port;
uint16_t priority;
uint16_t weight;
DnsResourceRecord *ptr_rr;
+ DnsResourceRecord *sub_ptr_rr;
DnsResourceRecord *srv_rr;
/* Section 6.8 of RFC 6763 allows having service
meson.add_install_script(sh, '-c',
ln_s.format(bindir / 'systemd-run',
- bindir / 'uid0'))
+ bindir / 'run0'))
custom_target(
- 'systemd-uid0',
- input : 'systemd-uid0.in',
- output : 'systemd-uid0',
+ 'systemd-run0',
+ input : 'systemd-run0.in',
+ output : 'systemd-run0',
command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'],
install : pamconfdir != 'no',
install_dir : pamconfdir)
_cleanup_free_ char *link = NULL;
int r;
- r = terminal_urlify_man("uid0", "1", &link);
+ r = terminal_urlify_man("run0", "1", &link);
if (r < 0)
return log_oom();
ARG_BACKGROUND,
};
- /* If invoked as "uid0" binary, let's expose a more sudo-like interface. We add various extensions
+ /* If invoked as "run0" binary, let's expose a more sudo-like interface. We add various extensions
* though (but limit the extension to long options). */
static const struct option options[] = {
if (strv_extendf(&arg_property, "LogExtraFields=ELEVATED_USER=%s", un) < 0)
return log_oom();
- if (strv_extend(&arg_property, "PAMName=systemd-uid0") < 0)
+ if (strv_extend(&arg_property, "PAMName=systemd-run0") < 0)
return log_oom();
if (!arg_background && arg_stdio == ARG_STDIO_PTY) {
log_parse_environment();
log_open();
- if (invoked_as(argv, "uid0"))
+ if (invoked_as(argv, "run0"))
r = parse_argv_sudo_mode(argc, argv);
else
r = parse_argv(argc, argv);
# SPDX-License-Identifier: LGPL-2.1-or-later
# This file is part of systemd.
#
-# Used by uid0 sessions
+# Used by run0 sessions
{% if ENABLE_HOMED %}
-account sufficient pam_systemd_home.so
#include "random-util.h"
#include "sparse-endian.h"
#include "stat-util.h"
+#include "tmpfile-util.h"
#include "tpm2-util.h"
#include "user-util.h"
#include "varlink.h"
assert(dfd >= 0);
assert(fn);
- /* For non-root users creating a temporary file using the openat(2) over "." will fail later, in the
- * linkat(2) step at the end. The reason is that linkat(2) requires the CAP_DAC_READ_SEARCH
- * capability when it uses the AT_EMPTY_PATH flag. */
- if (have_effective_cap(CAP_DAC_READ_SEARCH) > 0) {
- fd = openat(dfd, ".", O_CLOEXEC|O_WRONLY|O_TMPFILE, 0400);
- if (fd < 0)
- log_debug_errno(errno, "Failed to create temporary credential file with O_TMPFILE, proceeding without: %m");
- }
- if (fd < 0) {
- if (asprintf(&t, "credential.secret.%016" PRIx64, random_u64()) < 0)
- return -ENOMEM;
-
- fd = openat(dfd, t, O_CLOEXEC|O_WRONLY|O_CREAT|O_EXCL|O_NOFOLLOW, 0400);
- if (fd < 0)
- return -errno;
- }
+ fd = open_tmpfile_linkable_at(dfd, fn, O_CLOEXEC|O_WRONLY, &t);
+ if (fd < 0)
+ return log_debug_errno(fd, "Failed to create temporary file for credential host secret: %m");
r = chattr_secret(fd, 0);
if (r < 0)
if (r < 0)
goto fail;
- if (fsync(fd) < 0) {
+ if (fchmod(fd, 0400) < 0) {
r = -errno;
goto fail;
}
- warn_not_encrypted(fd, flags, dirname, fn);
-
- if (t) {
- r = rename_noreplace(dfd, t, dfd, fn);
- if (r < 0)
- goto fail;
-
- t = mfree(t);
- } else if (linkat(fd, "", dfd, fn, AT_EMPTY_PATH) < 0) {
+ if (fsync(fd) < 0) {
r = -errno;
goto fail;
}
- if (fsync(dfd) < 0) {
- r = -errno;
+ warn_not_encrypted(fd, flags, dirname, fn);
+
+ r = link_tmpfile_at(fd, dfd, t, fn, LINK_TMPFILE_SYNC);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to link host key into place: %m");
goto fail;
}
void *copy;
copy = memdup(buf.data, sizeof(buf.data));
- if (!copy) {
- r = -ENOMEM;
- goto fail;
- }
+ if (!copy)
+ return -ENOMEM;
*ret = IOVEC_MAKE(copy, sizeof(buf.data));
}
(void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
if (fstype) {
- char *t;
-
log_debug("Probed fstype '%s' on partition %s.", fstype, path);
-
- t = strdup(fstype);
- if (!t)
- return -ENOMEM;
-
- *ret_fstype = t;
- return 1;
+ return strdup_to_full(ret_fstype, fstype);
}
not_found:
r = dissected_image_mount(m, where, uid_shift, uid_range, userns_fd, flags);
if (r == -ENXIO)
- return log_error_errno(r, "Not root file system found in image.");
+ return log_error_errno(r, "Failed to mount image: No root file system found in image.");
if (r == -EMEDIUMTYPE)
- return log_error_errno(r, "No suitable os-release/extension-release file in image found.");
+ return log_error_errno(r, "Failed to mount image: No suitable os-release/extension-release file in image found.");
if (r == -EUNATCH)
- return log_error_errno(r, "Encrypted file system discovered, but decryption not requested.");
+ return log_error_errno(r, "Failed to mount image: Encrypted file system discovered, but decryption not requested.");
if (r == -EUCLEAN)
- return log_error_errno(r, "File system check on image failed.");
+ return log_error_errno(r, "Failed to mount image: File system check on image failed.");
if (r == -EBUSY)
- return log_error_errno(r, "File system already mounted elsewhere.");
+ return log_error_errno(r, "Failed to mount image: File system already mounted elsewhere.");
if (r == -EAFNOSUPPORT)
- return log_error_errno(r, "File system type not supported or not known.");
+ return log_error_errno(r, "Failed to mount image: File system type not supported or not known.");
if (r == -EIDRM)
- return log_error_errno(r, "File system is too uncommon, refused.");
+ return log_error_errno(r, "Failed to mount image: File system is too uncommon, refused.");
if (r < 0)
return log_error_errno(r, "Failed to mount image: %m");
return true;
}
+bool dns_subtype_name_is_valid(const char *name) {
+ size_t l;
+
+ /* This more or less implements RFC 6763, Section 7.2 */
+
+ if (!name)
+ return false;
+
+ if (!utf8_is_valid(name))
+ return false;
+
+ if (string_has_cc(name, NULL))
+ return false;
+
+ l = strlen(name);
+ if (l <= 0)
+ return false;
+ if (l > DNS_LABEL_MAX)
+ return false;
+
+ return true;
+}
+
int dns_service_join(const char *name, const char *type, const char *domain, char **ret) {
char escaped[DNS_LABEL_ESCAPED_MAX];
_cleanup_free_ char *n = NULL;
bool dns_srv_type_is_valid(const char *name);
bool dnssd_srv_type_is_valid(const char *name);
bool dns_service_name_is_valid(const char *name);
+bool dns_subtype_name_is_valid(const char *name);
int dns_service_join(const char *name, const char *type, const char *domain, char **ret);
int dns_service_split(const char *joined, char **ret_name, char **ret_type, char **ret_domain);
struct ifreq ifr = {
.ifr_data = (void*) &ecmd,
};
- char *d;
int r;
assert(ethtool_fd);
if (isempty(ecmd.driver))
return -ENODATA;
- d = strdup(ecmd.driver);
- if (!d)
- return -ENOMEM;
-
- *ret = d;
- return 0;
+ return strdup_to(ret, ecmd.driver);
}
int ethtool_get_link_info(
#include <sys/utsname.h>
#include <unistd.h>
+#include "sd-daemon.h"
+
#include "alloc-util.h"
#include "creds-util.h"
#include "fd-util.h"
#include "fs-util.h"
#include "hostname-setup.h"
#include "hostname-util.h"
+#include "initrd-util.h"
#include "log.h"
#include "macro.h"
#include "proc-cmdline.h"
assert(s);
- assert_se(uname(&u) >= 0);
+ if (uname(&u) < 0)
+ return -errno;
if (streq_ptr(s, u.nodename))
return 0;
}
int shorten_overlong(const char *s, char **ret) {
- char *h, *p;
+ _cleanup_free_ char *h = NULL;
/* Shorten an overlong name to HOST_NAME_MAX or to the first dot,
* whatever comes earlier. */
assert(s);
+ assert(ret);
h = strdup(s);
if (!h)
return -ENOMEM;
if (hostname_is_valid(h, 0)) {
- *ret = h;
+ *ret = TAKE_PTR(h);
return 0;
}
- p = strchr(h, '.');
+ char *p = strchr(h, '.');
if (p)
*p = 0;
strshorten(h, HOST_NAME_MAX);
- if (!hostname_is_valid(h, 0)) {
- free(h);
+ if (!hostname_is_valid(h, /* flags= */ 0))
return -EDOM;
- }
- *ret = h;
+ *ret = TAKE_PTR(h);
return 1;
}
r = write_string_file("/run/systemd/default-hostname", hostname,
WRITE_STRING_FILE_CREATE | WRITE_STRING_FILE_ATOMIC);
if (r < 0)
- log_warning_errno(r, "Failed to create \"/run/systemd/default-hostname\": %m");
+ log_warning_errno(r, "Failed to create \"/run/systemd/default-hostname\", ignoring: %m");
} else
unlink_or_warn("/run/systemd/default-hostname");
}
int hostname_setup(bool really) {
- _cleanup_free_ char *b = NULL;
- const char *hn = NULL;
+ _cleanup_free_ char *hn = NULL;
HostnameSource source;
bool enoent = false;
int r;
- r = proc_cmdline_get_key("systemd.hostname", 0, &b);
+ r = proc_cmdline_get_key("systemd.hostname", 0, &hn);
if (r < 0)
log_warning_errno(r, "Failed to retrieve system hostname from kernel command line, ignoring: %m");
else if (r > 0) {
- if (hostname_is_valid(b, VALID_HOSTNAME_TRAILING_DOT)) {
- hn = b;
+ if (hostname_is_valid(hn, VALID_HOSTNAME_TRAILING_DOT))
source = HOSTNAME_TRANSIENT;
- } else {
- log_warning("Hostname specified on kernel command line is invalid, ignoring: %s", b);
- b = mfree(b);
+ else {
+ log_warning("Hostname specified on kernel command line is invalid, ignoring: %s", hn);
+ hn = mfree(hn);
}
}
if (!hn) {
- r = read_etc_hostname(NULL, &b);
- if (r < 0) {
- if (r == -ENOENT)
- enoent = true;
- else
- log_warning_errno(r, "Failed to read configured hostname: %m");
- } else {
- hn = b;
+ r = read_etc_hostname(NULL, &hn);
+ if (r == -ENOENT)
+ enoent = true;
+ else if (r < 0)
+ log_warning_errno(r, "Failed to read configured hostname, ignoring: %m");
+ else
source = HOSTNAME_STATIC;
- }
}
if (!hn) {
- r = acquire_hostname_from_credential(&b);
- if (r >= 0) {
- hn = b;
+ r = acquire_hostname_from_credential(&hn);
+ if (r >= 0)
source = HOSTNAME_TRANSIENT;
- }
}
if (!hn) {
- _cleanup_free_ char *buf = NULL;
-
/* Don't override the hostname if it is already set and not explicitly configured */
- r = gethostname_full(GET_HOSTNAME_ALLOW_LOCALHOST, &buf);
+ r = gethostname_full(GET_HOSTNAME_ALLOW_LOCALHOST, &hn);
if (r == -ENOMEM)
return log_oom();
if (r >= 0) {
- log_debug("No hostname configured, leaving existing hostname <%s> in place.", buf);
- return 0;
+ log_debug("No hostname configured, leaving existing hostname <%s> in place.", hn);
+ goto finish;
}
if (enoent)
log_info("No hostname configured, using default hostname.");
- hn = b = get_default_hostname();
+ hn = get_default_hostname();
if (!hn)
return log_oom();
source = HOSTNAME_DEFAULT;
-
}
r = sethostname_idempotent_full(hn, really);
if (really)
hostname_update_source_hint(hn, source);
- return r;
+finish:
+ if (!in_initrd())
+ (void) sd_notifyf(/* unset_environment= */ false, "X_SYSTEMD_HOSTNAME=%s", hn);
+
+ return 0;
}
static const char* const hostname_source_table[] = {
static int specifier_name(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
const InstallInfo *i = ASSERT_PTR(userdata);
- char *ans;
if (unit_name_is_valid(i->name, UNIT_NAME_TEMPLATE) && i->default_instance)
return unit_name_replace_instance(i->name, i->default_instance, ret);
- ans = strdup(i->name);
- if (!ans)
- return -ENOMEM;
- *ret = ans;
- return 0;
+ return strdup_to(ret, i->name);
}
static int specifier_prefix(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
return r;
dash = strrchr(prefix, '-');
- if (dash) {
- dash = strdup(dash + 1);
- if (!dash)
- return -ENOMEM;
- *ret = dash;
- } else
- *ret = TAKE_PTR(prefix);
+ if (dash)
+ return strdup_to(ret, dash + 1);
+ *ret = TAKE_PTR(prefix);
return 0;
}
assert(config_path);
STRV_FOREACH(s, info->aliases) {
- _cleanup_free_ char *alias_path = NULL, *dst = NULL, *dst_updated = NULL;
+ _cleanup_free_ char *alias_path = NULL, *alias_target = NULL, *dst = NULL, *dst_updated = NULL;
r = install_name_printf(scope, info, *s, &dst);
if (r < 0) {
if (!alias_path)
return -ENOMEM;
+ r = in_search_path(lp, info->path);
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ /* The unit path itself is outside of the search path. To
+ * correctly apply the alias, we need the alias symlink to
+ * point to the symlink that was created in the search path. */
+ alias_target = path_join(config_path, info->name);
+ if (!alias_target)
+ return -ENOMEM;
+ }
+
bool broken;
r = chase(alias_path, lp->root_dir, CHASE_NONEXISTENT, /* ret_path = */ NULL, /* ret_fd = */ NULL);
if (r < 0 && r != -ENOENT) {
}
broken = r == 0; /* symlink target does not exist? */
- RET_GATHER(ret, create_symlink(lp, info->path, alias_path, force || broken, changes, n_changes));
+ RET_GATHER(ret, create_symlink(lp, alias_target ?: info->path, alias_path, force || broken, changes, n_changes));
}
return ret;
int unit_file_get_default(
RuntimeScope scope,
const char *root_dir,
- char **name) {
+ char **ret) {
_cleanup_(lookup_paths_done) LookupPaths lp = {};
_cleanup_(install_context_done) InstallContext ctx = { .scope = scope };
InstallInfo *info;
- char *n;
int r;
assert(scope >= 0);
assert(scope < _RUNTIME_SCOPE_MAX);
- assert(name);
+ assert(ret);
r = lookup_paths_init(&lp, scope, 0, root_dir);
if (r < 0)
if (r < 0)
return r;
- n = strdup(info->name);
- if (!n)
- return -ENOMEM;
-
- *name = n;
- return 0;
+ return strdup_to(ret, info->name);
}
int unit_file_lookup_state(
if (ret_path) {
assert(info);
- _cleanup_free_ char *p = strdup(info->path);
- if (!p)
- return -ENOMEM;
-
- *ret_path = TAKE_PTR(p);
+ r = strdup_to(ret_path, info->path);
+ if (r < 0)
+ return r;
}
return 1;
int unit_file_get_default(
RuntimeScope scope,
const char *root_dir,
- char **name);
+ char **ret);
int unit_file_add_dependency(
RuntimeScope scope,
UnitFileFlags flags,
return 0;
}
+int json_dispatch_int8(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
+ int8_t *i = ASSERT_PTR(userdata);
+ int64_t i64;
+ int r;
+
+ assert(variant);
+
+ r = json_dispatch_int64(name, variant, flags, &i64);
+ if (r < 0)
+ return r;
+
+ if (i64 < INT8_MIN || i64 > INT8_MAX)
+ return json_log(variant, flags, SYNTHETIC_ERRNO(ERANGE), "JSON field '%s' out of bounds.", strna(name));
+
+ *i = (int8_t) i64;
+ return 0;
+}
+
+int json_dispatch_uint8(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
+ uint8_t *u = ASSERT_PTR(userdata);
+ uint64_t u64;
+ int r;
+
+ assert(variant);
+
+ r = json_dispatch_uint64(name, variant, flags, &u64);
+ if (r < 0)
+ return r;
+
+ if (u64 > UINT8_MAX)
+ return json_log(variant, flags, SYNTHETIC_ERRNO(ERANGE), "JSON field '%s' out of bounds.", strna(name));
+
+ *u = (uint8_t) u64;
+ return 0;
+}
+
int json_dispatch_string(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
char **s = ASSERT_PTR(userdata);
int r;
int json_dispatch_int32(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
int json_dispatch_uint16(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
int json_dispatch_int16(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
+int json_dispatch_int8(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
+int json_dispatch_uint8(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
int json_dispatch_uid_gid(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
int json_dispatch_user_group_name(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
int json_dispatch_id128(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#include "env-util.h"
#include "errno-util.h"
#include "kbd-util.h"
#include "log.h"
-#include "nulstr-util.h"
#include "path-util.h"
#include "recurse-dir.h"
#include "set.h"
#include "strv.h"
#include "utf8.h"
+#define KBD_KEYMAP_DIRS \
+ "/usr/share/keymaps/", \
+ "/usr/share/kbd/keymaps/", \
+ "/usr/lib/kbd/keymaps/"
+
+int keymap_directories(char ***ret) {
+ assert(ret);
+
+ if (getenv_path_list("SYSTEMD_KEYMAP_DIRECTORIES", ret) >= 0)
+ return 0;
+
+ char **paths = strv_new(KBD_KEYMAP_DIRS);
+ if (!paths)
+ return log_oom_debug();
+
+ *ret = TAKE_PTR(paths);
+ return 0;
+}
+
struct recurse_dir_userdata {
const char *keymap_name;
Set *keymaps;
int get_keymaps(char ***ret) {
_cleanup_set_free_free_ Set *keymaps = NULL;
+ _cleanup_strv_free_ char **keymap_dirs = NULL;
int r;
+ r = keymap_directories(&keymap_dirs);
+ if (r < 0)
+ return r;
+
keymaps = set_new(&string_hash_ops);
if (!keymaps)
return -ENOMEM;
- NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) {
+ STRV_FOREACH(dir, keymap_dirs) {
r = recurse_dir_at(
AT_FDCWD,
- dir,
+ *dir,
/* statx_mask= */ 0,
/* n_depth_max= */ UINT_MAX,
RECURSE_DIR_IGNORE_DOT|RECURSE_DIR_ENSURE_TYPE,
if (r == -ENOENT)
continue;
if (ERRNO_IS_NEG_RESOURCE(r))
- return log_warning_errno(r, "Failed to read keymap list from %s: %m", dir);
+ return log_warning_errno(r, "Failed to read keymap list from %s: %m", *dir);
if (r < 0)
- log_debug_errno(r, "Failed to read keymap list from %s, ignoring: %m", dir);
+ log_debug_errno(r, "Failed to read keymap list from %s, ignoring: %m", *dir);
}
_cleanup_strv_free_ char **l = set_get_strv(keymaps);
}
int keymap_exists(const char *name) {
+ _cleanup_strv_free_ char **keymap_dirs = NULL;
int r;
if (!keymap_is_valid(name))
return -EINVAL;
- NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) {
+ r = keymap_directories(&keymap_dirs);
+ if (r < 0)
+ return r;
+
+ STRV_FOREACH(dir, keymap_dirs) {
r = recurse_dir_at(
AT_FDCWD,
- dir,
+ *dir,
/* statx_mask= */ 0,
/* n_depth_max= */ UINT_MAX,
RECURSE_DIR_IGNORE_DOT|RECURSE_DIR_ENSURE_TYPE,
if (ERRNO_IS_NEG_RESOURCE(r))
return r;
if (r < 0 && r != -ENOENT)
- log_debug_errno(r, "Failed to read keymap list from %s, ignoring: %m", dir);
+ log_debug_errno(r, "Failed to read keymap list from %s, ignoring: %m", *dir);
}
return false;
#include <stdbool.h>
-#define KBD_KEYMAP_DIRS \
- "/usr/share/keymaps/\0" \
- "/usr/share/kbd/keymaps/\0" \
- "/usr/lib/kbd/keymaps/\0"
-
-int get_keymaps(char ***l);
+int keymap_directories(char ***ret);
+int get_keymaps(char ***ret);
bool keymap_is_valid(const char *name);
int keymap_exists(const char *name);
int hash_password_full(const char *password, void **cd_data, int *cd_size, char **ret) {
_cleanup_free_ char *salt = NULL;
_cleanup_(erase_and_freep) void *_cd_data = NULL;
- char *p;
+ const char *p;
int r, _cd_size = 0;
assert(!!cd_data == !!cd_size);
return log_debug_errno(errno_or_else(SYNTHETIC_ERRNO(EINVAL)),
CRYPT_RA_NAME "() failed: %m");
- p = strdup(p);
- if (!p)
- return -ENOMEM;
-
- *ret = p;
- return 0;
+ return strdup_to(ret, p);
}
bool looks_like_hashed_password(const char *s) {
#include <sys/mount.h>
#include <unistd.h>
+#include "sd-daemon.h"
#include "sd-id128.h"
#include "alloc-util.h"
#include "creds-util.h"
#include "fd-util.h"
#include "id128-util.h"
+#include "initrd-util.h"
#include "io-util.h"
#include "log.h"
#include "machine-id-setup.h"
if (sd_id128_is_null(machine_id)) {
/* Try to read any existing machine ID */
- if (id128_read_fd(fd, ID128_FORMAT_PLAIN, ret) >= 0)
- return 0;
+ if (id128_read_fd(fd, ID128_FORMAT_PLAIN, &machine_id) >= 0)
+ goto finish;
/* Hmm, so, the id currently stored is not useful, then let's generate one */
r = generate_machine_id(root, &machine_id);
return r;
finish:
+ if (!in_initrd())
+ (void) sd_notifyf(/* unset_environment= */ false, "X_SYSTEMD_MACHINE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(machine_id));
+
if (ret)
*ret = machine_id;
if (device &&
sd_device_get_devtype(device, &t) >= 0 &&
- !isempty(t)) {
- p = strdup(t);
- if (!p)
- return -ENOMEM;
-
- *ret = p;
- return 0;
- }
+ !isempty(t))
+ return strdup_to(ret, t);
t = arphrd_to_name(iftype);
if (!t)
_cleanup_strv_free_erase_ char **suggestions = NULL;
_cleanup_(erase_and_freep) char *joined = NULL;
char buf[PWQ_MAX_ERROR_MESSAGE_LEN];
- size_t i;
int r;
r = pwq_allocate_context(&pwq);
if (!suggestions)
return log_oom();
- for (i = 0; i < N_SUGGESTIONS; i++) {
+ for (size_t i = 0; i < N_SUGGESTIONS; i++) {
r = sym_pwquality_generate(pwq, 64, suggestions + i);
if (r < 0)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to generate password, ignoring: %s",
r = sym_pwquality_check(pwq, password, old, username, &auxerror);
if (r < 0) {
if (ret_error) {
- _cleanup_free_ char *e = NULL;
-
- e = strdup(sym_pwquality_strerror(buf, sizeof(buf), r, auxerror));
- if (!e)
- return -ENOMEM;
-
- *ret_error = TAKE_PTR(e);
+ r = strdup_to(ret_error,
+ sym_pwquality_strerror(buf, sizeof(buf), r, auxerror));
+ if (r < 0)
+ return r;
}
return 0; /* all bad */
if (isempty(text))
text = path;
- if (!urlify_enabled()) {
- char *n;
-
- n = strdup(text);
- if (!n)
- return -ENOMEM;
-
- *ret = n;
- return 0;
- }
+ if (!urlify_enabled())
+ return strdup_to(ret, text);
r = file_url_from_path(path, &url);
if (r < 0)
return (int) l;
}
-static int insert_newline_color_erase(PTYForward *f, size_t offset) {
+static int insert_background_color(PTYForward *f, size_t offset) {
_cleanup_free_ char *s = NULL;
assert(f);
if (!f->background_color)
return 0;
- /* When we see a newline (ASCII 10) then this sets the background color to the desired one, and erase the rest
- * of the line with it */
-
- s = background_color_sequence(f);
- if (!s)
- return -ENOMEM;
-
- if (!strextend(&s, ANSI_ERASE_TO_END_OF_LINE))
- return -ENOMEM;
-
- return insert_string(f, offset, s);
-}
-
-static int insert_carriage_return_color(PTYForward *f, size_t offset) {
- _cleanup_free_ char *s = NULL;
-
- assert(f);
-
- if (!f->background_color)
- return 0;
-
- /* When we see a carriage return (ASCII 13) then this sets only the background */
-
s = background_color_sequence(f);
if (!s)
return -ENOMEM;
case ANSI_COLOR_STATE_TEXT:
break;
- case ANSI_COLOR_STATE_NEWLINE: {
- /* Immediately after a newline insert an ANSI sequence to erase the line with a background color */
-
- r = insert_newline_color_erase(f, i);
- if (r < 0)
- return r;
-
- i += r;
- break;
- }
-
- case ANSI_COLOR_STATE_CARRIAGE_RETURN: {
- /* Immediately after a carriage return insert an ANSI sequence set the background color back */
+ case ANSI_COLOR_STATE_NEWLINE:
+ case ANSI_COLOR_STATE_CARRIAGE_RETURN:
+ /* Immediately after a newline (ASCII 10) or carriage return (ASCII 13) insert an
+ * ANSI sequence set the background color back. */
- r = insert_carriage_return_color(f, i);
+ r = insert_background_color(f, i);
if (r < 0)
return r;
i += r;
break;
- }
- case ANSI_COLOR_STATE_ESC: {
+ case ANSI_COLOR_STATE_ESC:
if (c == '[') {
f->ansi_color_state = ANSI_COLOR_STATE_CSI_SEQUENCE;
f->ansi_color_state = ANSI_COLOR_STATE_OSC_SEQUENCE;
continue;
}
-
break;
- }
- case ANSI_COLOR_STATE_CSI_SEQUENCE: {
+ case ANSI_COLOR_STATE_CSI_SEQUENCE:
if (c >= 0x20 && c <= 0x3F) {
/* If this is a "parameter" or "intermediary" byte (i.e. ranges 0x20…0x2F and
f->csi_sequence = mfree(f->csi_sequence);
f->ansi_color_state = ANSI_COLOR_STATE_TEXT;
}
-
continue;
- }
- case ANSI_COLOR_STATE_OSC_SEQUENCE: {
+ case ANSI_COLOR_STATE_OSC_SEQUENCE:
if ((uint8_t) c >= ' ') {
if (strlen_ptr(f->osc_sequence) >= 64) {
f->osc_sequence = mfree(f->osc_sequence);
f->ansi_color_state = ANSI_COLOR_STATE_TEXT;
}
-
continue;
- }
default:
assert_not_reached();
/* Generic handler for simple string replacements */
int specifier_string(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
- char *n = NULL;
-
- assert(ret);
-
- if (!isempty(data)) {
- n = strdup(data);
- if (!n)
- return -ENOMEM;
- }
-
- *ret = n;
- return 0;
+ return strdup_to(ASSERT_PTR(ret), empty_to_null(data));
}
int specifier_real_path(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
int specifier_kernel_release(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
struct utsname uts;
- char *n;
assert(ret);
if (uname(&uts) < 0)
return -errno;
- n = strdup(uts.release);
- if (!n)
- return -ENOMEM;
-
- *ret = n;
- return 0;
+ return strdup_to(ret, uts.release);
}
int specifier_architecture(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
- char *t;
-
- assert(ret);
-
- t = strdup(architecture_to_string(uname_architecture()));
- if (!t)
- return -ENOMEM;
-
- *ret = t;
- return 0;
+ return strdup_to(ASSERT_PTR(ret),
+ architecture_to_string(uname_architecture()));
}
/* Note: fields in /etc/os-release might quite possibly be missing, even if everything is entirely valid
int specifier_tmp_dir(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
const char *p;
- char *copy;
int r;
assert(ret);
if (r < 0)
return r;
}
- copy = strdup(p);
- if (!copy)
- return -ENOMEM;
- *ret = copy;
- return 0;
+ return strdup_to(ret, p);
}
int specifier_var_tmp_dir(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
const char *p;
- char *copy;
int r;
assert(ret);
if (r < 0)
return r;
}
- copy = strdup(p);
- if (!copy)
- return -ENOMEM;
- *ret = copy;
- return 0;
+ return strdup_to(ret, p);
}
int specifier_escape_strv(char **l, char ***ret) {
DEFINE_TEST_MAIN_FULL(log_level, intro, NULL)
#define DEFINE_TEST_MAIN(log_level) \
DEFINE_TEST_MAIN_FULL(log_level, NULL, NULL)
+
+#define ASSERT_OK(expr) \
+ ({ \
+ typeof(expr) _result = (expr); \
+ if (_result < 0) { \
+ log_error_errno(_result, "%s:%i: Assertion failed: %s: %m", \
+ PROJECT_FILE, __LINE__, #expr); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_TRUE(expr) \
+ ({ \
+ if (!(expr)) { \
+ log_error("%s:%i: Assertion failed: expected \"%s\" to be true", \
+ PROJECT_FILE, __LINE__, #expr); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_FALSE(expr) \
+ ({ \
+ if ((expr)) { \
+ log_error("%s:%i: Assertion failed: expected \"%s\" to be false", \
+ PROJECT_FILE, __LINE__, #expr); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_NULL(expr) \
+ ({ \
+ if ((expr) != NULL) { \
+ log_error("%s:%i: Assertion failed: expected \"%s\" to be NULL", \
+ PROJECT_FILE, __LINE__, #expr); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_NOT_NULL(expr) \
+ ({ \
+ if ((expr) == NULL) { \
+ log_error("%s:%i: Assertion failed: expected \"%s\" to be not NULL", \
+ PROJECT_FILE, __LINE__, #expr); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_STREQ(expr1, expr2) \
+ ({ \
+ const char* _expr1 = (expr1); \
+ const char* _expr2 = (expr2); \
+ if (strcmp(_expr1, _expr2) != 0) { \
+ log_error("%s:%i: Assertion failed: expected \"%s == %s\", but \"%s != %s\"", \
+ PROJECT_FILE, __LINE__, #expr1, #expr2, _expr1, _expr2); \
+ abort(); \
+ } \
+ })
+
+/* DECIMAL_STR_FMT() uses _Generic which cannot be used in string concatenation so we have to format the
+ * input into strings first and then format those into the final assertion message. */
+
+#define ASSERT_EQ(expr1, expr2) \
+ ({ \
+ typeof(expr1) _expr1 = (expr1); \
+ typeof(expr2) _expr2 = (expr2); \
+ if (_expr1 != _expr2) { \
+ char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
+ char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
+ xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
+ xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
+ log_error("%s:%i: Assertion failed: expected \"%s == %s\", but \"%s != %s\"", \
+ PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_GE(expr1, expr2) \
+ ({ \
+ typeof(expr1) _expr1 = (expr1); \
+ typeof(expr2) _expr2 = (expr2); \
+ if (_expr1 < _expr2) { \
+ char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
+ char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
+ xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
+ xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
+ log_error("%s:%i: Assertion failed: expected \"%s >= %s\", but \"%s < %s\"", \
+ PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_LE(expr1, expr2) \
+ ({ \
+ typeof(expr1) _expr1 = (expr1); \
+ typeof(expr2) _expr2 = (expr2); \
+ if (_expr1 > _expr2) { \
+ char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
+ char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
+ xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
+ xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
+ log_error("%s:%i: Assertion failed: expected \"%s <= %s\", but \"%s > %s\"", \
+ PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_NE(expr1, expr2) \
+ ({ \
+ typeof(expr1) _expr1 = (expr1); \
+ typeof(expr2) _expr2 = (expr2); \
+ if (_expr1 == _expr2) { \
+ char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
+ char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
+ xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
+ xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
+ log_error("%s:%i: Assertion failed: expected \"%s != %s\", but \"%s == %s\"", \
+ PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_GT(expr1, expr2) \
+ ({ \
+ typeof(expr1) _expr1 = (expr1); \
+ typeof(expr2) _expr2 = (expr2); \
+ if (!(_expr1 > _expr2)) { \
+ char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
+ char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
+ xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
+ xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
+ log_error("%s:%i: Assertion failed: expected \"%s > %s\", but \"%s <= %s\"", \
+ PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_LT(expr1, expr2) \
+ ({ \
+ typeof(expr1) _expr1 = (expr1); \
+ typeof(expr2) _expr2 = (expr2); \
+ if (!(_expr1 < _expr2)) { \
+ char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
+ char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
+ xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
+ xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
+ log_error("%s:%i: Assertion failed: expected \"%s < %s\", but \"%s >= %s\"", \
+ PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \
+ abort(); \
+ } \
+ })
}
_cleanup_free_ char *desc = NULL;
- if (asprintf(&desc, "%s-%i", server->description ?: "varlink", v->fd) >= 0)
+ if (asprintf(&desc, "%s-%i", varlink_server_description(server), v->fd) >= 0)
v->description = TAKE_PTR(desc);
/* Link up the server and the connection, and take reference in both directions. Note that the
"Description=OpenSSH Per-Connection Server Daemon\n"
"Documentation=man:systemd-ssh-generator(8) man:sshd(8)\n"
"[Service]\n"
- "ExecStart=-%s -i\n"
- "StandardInput=socket",
+ "ExecStart=-%s -i -o \"AuthorizedKeysFile ${CREDENTIALS_DIRECTORY}/ssh.ephemeral-authorized_keys-all .ssh/authorized_keys\"\n"
+ "StandardInput=socket\n"
+ "ImportCredential=ssh.ephemeral-authorized_keys-all",
sshd_binary);
r = fflush_and_check(f);
const char *dest,
const char *unit,
const char *listen_stream,
- const char *comment) {
+ const char *comment,
+ bool with_ssh_access_target_dependency) {
int r;
fprintf(f,
"[Unit]\n"
"Description=OpenSSH Server Socket (systemd-ssh-generator, %s)\n"
- "Documentation=man:systemd-ssh-generator(8)\n"
+ "Documentation=man:systemd-ssh-generator(8)\n",
+ comment);
+
+ /* When this is a remotely accessible socket let's mark this with a milestone: ssh-access.target */
+ if (with_ssh_access_target_dependency)
+ fputs("Wants=ssh-access.target\n"
+ "Before=ssh-access.target\n",
+ f);
+
+ fprintf(f,
"\n[Socket]\n"
"ListenStream=%s\n"
"Accept=yes\n"
"PollLimitIntervalSec=30s\n"
"PollLimitBurst=50\n",
- comment,
listen_stream);
r = fflush_and_check(f);
dest,
"sshd-vsock.socket",
"vsock::22",
- "AF_VSOCK");
+ "AF_VSOCK",
+ /* with_ssh_access_target_dependency= */ true);
if (r < 0)
return r;
dest,
"sshd-unix-local.socket",
"/run/ssh-unix-local/socket",
- "AF_UNIX Local");
+ "AF_UNIX Local",
+ /* with_ssh_access_target_dependency= */ false);
if (r < 0)
return r;
dest,
"sshd-unix-export.socket",
"/run/host/unix-export/ssh",
- "AF_UNIX Export");
+ "AF_UNIX Export",
+ /* with_ssh_access_target_dependency= */ true);
if (r < 0)
return r;
dest,
socket ?: "sshd-extra.socket",
*i,
- *i);
+ *i,
+ /* with_ssh_access_target_dependency= */ true);
if (r < 0)
return r;
['c', '-std=iso9899:1990'],
['c', '-std=iso9899:2011']]
-if cc.has_argument('-std=iso9899:2017')
- opts += [['c', '-std=iso9899:2017']]
-endif
-
-if cc.has_argument('-std=c2x')
- opts += [['c', '-std=c2x']]
-endif
+foreach opt : ['-std=iso9899:2017',
+ '-std=c23',
+ ]
+ if cc.has_argument(opt)
+ opts += [['c', opt]]
+ endif
+endforeach
if cxx_cmd != ''
opts += [['c++'],
['c++', '-std=c++98'],
['c++', '-std=c++11']]
- if cxx.has_argument('-std=c++14')
- opts += [['c++', '-std=c++14']]
- endif
- if cxx.has_argument('-std=c++17')
- opts += [['c++', '-std=c++17']]
- endif
- if cxx.has_argument('-std=c++20')
- opts += [['c++', '-std=c++20']]
- endif
- if cxx.has_argument('-std=c++23')
- opts += [['c++', '-std=c++23']]
- endif
+
+ foreach opt : ['-std=c++14',
+ '-std=c++17',
+ '-std=c++20',
+ '-std=c++23',
+ '-std=c++26',
+ ]
+ if cxx.has_argument(opt)
+ opts += [['c++', opt]]
+ endif
+ endforeach
endif
foreach header : _systemd_headers + _not_installed_headers + [libudev_h_path]
int sd_dhcp_server_add_option(sd_dhcp_server *server, sd_dhcp_option *v);
int sd_dhcp_server_add_vendor_option(sd_dhcp_server *server, sd_dhcp_option *v);
int sd_dhcp_server_set_static_lease(sd_dhcp_server *server, const struct in_addr *address, uint8_t *client_id, size_t client_id_size);
-int sd_dhcp_server_set_lease_file(sd_dhcp_server *server, const char *path);
+int sd_dhcp_server_set_lease_file(sd_dhcp_server *server, int dir_fd, const char *path);
int sd_dhcp_server_set_max_lease_time(sd_dhcp_server *server, uint64_t t);
int sd_dhcp_server_set_default_lease_time(sd_dhcp_server *server, uint64_t t);
#endif
int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix);
+int sd_journal_stream_fd_with_namespace(const char *name_space, const char *identifier, int priority, int level_prefix);
/* Browse journal stream */
'test-dev-setup.c',
'test-device-nodes.c',
'test-devnum-util.c',
+ 'test-dirent-util.c',
'test-dns-domain.c',
'test-ellipsize.c',
'test-env-file.c',
'test-iovec-util.c',
'test-journal-importer.c',
'test-kbd-util.c',
+ 'test-label.c',
'test-limits-util.c',
'test-list.c',
'test-local-addresses.c',
'test-psi-util.c',
'test-ratelimit.c',
'test-raw-clone.c',
+ 'test-recovery-key.c',
'test-recurse-dir.c',
'test-replace-var.c',
'test-rlimit-util.c',
TEST(mask_supported, .sd_booted = true) {
CGroupMask m;
- CGroupController c;
assert_se(cg_mask_supported(&m) >= 0);
- for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++)
- printf("'%s' is supported: %s\n", cgroup_controller_to_string(c), yes_no(m & CGROUP_CONTROLLER_TO_MASK(c)));
+ for (CGroupController c = 0; c < _CGROUP_CONTROLLER_MAX; c++)
+ printf("'%s' is supported: %s\n",
+ cgroup_controller_to_string(c),
+ yes_no(m & CGROUP_CONTROLLER_TO_MASK(c)));
}
TEST(is_cgroup_fs, .sd_booted = true) {
TEST(cg_get_keyed_attribute) {
_cleanup_free_ char *val = NULL;
char *vals3[3] = {}, *vals3a[3] = {};
- int i, r;
+ int r;
r = cg_get_keyed_attribute("cpu", "/init.scope", "no_such_file", STRV_MAKE("no_such_attr"), &val);
if (IN_SET(r, -ENOMEDIUM, -ENOENT) || ERRNO_IS_PRIVILEGE(r)) {
assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat",
STRV_MAKE("usage_usec", "user_usec", "system_usec"), vals3) == 0);
- for (i = 0; i < 3; i++)
+ for (size_t i = 0; i < 3; i++)
free(vals3[i]);
assert_se(cg_get_keyed_attribute_graceful("cpu", "/init.scope", "cpu.stat",
assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat",
STRV_MAKE("system_usec", "user_usec", "usage_usec"), vals3a) == 0);
- for (i = 0; i < 3; i++)
+ for (size_t i = 0; i < 3; i++)
free(vals3a[i]);
assert_se(cg_get_keyed_attribute_graceful("cpu", "/init.scope", "cpu.stat",
log_info("cpu /init.scope cpu.stat [system_usec user_usec usage_usec] → \"%s\", \"%s\", \"%s\"",
vals3a[0], vals3a[1], vals3a[2]);
- for (i = 0; i < 3; i++) {
+ for (size_t i = 0; i < 3; i++) {
free(vals3[i]);
free(vals3a[i]);
}
log_debug("/* create source from %s */", srcfile);
- assert_se((src = open(srcfile, O_RDONLY|O_CLOEXEC)) >= 0);
+ ASSERT_OK((src = open(srcfile, O_RDONLY|O_CLOEXEC)));
log_debug("/* test compression */");
assert_se((dst = mkostemp_safe(pattern)) >= 0);
- assert_se(compress(src, dst, -1, &uncompressed_size) >= 0);
+ ASSERT_OK(compress(src, dst, -1, &uncompressed_size));
if (cat) {
assert_se(asprintf(&cmd, "%s %s | diff %s -", cat, pattern, srcfile) > 0);
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/stat.h>
+
+#include "alloc-util.h"
+#include "dirent-util.h"
+#include "fs-util.h"
+#include "mkdir.h"
+#include "path-util.h"
+#include "rm-rf.h"
+#include "stat-util.h"
+#include "string-util.h"
+#include "tmpfile-util.h"
+#include "tests.h"
+
+TEST (test_dirent_ensure_type) {
+ int r, dir_fd;
+ static struct dirent de = {
+ .d_type = DT_UNKNOWN,
+ .d_name = "test",
+ };
+
+ assert_se(de.d_type == DT_UNKNOWN);
+
+ dir_fd = 0;
+ dirent_ensure_type(dir_fd, &de);
+
+ /* Test when d_name is "." or ".." */
+ strcpy(de.d_name, ".");
+ r = dirent_ensure_type(dir_fd, &de);
+ assert_se(r == 0);
+ assert_se(de.d_type == DT_DIR);
+
+ strcpy(de.d_name, "..");
+ r = dirent_ensure_type(dir_fd, &de);
+ assert_se(r == 0);
+ assert_se(de.d_type == DT_DIR);
+}
+
+TEST (test_dirent_is_file) {
+ _cleanup_(rm_rf_physical_and_freep) char *t = NULL;
+ const char *name, *dotfile, *name_alias, *bakfile, *tilda;
+ const struct dirent *de_reg, *de_lnk, *de_dot, *de_bak, *de_tilda;
+ DIR *dir;
+
+ static const struct dirent de_unknown = {
+ .d_type = DT_UNKNOWN,
+ .d_name = "test_unknown",
+ };
+
+ assert_se(mkdtemp_malloc(NULL, &t) >= 0);
+
+ name = strjoina(t, "/test.txt");
+ dotfile = strjoina(t, "/.hidden_file");
+ bakfile = strjoina(t, "/test.bak");
+ tilda = strjoina(t, "/test~");
+ name_alias = strjoina(t, "/test_link");
+
+ assert_se(touch(name) >= 0);
+ assert_se(touch(dotfile) >= 0);
+ assert_se(touch(bakfile) >= 0);
+ assert_se(touch(tilda) >= 0);
+
+ if (symlink(name, name_alias) < 0) {
+ assert_se(IN_SET(errno, EINVAL, ENOSYS, ENOTTY, EPERM));
+ log_tests_skipped_errno(errno, "symlink() not possible");
+ }
+
+ dir = opendir(t);
+ if (dir == NULL) {
+ log_error_errno(errno, "Failed to open directory '%s': %m", t);
+ exit(EXIT_FAILURE);
+ }
+
+ rewinddir(dir);
+ while ((de_reg = readdir_ensure_type(dir)) != NULL)
+ if (strcmp(de_reg->d_name, "test.txt") == 0)
+ break;
+
+ rewinddir(dir);
+ while ((de_lnk = readdir_ensure_type(dir)) != NULL)
+ if (strcmp(de_lnk->d_name, "test_link") == 0)
+ break;
+
+ rewinddir(dir);
+ while ((de_dot = readdir_ensure_type(dir)) != NULL)
+ if (strcmp(de_dot->d_name, ".hidden_file") == 0)
+ break;
+
+ rewinddir(dir);
+ while ((de_bak = readdir(dir)) != NULL)
+ if (strcmp(de_bak->d_name, "test.bak") == 0)
+ break;
+
+ rewinddir(dir);
+ while ((de_tilda = readdir(dir)) != NULL)
+ if (strcmp(de_tilda->d_name, "test~") == 0)
+ break;
+
+ /* Test when d_type is DT_REG, DT_LNK, or DT_UNKNOWN */
+ assert_se(dirent_is_file(de_reg) == true);
+ if (de_lnk)
+ assert_se(dirent_is_file(de_lnk) == true);
+ else
+ log_tests_skipped("de_lnk is NULL, skipping test");
+ assert_se(dirent_is_file(&de_unknown) == true);
+
+ /* Test for hidden files */
+ assert_se(dirent_is_file(de_dot) == false);
+ assert_se(dirent_is_file(de_bak) == false);
+ assert_se(dirent_is_file(de_tilda) == false);
+
+ closedir(dir);
+}
+
+TEST (test_dirent_is_file_with_suffix) {
+ _cleanup_(rm_rf_physical_and_freep) char *t = NULL;
+ const char *name, *dotfile, *name_alias, *dotdot, *chr;
+ const struct dirent *de_reg, *de_lnk, *de_dot, *de_dotdot, *de_chr;
+ DIR *dir;
+
+ static const struct dirent de_unknown = {
+ .d_type = DT_UNKNOWN,
+ .d_name = "test_unknown",
+ };
+
+ assert_se(mkdtemp_malloc(NULL, &t) >= 0);
+
+ name = strjoina(t, "/test.txt");
+ dotfile = strjoina(t, "/.hidden_file");
+ dotdot = strjoina(t, "/..dotdot");
+ chr = strjoina(t, "/test_chr");
+ name_alias = strjoina(t, "/test_link");
+
+ assert_se(touch(name) >= 0);
+ assert_se(touch(dotfile) >= 0);
+ assert_se(touch(dotdot) >= 0);
+ assert_se(mknod(chr, 0775 | S_IFCHR, makedev(0, 0)) >= 0);
+
+ if (symlink(name, name_alias) < 0) {
+ assert_se(IN_SET(errno, EINVAL, ENOSYS, ENOTTY, EPERM));
+ log_tests_skipped_errno(errno, "symlink() not possible");
+ }
+
+ dir = opendir(t);
+ if (dir == NULL) {
+ log_error_errno(errno, "Failed to open directory '%s': %m", t);
+ exit(EXIT_FAILURE);
+ }
+
+ rewinddir(dir);
+ while ((de_reg = readdir_ensure_type(dir)) != NULL)
+ if (strcmp(de_reg->d_name, "test.txt") == 0)
+ break;
+
+ rewinddir(dir);
+ while ((de_lnk = readdir_ensure_type(dir)) != NULL)
+ if (strcmp(de_lnk->d_name, "test_link") == 0)
+ break;
+
+ rewinddir(dir);
+ while ((de_dot = readdir_ensure_type(dir)) != NULL)
+ if (strcmp(de_dot->d_name, ".hidden_file") == 0)
+ break;
+
+ rewinddir(dir);
+ while ((de_dotdot = readdir(dir)) != NULL)
+ if (strcmp(de_dotdot->d_name, "..dotdot") == 0)
+ break;
+
+ rewinddir(dir);
+ while ((de_chr = readdir(dir)) != NULL)
+ if (strcmp(de_chr->d_name, "test_chr") == 0)
+ break;
+
+ /* Test when d_type is not DT_REG, DT_LNK, or DT_UNKNOWN */
+ assert_se(!dirent_is_file_with_suffix(de_chr, NULL));
+
+ /* Test when suffix is NULL */
+ assert_se(dirent_is_file_with_suffix(de_reg, NULL) == true);
+ if (de_lnk)
+ assert_se(dirent_is_file_with_suffix(de_lnk, NULL) == true);
+ else
+ log_tests_skipped("de_lnk is NULL, skipping test");
+ assert_se(dirent_is_file_with_suffix(&de_unknown, NULL) == true);
+
+ /* Test for present suffix */
+ assert_se(dirent_is_file_with_suffix(de_reg, "txt") == true);
+ if (de_lnk)
+ assert_se(dirent_is_file_with_suffix(de_lnk, "link") == true);
+ else
+ log_tests_skipped("de_lnk is NULL, skipping test");
+ assert_se(dirent_is_file_with_suffix(&de_unknown, "unknown") == true);
+
+ /* Test for absent suffix */
+ assert_se(dirent_is_file_with_suffix(de_reg, "svg") == false);
+ if (de_lnk)
+ assert_se(dirent_is_file_with_suffix(de_lnk, "pdf") == false);
+ else
+ log_tests_skipped("de_lnk is NULL, skipping test");
+ assert_se(dirent_is_file_with_suffix(&de_unknown, "yes") == false);
+
+ /* Test for dot and dot-dot */
+ assert_se(dirent_is_file_with_suffix(de_dot, NULL) == false);
+ assert_se(dirent_is_file_with_suffix(de_dotdot, NULL) == false);
+
+ closedir(dir);
+}
+
+DEFINE_TEST_MAIN(LOG_INFO);
assert_se(xopenat_lock_full(tfd, "def", O_DIRECTORY, 0, 0755, LOCK_POSIX, LOCK_EX) == -EBADF);
}
+TEST(linkat_replace) {
+ _cleanup_(rm_rf_physical_and_freep) char *t = NULL;
+ _cleanup_close_ int tfd = -EBADF;
+
+ assert_se((tfd = mkdtemp_open(NULL, 0, &t)) >= 0);
+
+ _cleanup_close_ int fd1 = openat(tfd, "foo", O_CREAT|O_RDWR|O_CLOEXEC, 0600);
+ assert_se(fd1 >= 0);
+
+ assert_se(linkat_replace(tfd, "foo", tfd, "bar") >= 0);
+ assert_se(linkat_replace(tfd, "foo", tfd, "bar") >= 0);
+
+ _cleanup_close_ int fd1_check = openat(tfd, "bar", O_RDWR|O_CLOEXEC);
+ assert_se(fd1_check >= 0);
+
+ assert_se(inode_same_at(fd1, NULL, fd1_check, NULL, AT_EMPTY_PATH) > 0);
+
+ _cleanup_close_ int fd2 = openat(tfd, "baz", O_CREAT|O_RDWR|O_CLOEXEC, 0600);
+ assert_se(fd2 >= 0);
+
+ assert_se(inode_same_at(fd1, NULL, fd2, NULL, AT_EMPTY_PATH) == 0);
+
+ assert_se(linkat_replace(tfd, "foo", tfd, "baz") >= 0);
+
+ _cleanup_close_ int fd2_check = openat(tfd, "baz", O_RDWR|O_CLOEXEC);
+
+ assert_se(inode_same_at(fd2, NULL, fd2_check, NULL, AT_EMPTY_PATH) == 0);
+ assert_se(inode_same_at(fd1, NULL, fd2_check, NULL, AT_EMPTY_PATH) > 0);
+}
+
static int intro(void) {
arg_test_dir = saved_argv[1];
return EXIT_SUCCESS;
printf("%s %s\n", GREEN_CHECK_MARK(), joined);
if (streq(prefix, "root-") && streq(suffix, ""))
- assert_se(type.designator == PARTITION_ROOT);
+ ASSERT_EQ(type.designator, PARTITION_ROOT);
if (streq(prefix, "root-") && streq(suffix, "-verity"))
- assert_se(type.designator == PARTITION_ROOT_VERITY);
+ ASSERT_EQ(type.designator, PARTITION_ROOT_VERITY);
if (streq(prefix, "usr-") && streq(suffix, ""))
- assert_se(type.designator == PARTITION_USR);
+ ASSERT_EQ(type.designator, PARTITION_USR);
if (streq(prefix, "usr-") && streq(suffix, "-verity"))
- assert_se(type.designator == PARTITION_USR_VERITY);
+ ASSERT_EQ(type.designator, PARTITION_USR_VERITY);
- assert_se(type.arch == a);
+ ASSERT_EQ(type.arch, a);
}
}
GptPartitionType x, y;
x = gpt_partition_type_from_uuid(t->uuid); /* search first by uuid */
- assert_se(gpt_partition_type_from_string(t->name, &y) >= 0); /* search first by name */
+ ASSERT_GE(gpt_partition_type_from_string(t->name, &y), 0); /* search first by name */
- assert_se(t->arch == x.arch);
- assert_se(t->arch == y.arch);
- assert_se(t->designator == x.designator);
- assert_se(t->designator == y.designator);
+ ASSERT_EQ(t->arch, x.arch);
+ ASSERT_EQ(t->arch, y.arch);
+ ASSERT_EQ(t->designator, x.designator);
+ ASSERT_EQ(t->designator, y.designator);
}
}
TEST(override_architecture) {
GptPartitionType x, y;
- assert_se(gpt_partition_type_from_string("root-x86-64", &x) >= 0);
- assert_se(x.arch == ARCHITECTURE_X86_64);
+ ASSERT_GE(gpt_partition_type_from_string("root-x86-64", &x), 0);
+ ASSERT_EQ(x.arch, ARCHITECTURE_X86_64);
- assert_se(gpt_partition_type_from_string("root-arm64", &y) >= 0);
- assert(y.arch == ARCHITECTURE_ARM64);
+ ASSERT_GE(gpt_partition_type_from_string("root-arm64", &y), 0);
+ ASSERT_EQ(y.arch, ARCHITECTURE_ARM64);
x = gpt_partition_type_override_architecture(x, ARCHITECTURE_ARM64);
- assert_se(x.arch == y.arch);
- assert_se(x.designator == y.designator);
+ ASSERT_EQ(x.arch, y.arch);
+ ASSERT_EQ(x.designator, y.designator);
assert_se(sd_id128_equal(x.uuid, y.uuid));
assert_se(streq(x.name, y.name));
/* If the partition type does not have an architecture, nothing should change. */
- assert_se(gpt_partition_type_from_string("esp", &x) >= 0);
+ ASSERT_GE(gpt_partition_type_from_string("esp", &x), 0);
y = x;
x = gpt_partition_type_override_architecture(x, ARCHITECTURE_ARM64);
- assert_se(x.arch == y.arch);
- assert_se(x.designator == y.designator);
+ ASSERT_EQ(x.arch, y.arch);
+ ASSERT_EQ(x.designator, y.designator);
assert_se(sd_id128_equal(x.uuid, y.uuid));
assert_se(streq(x.name, y.name));
}
}
TEST(string_compare_func) {
- assert_se(string_compare_func("fred", "wilma") != 0);
+ ASSERT_NE(string_compare_func("fred", "wilma"), 0);
assert_se(string_compare_func("fred", "fred") == 0);
}
"",
result);
hex_result = hexmem(result, sizeof(result));
- assert_se(streq_ptr(hex_result, "cadd5e42114351181f3abff477641d88efb57d2b5641a1e5c6d623363a6d3bad"));
+ ASSERT_STREQ(hex_result, "cadd5e42114351181f3abff477641d88efb57d2b5641a1e5c6d623363a6d3bad");
hex_result = mfree(hex_result);
hmac_sha256_by_string("waldo",
}
TEST(linked_units) {
- const char *p, *q;
+ const char *p, *q, *s;
UnitFileState state;
InstallChange *changes = NULL;
size_t n_changes = 0, i;
p = strjoina(root, "/opt/linked.service");
assert_se(write_string_file(p,
"[Install]\n"
+ "Alias=linked-alias.service\n"
"WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
p = strjoina(root, "/opt/linked2.service");
/* Now, let's not just link it, but also enable it */
assert_se(unit_file_enable(RUNTIME_SCOPE_SYSTEM, 0, root, STRV_MAKE("/opt/linked.service"), &changes, &n_changes) >= 0);
- assert_se(n_changes == 2);
+ assert_se(n_changes == 3);
p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/linked.service");
q = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/linked.service");
+ s = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/linked-alias.service");
for (i = 0 ; i < n_changes; i++) {
assert_se(changes[i].type == INSTALL_CHANGE_SYMLINK);
- assert_se(streq(changes[i].source, "/opt/linked.service"));
+
+ if (s && streq(changes[i].path, s))
+ /* The alias symlink should point within the search path. */
+ assert_se(streq(changes[i].source, SYSTEM_CONFIG_UNIT_DIR"/linked.service"));
+ else
+ assert_se(streq(changes[i].source, "/opt/linked.service"));
if (p && streq(changes[i].path, p))
p = NULL;
else if (q && streq(changes[i].path, q))
q = NULL;
+ else if (s && streq(changes[i].path, s))
+ s = NULL;
else
assert_not_reached();
}
- assert_se(!p && !q);
+ assert_se(!p && !q && !s);
install_changes_free(changes, n_changes);
changes = NULL; n_changes = 0;
assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM, root, "linked.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+ assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM, root, "linked-alias.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
/* And let's unlink it again */
assert_se(unit_file_disable(RUNTIME_SCOPE_SYSTEM, 0, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0);
- assert_se(n_changes == 2);
+ assert_se(n_changes == 3);
p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/linked.service");
q = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/linked.service");
+ s = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/linked-alias.service");
for (i = 0; i < n_changes; i++) {
assert_se(changes[i].type == INSTALL_CHANGE_UNLINK);
p = NULL;
else if (q && streq(changes[i].path, q))
q = NULL;
+ else if (s && streq(changes[i].path, s))
+ s = NULL;
else
assert_not_reached();
}
- assert_se(!p && !q);
+ assert_se(!p && !q && !s);
install_changes_free(changes, n_changes);
changes = NULL; n_changes = 0;
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <errno.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "errno-util.h"
+#include "fd-util.h"
+#include "fs-util.h"
+#include "label.h"
+#include "path-util.h"
+#include "string-util.h"
+#include "tests.h"
+
+static struct stat buf;
+static int check_path(int dir_fd, const char *path) {
+ assert(path);
+ assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
+
+ if (isempty(path))
+ return -EINVAL;
+
+ /* assume length of pathname is not greater than 40*/
+ if (strlen(path) > 40)
+ return -ENAMETOOLONG;
+
+ /* assume a case where a specific label isn't allowed */
+ if (path_equal(path, "/restricted_directory"))
+ return -EACCES;
+ return 0;
+}
+
+static int pre_labelling_func(int dir_fd, const char *path, mode_t mode) {
+ int r;
+
+ assert(mode != MODE_INVALID);
+ r = check_path(dir_fd, path);
+ if (r < 0)
+ return log_error_errno(r, "Error in pathname =>: %m");
+
+ return 0;
+}
+
+static int post_labelling_func(int dir_fd, const char *path) {
+ int r;
+
+ /* assume label policies that restrict certain labels */
+ r = check_path(dir_fd, path);
+ if (r < 0)
+ return log_error_errno(r, "Error in pathname =>: %m");
+
+ /* Set file data to buf */
+ r = RET_NERRNO(fstatat(dir_fd, path, &buf, 0));
+ if (r < 0)
+ return log_error_errno(r, "Error in getting file status =>: %m");
+
+ return 0; /* on success */
+}
+
+static int get_dir_fd(const char *dir_path, mode_t mode) {
+ /* create a new directory and return its descriptor*/
+ int dir_fd = -EBADF;
+
+ assert(dir_path);
+ dir_fd = RET_NERRNO(open_mkdir_at(AT_FDCWD, dir_path, O_CLOEXEC, mode));
+ if (dir_fd < 0)
+ return log_error_errno(dir_fd, "Error occurred while opening directory =>: %m");
+
+ return dir_fd;
+}
+
+static int labelling_op(int dir_fd, const char *text, const char *path, mode_t mode) {
+ /* Write some content into the file */
+ ssize_t count;
+ _cleanup_close_ int write_fd = -EBADF;
+ int r;
+
+ assert(text);
+ assert(mode != MODE_INVALID);
+ r = check_path(dir_fd, path);
+ if (r < 0)
+ return log_error_errno(r, "Error in pathname =>: %m");
+
+ /* Open the file within the directory for writing*/
+ write_fd = RET_NERRNO(openat(dir_fd, path, O_CLOEXEC|O_WRONLY|O_TRUNC|O_CREAT, 0644));
+ if (write_fd < 0)
+ return log_error_errno(write_fd, "Error in opening directory for writing =>: %m");
+
+ /* Write data to the file*/
+ count = RET_NERRNO(write(write_fd, text, strlen(text)));
+ if (count < 0)
+ return log_error_errno(count, "Error occurred while opening file for writing =>: %m");
+ return 0;
+}
+
+TEST(label_ops_set) {
+ static const LabelOps test_label_ops = {
+ .pre = NULL,
+ .post = NULL,
+ };
+
+ label_ops_reset();
+ assert_se(label_ops_set(&test_label_ops) == 0);
+ /* attempt to reset label_ops when already set */
+ assert_se(label_ops_set(&test_label_ops) == -EBUSY);
+}
+
+TEST(label_ops_pre) {
+ _cleanup_close_ int fd;
+ static const LabelOps test_label_ops = {
+ .pre = pre_labelling_func,
+ .post = NULL,
+ };
+
+ label_ops_reset();
+ label_ops_set(&test_label_ops);
+ fd = get_dir_fd("file1.txt", 0755);
+ assert_se(label_ops_pre(fd, "file1.txt", 0644) == 0);
+ assert_se(label_ops_pre(fd, "/restricted_directory", 0644) == -EACCES);
+ assert_se(label_ops_pre(fd, "", 0700) == -EINVAL);
+ assert_se(label_ops_pre(fd, "/tmp", 0700) == 0);
+ assert_se(label_ops_pre(fd, "wekrgoierhgoierhqgherhgwklegnlweehgorwfkryrit", 0644) == -ENAMETOOLONG);
+}
+
+TEST(label_ops_post) {
+ _cleanup_close_ int fd = -EBADF;
+ const char *text1, *text2;
+ static const LabelOps test_label_ops = {
+ .pre = NULL,
+ .post = post_labelling_func,
+ };
+
+ label_ops_reset();
+ label_ops_set(&test_label_ops);
+
+ /* Open directory */
+ fd = RET_NERRNO(get_dir_fd("label_test_dir", 0755));
+ text1 = "Add initial texts to file for testing label operations to file1\n";
+
+ assert(labelling_op(fd, text1, "file1.txt", 0644) == 0);
+ assert_se(label_ops_post(fd, "file1.txt") == 0);
+ assert_se(strlen(text1) == (size_t)buf.st_size);
+ text2 = "Add text2 data to file2\n";
+
+ assert(labelling_op(fd, text2, "file2.txt", 0644) == 0);
+ assert_se(label_ops_post(fd, "file2.txt") == 0);
+ assert_se(strlen(text2) == (size_t)buf.st_size);
+ assert_se(label_ops_post(fd, "file3.txt") == -ENOENT);
+ assert_se(label_ops_post(fd, "/abcd") == -ENOENT);
+ assert_se(label_ops_post(fd, "/restricted_directory") == -EACCES);
+ assert_se(label_ops_post(fd, "") == -EINVAL);
+}
+
+DEFINE_TEST_MAIN(LOG_INFO)
*/
/* file mountpoints */
- assert_se(mkdtemp(tmp_dir) != NULL);
+ ASSERT_NOT_NULL(mkdtemp(tmp_dir));
file1 = path_join(tmp_dir, "file1");
assert_se(file1);
file2 = path_join(tmp_dir, "file2");
#include "tmpfile-util.h"
TEST(path_is_os_tree) {
- assert_se(path_is_os_tree("/") > 0);
- assert_se(path_is_os_tree("/etc") == 0);
+ ASSERT_GT(path_is_os_tree("/"), 0);
+ ASSERT_EQ(path_is_os_tree("/etc"), 0);
assert_se(path_is_os_tree("/idontexist") == -ENOENT);
}
TEST(parse_os_release) {
/* Let's assume that we're running in a valid system, so os-release is available */
_cleanup_free_ char *id = NULL, *id2 = NULL, *name = NULL, *foobar = NULL;
- assert_se(parse_os_release(NULL, "ID", &id) == 0);
+ ASSERT_EQ(parse_os_release(NULL, "ID", &id), 0);
log_info("ID: %s", id);
- assert_se(setenv("SYSTEMD_OS_RELEASE", "/dev/null", 1) == 0);
- assert_se(parse_os_release(NULL, "ID", &id2) == 0);
+ ASSERT_EQ(setenv("SYSTEMD_OS_RELEASE", "/dev/null", 1), 0);
+ ASSERT_EQ(parse_os_release(NULL, "ID", &id2), 0);
log_info("ID: %s", strnull(id2));
_cleanup_(unlink_tempfilep) char tmpfile[] = "/tmp/test-os-util.XXXXXX";
- assert_se(write_tmpfile(tmpfile,
+ ASSERT_EQ(write_tmpfile(tmpfile,
"ID=the-id \n"
- "NAME=the-name") == 0);
+ "NAME=the-name"), 0);
- assert_se(setenv("SYSTEMD_OS_RELEASE", tmpfile, 1) == 0);
- assert_se(parse_os_release(NULL, "ID", &id, "NAME", &name) == 0);
+ ASSERT_EQ(setenv("SYSTEMD_OS_RELEASE", tmpfile, 1), 0);
+ ASSERT_EQ(parse_os_release(NULL, "ID", &id, "NAME", &name), 0);
log_info("ID: %s NAME: %s", id, name);
assert_se(streq(id, "the-id"));
assert_se(streq(name, "the-name"));
_cleanup_(unlink_tempfilep) char tmpfile2[] = "/tmp/test-os-util.XXXXXX";
- assert_se(write_tmpfile(tmpfile2,
+ ASSERT_EQ(write_tmpfile(tmpfile2,
"ID=\"ignored\" \n"
"ID=\"the-id\" \n"
- "NAME='the-name'") == 0);
+ "NAME='the-name'"), 0);
- assert_se(setenv("SYSTEMD_OS_RELEASE", tmpfile2, 1) == 0);
- assert_se(parse_os_release(NULL, "ID", &id, "NAME", &name) == 0);
+ ASSERT_EQ(setenv("SYSTEMD_OS_RELEASE", tmpfile2, 1), 0);
+ ASSERT_EQ(parse_os_release(NULL, "ID", &id, "NAME", &name), 0);
log_info("ID: %s NAME: %s", id, name);
assert_se(streq(id, "the-id"));
assert_se(streq(name, "the-name"));
- assert_se(parse_os_release(NULL, "FOOBAR", &foobar) == 0);
+ ASSERT_EQ(parse_os_release(NULL, "FOOBAR", &foobar), 0);
log_info("FOOBAR: %s", strnull(foobar));
- assert_se(foobar == NULL);
+ ASSERT_NULL(foobar);
assert_se(unsetenv("SYSTEMD_OS_RELEASE") == 0);
}
assert_se(a = path_join(tempdir, "/usr/lib/extension-release.d/extension-release.test"));
assert_se(mkdir_parents(a, 0777) >= 0);
+ ASSERT_GE(mkdir_parents(a, 0777), 0);
r = write_string_file(a, "ID=the-id \n VERSION_ID=the-version-id", WRITE_STRING_FILE_CREATE);
if (r < 0)
if (r < 0)
log_error_errno(r, "Failed to write file: %m");
- assert_se(parse_extension_release(tempdir, IMAGE_CONFEXT, "tester", false, "ID", &id, "VERSION_ID", &version_id) == 0);
+ ASSERT_EQ(parse_extension_release(tempdir, IMAGE_CONFEXT, "tester", false, "ID", &id, "VERSION_ID", &version_id), 0);
log_info("ID: %s VERSION_ID: %s", id, version_id);
assert_se(streq(id, "the-id"));
assert_se(streq(version_id, "the-version-id"));
assert_se(parse_extension_release(tempdir, IMAGE_CONFEXT, "tester", false, "FOOBAR", &foobar) == 0);
log_info("FOOBAR: %s", strnull(foobar));
- assert_se(foobar == NULL);
+ ASSERT_NULL(foobar);
assert_se(parse_extension_release(tempdir, IMAGE_SYSEXT, "test", false, "FOOBAR", &foobar) == 0);
log_info("FOOBAR: %s", strnull(foobar));
- assert_se(foobar == NULL);
+ ASSERT_NULL(foobar);
}
TEST(load_os_release_pairs) {
_cleanup_(unlink_tempfilep) char tmpfile[] = "/tmp/test-os-util.XXXXXX";
- assert_se(write_tmpfile(tmpfile,
+ ASSERT_EQ(write_tmpfile(tmpfile,
"ID=\"ignored\" \n"
"ID=\"the-id\" \n"
- "NAME='the-name'") == 0);
+ "NAME='the-name'"), 0);
- assert_se(setenv("SYSTEMD_OS_RELEASE", tmpfile, 1) == 0);
+ ASSERT_EQ(setenv("SYSTEMD_OS_RELEASE", tmpfile, 1), 0);
_cleanup_strv_free_ char **pairs = NULL;
- assert_se(load_os_release_pairs(NULL, &pairs) == 0);
+ ASSERT_EQ(load_os_release_pairs(NULL, &pairs), 0);
assert_se(strv_equal(pairs, STRV_MAKE("ID", "the-id",
"NAME", "the-name")));
- assert_se(unsetenv("SYSTEMD_OS_RELEASE") == 0);
+ ASSERT_EQ(unsetenv("SYSTEMD_OS_RELEASE"), 0);
}
TEST(os_release_support_ended) {
int r;
- assert_se(os_release_support_ended("1999-01-01", false, NULL) == true);
- assert_se(os_release_support_ended("2037-12-31", false, NULL) == false);
+ ASSERT_TRUE(os_release_support_ended("1999-01-01", false, NULL));
+ ASSERT_FALSE(os_release_support_ended("2037-12-31", false, NULL));
assert_se(os_release_support_ended("-1-1-1", true, NULL) == -EINVAL);
r = os_release_support_ended(NULL, false, NULL);
log_error("---%s---", s);
assert_se(streq(s, values[i++]));
}
- assert_se(values[i] == NULL);
+ ASSERT_NULL(values[i]);
i = 1;
PATH_FOREACH_PREFIX(s, "/a/b/c/d") {
log_error("---%s---", s);
assert_se(streq(s, values[i++]));
}
- assert_se(values[i] == NULL);
+ ASSERT_NULL(values[i]);
i = 0;
PATH_FOREACH_PREFIX_MORE(s, "////a////b////c///d///////")
assert_se(streq(s, values[i++]));
- assert_se(values[i] == NULL);
+ ASSERT_NULL(values[i]);
i = 1;
PATH_FOREACH_PREFIX(s, "////a////b////c///d///////")
assert_se(streq(s, values[i++]));
- assert_se(values[i] == NULL);
+ ASSERT_NULL(values[i]);
PATH_FOREACH_PREFIX(s, "////")
assert_not_reached();
assert_cc(FILENAME_MAX == PATH_MAX);
}
+TEST(path_implies_directory) {
+ assert_se(!path_implies_directory(NULL));
+ assert_se(!path_implies_directory(""));
+ assert_se(path_implies_directory("/"));
+ assert_se(path_implies_directory("////"));
+ assert_se(path_implies_directory("////.///"));
+ assert_se(path_implies_directory("////./"));
+ assert_se(path_implies_directory("////."));
+ assert_se(path_implies_directory("."));
+ assert_se(path_implies_directory("./"));
+ assert_se(path_implies_directory("/."));
+ assert_se(path_implies_directory(".."));
+ assert_se(path_implies_directory("../"));
+ assert_se(path_implies_directory("/.."));
+ assert_se(!path_implies_directory("a"));
+ assert_se(!path_implies_directory("ab"));
+ assert_se(path_implies_directory("ab/"));
+ assert_se(!path_implies_directory("ab/a"));
+ assert_se(path_implies_directory("ab/a/"));
+ assert_se(path_implies_directory("ab/a/.."));
+ assert_se(path_implies_directory("ab/a/."));
+ assert_se(path_implies_directory("ab/a//"));
+}
+
DEFINE_TEST_MAIN(LOG_DEBUG);
memset(buf, 0xff, sizeof(buf));
draw_cylon(buf, sizeof(buf), CYLON_WIDTH, pos);
- assert_se(strlen(buf) < sizeof(buf));
+ ASSERT_LE(strlen(buf), sizeof(buf));
}
TEST(draw_cylon) {
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <string.h>
+
+#include "memory-util.h"
+#include "random-util.h"
+#include "recovery-key.h"
+#include "tests.h"
+
+TEST(make_recovery_key) {
+ _cleanup_(erase_and_freep) char *recovery_key = NULL;
+ size_t length;
+ const size_t num_test = 10;
+ char *generated_keys[num_test];
+ int r;
+
+ /* Check for successful recovery-key creation */
+ r = make_recovery_key(&recovery_key);
+ assert_se(r == 0);
+ ASSERT_NOT_NULL(recovery_key);
+
+ /* Check that length of formatted key is 72 with 64 modhex characters */
+ length = strlen(recovery_key);
+ assert_se(length == RECOVERY_KEY_MODHEX_FORMATTED_LENGTH - 1);
+ /* Check modhex characters in formatted key with dashes */
+ for (size_t i = 0; i < length; i++) {
+ assert_se((recovery_key[i] >= 'a' && recovery_key[i] <= 'v') || recovery_key[i] == '-');
+ if (i % 9 == 8)
+ /* confirm '-' is after every 8 characters */
+ assert_se(recovery_key[i] == '-');
+ }
+ /* Repeat tests to determine randomness of generated keys */
+ for (size_t test = 0; test < num_test; ++test) {
+ r = make_recovery_key(&generated_keys[test]);
+ assert_se(r == 0);
+ length = strlen(generated_keys[test]);
+ assert_se(length == RECOVERY_KEY_MODHEX_FORMATTED_LENGTH - 1);
+ for (size_t i = 0; i < length; i++) {
+ assert_se((generated_keys[test][i] >= 'a' && generated_keys[test][i] <= 'v')
+ || generated_keys[test][i] == '-');
+ if (i % 9 == 8)
+ assert_se(generated_keys[test][i] == '-');
+ }
+ /* Check for uniqueness of each generated recovery key */
+ for (size_t prev = 0; prev < test; ++prev)
+ assert_se(!streq(generated_keys[test], generated_keys[prev]));
+ }
+ for (size_t i = 0; i < num_test; i++)
+ free(generated_keys[i]);
+}
+
+TEST(decode_modhex_char) {
+
+ assert_se(decode_modhex_char('c') == 0);
+ assert_se(decode_modhex_char('C') == 0);
+ assert_se(decode_modhex_char('b') == 1);
+ assert_se(decode_modhex_char('B') == 1);
+ assert_se(decode_modhex_char('d') == 2);
+ assert_se(decode_modhex_char('D') == 2);
+ assert_se(decode_modhex_char('e') == 3);
+ assert_se(decode_modhex_char('E') == 3);
+ assert_se(decode_modhex_char('f') == 4);
+ assert_se(decode_modhex_char('F') == 4);
+ assert_se(decode_modhex_char('g') == 5);
+ assert_se(decode_modhex_char('G') == 5);
+ assert_se(decode_modhex_char('h') == 6);
+ assert_se(decode_modhex_char('H') == 6);
+ assert_se(decode_modhex_char('i') == 7);
+ assert_se(decode_modhex_char('I') == 7);
+ assert_se(decode_modhex_char('j') == 8);
+ assert_se(decode_modhex_char('J') == 8);
+ assert_se(decode_modhex_char('k') == 9);
+ assert_se(decode_modhex_char('K') == 9);
+ assert_se(decode_modhex_char('l') == 10);
+ assert_se(decode_modhex_char('L') == 10);
+ assert_se(decode_modhex_char('n') == 11);
+ assert_se(decode_modhex_char('N') == 11);
+ assert_se(decode_modhex_char('r') == 12);
+ assert_se(decode_modhex_char('R') == 12);
+ assert_se(decode_modhex_char('t') == 13);
+ assert_se(decode_modhex_char('T') == 13);
+ assert_se(decode_modhex_char('u') == 14);
+ assert_se(decode_modhex_char('U') == 14);
+ assert_se(decode_modhex_char('v') == 15);
+ assert_se(decode_modhex_char('V') == 15);
+ assert_se(decode_modhex_char('a') == -EINVAL);
+ assert_se(decode_modhex_char('A') == -EINVAL);
+ assert_se(decode_modhex_char('x') == -EINVAL);
+ assert_se(decode_modhex_char('.') == -EINVAL);
+ assert_se(decode_modhex_char('/') == -EINVAL);
+ assert_se(decode_modhex_char('\0') == -EINVAL);
+}
+
+TEST(normalize_recovery_key) {
+ _cleanup_(erase_and_freep) char *normalized_key1 = NULL;
+ _cleanup_(erase_and_freep) char *normalized_key2 = NULL;
+ _cleanup_(erase_and_freep) char *normalized_key3 = NULL;
+ int r;
+
+ /* Case 1: Normalization without dashes */
+ r = normalize_recovery_key("cdefghijcdefghijcdefghijcdefghijcdefghijcdefghijcdefghijcdefghij",
+ &normalized_key1);
+ assert(r == 0);
+ assert(streq(normalized_key1, "cdefghij-cdefghij-cdefghij-cdefghij-cdefghij-cdefghij-cdefghij-cdefghij"));
+
+ /* Case 2: Normalization with dashes */
+ r = normalize_recovery_key("cdefVhij-cDefghij-cdefkhij-cdufghij-cdefgdij-cidefIhj-cdefNijR-cdVfguij",
+ &normalized_key2);
+ assert_se(r == 0);
+ assert_se(streq(normalized_key2, "cdefvhij-cdefghij-cdefkhij-cdufghij-cdefgdij-cidefihj-cdefnijr-cdvfguij"));
+
+ /* Case 3: Invalid password length */
+ r = normalize_recovery_key("1234-5678-90AB-CDEF-1234-5678-90AB-CDEF", &normalized_key1);
+ assert(r == -EINVAL);
+
+ /* Case 4: Invalid password format(missing dash) */
+ r = normalize_recovery_key("cdefghij-cdefghij-cdefghij-cdefghij-cdefghij-cdefghij-cdefghijcdefghij",
+ &normalized_key1);
+ assert_se(r == -EINVAL);
+
+ /* Case 5: Normalization of Upper cases password without dashes */
+ r = normalize_recovery_key("BFGHICEHHIUVLKJIHFHEDlntruvcdefjiTUVKLNIJVTUTKJIHDFBCBGHIJHHFDBC",
+ &normalized_key3);
+ assert(r == 0);
+ assert_se(streq(normalized_key3, "bfghiceh-hiuvlkji-hfhedlnt-ruvcdefj-ituvklni-jvtutkji-hdfbcbgh-ijhhfdbc"));
+
+ /* Case 6: Minimum password length */
+ r = normalize_recovery_key("", &normalized_key1);
+ assert_se(r == -EINVAL);
+
+ /* Case 7: Invalid characters and numbers in password */
+ r = normalize_recovery_key("cde123hi-cdefgzij-cdefghij-cdefghij-cdefghij-cdefghij-cdefghijcdefghij",
+ &normalized_key1);
+ assert_se(r == -EINVAL);
+}
+
+DEFINE_TEST_MAIN(LOG_INFO);
}
}
+TEST(strdup_to_full) {
+ _cleanup_free_ char *dst;
+
+ assert_se(strdup_to_full(NULL, NULL) == 0);
+ assert_se(strdup_to_full(&dst, NULL) == 0);
+
+ assert_se(strdup_to_full(NULL, "") == 1);
+ assert_se(strdup_to_full(&dst, "") == 1);
+ assert_se(streq_ptr(dst, ""));
+ dst = mfree(dst);
+
+ assert_se(strdup_to_full(NULL, "x") == 1);
+ assert_se(strdup_to_full(&dst, "x") == 1);
+ assert_se(streq_ptr(dst, "x"));
+}
+
+TEST(strdup_to) {
+ _cleanup_free_ char *dst;
+
+ assert_se(strdup_to(&dst, NULL) == 0);
+
+ assert_se(strdup_to(&dst, "") == 0);
+ assert_se(streq_ptr(dst, ""));
+ dst = mfree(dst);
+
+ assert_se(strdup_to(&dst, "x") == 0);
+ assert_se(streq_ptr(dst, "x"));
+}
+
TEST(ascii_strcasecmp_n) {
assert_se(ascii_strcasecmp_n("", "", 0) == 0);
assert_se(ascii_strcasecmp_n("", "", 1) == 0);
}
TEST(uid_ptr) {
- assert_se(UID_TO_PTR(0) != NULL);
- assert_se(UID_TO_PTR(1000) != NULL);
+ ASSERT_NOT_NULL(UID_TO_PTR(0));
+ ASSERT_NOT_NULL(UID_TO_PTR(1000));
assert_se(PTR_TO_UID(UID_TO_PTR(0)) == 0);
assert_se(PTR_TO_UID(UID_TO_PTR(1000)) == 1000);
static char *arg_tpm2_device = NULL;
static bool arg_early = false;
+static bool arg_graceful = false;
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device, freep);
" --tpm2-device=PATH\n"
" Pick TPM2 device\n"
" --early=BOOL Store SRK public key in /run/ rather than /var/lib/\n"
+ " --graceful Exit gracefully if no TPM2 device is found\n"
"\nSee the %2$s for details.\n",
program_invocation_short_name,
link,
ARG_VERSION = 0x100,
ARG_TPM2_DEVICE,
ARG_EARLY,
+ ARG_GRACEFUL,
};
static const struct option options[] = {
{ "version", no_argument, NULL, ARG_VERSION },
{ "tpm2-device", required_argument, NULL, ARG_TPM2_DEVICE },
{ "early", required_argument, NULL, ARG_EARLY },
+ { "graceful", no_argument, NULL, ARG_GRACEFUL },
{}
};
arg_early = r;
break;
+ case ARG_GRACEFUL:
+ arg_graceful = true;
+ break;
+
case '?':
return -EINVAL;
if (r <= 0)
return r;
+ if (arg_graceful && tpm2_support() != TPM2_SUPPORT_FULL) {
+ log_notice("No complete TPM2 support detected, exiting gracefully.");
+ return EXIT_SUCCESS;
+ }
+
umask(0022);
_cleanup_(public_key_data_done) struct public_key_data runtime_key = {}, persistent_key = {}, tpm2_key = {};
#include "dirent-util.h"
#include "fd-util.h"
#include "discover-image.h"
+#include "pidref.h"
#include "sd-daemon.h"
#include "sd-event.h"
#include "sd-id128.h"
#include "gpt.h"
#include "hexdecoct.h"
#include "hostname-util.h"
+#include "io-util.h"
#include "kernel-image.h"
#include "log.h"
#include "machine-credential.h"
#include "stat-util.h"
#include "string-util.h"
#include "strv.h"
+#include "time-util.h"
#include "tmpfile-util.h"
#include "unit-name.h"
#include "vmspawn-mount.h"
static char **arg_kernel_cmdline_extra = NULL;
static char **arg_extra_drives = NULL;
static char *arg_background = NULL;
+static bool arg_pass_ssh_key = true;
+static char *arg_ssh_key_type = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_directory, freep);
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
STATIC_DESTRUCTOR_REGISTER(arg_kernel_cmdline_extra, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_extra_drives, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_background, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_ssh_key_type, freep);
static int help(void) {
_cleanup_free_ char *link = NULL;
"\n%3$sIntegration:%4$s\n"
" --forward-journal=FILE|DIR\n"
" Forward the VM's journal to the host\n"
+ " --pass-ssh-key=BOOL Create an SSH key to access the VM\n"
+ " --ssh-key-type=TYPE Choose what type of SSH key to pass\n"
"\n%3$sInput/Output:%4$s\n"
" --console=MODE Console mode (interactive, native, gui)\n"
" --background=COLOR Set ANSI color for background\n"
ARG_SECURE_BOOT,
ARG_PRIVATE_USERS,
ARG_FORWARD_JOURNAL,
+ ARG_PASS_SSH_KEY,
+ ARG_SSH_KEY_TYPE,
ARG_SET_CREDENTIAL,
ARG_LOAD_CREDENTIAL,
ARG_FIRMWARE,
{ "secure-boot", required_argument, NULL, ARG_SECURE_BOOT },
{ "private-users", required_argument, NULL, ARG_PRIVATE_USERS },
{ "forward-journal", required_argument, NULL, ARG_FORWARD_JOURNAL },
+ { "pass-ssh-key", required_argument, NULL, ARG_PASS_SSH_KEY },
+ { "ssh-key-type", required_argument, NULL, ARG_SSH_KEY_TYPE },
{ "set-credential", required_argument, NULL, ARG_SET_CREDENTIAL },
{ "load-credential", required_argument, NULL, ARG_LOAD_CREDENTIAL },
{ "firmware", required_argument, NULL, ARG_FIRMWARE },
return r;
break;
+ case ARG_PASS_SSH_KEY:
+ r = parse_boolean(optarg);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse --pass-ssh-key= argument: %s", optarg);
+
+ arg_pass_ssh_key = r;
+ break;
+
+ case ARG_SSH_KEY_TYPE:
+ if (!string_is_safe(optarg))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid value for --arg-ssh-key-type=: %s", optarg);
+
+ r = free_and_strdup_warn(&arg_ssh_key_type, optarg);
+ if (r < 0)
+ return r;
+ break;
+
case ARG_SET_CREDENTIAL: {
r = machine_credential_set(&arg_credentials, optarg);
if (r < 0)
if (dot)
(void) pty_forward_set_title_prefix(f, dot);
}
+static int generate_ssh_keypair(const char *key_path, const char *key_type) {
+ _cleanup_free_ char *ssh_keygen = NULL;
+ _cleanup_strv_free_ char **cmdline = NULL;
+ int r;
+
+ assert(key_path);
+
+ r = find_executable("ssh-keygen", &ssh_keygen);
+ if (r < 0)
+ return log_error_errno(r, "Failed to find ssh-keygen: %m");
+
+ cmdline = strv_new(ssh_keygen, "-f", key_path, /* don't encrypt the key */ "-N", "");
+ if (!cmdline)
+ return log_oom();
+
+ if (key_type) {
+ r = strv_extend_many(&cmdline, "-t", key_type);
+ if (r < 0)
+ return log_oom();
+ }
+
+ if (DEBUG_LOGGING) {
+ _cleanup_free_ char *joined = quote_command_line(cmdline, SHELL_ESCAPE_EMPTY);
+ if (!joined)
+ return log_oom();
+
+ log_debug("Executing: %s", joined);
+ }
+
+ r = safe_fork(
+ ssh_keygen,
+ FORK_WAIT|FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_RLIMIT_NOFILE_SAFE|FORK_REARRANGE_STDIO,
+ NULL);
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ execv(ssh_keygen, cmdline);
+ log_error_errno(errno, "Failed to execve %s: %m", ssh_keygen);
+ _exit(EXIT_FAILURE);
+ }
+
+ return 0;
+}
static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
_cleanup_(ovmf_config_freep) OvmfConfig *ovmf_config = NULL;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
_cleanup_free_ char *machine = NULL, *qemu_binary = NULL, *mem = NULL, *trans_scope = NULL, *kernel = NULL;
+ _cleanup_(rm_rf_physical_and_freep) char *ssh_private_key_path = NULL, *ssh_public_key_path = NULL;
_cleanup_close_ int notify_sock_fd = -EBADF;
_cleanup_strv_free_ char **cmdline = NULL;
_cleanup_free_ int *pass_fds = NULL;
return r;
}
+ if (arg_pass_ssh_key) {
+ _cleanup_free_ char *scope_prefix = NULL, *privkey_path = NULL, *pubkey_path = NULL;
+ const char *key_type = arg_ssh_key_type ?: "ed25519";
+
+ r = unit_name_to_prefix(trans_scope, &scope_prefix);
+ if (r < 0)
+ return log_error_errno(r, "Failed to strip .scope suffix from scope: %m");
+
+ privkey_path = strjoin(arg_runtime_directory, "/", scope_prefix, "-", key_type);
+ if (!privkey_path)
+ return log_oom();
+
+ pubkey_path = strjoin(privkey_path, ".pub");
+ if (!pubkey_path)
+ return log_oom();
+
+ r = generate_ssh_keypair(privkey_path, key_type);
+ if (r < 0)
+ return r;
+
+ ssh_private_key_path = TAKE_PTR(privkey_path);
+ ssh_public_key_path = TAKE_PTR(pubkey_path);
+ }
+
+ if (ssh_public_key_path && ssh_private_key_path) {
+ _cleanup_free_ char *scope_prefix = NULL, *cred_path = NULL;
+
+ cred_path = strjoin("ssh.ephemeral-authorized_keys-all:", ssh_public_key_path);
+ if (!cred_path)
+ return log_oom();
+
+ r = machine_credential_load(&arg_credentials, cred_path);
+ if (r < 0)
+ return log_error_errno(r, "Failed to load credential %s: %m", cred_path);
+
+ r = unit_name_to_prefix(trans_scope, &scope_prefix);
+ if (r < 0)
+ return log_error_errno(r, "Failed to strip .scope suffix from scope: %m");
+ }
+
if (ARCHITECTURE_SUPPORTS_SMBIOS)
FOREACH_ARRAY(cred, arg_credentials.credentials, arg_credentials.n_credentials) {
_cleanup_free_ char *cred_data_b64 = NULL;
local workspace="${1:?}"
local dropin_dir
- mkdir -p "$workspace/test-journals/"
- cp -av "${TEST_BASE_DIR:?}/test-journals/"* "$workspace/test-journals/"
-
image_install curl setterm unzstd
image_install -o openssl
# Necessary for RH-based systems, otherwise MHD fails with:
# shellcheck source=test/test-functions
. "${TEST_BASE_DIR:?}/test-functions"
-# (Hopefully) a temporary workaround for https://github.com/systemd/systemd/issues/30573
-KERNEL_APPEND="${KERNEL_APPEND:-} SYSTEMD_DEFAULT_MOUNT_RATE_LIMIT_BURST=100"
-
# Make sure vsock is available in the VM
CID=$((RANDOM + 3))
QEMU_OPTIONS+=" -device vhost-vsock-pci,guest-cid=$CID"
foreach subdir : [
'auxv',
'journal-data',
+ 'test-journals',
'units',
'test-execute',
'test-fstab-generator',
# For the networkd instance invoked below cannot support varlink connection.
# Hence, 'networkctl persistent-storage yes' cannot be used.
-touch /run/systemd/netif/persistent-storage-ready
+export SYSTEMD_NETWORK_PERSISTENT_STORAGE_READY=1
# run networkd as in systemd-networkd.service
exec $(systemctl cat systemd-networkd.service | sed -n '/^ExecStart=/ {{ s/^.*=//; s/^[@+-]//; s/^!*//; p}}')
RESULTS["$test"]="$result"
TIMES["$test"]="$SECONDS"
- [[ "$result" -ne 0 ]] && FAILURES=$((FAILURES + 1))
- done
-fi
-
-# Run clean-again, if requested, and if no tests failed
-if [[ $FAILURES -eq 0 && $CLEAN_AGAIN -eq 1 ]]; then
- for test in "${!RESULTS[@]}"; do
- test_run "$test" make -C "$test" clean-again
+ # Run clean-again here to free up space, if requested, and if the test succeeded
+ if [[ "$result" -ne 0 ]]; then
+ FAILURES=$((FAILURES + 1))
+ elif [[ $CLEAN_AGAIN -eq 1 ]]; then
+ test_run "$test" make -C "$test" clean-again
+ fi
done
fi
[ -n "$TESTDIR" ] || return
rm -rf "$TESTDIR/unprivileged-nspawn-root"
[[ -n "$initdir" ]] && _umount_dir "$initdir"
+ # Test specific images are not reused, so delete them or we run out of disk space
+ if [[ -n "$IMAGE_PUBLIC" ]] && [ "$(basename "$IMAGE_PUBLIC")" != "default.img" ]; then
+ rm -vf "$IMAGE_PUBLIC"
+ fi
+ if [[ -n "$IMAGE_PRIVATE" ]] && [ "$(basename "$IMAGE_PRIVATE")" != "default.img" ]; then
+ rm -vf "$IMAGE_PRIVATE"
+ fi
}
test_create_image() {
"$systemctl" --root="$root" enable '/link5copy.service'
islink "$root/etc/systemd/system/link5copy.service" '/link5copy.service'
-islink "$root/etc/systemd/system/link5alias.service" '/link5copy.service'
-islink "$root/etc/systemd/system/link5alias2.service" '/link5copy.service'
+islink "$root/etc/systemd/system/link5alias.service" '/etc/systemd/system/link5copy.service'
+islink "$root/etc/systemd/system/link5alias2.service" '/etc/systemd/system/link5copy.service'
"$systemctl" --root="$root" disable 'link5copy.service'
test ! -h "$root/etc/systemd/system/link5copy.service"
--- /dev/null
+#!/usr/bin/env bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -eux
+set -o pipefail
+
+systemctl enable --now systemd-journald@cat-test.socket
+
+systemd-cat --namespace cat-test env CAT_TEST_RESULT=1
+
+timeout 30 bash -c "until systemctl -q is-active systemd-journald@cat-test.service; do sleep .5; done"
+
+journalctl --namespace cat-test --grep "JOURNAL_STREAM="
+journalctl --namespace cat-test --grep "CAT_TEST_RESULT=1"
+
+systemctl disable --now systemd-journald@cat-test.socket
JOURNAL_DIR="$(mktemp -d)"
REMOTE_OUT="$(mktemp -d)"
# tar on C8S doesn't support the --zstd option
-unzstd --stdout "/test-journals/afl-corrupted-journals.tar.zst" | tar -xC "$JOURNAL_DIR/"
+unzstd --stdout "/usr/lib/systemd/tests/testdata/test-journals/afl-corrupted-journals.tar.zst" | tar -xC "$JOURNAL_DIR/"
while read -r file; do
filename="${file##*/}"
unzstd "$file" -o "$JOURNAL_DIR/${filename%*.zst}"
-done < <(find /test-journals/corrupted/ -name "*.zst")
+done < <(find /usr/lib/systemd/tests/testdata/test-journals/corrupted/ -name "*.zst")
# First, try each of them sequentially. Skip this part when running with plain
# QEMU, as it is excruciatingly slow
# Note: we care only about exit code 124 (timeout) and special bash exit codes
while read -r file; do
filename="${file##*/}"
unzstd "$file" -o "$JOURNAL_DIR/${filename%*.zst}"
-done < <(find /test-journals/no-rtc -name "*.zst")
+done < <(find /usr/lib/systemd/tests/testdata/test-journals/no-rtc -name "*.zst")
journalctl --directory="$JOURNAL_DIR" --list-boots --output=json >/tmp/lb1
diff -u /tmp/lb1 - <<'EOF'
world
EOF
rm -f "$CURSOR_FILE"
+
+# Check that --until works with --after-cursor and --lines/-n
+# See: https://github.com/systemd/systemd/issues/31776
+CURSOR_FILE="$(mktemp)"
+journalctl -q -n 0 --cursor-file="$CURSOR_FILE"
+TIMESTAMP="$(journalctl -q -n 1 --cursor="$(<"$CURSOR_FILE")" --output=short-unix | cut -d ' ' -f 1 | cut -d '.' -f 1)"
+[[ -z "$(journalctl -q -n 10 --after-cursor="$(<"$CURSOR_FILE")" --until "@$((TIMESTAMP - 3))")" ]]
+rm -f "$CURSOR_FILE"
}
mkdir /tmp/blob1 /tmp/blob2
-echo data1 blob1 > /tmp/blob1/test1
-echo data1 blob2 > /tmp/blob2/test1
-echo data2 blob1 > /tmp/blob1/test2
-echo data2 blob2 > /tmp/blob2/test2
-echo invalid filename > /tmp/blob1/файл
-echo data3 > /tmp/external-test3
-echo avatardata > /tmp/external-avatar
+echo data1 blob1 >/tmp/blob1/test1
+echo data1 blob2 >/tmp/blob2/test1
+echo data2 blob1 >/tmp/blob1/test2
+echo data2 blob2 >/tmp/blob2/test2
+echo invalid filename >/tmp/blob1/файл
+echo data3 >/tmp/external-test3
+echo avatardata >/tmp/external-avatar
ln -s /tmp/external-avatar /tmp/external-avatar-lnk
dd if=/dev/urandom of=/tmp/external-barely-fits bs=1M count=64
dd if=/dev/urandom of=/tmp/external-toobig bs=1M count=65
umount /proc/version
rm -f "$TMP_KVER"
-# Check that invoking the tool under the uid0 alias name works
-uid0 ls /
-assert_eq "$(uid0 echo foo)" "foo"
+# Check that invoking the tool under the run0 alias name works
+run0 ls /
+assert_eq "$(run0 echo foo)" "foo"
# Check if we set some expected environment variables
for arg in "" "--user=root" "--user=testuser"; do
- assert_eq "$(uid0 ${arg:+"$arg"} bash -c 'echo $SUDO_USER')" "$USER"
- assert_eq "$(uid0 ${arg:+"$arg"} bash -c 'echo $SUDO_UID')" "$(id -u "$USER")"
- assert_eq "$(uid0 ${arg:+"$arg"} bash -c 'echo $SUDO_GID')" "$(id -u "$USER")"
+ assert_eq "$(run0 ${arg:+"$arg"} bash -c 'echo $SUDO_USER')" "$USER"
+ assert_eq "$(run0 ${arg:+"$arg"} bash -c 'echo $SUDO_UID')" "$(id -u "$USER")"
+ assert_eq "$(run0 ${arg:+"$arg"} bash -c 'echo $SUDO_GID')" "$(id -u "$USER")"
done
-# Let's chain a couple of uid0 calls together, for fun
-readarray -t cmdline < <(printf "%.0suid0\n" {0..31})
+# Let's chain a couple of run0 calls together, for fun
+readarray -t cmdline < <(printf "%.0srun0\n" {0..31})
assert_eq "$("${cmdline[@]}" bash -c 'echo $SUDO_USER')" "$USER"
args = parser.parse_args()
args.output.mkdir(exist_ok=True)
+ # Make sure we don't inherit any setgid/setuid bit or such.
+ args.output.chmod(mode=0o755)
for exe in args.executables:
extract_interfaces_xml(args.output, exe)
cd "${MESON_SOURCE_ROOT:?}"
+if [ -e .git ]; then
+ git config submodule.recurse true
+ git config fetch.recurseSubmodules on-demand
+ git config push.recurseSubmodules no
+fi
+
if [ ! -f .git/hooks/pre-commit.sample ] || [ -f .git/hooks/pre-commit ]; then
exit 2 # not needed
fi
[Service]
Environment=HOME=/root
WorkingDirectory=-/root
-ExecStartPre=-{{BINDIR}}/plymouth --wait quit
+ExecStartPre=-plymouth --wait quit
ExecStart=-{{LIBEXECDIR}}/systemd-sulogin-shell emergency
Type=idle
StandardInput=tty-force
{ 'file' : 'sockets.target' },
{ 'file' : 'soft-reboot.target' },
{ 'file' : 'sound.target' },
+ { 'file' : 'ssh-access.target' },
{
'file' : 'suspend-then-hibernate.target',
'conditions' : ['ENABLE_HIBERNATE'],
'conditions' : ['ENABLE_BOOTLOADER'],
},
{
- 'file' : 'systemd-bootctl@.service.in',
+ 'file' : 'systemd-bootctl@.service',
'conditions' : ['ENABLE_BOOTLOADER'],
},
{
{ 'file' : 'systemd-reboot.service' },
{ 'file' : 'systemd-remount-fs.service.in' },
{
- 'file' : 'systemd-repart.service.in',
+ 'file' : 'systemd-repart.service',
'conditions' : ['ENABLE_REPART'],
'symlinks' : ['sysinit.target.wants/', 'initrd-root-fs.target.wants/'],
},
[Service]
Environment=HOME=/root
WorkingDirectory=-/root
-ExecStartPre=-{{BINDIR}}/plymouth --wait quit
+ExecStartPre=-plymouth --wait quit
ExecStart=-{{LIBEXECDIR}}/systemd-sulogin-shell rescue
Type=idle
StandardInput=tty-force
--- /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=SSH Access Available
+Documentation=man:systemd.special(7)
ConditionVirtualization=no
ConditionDirectoryNotEmpty=/sys/class/power_supply/
ConditionKernelCommandLine=!systemd.battery_check=0
+ConditionKernelCommandLine=!systemd.battery-check=0
AssertPathExists=/etc/initrd-release
DefaultDependencies=no
After=plymouth-start.service
# (at your option) any later version.
[Unit]
-Description=Boot Control (Varlink)
+Description=Boot Entries Service Socket
Documentation=man:bootctl(1)
DefaultDependencies=no
After=local-fs.target
# (at your option) any later version.
[Unit]
-Description=Boot Control (Varlink)
+Description=Boot Entries Service
Documentation=man:bootctl(1)
DefaultDependencies=no
Conflicts=shutdown.target
[Service]
Environment=LISTEN_FDNAMES=varlink
-ExecStart={{BINDIR}}/bootctl
+ExecStart=bootctl
# (at your option) any later version.
[Unit]
-Description=Credential Encryption/Decryption (Varlink)
+Description=Credential Encryption/Decryption
Documentation=man:systemd-creds(1)
DefaultDependencies=no
Before=sockets.target
# (at your option) any later version.
[Unit]
-Description=Credential Encryption/Decryption (Varlink)
+Description=Credential Encryption/Decryption
Documentation=man:systemd-creds(1)
DefaultDependencies=no
Conflicts=shutdown.target initrd-switch-root.target
# (at your option) any later version.
[Unit]
-Description=Hostname Service Varlink Socket
+Description=Hostname Service Socket
Documentation=man:systemd-hostnamed.service(8)
Documentation=man:hostname(5)
Documentation=man:machine-info(5)
# (at your option) any later version.
[Unit]
-Description=Journal Socket
+Description=Journal Sockets
Documentation=man:systemd-journald.service(8) man:journald.conf(5)
DefaultDependencies=no
Before=sockets.target
# (at your option) any later version.
[Unit]
-Description=Journal Socket for Namespace %i
+Description=Journal Sockets for Namespace %i
Documentation=man:systemd-journald.service(8) man:journald.conf(5)
StopWhenUnneeded=yes
PassSecurity=yes
ReceiveBuffer=8M
SendBuffer=8M
+
+[Install]
+WantedBy=sockets.target
# (at your option) any later version.
[Unit]
-Description=Commit a transient machine-id on disk
+Description=Save Transient machine-id to Disk
Documentation=man:systemd-machine-id-commit.service(8)
DefaultDependencies=no
Conflicts=shutdown.target
ConditionDirectoryNotEmpty=|/etc/modules-load.d
ConditionDirectoryNotEmpty=|/run/modules-load.d
ConditionKernelCommandLine=|modules-load
+ConditionKernelCommandLine=|modules_load
ConditionKernelCommandLine=|rd.modules-load
+ConditionKernelCommandLine=|rd.modules_load
[Service]
Type=oneshot
ExecStart=!!{{LIBEXECDIR}}/systemd-networkd
FileDescriptorStoreMax=512
ImportCredential=network.wireguard.*
-InaccessiblePaths=-/boot -/efi
LockPersonality=yes
MemoryDenyWriteExecute=yes
NoNewPrivileges=yes
ProtectHome=yes
ProtectKernelLogs=yes
ProtectKernelModules=yes
-ProtectSystem=full
+ProtectSystem=strict
Restart=on-failure
RestartKillSignal=SIGUSR2
RestartSec=0
# (at your option) any later version.
[Unit]
-Description=TPM2 PCR Extension (Varlink)
+Description=TPM PCR Measurements
Documentation=man:systemd-pcrextend(8)
DefaultDependencies=no
After=tpm2.target
# (at your option) any later version.
[Unit]
-Description=TPM2 PCR Extension (Varlink)
+Description=TPM PCR Measurements
Documentation=man:systemd-pcrphase.service(8)
DefaultDependencies=no
After=tpm2.target
# (at your option) any later version.
[Unit]
-Description=TPM2 PCR Root File System Measurement
+Description=TPM PCR Root File System Measurement
Documentation=man:systemd-pcrfs-root.service(8)
DefaultDependencies=no
Conflicts=shutdown.target
# (at your option) any later version.
[Unit]
-Description=TPM2 PCR File System Measurement of %f
+Description=TPM PCR File System Measurement of %f
Documentation=man:systemd-pcrfs@.service(8)
DefaultDependencies=no
BindsTo=%i.mount
# (at your option) any later version.
[Unit]
-Description=Lock File Systems to TPM2 PCR Policy
+Description=Lock File Systems to TPM PCR Policy
Documentation=man:systemd-pcrlock(8)
DefaultDependencies=no
Conflicts=shutdown.target
# (at your option) any later version.
[Unit]
-Description=Lock Firmware Code to TPM2 PCR Policy
+Description=Lock Firmware Code to TPM PCR Policy
Documentation=man:systemd-pcrlock(8)
DefaultDependencies=no
Conflicts=shutdown.target
# (at your option) any later version.
[Unit]
-Description=Lock Firmware Configuration to TPM2 PCR Policy
+Description=Lock Firmware Configuration to TPM PCR Policy
Documentation=man:systemd-pcrlock(8)
DefaultDependencies=no
Conflicts=shutdown.target
# (at your option) any later version.
[Unit]
-Description=Lock Machine ID to TPM2 PCR Policy
+Description=Lock Machine ID to TPM PCR Policy
Documentation=man:systemd-pcrlock(8)
DefaultDependencies=no
Conflicts=shutdown.target
# (at your option) any later version.
[Unit]
-Description=Make TPM2 PCR Policy
+Description=Make TPM PCR Policy
Documentation=man:systemd-pcrlock(8)
DefaultDependencies=no
Conflicts=shutdown.target
# (at your option) any later version.
[Unit]
-Description=Lock UEFI SecureBoot Authority to TPM2 PCR Policy
+Description=Lock UEFI SecureBoot Authority to TPM PCR Policy
Documentation=man:systemd-pcrlock(8)
DefaultDependencies=no
Conflicts=shutdown.target
# (at your option) any later version.
[Unit]
-Description=Lock UEFI SecureBoot Policy to TPM2 PCR Policy
+Description=Lock UEFI SecureBoot Policy to TPM PCR Policy
Documentation=man:systemd-pcrlock(8)
DefaultDependencies=no
Conflicts=shutdown.target
# (at your option) any later version.
[Unit]
-Description=Make TPM2 PCR Policy (Varlink)
+Description=Make TPM PCR Policy
Documentation=man:systemd-pcrlock(8)
DefaultDependencies=no
After=tpm2.target
# (at your option) any later version.
[Unit]
-Description=Make TPM2 PCR Policy (Varlink)
+Description=Make TPM PCR Policy
Documentation=man:systemd-pcrlock(8)
DefaultDependencies=no
Conflicts=shutdown.target
# (at your option) any later version.
[Unit]
-Description=TPM2 PCR Machine ID Measurement
+Description=TPM PCR Machine ID Measurement
Documentation=man:systemd-pcrmachine.service(8)
DefaultDependencies=no
Conflicts=shutdown.target
# (at your option) any later version.
[Unit]
-Description=TPM2 PCR Barrier (initrd)
+Description=TPM PCR Barrier (initrd)
Documentation=man:systemd-pcrphase-initrd.service(8)
DefaultDependencies=no
Conflicts=shutdown.target initrd-switch-root.target
# (at your option) any later version.
[Unit]
-Description=TPM2 PCR Barrier (Initialization)
+Description=TPM PCR Barrier (Initialization)
Documentation=man:systemd-pcrphase-sysinit.service(8)
DefaultDependencies=no
Conflicts=shutdown.target
# (at your option) any later version.
[Unit]
-Description=TPM2 PCR Barrier (User)
+Description=TPM PCR Barrier (User)
Documentation=man:systemd-pcrphase.service(8)
After=remote-fs.target remote-cryptsetup.target tpm2.target
Before=systemd-user-sessions.service
[Service]
Type=oneshot
RemainAfterExit=yes
-ExecStart={{BINDIR}}/systemd-repart --dry-run=no
+ExecStart=systemd-repart --dry-run=no
# The tool returns 76 if it can't find the root block device
SuccessExitStatus=76
# (at your option) any later version.
[Unit]
-Description=System Extension Image Management (Varlink)
+Description=System Extension Image Management
Documentation=man:systemd-sysext(8)
DefaultDependencies=no
After=local-fs.target
# (at your option) any later version.
[Unit]
-Description=System Extension Image Management (Varlink)
+Description=System Extension Image Management
Documentation=man:systemd-sysext(8)
DefaultDependencies=no
After=local-fs.target
# (at your option) any later version.
[Unit]
-Description=TPM2 SRK Setup (Early)
+Description=Early TPM SRK Setup
Documentation=man:systemd-tpm2-setup.service(8)
DefaultDependencies=no
Conflicts=shutdown.target
[Service]
Type=oneshot
RemainAfterExit=yes
-ExecStart={{LIBEXECDIR}}/systemd-tpm2-setup --early=yes
+ExecStart={{LIBEXECDIR}}/systemd-tpm2-setup --early=yes --graceful
# (at your option) any later version.
[Unit]
-Description=TPM2 SRK Setup
+Description=TPM SRK Setup
Documentation=man:systemd-tpm2-setup.service(8)
DefaultDependencies=no
Conflicts=shutdown.target
[Service]
Type=oneshot
RemainAfterExit=yes
-ExecStart={{LIBEXECDIR}}/systemd-tpm2-setup
+ExecStart={{LIBEXECDIR}}/systemd-tpm2-setup --graceful