]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #31777 from keszybz/unit-retitling-and-comments
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Fri, 15 Mar 2024 14:57:10 +0000 (15:57 +0100)
committerGitHub <noreply@github.com>
Fri, 15 Mar 2024 14:57:10 +0000 (15:57 +0100)
Unit retitling and comments

62 files changed:
.github/workflows/cflite_pr.yml
.github/workflows/cifuzz.yml
NEWS
TODO
docs/CONTAINER_INTERFACE.md
docs/VM_INTERFACE.md [new file with mode: 0644]
docs/WRITING_VM_AND_CONTAINER_MANAGERS.md
man/rules/meson.build
man/sd_journal_stream_fd.xml
man/sd_notify.xml
man/systemd-bless-boot.service.xml
man/systemd-cat.xml
man/systemd-soft-reboot.service.xml
man/systemd.service.xml
man/systemd.special.xml
man/systemd.xml
po/POTFILES.skip
shell-completion/bash/systemd-cat
shell-completion/zsh/_systemd
src/basic/fs-util.c
src/basic/fs-util.h
src/basic/path-util.c
src/basic/path-util.h
src/basic/stat-util.c
src/basic/stat-util.h
src/basic/tmpfile-util.c
src/boot/bless-boot.c
src/core/exec-invoke.c
src/core/main.c
src/core/manager.c
src/core/manager.h
src/core/target.c
src/core/unit.c
src/core/unit.h
src/journal/cat.c
src/libsystemd/libsystemd.sym
src/libsystemd/sd-journal/journal-send.c
src/libsystemd/sd-journal/journal-send.h
src/libsystemd/sd-journal/sd-journal.c
src/network/networkd-address.c
src/network/networkd-dhcp-server.c
src/network/networkd-dhcp-server.h
src/network/networkd-link.c
src/network/networkd-queue.c
src/network/networkd-queue.h
src/network/networkd-route.c
src/nspawn/nspawn.c
src/shared/creds-util.c
src/shared/hostname-setup.c
src/shared/json.c
src/shared/json.h
src/shared/machine-id-setup.c
src/ssh-generator/ssh-generator.c
src/systemd/sd-journal.h
src/test/meson.build
src/test/test-dirent-util.c [new file with mode: 0644]
src/test/test-fs-util.c
src/test/test-path-util.c
test/units/testsuite-04.cat.sh [new file with mode: 0755]
units/meson.build
units/ssh-access.target [new file with mode: 0644]
units/systemd-journald@.socket

index 707ea0b6ba625996e7736b38a4dbc1fc0a1bf117..bf7a14e356ac94c2b208bff0074b23666b59433d 100644 (file)
@@ -23,6 +23,7 @@ jobs:
       matrix:
         sanitizer: [address, undefined, memory]
     steps:
+    - run: sudo sysctl -w vm.mmap_rnd_bits=28
     - name: Build Fuzzers
       id: build
       uses: google/clusterfuzzlite/actions/build_fuzzers@v1
index a12ad9335f9d00ae230ab93b44caccf1752b9799..3aaaa3fd751f6e438e3e692baa9de0ed65fef380 100644 (file)
@@ -39,6 +39,7 @@ jobs:
       security-events: write
 
     steps:
+      - run: sudo sysctl -w vm.mmap_rnd_bits=28
       - name: Build Fuzzers
         id: build
         uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
diff --git a/NEWS b/NEWS
index 86b7ba77680dc3145e89506123820f163f94e48e..e7861b3303515e7bfafcc3363d9d1292ab878f60 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -8,24 +8,25 @@ CHANGES WITH 256 in spe:
           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
@@ -36,18 +37,435 @@ CHANGES WITH 256 in spe:
           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 embedded in the name, and they may be ordered by version
+          and the newest one can be reliably 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 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' 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 'uid0', 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 fed 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 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.
+
+        * The remaining documentation that was on
+          https://freedesktop.org/wiki/Software/systemd/ has been moved to
+          https://systemd.io.
+
 
 CHANGES WITH 255:
 
diff --git a/TODO b/TODO
index 5fd4fdcf69cd9e98059a7267a949c0c997ca6983..3b76e98bdeb7906e8a43908ecdc666c61e5aa2bc 100644 (file)
--- a/TODO
+++ b/TODO
@@ -130,6 +130,11 @@ Deprecations and removals:
 
 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
@@ -140,11 +145,10 @@ Features:
   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,
@@ -190,10 +194,6 @@ Features:
   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
@@ -932,6 +932,8 @@ Features:
   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)
 
@@ -1419,6 +1421,9 @@ Features:
 
 * 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".
 
@@ -2545,6 +2550,7 @@ Features:
    - allow Name= to be specified repeatedly in the [Match] section. Maybe also
      support Name=foo*|bar*|baz ?
    - whenever uplink info changes, make DHCP server send out FORCERENEW
+   - figure out spelling: NamespaceId vs. NamespaceNSID
 
 * in networkd, when matching device types, fix up DEVTYPE rubbish the kernel passes to us
 
index dcecdecc3eb71d7f8d1d2317ba6cc4b1d1994c33..549dae31fe57bda7f8a4b3706fd8416f40fa674c 100644 (file)
@@ -8,7 +8,7 @@ SPDX-License-Identifier: LGPL-2.1-or-later
 # 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
@@ -121,7 +121,7 @@ manager, please consider supporting the following interfaces.
    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
@@ -131,7 +131,7 @@ manager, please consider supporting the following interfaces.
    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`
@@ -165,10 +165,15 @@ manager, please consider supporting the following interfaces.
    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)
@@ -190,12 +195,14 @@ manager, please consider supporting the following interfaces.
    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
 
diff --git a/docs/VM_INTERFACE.md b/docs/VM_INTERFACE.md
new file mode 100644 (file)
index 0000000..abe7067
--- /dev/null
@@ -0,0 +1,54 @@
+---
+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.
index 4d1b649df35bc4f8a2074edcc8f5c75730b41a84..272261c5734e653403a74702894fc40cb6c259f4 100644 (file)
@@ -5,25 +5,50 @@ layout: default
 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).
index 1f07e606c9689f75f6ac1bf16f4ac9771132f099..465ea4e4b3ece15cf278a337f50607efd8e620b1 100644 (file)
@@ -795,7 +795,7 @@ manpages = [
    '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'],
index 13939ff19e4e5dadfda32e38c61f047d196d77ec..ff0d2eedd939c6c014f4474098bb2761bcc6c286 100644 (file)
@@ -17,6 +17,7 @@
 
   <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>
index a56d03946868311bfccd0d332fbc25c37008223b..d8fe6468a29cc8040acfbad6efb45e3ec6448ec5 100644 (file)
     </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>
index 043ee712540e3da7017797ecff12a9e29d3d832a..7ace7703b9aab14480fd151ebe549ad3a8f6efb1 100644 (file)
@@ -37,7 +37,7 @@
     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
index 040da7c5c237c3629ab6865b2e9311ca89f0d68b..280492dea592bd7d349c66e6c22224b81a51311d 100644 (file)
         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>
index 138c919ee73a9181a15141e8c602b339bc420e95..354a24679a246943fcef23f4e77500bf4a2961d4 100644 (file)
       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
index 154a7a2e66a06aa67b24e6bded5d8063bfc2970c..67a3930a28a578be78fb360cd5d3375802822033 100644 (file)
 
           <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>
index 988b7175ba8dd90ebd44074efa2ab896f7fc3cf9..5980a8f93041b45ae700493a46010c8a26973660 100644 (file)
@@ -83,6 +83,7 @@
     <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>
index 960df97f0b358a1b861e988241f72767a3679901..b66707faba6cc96e5e7b24dc04b5e18ad4a207e3 100644 (file)
   <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
+          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>.</para>
 
-          <para>This feature is useful for hypervisors/VMMs or other processes on the host to receive a
+          <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>
index befe6a08c564f665965264d53be33d4800858b5d..84d56c8a2239b8665c3438e0475f5d1f6108944c 100644 (file)
@@ -1,3 +1,4 @@
+pkg/debian
 src/basic/parse-util.c
 src/boot/efi/addon.c
 src/boot/efi/boot.c
index 6ccc7bf000f19c45617861a9bb8b3f19535cd844..0d7e3d7a893c53cc66786dd19eedcd7281ef7fc8 100644 (file)
@@ -31,7 +31,7 @@ _systemd_cat() {
 
     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
@@ -47,6 +47,9 @@ _systemd_cat() {
             --level-prefix)
                 comps='yes no'
                 ;;
+            --namespace)
+                comps=$(journalctl --list-namespaces --output=cat 2>/dev/null)
+                ;;
         esac
         COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
         return 0
index 863631571efe168e775bdc2d064a66c5c2fd23c3..44476144c118493c677b96d7f98307324b5332ff 100644 (file)
@@ -19,6 +19,7 @@ case "$service" in
             {-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)
index 5bc7d2f95beb568c89c7dafe0d24c21739c9d3ba..7f0b5814be540189366bba72c97b5c496674c2da 100644 (file)
@@ -1236,3 +1236,99 @@ int xopenat_lock_full(
 
         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;
+}
index 6a1e2e76d14929fc246d988e511c33d4ddd45b38..58a7d0a74595cfc3fd02ecefca5a80748688b29d 100644 (file)
@@ -146,3 +146,7 @@ int xopenat_lock_full(int dir_fd, const char *path, int open_flags, XOpenFlags x
 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);
index 6810bf66aa32f8b7459fc8ab0c8f96fd4bf3e638..05a21f8f8e271deab4a9f693d9ab478bb64a8383 100644 (file)
@@ -1336,6 +1336,20 @@ bool dot_or_dot_dot(const char *path) {
         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
index 39b6714525e95d20170a32ae2c15760dcb752d25..47699e6414210e7efb2f9464068019664f5beda3 100644 (file)
@@ -76,6 +76,10 @@ char* path_extend_internal(char **x, ...);
 #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;
@@ -201,6 +205,8 @@ bool valid_device_allow_pattern(const char *path);
 
 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;
 
index 4040b172268f8b02f7a506a843de2877dc6c81d0..c208d7c59dcd3d47522bfdcb350ba77d855dab12 100644 (file)
@@ -239,7 +239,7 @@ int null_or_empty_path_with_root(const char *fn, const char *root) {
         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);
index 06bd9fdd97b7840c41328d1aeb0a05e6c367a5be..7556f8f59a6ff44afbe0942fc731b656b9c3fa44 100644 (file)
@@ -45,6 +45,7 @@ static inline int null_or_empty_path(const char *fn) {
         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);
index e77ca9424892d7a113b258c388a04edabfa9282e..3a3f7dcc0ff1c7b1e106b3b26d309a234a92c6b9 100644 (file)
@@ -330,28 +330,7 @@ int fopen_tmpfile_linkable(const char *target, int flags, char **ret_path, FILE
         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);
@@ -370,33 +349,14 @@ int link_tmpfile_at(int fd, int dir_fd, const char *path, const char *target, Li
                         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);
index 0c0b4f23c7709a170f0e315655180e8f39f55df4..07e4e306a3ea83fc269a66ee1e295ffa4b374ef2 100644 (file)
@@ -316,13 +316,6 @@ static int make_bad(const char *prefix, uint64_t done, const char *suffix, char
         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;
@@ -370,14 +363,14 @@ static int verb_status(int argc, char *argv[], void *userdata) {
                         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;
                 }
@@ -385,7 +378,7 @@ static int verb_status(int argc, char *argv[], void *userdata) {
                 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;
                 }
@@ -445,17 +438,17 @@ static int verb_set(int argc, char *argv[], void *userdata) {
                 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)
@@ -474,7 +467,7 @@ static int verb_set(int argc, char *argv[], void *userdata) {
                         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");
 
index 0db13bfa8807d3c7c960ff393762aa3e4dcfccd2..a1401f3e4903a9586778cffadfacb0f1472c5e87 100644 (file)
@@ -41,6 +41,7 @@
 #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"
@@ -159,9 +160,11 @@ static int connect_journal_socket(
         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();
index 07ec98252e8465d6958ad5c790455fd09af3aa61..551fb425c43e2ffb286fae8d50715671d51c7cc3 100644 (file)
@@ -3282,7 +3282,8 @@ finish:
 #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. */
@@ -3295,7 +3296,8 @@ finish:
 
         /* 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);
index d307c07a624eb392bc9707234e593e1837826933..7eeb7f3a26ba9130f75dbdc54a0702a2286cc7b5 100644 (file)
@@ -264,12 +264,11 @@ static void manager_print_jobs_in_progress(Manager *m) {
                                       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;
 }
 
@@ -483,21 +482,19 @@ static int enable_special_signals(Manager *m) {
         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;
@@ -597,6 +594,17 @@ static int manager_setup_signals(Manager *m) {
         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);
 
@@ -2869,8 +2877,8 @@ static void manager_start_special(Manager *m, const char *name, JobMode mode) {
 
         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;
 }
 
@@ -3362,16 +3370,18 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
         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);
@@ -3390,21 +3400,22 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
                         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;
 
@@ -3422,6 +3433,27 @@ void manager_send_unit_plymouth(Manager *m, Unit *u) {
                                "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);
 
@@ -3731,7 +3763,7 @@ static void manager_notify_finished(Manager *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);
@@ -3740,7 +3772,7 @@ static void user_manager_send_ready(Manager *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)
@@ -3750,14 +3782,19 @@ static void user_manager_send_ready(Manager *m) {
         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)
@@ -3781,7 +3818,7 @@ static void manager_check_basic_target(Manager *m) {
                 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);
@@ -3812,7 +3849,7 @@ void manager_check_finished(Manager *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);
@@ -3842,7 +3879,7 @@ void manager_send_reloading(Manager *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));
 
index 9f1a21b22dbe82592f2ff77ceb77875f8fcc33e9..4d82c4a6a0daa7f91418057b61eca7ec0c118cd5 100644 (file)
@@ -575,6 +575,7 @@ void manager_reset_failed(Manager *m);
 
 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);
 
index 8f2a331f92b9df10cfb1867bb4efb78315df91c3..3851f21442dfe2578a62541ca13b037c47eba5b4 100644 (file)
@@ -213,4 +213,6 @@ const UnitVTable target_vtable = {
                         [JOB_DONE]       = "Stopped target %s.",
                 },
         },
+
+        .notify_supervisor = true,
 };
index 2c6a0b3e5727c0e5c3302881c113a9248e6d20ed..c0f802a137568db44c6e451c2967b654cfc2f007 100644 (file)
@@ -2678,12 +2678,14 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
 
                         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);
                 }
 
index b1cc2c2d01311f12f91964751ac658e86788263e..7134d362fe11120bea2b4e0d8fbb353b5086c0a3 100644 (file)
@@ -731,6 +731,9 @@ typedef struct UnitVTable {
         /* 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;
index 0325add12f4d7f01d3af712b14e1fcb37c2edfad..1634f30b44e1958940ed364f31384ba354624397 100644 (file)
@@ -24,6 +24,7 @@
 #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;
@@ -44,6 +45,7 @@ static int help(void) {
                "  -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(),
@@ -58,7 +60,8 @@ static int parse_argv(int argc, char *argv[]) {
         enum {
                 ARG_VERSION = 0x100,
                 ARG_STDERR_PRIORITY,
-                ARG_LEVEL_PREFIX
+                ARG_LEVEL_PREFIX,
+                ARG_NAMESPACE,
         };
 
         static const struct option options[] = {
@@ -68,6 +71,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "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       },
                 {}
         };
 
@@ -117,6 +121,13 @@ static int parse_argv(int argc, char *argv[]) {
                                 return r;
                         break;
 
+                case ARG_NAMESPACE:
+                        if (isempty(optarg))
+                                arg_namespace = NULL;
+                        else
+                                arg_namespace = optarg;
+                        break;
+
                 case '?':
                         return -EINVAL;
 
@@ -137,12 +148,12 @@ static int run(int argc, char *argv[]) {
         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");
         }
index 22cf48c5f8db7b05c3479edf595d243a360b9a46..d23da4c1515c84cd4e54fea36a117c3478d1f9ad 100644 (file)
@@ -839,4 +839,5 @@ LIBSYSTEMD_256 {
 global:
         sd_bus_creds_get_pidfd_dup;
         sd_bus_creds_new_from_pidfd;
+        sd_journal_stream_fd_with_namespace;
 } LIBSYSTEMD_255;
index be23b2fe75d631f03f032f984ba2f5eb0e020049..650581addf41bee70a18c2c0394180b60393ba95 100644 (file)
@@ -398,20 +398,28 @@ _public_ int sd_journal_perror(const char *message) {
         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;
 
@@ -422,6 +430,9 @@ _public_ int sd_journal_stream_fd(const char *identifier, int priority, int leve
 
         identifier = strempty(identifier);
 
+        char *header;
+        size_t l;
+
         l = strlen(identifier);
         header = newa(char, l + 1 + 1 + 2 + 2 + 2 + 2 + 2);
 
@@ -446,6 +457,10 @@ _public_ int sd_journal_stream_fd(const char *identifier, int priority, int leve
         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;
index 24315e249b32d9d0f7a88189d487dd98ac0d0305..6fe6325090ec768c08c58af37babfbe1aa33a152 100644 (file)
@@ -2,6 +2,23 @@
 #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;                                                                   \
+        })
index fba436fbe3f0e1afadb3b86f45c2d3cb7c371989..ef57f156ac5910378b877302106b8b9356416de7 100644 (file)
@@ -1473,17 +1473,6 @@ static void track_file_disposition(sd_journal *j, JournalFile *f) {
                 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,
@@ -1503,7 +1492,7 @@ static int add_any_file(
                         /* 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) {
@@ -1811,7 +1800,7 @@ static int directory_open(sd_journal *j, const char *path, DIR **ret) {
         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;
 
index 49a43753c5e7bdffa1050573fc795cd60b9e5b4f..d9c3dae85c58b9d6a3ab8088b1f451827a73d401 100644 (file)
@@ -1415,43 +1415,6 @@ void link_foreignize_addresses(Link *link) {
                 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;
 
@@ -1524,21 +1487,67 @@ static int address_configure(const Address *address, const struct ifa_cacheinfo
         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) {
@@ -1550,7 +1559,26 @@ 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);
@@ -1595,19 +1623,14 @@ int link_request_address(
                 /* 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;
@@ -1616,12 +1639,6 @@ int link_request_address(
                 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,
index 57019400e6a28effc4c0021297194be236c3bc07..eddbaad917ce5e92ff440e1a2628b3305168a3d9 100644 (file)
@@ -144,7 +144,7 @@ int network_adjust_dhcp_server(Network *network, Set **addresses) {
         return 0;
 }
 
-static int link_start_dhcp4_server(Link *link) {
+int link_start_dhcp4_server(Link *link) {
         int r;
 
         assert(link);
index b845a6d1c777f41467dc909eb512e161277ee71c..dbc7d95cadba470a3f94f01f8ba99f19c5e607a5 100644 (file)
@@ -12,6 +12,7 @@ int network_adjust_dhcp_server(Network *network, Set **addresses);
 
 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);
index 650e94c31378626b3bb38dcfc8fd78bb1d5a1a91..3e8aa9e37aaadedf31dd6799558a7b8bfd1cc513 100644 (file)
@@ -713,11 +713,9 @@ static int link_acquire_dynamic_ipv4_conf(Link *link) {
                 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)
index f1dd6b44d251cdc71897ab014900e04593b28138..98c629f161dc6bf556f648d18cfd889cef53d29d 100644 (file)
@@ -216,6 +216,23 @@ int link_queue_request_full(
                            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;
index bdedc775377b9c56ed1df117cc01032757fe4642..e35cd73efd944def8120bce462d904cef36e557a 100644 (file)
@@ -107,6 +107,8 @@ int link_queue_request_full(
                 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,
index 3c5de98e7c96181439a0b640855f4d0750302890..efe378a457289beac0309786376b44fa90eedaf1 100644 (file)
@@ -780,16 +780,7 @@ static int route_requeue_request(Request *req, Link *link, const Route *route) {
         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)
index c415d3cec1416a7eb53b8e547072da18acac6194..3189c03639535eb92c2bd585204371273accecce 100644 (file)
@@ -4408,6 +4408,17 @@ static int nspawn_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t r
         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)
index 2d5846a06ffe662d1fb1a6e88d76463c4c6bd3cd..ba8aee335541aab8add01185327f622b6b5bc8a8 100644 (file)
@@ -28,6 +28,7 @@
 #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"
@@ -377,22 +378,9 @@ static int make_credential_host_secret(
         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)
@@ -412,26 +400,21 @@ static int make_credential_host_secret(
         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;
         }
 
@@ -439,10 +422,8 @@ static int make_credential_host_secret(
                 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));
         }
index c538506eaf616e626284884bdd58584c77a05e32..6cfd4b54bf631c053fe84088b4223725218b887b 100644 (file)
@@ -6,6 +6,8 @@
 #include <sys/utsname.h>
 #include <unistd.h>
 
+#include "sd-daemon.h"
+
 #include "alloc-util.h"
 #include "creds-util.h"
 #include "fd-util.h"
@@ -13,6 +15,7 @@
 #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"
@@ -24,7 +27,8 @@ static int sethostname_idempotent_full(const char *s, bool really) {
 
         assert(s);
 
-        assert_se(uname(&u) >= 0);
+        if (uname(&u) < 0)
+                return -errno;
 
         if (streq_ptr(s, u.nodename))
                 return 0;
@@ -41,34 +45,33 @@ int sethostname_idempotent(const char *s) {
 }
 
 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;
 }
 
@@ -147,74 +150,64 @@ void hostname_update_source_hint(const char *hostname, HostnameSource source) {
                 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);
@@ -230,7 +223,11 @@ int hostname_setup(bool 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[] = {
index 7ec6368e1eccbc1e36f1cea920514b490aafc24b..edfae5b47be12b4fb85177c98526456535cdd4f8 100644 (file)
@@ -4812,6 +4812,42 @@ int json_dispatch_uint16(const char *name, JsonVariant *variant, JsonDispatchFla
         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;
index 9c8448f728b82e450de8034c1c2c7d5e18cf832c..ec6274ad8d9ec4cde7bf62aa444d43e0e18e77ea 100644 (file)
@@ -421,6 +421,8 @@ int json_dispatch_uint32(const char *name, JsonVariant *variant, JsonDispatchFla
 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);
index f821ea7c9d693585777d6c0d46b9f47ad4af7054..df99b0b009537ca48df2126e793ac93755db2fe2 100644 (file)
@@ -5,6 +5,7 @@
 #include <sys/mount.h>
 #include <unistd.h>
 
+#include "sd-daemon.h"
 #include "sd-id128.h"
 
 #include "alloc-util.h"
@@ -12,6 +13,7 @@
 #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"
@@ -141,8 +143,8 @@ int machine_id_setup(const char *root, bool force_transient, sd_id128_t machine_
         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);
@@ -207,6 +209,9 @@ int machine_id_setup(const char *root, bool force_transient, sd_id128_t machine_
                 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;
 
index 08532690a9c7581e56c35b47b5646df942c2330b..613e88dd194f699535fd85221a6cb053f894f17f 100644 (file)
@@ -128,7 +128,8 @@ static int write_socket_unit(
                 const char *dest,
                 const char *unit,
                 const char *listen_stream,
-                const char *comment) {
+                const char *comment,
+                bool with_ssh_access_target_dependency) {
 
         int r;
 
@@ -149,13 +150,21 @@ static int write_socket_unit(
         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);
@@ -230,7 +239,8 @@ static int add_vsock_socket(
                         dest,
                         "sshd-vsock.socket",
                         "vsock::22",
-                        "AF_VSOCK");
+                        "AF_VSOCK",
+                        /* with_ssh_access_target_dependency= */ true);
         if (r < 0)
                 return r;
 
@@ -264,7 +274,8 @@ static int add_local_unix_socket(
                         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;
 
@@ -320,7 +331,8 @@ static int add_export_unix_socket(
                         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;
 
@@ -370,7 +382,8 @@ static int add_extra_sockets(
                                 dest,
                                 socket ?: "sshd-extra.socket",
                                 *i,
-                                *i);
+                                *i,
+                                /* with_ssh_access_target_dependency= */ true);
                 if (r < 0)
                         return r;
 
index e4a67f048b8524111d3e1274d96a81844b8d8903..7434051ce1fb92a1d8b7aea760d50a63d3c0d5b3 100644 (file)
@@ -57,6 +57,7 @@ int sd_journal_perror_with_location(const char *file, const char *line, const ch
 #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 */
 
index e9e94637909a3b8926e9273da7424d0a74ee08e7..96f934b2191435d02722fe8d15f1d27c5bd9a644 100644 (file)
@@ -74,6 +74,7 @@ simple_tests += files(
         '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',
diff --git a/src/test/test-dirent-util.c b/src/test/test-dirent-util.c
new file mode 100644 (file)
index 0000000..f981697
--- /dev/null
@@ -0,0 +1,213 @@
+/* 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);
index b32feffd30333f19f3c2ad3cdd7af0316d6b8b88..b27c79fdc93d1ac8ae69ed22abb05e10d1bd6428 100644 (file)
@@ -753,6 +753,36 @@ TEST(xopenat_lock_full) {
         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;
index f5a425689a3f0a9481484e6916e481d0ea47a717..ca11bf3a29c854073bc031f1e9dd9d3c9fde252e 100644 (file)
@@ -1305,4 +1305,28 @@ TEST(print_MAX) {
         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);
diff --git a/test/units/testsuite-04.cat.sh b/test/units/testsuite-04.cat.sh
new file mode 100755 (executable)
index 0000000..bef3e18
--- /dev/null
@@ -0,0 +1,15 @@
+#!/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
index 1458cc5986765a91bc6e464b4dc4a953e9b62285..151d3bc6098a5f3217c95f53c5557ef67dae921f 100644 (file)
@@ -203,6 +203,7 @@ units = [
         { 'file' : 'sockets.target' },
         { 'file' : 'soft-reboot.target' },
         { 'file' : 'sound.target' },
+        { 'file' : 'ssh-access.target' },
         {
           'file' : 'suspend-then-hibernate.target',
           'conditions' : ['ENABLE_HIBERNATE'],
diff --git a/units/ssh-access.target b/units/ssh-access.target
new file mode 100644 (file)
index 0000000..f9b6a4c
--- /dev/null
@@ -0,0 +1,12 @@
+#  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)
index bd686b5f69d5372a4f0cd2a5a147f9b58b062252..65813a5f6d7b8d71e2e030f0aa72ea0010eb1b36 100644 (file)
@@ -22,3 +22,6 @@ PassCredentials=yes
 PassSecurity=yes
 ReceiveBuffer=8M
 SendBuffer=8M
+
+[Install]
+WantedBy=sockets.target