chiark / gitweb /
Merge pull request #22 from elogind/dev_v232
authorSven Eden <yamakuzure@gmx.net>
Fri, 7 Jul 2017 13:18:23 +0000 (15:18 +0200)
committerGitHub <noreply@github.com>
Fri, 7 Jul 2017 13:18:23 +0000 (15:18 +0200)
Dev v232 merge to master

100 files changed:
.gitignore
.mailmap
Makefile-man.am
Makefile.am
NEWS
TODO
cb/elogind.cbp
coccinelle/free_and_replace.cocci [new file with mode: 0644]
configure.ac
man/less-variables.xml
man/sd-event.xml
man/sd_event_source_set_priority.xml
man/sd_id128_get_machine.xml
man/sd_notify.xml
man/standard-options.xml
src/basic/alloc-util.h
src/basic/audit-util.c
src/basic/capability-util.c
src/basic/cgroup-util.c
src/basic/cgroup-util.h
src/basic/def.h
src/basic/escape.c
src/basic/fileio.c
src/basic/fileio.h
src/basic/fs-util.c
src/basic/fs-util.h
src/basic/gunicode.c
src/basic/hostname-util.c
src/basic/list.h
src/basic/log.c
src/basic/log.h
src/basic/missing.h
src/basic/mount-util.c
src/basic/mount-util.h
src/basic/parse-util.c
src/basic/parse-util.h
src/basic/path-util.c
src/basic/path-util.h
src/basic/prioq.c
src/basic/proc-cmdline.c
src/basic/proc-cmdline.h
src/basic/process-util.h
src/basic/rm-rf.c
src/basic/set.h
src/basic/socket-util.c
src/basic/socket-util.h
src/basic/string-util.c
src/basic/string-util.h
src/basic/strv.c
src/basic/strv.h
src/basic/terminal-util.c
src/basic/terminal-util.h
src/basic/time-util.c
src/basic/time-util.h
src/basic/user-util.c
src/basic/user-util.h
src/basic/util.c
src/basic/util.h
src/basic/virt.c
src/basic/virt.h
src/core/cgroup.c
src/core/cgroup.h
src/core/mount-setup.c
src/libelogind/libelogind.sym
src/libelogind/sd-bus/bus-common-errors.c
src/libelogind/sd-bus/bus-error.c
src/libelogind/sd-bus/bus-internal.h
src/libelogind/sd-bus/bus-slot.c
src/libelogind/sd-bus/bus-track.c
src/libelogind/sd-bus/bus-track.h
src/libelogind/sd-bus/sd-bus.c
src/libelogind/sd-event/sd-event.c
src/libelogind/sd-id128/id128-util.c
src/libelogind/sd-id128/id128-util.h
src/libelogind/sd-id128/sd-id128.c
src/login/elogind-user.m4
src/login/elogind.c
src/login/loginctl.c
src/login/logind-button.c
src/login/logind-device.c
src/login/logind-inhibit.c
src/login/logind-seat.c
src/login/logind-session-dbus.c
src/login/logind-session.c
src/login/logind-user.c
src/login/logind-utmp.c
src/login/logind.c
src/shared/acl-util.c
src/shared/bus-util.c
src/shared/bus-util.h
src/shared/clean-ipc.c
src/shared/clean-ipc.h
src/shared/conf-parser.c
src/shared/conf-parser.h
src/shared/pager.c
src/shared/sleep-config.c
src/systemd/sd-bus.h
src/systemd/sd-id128.h
src/systemd/sd-messages.h
src/update-utmp/update-utmp.c

index 00e474d9b250e1de07867f791b18f89f9c5b2501..5450aaab18e3d301b459e06d41412be6ca0e8269 100644 (file)
@@ -1,6 +1,6 @@
 *.a
 *.cache
-*.html
+*.gch
 *.la
 *.lo
 *.log
@@ -37,6 +37,7 @@
 /exported
 /exported-*
 /hostnamectl
+/image.raw
 /install-tree
 /journalctl
 /libtool
@@ -90,6 +91,7 @@
 /systemd-machine-id-setup
 /systemd-machined
 /systemd-modules-load
+/systemd-mount
 /systemd-networkd
 /systemd-networkd-wait-online
 /systemd-notify
 /systemd-rc-local-generator
 /systemd-remount-fs
 /systemd-reply-password
-/systemd-resolve-host
+/systemd-resolve
 /systemd-resolved
 /systemd-rfkill
 /systemd-run
 /systemd-vconsole-setup
 /tags
 /test-acd
+/test-acl-util
 /test-af-list
 /test-alloc-util
 /test-architecture
 /test-arphrd-list
+/test-ask-password-api
 /test-async
 /test-audit-type
 /test-barrier
 /test-bus-policy
 /test-bus-server
 /test-bus-signature
+/test-bus-track
 /test-bus-zero-copy
 /test-calendarspec
 /test-cap-list
 /test-daemon
 /test-date
 /test-device-nodes
+/test-dnssec-complex
 /test-dhcp-client
 /test-dhcp-option
 /test-dhcp-server
 /test-dhcp6-client
 /test-dns-domain
+/test-dns-packet
+/test-dnssec
 /test-efi-disk.img
 /test-ellipsize
 /test-engine
-/test-env-replace
+/test-env-util
+/test-escape
 /test-event
 /test-execute
 /test-extract-word
+/test-fd-util
 /test-fdset
 /test-fileio
 /test-firewall-util
+/test-fs-util
 /test-fstab-util
+/test-glob-util
 /test-hashmap
+/test-hexdecoct
 /test-hostname
 /test-hostname-util
 /test-id128
 /test-inhibit
 /test-install
 /test-install-root
+/test-io-util
 /test-ipcrm
 /test-ipv4ll
 /test-ipv4ll-manual
 /test-ndisc-rs
 /test-netlink
 /test-netlink-manual
+/test-networkd-conf
 /test-network
 /test-network-tables
 /test-ns
+/test-nss
 /test-parse-util
+/test-patch-uid
 /test-path
 /test-path-lookup
 /test-path-util
 /test-prioq
+/test-proc-cmdline
 /test-process-util
 /test-pty
 /test-qcow2
 /test-ratelimit
 /test-replace-var
 /test-resolve
+/test-resolve-tables
 /test-ring
+/test-rlimit-util
 /test-sched-prio
+/test-seccomp
+/test-selinux
 /test-set
+/test-sizeof
 /test-sigbus
+/test-signal-util
 /test-siphash24
 /test-sleep
 /test-socket-util
-/test-ssd
+/test-stat-util
 /test-strbuf
 /test-string-util
 /test-strip-tab-ansi
index d56fb6784526798a9d141919ac25aa2c981a8b60..d007ba741e58c4dadd800901bb4a84e41c51d449 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -74,3 +74,18 @@ Thomas H. P. Andersen <phomes@gmail.com>
 Michael Olbrich <m.olbrich@pengutronix.de>
 Douglas Christman <DouglasChristman@gmail.com>
 Alexander Kuleshov <kuleshovmail@gmail.com> <0xAX@users.noreply.github.com>
+Andreas Henriksson <andreas@fatal.se>
+Daniel Rusek <mail@asciiwolf.com>
+Dennis Wassenberg <dennis.wassenberg@secunet.com>
+Reid Price <reid.price@gmail.com>
+Stefan Schweter <stefan@schweter.it>
+Seraphime Kirkovski <kirkseraph@gmail.com>
+Bart Rulon <barron@lexmark.com>
+Richard W.M. Jones <rjones@redhat.com>
+Roman Stingler <coolx67@gmx.at>
+Michael Hoy <rimmington@gmail.com>
+Tiago Levit <liamgliam@gmail.com>
+Eric Cook <llua@users.noreply.github.com>
+Lukáš Nykrýn <lnykryn@redhat.com>
+Heikki Kemppainen <heikki.kemppainen@nokia.com>
+Hendrik Brueckner <hbrueckner@users.noreply.github.com>
index 895b64bf0464a31ebdddaa2b3d9d9b48b5d4082d..cd82c48193bbab9d36bb331a33f192d212a5533d 100644 (file)
@@ -54,6 +54,7 @@ MANPAGES_ALIAS += \
        man/sd_event_source_unrefp.3 \
        man/sd_id128_from_string.3 \
        man/sd_id128_get_boot.3 \
+       man/sd_id128_get_invocation.3 \
        man/sd_machine_get_ifindices.3 \
        man/sd_notifyf.3 \
        man/sd_pid_notify.3 \
@@ -82,6 +83,7 @@ man/sd_event_source_set_io_fd.3: man/sd_event_add_io.3
 man/sd_event_source_unrefp.3: man/sd_event_source_unref.3
 man/sd_id128_from_string.3: man/sd_id128_to_string.3
 man/sd_id128_get_boot.3: man/sd_id128_get_machine.3
+man/sd_id128_get_invocation.3: man/sd_id128_get_machine.3
 man/sd_machine_get_ifindices.3: man/sd_machine_get_class.3
 man/sd_notifyf.3: man/sd_notify.3
 man/sd_pid_notify.3: man/sd_notify.3
@@ -156,6 +158,9 @@ man/sd_id128_from_string.html: man/sd_id128_to_string.html
 man/sd_id128_get_boot.html: man/sd_id128_get_machine.html
        $(html-alias)
 
+man/sd_id128_get_invocation.html: man/sd_id128_get_machine.html
+       $(html-alias)
+
 man/sd_machine_get_ifindices.html: man/sd_machine_get_class.html
        $(html-alias)
 
index 825057207c98b06ea151dfa55f1d9f1529e24c91..d53f242d4136da88e54d157c5bbcc12509f45349 100644 (file)
@@ -38,9 +38,9 @@ SUBDIRS = . po
 # Keep the test-suite.log
 .PRECIOUS: $(TEST_SUITE_LOG) Makefile
 
-LIBELOGIND_CURRENT=16
-LIBELOGIND_REVISION=4
-LIBELOGIND_AGE=16
+LIBELOGIND_CURRENT=17
+LIBELOGIND_REVISION=2
+LIBELOGIND_AGE=17
 
 # Dirs of external packages
 dbuspolicydir=@dbuspolicydir@
@@ -76,8 +76,6 @@ EXTRA_DIST =
 BUILT_SOURCES =
 INSTALL_EXEC_HOOKS =
 UNINSTALL_EXEC_HOOKS =
-INSTALL_DATA_HOOKS =
-UNINSTALL_DATA_HOOKS =
 DISTCLEAN_LOCAL_HOOKS =
 CLEAN_LOCAL_HOOKS =
 pkginclude_HEADERS =
@@ -96,6 +94,7 @@ dist_dbussystemservice_DATA =
 check_PROGRAMS =
 check_DATA =
 dist_rootlibexec_DATA =
+rootlib_LTLIBRARIES =
 tests=
 manual_tests =
 if ENABLE_TESTS
@@ -123,7 +122,6 @@ CLEANFILES = $(BUILT_SOURCES) \
        $(m4_files:.m4=)
 
 .PHONY: $(INSTALL_EXEC_HOOKS) $(UNINSTALL_EXEC_HOOKS) \
-       $(INSTALL_DATA_HOOKS) $(UNINSTALL_DATA_HOOKS) \
        $(DISTCLEAN_LOCAL_HOOKS) $(CLEAN_LOCAL_HOOKS)
 
 AM_CPPFLAGS = \
@@ -162,16 +160,6 @@ AM_CFLAGS = $(OUR_CFLAGS)
 AM_LDFLAGS = $(OUR_LDFLAGS)
 
 # ------------------------------------------------------------------------------
-define move-to-rootlibdir
-       if test "$(libdir)" != "$(rootlibdir)"; then \
-               $(MKDIR_P) $(DESTDIR)$(rootlibdir) && \
-               so_img_name=$$(readlink $(DESTDIR)$(libdir)/$$libname) && \
-               rm -f $(DESTDIR)$(libdir)/$$libname && \
-               $(LN_S) --relative -f $(DESTDIR)$(rootlibdir)/$$so_img_name $(DESTDIR)$(libdir)/$$libname && \
-               mv $(DESTDIR)$(libdir)/$$libname.* $(DESTDIR)$(rootlibdir); \
-       fi
-endef
-
 install-touch-usr-hook:
        touch -c $(DESTDIR)/$(prefix)
 
@@ -505,9 +493,7 @@ libelogind_shared_la_LIBADD = \
        $(SECCOMP_LIBS)
 
 libelogind_shared_la_LDFLAGS = \
-       $(AM_LDFLAGS) \
-       -release $(PACKAGE_VERSION)
-
+       $(AM_LDFLAGS)
  # -----------------------------------------------------------------------------
 gperf_txt_sources = \
        src/basic/errno-list.txt
@@ -641,15 +627,6 @@ libelogind_la_LIBADD = \
        libelogind-internal.la \
        libbasic.la
 
-libelogind-install-hook:
-       libname=libelogind.so && $(move-to-rootlibdir)
-
-libelogind-uninstall-hook:
-       rm -f $(DESTDIR)$(rootlibdir)/libelogind.so*
-
-INSTALL_EXEC_HOOKS += libelogind-install-hook
-UNINSTALL_EXEC_HOOKS += libelogind-uninstall-hook
-
 pkgconfiglib_DATA += \
        src/libelogind/libelogind.pc
 
@@ -673,7 +650,7 @@ header-uninstall-hook:
 INSTALL_EXEC_HOOKS += header-install-hook
 UNINSTALL_EXEC_HOOKS += header-uninstall-hook
 
-lib_LTLIBRARIES += \
+rootlib_LTLIBRARIES += \
        libelogind.la
 
 # ------------------------------------------------------------------------------
@@ -829,8 +806,10 @@ pam_elogind_la_LIBADD = \
 pamlib_LTLIBRARIES = \
        pam_elogind.la
 
+if ENABLE_PAM_CONFIG
 dist_pamconf_DATA = \
        src/login/elogind-user
+endif
 
 EXTRA_DIST += \
        src/login/elogind-user.m4
@@ -1009,9 +988,7 @@ EXTRA_DIST += \
 
 install-exec-hook: $(INSTALL_EXEC_HOOKS)
 
-uninstall-hook: $(UNINSTALL_DATA_HOOKS) $(UNINSTALL_EXEC_HOOKS)
-
-install-data-hook: $(INSTALL_DATA_HOOKS)
+uninstall-hook: $(UNINSTALL_EXEC_HOOKS)
 
 distclean-local: $(DISTCLEAN_LOCAL_HOOKS)
 
@@ -1193,7 +1170,7 @@ print-%:
        @echo $($*)
 
 git-contrib:
-       @git shortlog -s `git describe --abbrev=0`.. | cut -c8- | awk '{ print $$0 "," }' | sort -u
+       @git shortlog -s `git describe --abbrev=0`.. | cut -c8- | sed 's/ / /g' | awk '{ print $$0 "," }' | sort -u
 
 EXTRA_DIST += \
         tools/gdb-sd_dump_hashmaps.py
diff --git a/NEWS b/NEWS
index ca54685878ff3ec15f3f6b8469ba6b9df2a84a55..b10a6f538f4934a43d9b53f4170b962d50c763a1 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,354 @@
 systemd System and Service Manager
 
+CHANGES WITH 232:
+
+        * The new RemoveIPC= option can be used to remove IPC objects owned by
+          the user or group of a service when that service exits.
+
+        * The new ProtectKernelModules= option can be used to disable explicit
+          load and unload operations of kernel modules by a service. In
+          addition access to /usr/lib/modules is removed if this option is set.
+
+        * ProtectSystem= option gained a new value "strict", which causes the
+          whole file system tree with the exception of /dev, /proc, and /sys,
+          to be remounted read-only for a service.
+
+        * The new ProtectKernelTunables= option can be used to disable
+          modification of configuration files in /sys and /proc by a service.
+          Various directories and files are remounted read-only, so access is
+          restricted even if the file permissions would allow it.
+
+        * The new ProtectControlGroups= option can be used to disable write
+          access by a service to /sys/fs/cgroup.
+
+        * Various systemd services have been hardened with
+          ProtectKernelTunables=yes, ProtectControlGroups=yes,
+          RestrictAddressFamilies=.
+
+        * Support for dynamically creating users for the lifetime of a service
+          has been added. If DynamicUser=yes is specified, user and group IDs
+          will be allocated from the range 61184..65519 for the lifetime of the
+          service. They can be resolved using the new nss-systemd.so NSS
+          module. The module must be enabled in /etc/nsswitch.conf. Services
+          started in this way have PrivateTmp= and RemoveIPC= enabled, so that
+          any resources allocated by the service will be cleaned up when the
+          service exits. They also have ProtectHome=read-only and
+          ProtectSystem=strict enabled, so they are not able to make any
+          permanent modifications to the system.
+
+        * The nss-systemd module also always resolves root and nobody, making
+          it possible to have no /etc/passwd or /etc/group files in minimal
+          container or chroot environments.
+
+        * Services may be started with their own user namespace using the new
+          boolean PrivateUsers= option. Only root, nobody, and the uid/gid
+          under which the service is running are mapped. All other users are
+          mapped to nobody.
+
+        * Support for the cgroup namespace has been added to systemd-nspawn. If
+          supported by kernel, the container system started by systemd-nspawn
+          will have its own view of the cgroup hierarchy. This new behaviour
+          can be disabled using $SYSTEMD_NSPAWN_USE_CGNS environment variable.
+
+        * The new MemorySwapMax= option can be used to limit the maximum swap
+          usage under the unified cgroup hierarchy.
+
+        * Support for the CPU controller in the unified cgroup hierarchy has
+          been added, via the CPUWeight=, CPUStartupWeight=, CPUAccounting=
+          options. This controller requires out-of-tree patches for the kernel
+          and the support is provisional.
+
+        * Mount and automount units may now be created transiently
+          (i.e. dynamically at runtime via the bus API, instead of requiring
+          unit files in the file system).
+
+        * systemd-mount is a new tool which may mount file systems â€“ much like
+          mount(8), optionally pulling in additional dependencies through
+          transient .mount and .automount units. For example, this tool
+          automatically runs fsck on a backing block device before mounting,
+          and allows the automount logic to be used dynamically from the
+          command line for establishing mount points. This tool is particularly
+          useful when dealing with removable media, as it will ensure fsck is
+          run â€“ if necessary â€“ before the first access and that the file system
+          is quickly unmounted after each access by utilizing the automount
+          logic. This maximizes the chance that the file system on the
+          removable media stays in a clean state, and if it isn't in a clean
+          state is fixed automatically.
+
+        * LazyUnmount=yes option for mount units has been added to expose the
+          umount --lazy option. Similarly, ForceUnmount=yes exposes the --force
+          option.
+
+        * /efi will be used as the mount point of the EFI boot partition, if
+          the directory is present, and the mount point was not configured
+          through other means (e.g. fstab). If /efi directory does not exist,
+          /boot will be used as before. This makes it easier to automatically
+          mount the EFI partition on systems where /boot is used for something
+          else.
+
+        * When operating on GPT disk images for containers, systemd-nspawn will
+          now mount the ESP to /boot or /efi according to the same rules as PID
+          1 running on a host. This allows tools like "bootctl" to operate
+          correctly within such containers, in order to make container images
+          bootable on physical systems.
+
+        * disk/by-id and disk/by-path symlinks are now created for NVMe drives.
+
+        * Two new user session targets have been added to support running
+          graphical sessions under the systemd --user instance:
+          graphical-session.target and graphical-session-pre.target. See
+          systemd.special(7) for a description of how those targets should be
+          used.
+
+        * The vconsole initialization code has been significantly reworked to
+          use KD_FONT_OP_GET/SET ioctls instead of KD_FONT_OP_COPY and better
+          support unicode keymaps. Font and keymap configuration will now be
+          copied to all allocated virtual consoles.
+
+        * FreeBSD's bhyve virtualization is now detected.
+
+        * Information recorded in the journal for core dumps now includes the
+          contents of /proc/mountinfo and the command line of the process at
+          the top of the process hierarchy (which is usually the init process
+          of the container).
+
+        * systemd-journal-gatewayd learned the --directory= option to serve
+          files from the specified location.
+
+        * journalctl --root=… can be used to peruse the journal in the
+          /var/log/ directories inside of a container tree. This is similar to
+          the existing --machine= option, but does not require the container to
+          be active.
+
+        * The hardware database has been extended to support
+          ID_INPUT_TRACKBALL, used in addition to ID_INPUT_MOUSE to identify
+          trackball devices.
+
+          MOUSE_WHEEL_CLICK_ANGLE_HORIZONTAL hwdb property has been added to
+          specify the click rate for mice which include a horizontal wheel with
+          a click rate that is different than the one for the vertical wheel.
+
+        * systemd-run gained a new --wait option that makes service execution
+          synchronous. (Specifically, the command will not return until the
+          specified service binary exited.)
+
+        * systemctl gained a new --wait option that causes the start command to
+          wait until the units being started have terminated again.
+
+        * A new journal output mode "short-full" has been added which displays
+          timestamps with abbreviated English day names and adds a timezone
+          suffix. Those timestamps include more information than the default
+          "short" output mode, and can be passed directly to journalctl's
+          --since= and --until= options.
+
+        * /etc/resolv.conf will be bind-mounted into containers started by
+          systemd-nspawn, if possible, so any changes to resolv.conf contents
+          are automatically propagated to the container.
+
+        * The number of instances for socket-activated services originating
+          from a single IP address can be limited with
+          MaxConnectionsPerSource=, extending the existing setting of
+          MaxConnections=.
+
+        * systemd-networkd gained support for vcan ("Virtual CAN") interface
+          configuration.
+
+        * .netdev and .network configuration can now be extended through
+          drop-ins.
+
+        * UDP Segmentation Offload, TCP Segmentation Offload, Generic
+          Segmentation Offload, Generic Receive Offload, Large Receive Offload
+          can be enabled and disabled using the new UDPSegmentationOffload=,
+          TCPSegmentationOffload=, GenericSegmentationOffload=,
+          GenericReceiveOffload=, LargeReceiveOffload= options in the
+          [Link] section of .link files.
+
+        * The Spanning Tree Protocol, Priority, Aging Time, and the Default
+          Port VLAN ID can be configured for bridge devices using the new STP=,
+          Priority=, AgeingTimeSec=, and DefaultPVID= settings in the [Bridge]
+          section of .netdev files.
+
+        * The route table to which routes received over DHCP or RA should be
+          added can be configured with the new RouteTable= option in the [DHCP]
+          and [IPv6AcceptRA] sections of .network files.
+
+        * The Address Resolution Protocol can be disabled on links managed by
+          systemd-networkd using the ARP=no setting in the [Link] section of
+          .network files.
+
+        * New environment variables $SERVICE_RESULT, $EXIT_CODE and
+          $EXIT_STATUS are set for ExecStop= and ExecStopPost= commands, and
+          encode information about the result and exit codes of the current
+          service runtime cycle.
+
+        * systemd-sysctl will now configure kernel parameters in the order
+          they occur in the configuration files. This matches what sysctl
+          has been traditionally doing.
+
+        * kernel-install "plugins" that are executed to perform various
+          tasks after a new kernel is added and before an old one is removed
+          can now return a special value to terminate the procedure and
+          prevent any later plugins from running.
+
+        * Journald's SplitMode=login setting has been deprecated. It has been
+          removed from documentation, and its use is discouraged. In a future
+          release it will be completely removed, and made equivalent to current
+          default of SplitMode=uid.
+
+        * Storage=both option setting in /etc/systemd/coredump.conf has been
+          removed. With fast LZ4 compression storing the core dump twice is not
+          useful.
+
+        * The --share-system systemd-nspawn option has been replaced with an
+          (undocumented) variable $SYSTEMD_NSPAWN_SHARE_SYSTEM, but the use of
+          this functionality is discouraged. In addition the variables
+          $SYSTEMD_NSPAWN_SHARE_NS_IPC, $SYSTEMD_NSPAWN_SHARE_NS_PID,
+          $SYSTEMD_NSPAWN_SHARE_NS_UTS may be used to control the unsharing of
+          individual namespaces.
+
+        * "machinectl list" now shows the IP address of running containers in
+          the output, as well as OS release information.
+
+        * "loginctl list" now shows the TTY of each session in the output.
+
+        * sd-bus gained new API calls sd_bus_track_set_recursive(),
+          sd_bus_track_get_recursive(), sd_bus_track_count_name(),
+          sd_bus_track_count_sender(). They permit usage of sd_bus_track peer
+          tracking objects in a "recursive" mode, where a single client can be
+          counted multiple times, if it takes multiple references.
+
+        * sd-bus gained new API calls sd_bus_set_exit_on_disconnect() and
+          sd_bus_get_exit_on_disconnect(). They may be used to to make a
+          process using sd-bus automatically exit if the bus connection is
+          severed.
+
+        * Bus clients of the service manager may now "pin" loaded units into
+          memory, by taking an explicit reference on them. This is useful to
+          ensure the client can retrieve runtime data about the service even
+          after the service completed execution. Taking such a reference is
+          available only for privileged clients and should be helpful to watch
+          running services in a race-free manner, and in particular collect
+          information about exit statuses and results.
+
+        * The nss-resolve module has been changed to strictly return UNAVAIL
+          when communication via D-Bus with resolved failed, and NOTFOUND when
+          a lookup completed but was negative. This means it is now possible to
+          neatly configure fallbacks using nsswitch.conf result checking
+          expressions. Taking benefit of this, the new recommended
+          configuration line for the "hosts" entry in /etc/nsswitch.conf is:
+
+              hosts: files mymachines resolve [!UNAVAIL=return] dns myhostname
+
+        * A new setting CtrlAltDelBurstAction= has been added to
+          /etc/systemd/system.conf which may be used to configure the precise
+          behaviour if the user on the console presses Ctrl-Alt-Del more often
+          than 7 times in 2s. Previously this would unconditionally result in
+          an expedited, immediate reboot. With this new setting the precise
+          operation may be configured in more detail, and also turned off
+          entirely.
+
+        * In .netdev files two new settings RemoteChecksumTx= and
+          RemoteChecksumRx= are now understood that permit configuring the
+          remote checksumming logic for VXLAN networks.
+
+        * The service manager learnt a new "invocation ID" concept for invoked
+          services. Each runtime cycle of a service will get a new invocation
+          ID (a 128bit random UUID) assigned that identifies the current
+          run of the service uniquely and globally. A new invocation ID
+          is generated each time a service starts up. The journal will store
+          the invocation ID of a service along with any logged messages, thus
+          making the invocation ID useful for matching the online runtime of a
+          service with the offline log data it generated in a safe way without
+          relying on synchronized timestamps. In many ways this new service
+          invocation ID concept is similar to the kernel's boot ID concept that
+          uniquely and globally identifies the runtime of each boot. The
+          invocation ID of a service is passed to the service itself via an
+          environment variable ($INVOCATION_ID). A new bus call
+          GetUnitByInvocationID() has been added that is similar to GetUnit()
+          but instead of retrieving the bus path for a unit by its name
+          retrieves it by its invocation ID. The returned path is valid only as
+          long as the passed invocation ID is current.
+
+        * systemd-resolved gained a new "DNSStubListener" setting in
+          resolved.conf. It either takes a boolean value or the special values
+          "udp" and "tcp", and configures whether to enable the stub DNS
+          listener on 127.0.0.53:53.
+
+        * IP addresses configured via networkd may now carry additional
+          configuration settings supported by the kernel. New options include:
+          HomeAddress=, DuplicateAddressDetection=, ManageTemporaryAddress=,
+          PrefixRoute=, AutoJoin=.
+
+        * The PAM configuration fragment file for "user@.service" shipped with
+          systemd (i.e. the --user instance of systemd) has been stripped to
+          the minimum necessary to make the system boot. Previously, it
+          contained Fedora-specific stanzas that did not apply to other
+          distributions. It is expected that downstream distributions add
+          additional configuration lines, matching their needs to this file,
+          using it only as rough template of what systemd itself needs. Note
+          that this reduced fragment does not even include an invocation of
+          pam_limits which most distributions probably want to add, even though
+          systemd itself does not need it. (There's also the new build time
+          option --with-pamconfdir=no to disable installation of the PAM
+          fragment entirely.)
+
+        * If PrivateDevices=yes is set for a service the CAP_SYS_RAWIO
+          capability is now also dropped from its set (in addition to
+          CAP_SYS_MKNOD as before).
+
+        * In service unit files it is now possible to connect a specific named
+          file descriptor with stdin/stdout/stdout of an executed service. The
+          name may be specified in matching .socket units using the
+          FileDescriptorName= setting.
+
+        * A number of journal settings may now be configured on the kernel
+          command line. Specifically, the following options are now understood:
+          systemd.journald.max_level_console=,
+          systemd.journald.max_level_store=,
+          systemd.journald.max_level_syslog=, systemd.journald.max_level_kmsg=,
+          systemd.journald.max_level_wall=.
+
+        * "systemctl is-enabled --full" will now show by which symlinks a unit
+          file is enabled in the unit dependency tree.
+
+        * Support for VeraCrypt encrypted partitions has been added to the
+          "cryptsetup" logic and /etc/crypttab.
+
+        * systemd-detect-virt gained support for a new --private-users switch
+          that checks whether the invoking processes are running inside a user
+          namespace. Similar, a new special value "private-users" for the
+          existing ConditionVirtualization= setting has been added, permitting
+          skipping of specific units in user namespace environments.
+
+        Contributions from: Alban Crequy, Alexander Kuleshov, Alfie John,
+        Andreas Henriksson, Andrew Jeddeloh, Balázs Ãšr, Bart Rulon, Benjamin
+        Richter, Ben Gamari, Ben Harris, Brian J. Murrell, Christian Brauner,
+        Christian Rebischke, Clinton Roy, Colin Walters, Cristian Rodríguez,
+        Daniel Hahler, Daniel Mack, Daniel Maixner, Daniel Rusek, Dan Dedrick,
+        Davide Cavalca, David Herrmann, David Michael, Dennis Wassenberg,
+        Djalal Harouni, Dongsu Park, Douglas Christman, Elias Probst, Eric
+        Cook, Erik Karlsson, Evgeny Vereshchagin, Felipe Sateler, Felix Zhang,
+        Franck Bui, George Hilliard, Giuseppe Scrivano, HATAYAMA Daisuke,
+        Heikki Kemppainen, Hendrik Brueckner, hi117, Ismo Puustinen, Ivan
+        Shapovalov, Jakub Filak, Jakub Wilk, Jan Synacek, Jason Kölker,
+        Jean-Sébastien Bour, Jiří Pírko, Jonathan Boulle, Jorge Niedbalski,
+        Keith Busch, kristbaum, Kyle Russell, Lans Zhang, Lennart Poettering,
+        Leonardo Brondani Schenkel, Lucas Werkmeister, Luca Bruno, Lukáš
+        Nykrýn, Maciek Borzecki, Mantas MikulÄ—nas, Marc-Antoine Perennou,
+        Marcel Holtmann, Marcos Mello, Martin Ejdestig, Martin Pitt, Matej
+        Habrnal, Maxime de Roucy, Michael Biebl, Michael Chapman, Michael Hoy,
+        Michael Olbrich, Michael Pope, Michal Sekletar, Michal Soltys, Mike
+        Gilbert, Nick Owens, Patrik Flykt, PaweÅ‚ Szewczyk, Peter Hutterer,
+        Piotr DrÄ…g, Reid Price, Richard W.M. Jones, Roman Stingler, Ronny
+        Chevalier, Seraphime Kirkovski, Stefan Schweter, Steve Muir, Susant
+        Sahani, Tejun Heo, Thomas Blume, Thomas H. P. Andersen, Tiago Levit,
+        Tobias Jungel, Tomáš JanouÅ¡ek, Topi Miettinen, Torstein Husebø, Umut
+        Tezduyar Lindskog, Vito Caputo, WaLyong Cho, Wilhelm Schuster, Yann
+        E. MORIN, Yi EungJun, Yuki Inoguchi, Yu Watanabe, Zbigniew
+        JÄ™drzejewski-Szmek, Zeal Jagannatha
+
+        â€” Santa Fe, 2016-11-03
+
 CHANGES WITH 231:
 
         * In service units the various ExecXYZ= settings have been extended
@@ -176,7 +525,7 @@ CHANGES WITH 231:
           file. It can be used in lieu of %systemd_requires in packages which
           don't use any systemd functionality and are intended to be installed
           in minimal containers without systemd present. This macro provides
-          ordering dependecies to ensure that if the package is installed in
+          ordering dependencies to ensure that if the package is installed in
           the same rpm transaction as systemd, systemd will be installed before
           the scriptlets for the package are executed, allowing unit presets
           to be handled.
@@ -211,11 +560,14 @@ CHANGES WITH 231:
           "mkosi" is invoked in the build tree a new raw OS image is generated
           incorporating the systemd sources currently being worked on and a
           clean, fresh distribution installation. The generated OS image may be
-          booted up with "systemd-nspawn -b -i", qemu-kvm or on any physcial
+          booted up with "systemd-nspawn -b -i", qemu-kvm or on any physical
           UEFI PC. This functionality is particularly useful to easily test
           local changes made to systemd in a pristine, defined environment. See
           HACKING for details.
 
+        * configure learned the --with-support-url= option to specify the
+          distribution's bugtracker.
+
         Contributions from: Alban Crequy, Alessandro Puccetti, Alessio Igor
         Bogani, Alexander Kuleshov, Alexander Kurtz, Alex Gaynor, Andika
         Triwidada, Andreas Pokorny, Andreas Rammhold, Andrew Jeddeloh, Ansgar
@@ -385,13 +737,13 @@ CHANGES WITH 230:
           of the owners and the ACLs of all files and directories in a
           container tree to match the UID/GID user namespacing range selected
           for the container invocation. This mode is enabled via the new
-          --private-user-chown switch. It also gained support for automatically
-          choosing a free, previously unused UID/GID range when starting a
-          container, via the new --private-users=pick setting (which implies
-          --private-user-chown). Together, these options for the first time
-          make user namespacing for nspawn containers fully automatic and thus
-          deployable. The systemd-nspawn@.service template unit file has been
-          changed to use this functionality by default.
+          --private-users-chown switch. It also gained support for
+          automatically choosing a free, previously unused UID/GID range when
+          starting a container, via the new --private-users=pick setting (which
+          implies --private-users-chown). Together, these options for the first
+          time make user namespacing for nspawn containers fully automatic and
+          thus deployable. The systemd-nspawn@.service template unit file has
+          been changed to use this functionality by default.
 
         * systemd-nspawn gained a new --network-zone= switch, that allows
           creating ad-hoc virtual Ethernet links between multiple containers,
@@ -871,7 +1223,7 @@ CHANGES WITH 228:
           --user instance of systemd these specifiers where correctly
           resolved, but hardly made any sense, since the user instance
           lacks privileges to do user switches anyway, and User= is
-          hence useless. Morever, even in the --user instance of
+          hence useless. Moreover, even in the --user instance of
           systemd behaviour was awkward as it would only take settings
           from User= assignment placed before the specifier into
           account. In order to unify and simplify the logic around
@@ -1007,7 +1359,7 @@ CHANGES WITH 227:
         * The RuntimeDirectory= setting now understands unit
           specifiers like %i or %f.
 
-        * A new (still internal) libary API sd-ipv4acd has been added,
+        * A new (still internal) library API sd-ipv4acd has been added,
           that implements address conflict detection for IPv4. It's
           based on code from sd-ipv4ll, and will be useful for
           detecting DHCP address conflicts.
@@ -1576,7 +1928,7 @@ CHANGES WITH 220:
 
         * systemd-nspawn gained a new --property= setting to set unit
           properties for the container scope. This is useful for
-          setting resource parameters (e.g "CPUShares=500") on
+          setting resource parameters (e.g. "CPUShares=500") on
           containers started from the command line.
 
         * systemd-nspawn gained a new --private-users= switch to make
@@ -1874,7 +2226,7 @@ CHANGES WITH 219:
           files.
 
         * systemd now provides a way to store file descriptors
-          per-service in PID 1.This is useful for daemons to ensure
+          per-service in PID 1. This is useful for daemons to ensure
           that fds they require are not lost during a daemon
           restart. The fds are passed to the daemon on the next
           invocation in the same way socket activation fds are
@@ -2922,7 +3274,7 @@ CHANGES WITH 214:
           time, the extended attribute calls have moved to glibc, and
           libattr is thus unnecessary.
 
-        * Virtualization detection works without priviliges now. This
+        * Virtualization detection works without privileges now. This
           means the systemd-detect-virt binary no longer requires
           CAP_SYS_PTRACE file capabilities, and our daemons can run
           with fewer privileges.
@@ -3646,7 +3998,7 @@ CHANGES WITH 209:
           /usr/lib/net/links/99-default.link. Old
           80-net-name-slot.rules udev configuration file has been
           removed, so local configuration overriding this file should
-          be adapated to override 99-default.link instead.
+          be adapted to override 99-default.link instead.
 
         * When the User= switch is used in a unit file, also
           initialize $SHELL= based on the user database entry.
@@ -4289,7 +4641,7 @@ CHANGES WITH 206:
 
         * logind's device ACLs may now be applied to these "dead"
           devices nodes too, thus finally allowing managed access to
-          devices such as /dev/snd/sequencer whithout loading the
+          devices such as /dev/snd/sequencer without loading the
           backing module right-away.
 
         * A new RPM macro has been added that may be used to apply
@@ -4780,7 +5132,7 @@ CHANGES WITH 199:
           processes executed in parallel based on the number of available
           CPUs instead of the amount of available RAM. This is supposed
           to provide a more reliable default and limit a too aggressive
-          paralellism for setups with 1000s of devices connected.
+          parallelism for setups with 1000s of devices connected.
 
         Contributions from: Auke Kok, Colin Walters, Cristian
         Rodríguez, Daniel Buch, Dave Reisner, Frederic Crozat, Hannes
@@ -5118,7 +5470,7 @@ CHANGES WITH 197:
           presenting log data.
 
         * systemctl will no longer show control group information for
-          a unit if the control group is empty anyway.
+          a unit if the control group is empty anyway.
 
         * logind can now automatically suspend/hibernate/shutdown the
           system on idle.
@@ -5909,7 +6261,7 @@ CHANGES WITH 186:
         * The SysV search path is no longer exported on the D-Bus
           Manager object.
 
-        * The Names= option is been removed from unit file parsing.
+        * The Names= option has been removed from unit file parsing.
 
         * There's a new man page bootup(7) detailing the boot process.
 
@@ -6054,7 +6406,7 @@ CHANGES WITH 183:
           about this in more detail.
 
         * var-run.mount and var-lock.mount are no longer provided
-          (which prevously bind mounted these directories to their new
+          (which previously bind mounted these directories to their new
           places). Distributions which have not converted these
           directories to symlinks should consider stealing these files
           from git history and add them downstream.
@@ -6195,7 +6547,7 @@ CHANGES WITH 44:
         * Many bugfixes for the journal, including endianness fixes and
           ensuring that disk space enforcement works
 
-        * sd-login.h is C++ comptaible again
+        * sd-login.h is C++ compatible again
 
         * Extend the /etc/os-release format on request of the Debian
           folks
@@ -6423,7 +6775,7 @@ CHANGES WITH 38:
 
         * New man pages for all APIs from libsystemd-login.
 
-        * The build tree got reorganized and the build system is a
+        * The build tree got reorganized and the build system is a
           lot more modular allowing embedded setups to specifically
           select the components of systemd they are interested in.
 
diff --git a/TODO b/TODO
index ef25ef578e667e7ad72c2ec39d6dec6e7eddf3fa..c8266a549dde153d2657d85a0a1c134e2bd5be5d 100644 (file)
--- a/TODO
+++ b/TODO
@@ -23,54 +23,96 @@ External:
 
 Janitorial Clean-ups:
 
-* code cleanup: retire FOREACH_WORD_QUOTED, port to extract_first_word() loops instead
+* code cleanup: retire FOREACH_WORD_QUOTED, port to extract_first_word() loops instead.
+  For example, most conf parsing callbacks should use it.
 
 * replace manual readdir() loops with FOREACH_DIRENT or FOREACH_DIRENT_ALL
 
-* Get rid of the last strerror() invocations in favour of %m and strerror_r()
-
 * Rearrange tests so that the various test-xyz.c match a specific src/basic/xyz.c again
 
 Features:
 
+* drop nss-myhostname in favour of nss-resolve?
+
+* drop internal dlopen() based nss-dns fallback in nss-resolve, and rely on the
+  external nsswitch.conf based one
+
+* add a percentage syntax for TimeoutStopSec=, e.g. TimeoutStopSec=150%, and
+  then use that for the setting used in user@.service. It should be understood
+  relative to the configured default value.
+
+* on cgroupsv2 add DelegateControllers=, to pick the precise cgroup controllers to delegate
+
+* in networkd, when matching device types, fix up DEVTYPE rubbish the kernel passes to us
+
+* enable LockMLOCK to take a percentage value relative to physical memory
+
+* switch to ProtectSystem=strict for all our long-running services where that's possible
+
+* If RootDirectory= is used, mount /proc, /sys, /dev into it, if not mounted yet
+
+* Permit masking specific netlink APIs with RestrictAddressFamily=
+
+* nspawn: start UID allocation loop from hash of container name
+
+* nspawn: support that /proc, /sys/, /dev are pre-mounted
+
+* define gpt header bits to select volatility mode
+
+* nspawn: mount loopback filesystems with "discard"
+
 * ProtectKernelLogs= (drops CAP_SYSLOG, add seccomp for syslog() syscall, and DeviceAllow to /dev/kmsg) in service files
 
 * ProtectClock= (drops CAP_SYS_TIMES, adds seecomp filters for settimeofday, adjtimex), sets DeviceAllow o /dev/rtc
 
-* ProtectMount= (drop mount/umount/pivot_root from seccomp, disallow fuse via DeviceAllow, imply Mountflags=slave)
+* ProtectKernelModules= (drops CAP_SYS_MODULE and filters the kmod syscalls)
+
+* ProtectTracing= (drops CAP_SYS_PTRACE, blocks ptrace syscall, makes /sys/kernel/tracing go away)
 
-* ProtectDevices= should also take iopl/ioperm/pciaccess away
+* ProtectMount= (drop mount/umount/pivot_root from seccomp, disallow fuse via DeviceAllow, imply Mountflags=slave)
 
 * ProtectKeyRing= to take keyring calls away
 
-* PrivateUsers= which maps the all user ids except root and the one specified
-  in User= to nobody
+* RemoveKeyRing= to remove all keyring entries of the specified user
+
+* ProtectReboot= that masks reboot() and kexec_load() syscalls, prohibits kill
+  on PID 1 with the relevant signals, and makes relevant files in /sys and
+  /proc (such as the sysrq stuff) unavailable
 
-* Add AllocateUser= for allowing dynamic user ids per-service
+* DeviceAllow= should also generate seccomp filters for mknod()
 
 * Add DataDirectory=, CacheDirectory= and LogDirectory= to match
   RuntimeDirectory=, and create it as necessary when starting a service, owned by the right user.
 
 * Add BindDirectory= for allowing arbitrary, private bind mounts for services
 
-* Beef up RootDirectory= to use namespacing/bind mounts as soon as fs
-  namespaces are enabled by the service
-
 * Add RootImage= for mounting a disk image or file as root directory
 
 * RestrictNamespaces= or so in services (taking away the ability to create namespaces, with setns, unshare, clone)
 
-* nspawn: make /proc/sys/net writable?
-
 * make sure the ratelimit object can deal with USEC_INFINITY as way to turn off things
 
 * journalctl: make sure -f ends when the container indicated by -M terminates
 
+* mount: automatically search for "main" partition of an image has multiple
+  partitions
+
 * expose the "privileged" flag of ExecCommand on the bus, and open it up to
   transient units
 
+* in nss-systemd, if we run inside of RootDirectory= with PrivateUsers= set,
+  find a way to map the User=/Group= of the service to the right name. This way
+  a user/group for a service only has to exist on the host for the right
+  mapping to work.
+
 * allow attaching additional journald log fields to cgroups
 
+* add bus API for creating unit files in /etc, reusing the code for transient units
+
+* add bus API to remove unit files from /etc
+
+* add bus API to retrieve current unit file contents (i.e. implement "systemctl cat" on the bus only)
+
 * rework fopen_temporary() to make use of open_tmpfile_linkable() (problem: the
   kernel doesn't support linkat() that replaces existing files, currently)
 
@@ -82,8 +124,6 @@ Features:
 * journald: sigbus API via a signal-handler safe function that people may call
   from the SIGBUS handler
 
-* when using UTF8, ellipsize with "…" rather than "...", so that we can show more contents before truncating
-
 * move specifier expansion from service_spawn() into load-fragment.c
 
 * optionally, also require WATCHDOG=1 notifications during service start-up and shutdown
@@ -97,8 +137,6 @@ Features:
 
 * add systemctl stop --job-mode=triggering that follows TRIGGERED_BY deps and adds them to the same transaction
 
-* Maybe add a way how users can "pin" units into memory, so that they are not subject to automatic GC?
-
 * PID1: find a way how we can reload unit file configuration for
   specific units only, without reloading the whole of systemd
 
@@ -114,8 +152,6 @@ Features:
 
 * PID 1 should send out sd_notify("WATCHDOG=1") messages (for usage in the --user mode, and when run via nspawn)
 
-* consider throwing a warning if a service declares it wants to be "Before=" a .device unit.
-
 * there's probably something wrong with having user mounts below /sys,
   as we have for debugfs. for exmaple, src/core/mount.c handles mounts
   prefixed with /sys generally special.
@@ -153,7 +189,7 @@ Features:
 * implement a per-service firewall based on net_cls
 
 * Port various tools to make use of verbs.[ch], where applicable: busctl,
-  bootctl, coredumpctl, hostnamectl, localectl, systemd-analyze, timedatectl
+  coredumpctl, hostnamectl, localectl, systemd-analyze, timedatectl
 
 * hostnamectl: show root image uuid
 
@@ -170,7 +206,7 @@ Features:
 * synchronize console access with BSD locks:
   http://lists.freedesktop.org/archives/systemd-devel/2014-October/024582.html
 
-* as soon as we have kdbus, and sender timestamps, revisit coalescing multiple parallel daemon reloads:
+* as soon as we have sender timestamps, revisit coalescing multiple parallel daemon reloads:
   http://lists.freedesktop.org/archives/systemd-devel/2014-December/025862.html
 
 * in systemctl list-unit-files: show the install value the presets would suggest for a service in a third column
@@ -210,10 +246,6 @@ Features:
 
 * timesyncd: add ugly bus calls to set NTP servers per-interface, for usage by NM
 
-* extract_many_words() should probably be used by a lot of code that
-  currently uses FOREACH_WORD and friends. For example, most conf
-  parsing callbacks should use it.
-
 * merge ~/.local/share and ~/.local/lib into one similar /usr/lib and /usr/share....
 
 * systemd.show_status= should probably have a mode where only failed
@@ -270,9 +302,6 @@ Features:
 
 * MessageQueueMessageSize= (and suchlike) should use parse_iec_size().
 
-* "busctl status" works only as root on dbus1, since we cannot read
-  /proc/$PID/exe
-
 * implement Distribute= in socket units to allow running multiple
   service instances processing the listening socket, and open this up
   for ReusePort=
@@ -283,8 +312,6 @@ Features:
   and passes this back to PID1 via SCM_RIGHTS. This also could be used
   to allow Chown/chgrp on sockets without requiring NSS in PID 1.
 
-* New service property: maximum CPU runtime for a service
-
 * introduce bus call FreezeUnit(s, b), as well as "systemctl freeze
   $UNIT" and "systemctl thaw $UNIT" as wrappers around this. The calls
   should SIGSTOP all unit processes in a loop until all processes of
@@ -321,12 +348,10 @@ Features:
   error. Currently, we just ignore it and read the unit from the search
   path anyway.
 
-* refuse boot if /etc/os-release is missing or /etc/machine-id cannot be set up
+* refuse boot if /usr/lib/os-release is missing or /etc/machine-id cannot be set up
 
 * btrfs raid assembly: some .device jobs stay stuck in the queue
 
-* make sure gdm does not use multi-user-x but the new default X configuration file, and then remove multi-user-x from systemd
-
 * man: the documentation of Restart= currently is very misleading and suggests the tools from ExecStartPre= might get restarted.
 
 * load .d/*.conf dropins for device units
@@ -474,7 +499,6 @@ Features:
     message that works, but alraedy after a short tiemout
   - check if we can make journalctl by default use --follow mode inside of less if called without args?
   - maybe add API to send pairs of iovecs via sd_journal_send
-  - journal: when writing journal auto-rotate if time jumps backwards
   - journal: add a setgid "systemd-journal" utility to invoke from libsystemd-journal, which passes fds via STDOUT and does PK access
   - journactl: support negative filtering, i.e. FOOBAR!="waldo",
     and !FOOBAR for events without FOOBAR.
@@ -583,9 +607,6 @@ Features:
 * currently x-systemd.timeout is lost in the initrd, since crypttab is copied into dracut, but fstab is not
 
 * nspawn:
-  - to allow "linking" of nspawn containers, extend --network-bridge= so
-    that it can dynamically create bridge interfaces that are refcounted
-    by the containers on them. For each group of containers to link together
   - nspawn -x should support ephemeral instances of gpt images
   - emulate /dev/kmsg using CUSE and turn off the syslog syscall
     with seccomp. That should provide us with a useful log buffer that
@@ -594,8 +615,6 @@ Features:
   - as soon as networkd has a bus interface, hook up --network-interface=,
     --network-bridge= with networkd, to trigger netdev creation should an
     interface be missing
-  - don't copy /etc/resolv.conf from host into container unless we are in
-    shared-network mode
   - a nice way to boot up without machine id set, so that it is set at boot
     automatically for supporting --ephemeral. Maybe hash the host machine id
     together with the machine name to generate the machine id for the container
@@ -612,8 +631,6 @@ Features:
     is used
 
 * machined:
-  - "machinectl list" should probably show columns for OS version and IP
-    addresses
   - add an API so that libvirt-lxc can inform us about network interfaces being
     removed or added to an existing machine
   - "machinectl migrate" or similar to copy a container from or to a
@@ -663,7 +680,7 @@ Features:
 
 * coredump:
   - save coredump in Windows/Mozilla minidump format
-  - move PID 1 segfaults to /var/lib/systemd/coredump?
+  - when truncating coredumps, also log the full size that the process had, and make a metadata field so we can report truncated coredumps
 
 * support crash reporting operation modes (https://live.gnome.org/GnomeOS/Design/Whiteboards/ProblemReporting)
 
@@ -730,7 +747,6 @@ Features:
   - GC unreferenced jobs (such as .device jobs)
   - move PAM code into its own binary
   - when we automatically restart a service, ensure we restart its rdeps, too.
-  - for services: do not set $HOME in services unless requested
   - hide PAM options in fragment parser when compile time disabled
   - Support --test based on current system state
   - If we show an error about a unit (such as not showing up) and it has no Description string, then show a description string generated form the reverse of unit_name_mangle().
@@ -780,7 +796,6 @@ Features:
    - add reduced [Link] support to .network files
    - add Scope= parsing option for [Network]
    - properly handle routerless dhcp leases
-   - add more attribute support for SIT tunnel
    - work with non-Ethernet devices
    - add support for more bond options
    - dhcp: do we allow configuring dhcp routes on interfaces that are not the one we got the dhcp info from?
@@ -797,7 +812,6 @@ Features:
      support Name=foo*|bar*|baz ?
    - duplicate address check for static IPs (like ARPCHECK in network-scripts)
    - allow DUID/IAID to be customized, see issue #394.
-   - support configuration option for TSO (tcp segmentation offload)
    - whenever uplink info changes, make DHCP server send out FORCERENEW
 
 * networkd-wait-online:
@@ -819,6 +833,7 @@ Features:
      or interface down
    - some servers don't do rapid commit without a filled in IA_NA, verify
      this behavior
+   - RouteTable= ?
 
 External:
 
index 8524706f5e180aa03607e9e29460187a0de370b8..90317eda88b12a5af75b3525c5c7ed5fd93b8c35 100644 (file)
                <Unit filename="../src/libelogind/sd-event/sd-event.c">
                        <Option compilerVar="CC" />
                </Unit>
+               <Unit filename="../src/libelogind/sd-id128/id128-util.c">
+                       <Option compilerVar="CC" />
+               </Unit>
+               <Unit filename="../src/libelogind/sd-id128/id128-util.h" />
                <Unit filename="../src/libelogind/sd-id128/sd-id128.c">
                        <Option compilerVar="CC" />
                </Unit>
diff --git a/coccinelle/free_and_replace.cocci b/coccinelle/free_and_replace.cocci
new file mode 100644 (file)
index 0000000..9dcdbf4
--- /dev/null
@@ -0,0 +1,15 @@
+@@
+expression p, q;
+@@
+- free(p);
+- p = q;
+- q = NULL;
+- return 0;
++ return free_and_replace(p, q);
+@@
+expression p, q;
+@@
+- free(p);
+- p = q;
+- q = NULL;
++ free_and_replace(p, q);
index 4f61599cfa0e5cf786b68ff3e5840024adafdf4d..8c93ea011ad6eeee25161c6cf90047e1460a55dc 100644 (file)
@@ -20,7 +20,7 @@
 AC_PREREQ([2.64])
 
 AC_INIT([elogind],
-        [231.4],
+        [232.2],
         [https://github.com/elogind/elogind/issues],
         [elogind],
         [https://github.com/elogind/elogind])
@@ -248,23 +248,14 @@ AS_CASE([$CC], [*clang*],
                -Wno-gnu-variable-sized-type-not-at-end \
         ])])
 
-
-# ------------------------------------------------------------------------------
-# On some distributions -flto, even if available, leads to linking errors.
-# We therefore make it optional
-have_lto=no
-AC_ARG_ENABLE([lto],
-        [AS_HELP_STRING([--disable-lto], [Disable link time optimization (default: test)])])
-
-AS_IF([test "x$enable_lto" != "xno"], [
-        AS_CASE([$CFLAGS], [*-O[[12345sz\ ]]*],
-                [have_lto=yes],
-                [AC_MSG_RESULT([skipping -flto, optimization not enabled])])
-        AS_IF([test "$have_lto" != "no"],
-                [CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [-flto])]
-        )
-        AC_SUBST([OUR_CFLAGS], "$with_cflags $sanitizer_cflags")
-])
+AC_ARG_ENABLE([lto], [AS_HELP_STRING([--disable-lto], [disable -flto])],
+                     [], [enable_lto=yes])
+AS_CASE([$CFLAGS], [*-O[[12345sz\ ]]*],
+        [AS_IF([test "x$enable_lto" = "xyes"],
+               [CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [-flto])],
+               [AC_MSG_RESULT([disabling -flto as requested])])],
+        [AC_MSG_RESULT([skipping -flto, optimization not enabled])])
+AC_SUBST([OUR_CFLAGS], "$with_cflags $sanitizer_cflags")
 
 # ------------------------------------------------------------------------------
 AS_CASE([$CFLAGS], [*-O[[12345sz\ ]]*],
@@ -722,9 +713,10 @@ AC_ARG_WITH([pamlibdir],
 AX_NORMALIZE_PATH([with_pamlibdir])
 
 AC_ARG_WITH([pamconfdir],
-        AS_HELP_STRING([--with-pamconfdir=DIR], [Directory for PAM configuration]),
+        AS_HELP_STRING([--with-pamconfdir=DIR], [Directory for PAM configuration (pass no to disable installing)]),
         [],
         [with_pamconfdir=${sysconfdir}/pam.d])
+AM_CONDITIONAL(ENABLE_PAM_CONFIG, [test "$with_pamconfdir" != "no"])
 AX_NORMALIZE_PATH([with_pamconfdir])
 
 AC_ARG_ENABLE([split-usr],
@@ -818,7 +810,6 @@ AC_MSG_RESULT([
         test coverage:           ${have_coverage}
         Split /usr:              ${enable_split_usr}
         utmp/wtmp support:       ${have_utmp}
-        Link time optimization:  ${have_lto}
         extra debugging:         ${enable_debug}
         cgroup controller:       ${with_cgroupctrl}
 
index 0fb4d7fbcf9fdfe34e85d22dae1cdb47796ce93b..1f34cbc1bfe3ec492dcefb639dfed1711ba5dfed 100644 (file)
@@ -3,27 +3,34 @@
                  "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
 
 <refsect1>
-        <title>Environment</title>
-
-        <variablelist class='environment-variables'>
-                <varlistentry id='pager'>
-                        <term><varname>$SYSTEMD_PAGER</varname></term>
-
-                        <listitem><para>Pager to use when
-                        <option>--no-pager</option> is not given;
-                        overrides <varname>$PAGER</varname>.  Setting
-                        this to an empty string or the value
-                        <literal>cat</literal> is equivalent to passing
-                        <option>--no-pager</option>.</para></listitem>
-                </varlistentry>
-
-                <varlistentry id='less'>
-                        <term><varname>$SYSTEMD_LESS</varname></term>
-
-                        <listitem><para>Override the default
-                        options passed to
-                        <command>less</command>
-                        (<literal>FRSXMK</literal>).</para></listitem>
-                </varlistentry>
-        </variablelist>
+  <title>Environment</title>
+
+  <variablelist class='environment-variables'>
+    <varlistentry id='pager'>
+      <term><varname>$SYSTEMD_PAGER</varname></term>
+
+      <listitem><para>Pager to use when <option>--no-pager</option> is not given; overrides
+      <varname>$PAGER</varname>. If neither <varname>$SYSTEMD_PAGER</varname> nor <varname>$PAGER</varname> are set, a
+      set of well-known pager implementations are tried in turn, including
+      <citerefentry><refentrytitle>less</refentrytitle><manvolnum>1</manvolnum></citerefentry> and
+      <citerefentry><refentrytitle>more</refentrytitle><manvolnum>1</manvolnum></citerefentry>, until one is found. If
+      no pager implementation is discovered no pager is invoked. Setting this environment variable to an empty string
+      or the value <literal>cat</literal> is equivalent to passing <option>--no-pager</option>.</para></listitem>
+    </varlistentry>
+
+    <varlistentry id='less'>
+      <term><varname>$SYSTEMD_LESS</varname></term>
+
+      <listitem><para>Override the options passed to <command>less</command> (by default
+      <literal>FRSXMK</literal>).</para></listitem>
+    </varlistentry>
+
+    <varlistentry id='lesscharset'>
+      <term><varname>$SYSTEMD_LESSCHARSET</varname></term>
+
+      <listitem><para>Override the charset passed to <command>less</command> (by default <literal>utf-8</literal>, if
+      the invoking terminal is determined to be UTF-8 compatible).</para></listitem>
+    </varlistentry>
+
+    </variablelist>
 </refsect1>
index b68f4fc47b30a6340210d2435fea4c8f250453b8..4fcd35685c0ad1d0b4352e95141e6ddc8a1504c4 100644 (file)
@@ -97,7 +97,7 @@
     iteration a single event source is dispatched. Each time an event
     source is dispatched the kernel is polled for new events, before
     the next event source is dispatched. The event loop is designed to
-    honour priorities and provide fairness within each priority. It is
+    honor priorities and provide fairness within each priority. It is
     not designed to provide optimal throughput, as this contradicts
     these goals due the limitations of the underlying <citerefentry
     project='man-pages'><refentrytitle>epoll</refentrytitle><manvolnum>7</manvolnum></citerefentry>
index 6457cfc9b7e49bea658badbbbd932d22fdc917e7..3e325502e2a56321d6cac7ff015294299b96e4e5 100644 (file)
@@ -57,9 +57,9 @@
       <funcsynopsisinfo>#include &lt;elogind/sd-event.h&gt;</funcsynopsisinfo>
 
       <funcsynopsisinfo><token>enum</token> {
-        <constant>SD_EVENT_SOURCE_IMPORTANT</constant> = -100,
-        <constant>SD_EVENT_SOURCE_NORMAL</constant> = 0,
-        <constant>SD_EVENT_SOURCE_IDLE</constant> = 100,
+        <constant>SD_EVENT_PRIORITY_IMPORTANT</constant> = -100,
+        <constant>SD_EVENT_PRIORITY_NORMAL</constant> = 0,
+        <constant>SD_EVENT_PRIORITY_IDLE</constant> = 100,
 };</funcsynopsisinfo>
 
       <funcprototype>
     reliable. However, it is guaranteed that if events are seen on
     multiple same-priority event sources at the same time, each one is
     not dispatched again until all others have been dispatched
-    once. This behaviour guarantees that within each priority
+    once. This behavior guarantees that within each priority
     particular event sources do not starve or dominate the event
     loop.</para>
 
index 4fa6f84cf2c6c34725892149cab1cbcb1ea86d32..cd6c39032c497b8995bd705dda38cf4b0b07f243 100644 (file)
@@ -45,6 +45,7 @@
   <refnamediv>
     <refname>sd_id128_get_machine</refname>
     <refname>sd_id128_get_boot</refname>
+    <refname>sd_id128_get_invocation</refname>
     <refpurpose>Retrieve 128-bit IDs</refpurpose>
   </refnamediv>
 
         <paramdef>sd_id128_t *<parameter>ret</parameter></paramdef>
       </funcprototype>
 
+      <funcprototype>
+        <funcdef>int <function>sd_id128_get_invocation</function></funcdef>
+        <paramdef>sd_id128_t *<parameter>ret</parameter></paramdef>
+      </funcprototype>
+
     </funcsynopsis>
   </refsynopsisdiv>
 
     for more information. This function also internally caches the
     returned ID to make this call a cheap operation.</para>
 
-    <para>Note that <function>sd_id128_get_boot()</function> always
-    returns a UUID v4 compatible ID.
-    <function>sd_id128_get_machine()</function> will also return a
-    UUID v4-compatible ID on new installations but might not on older.
-    It is possible to convert the machine ID into a UUID v4-compatible
+    <para><function>sd_id128_get_invocation()</function> returns the invocation ID of the currently executed
+    service. In its current implementation, this reads and parses the <varname>$INVOCATION_ID</varname> environment
+    variable that the service manager sets when activating a service, see
+    <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for details. The
+    ID is cached internally. In future a different mechanism to determine the invocation ID may be added.</para>
+
+    <para>Note that <function>sd_id128_get_boot()</function> and <function>sd_id128_get_invocation()</function> always
+    return UUID v4 compatible IDs.  <function>sd_id128_get_machine()</function> will also return a UUID v4-compatible
+    ID on new installations but might not on older.  It is possible to convert the machine ID into a UUID v4-compatible
     one. For more information, see
     <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
 
   <refsect1>
     <title>Notes</title>
 
-    <para>The <function>sd_id128_get_machine()</function> and
-    <function>sd_id128_get_boot()</function> interfaces are available
-    as a shared library, which can be compiled and linked to with the
-    <literal>libelogind</literal> <citerefentry project='die-net'><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry>
-    file.</para>
+    <para>The <function>sd_id128_get_machine()</function>, <function>sd_id128_get_boot()</function> and
+    <function>sd_id128_get_invocation()</function> interfaces are available as a shared library, which can be compiled
+    and linked to with the <literal>libsystemd</literal> <citerefentry
+    project='die-net'><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry> file.</para>
   </refsect1>
 
   <refsect1>
     <title>See Also</title>
 
     <para>
-      <citerefentry><refentrytitle>elogind</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>sd-id128</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
-      <citerefentry><refentrytitle>random</refentrytitle><manvolnum>4</manvolnum></citerefentry>,
-      <citerefentry><refentrytitle>sd_id128_randomize</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+      <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_id128_randomize</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry project='man-pages'><refentrytitle>random</refentrytitle><manvolnum>4</manvolnum></citerefentry>
     </para>
   </refsect1>
 
index 03efe0193a7501bfd3bb4863feaa1903bc335156..f2710b6ab3d07caa015e0efd3701ef7a18c64069 100644 (file)
       <varlistentry>
         <term>FDSTORE=1</term>
 
-        <listitem><para>Stores additional file descriptors in the
-        service manager. File descriptors sent this way will be
-        maintained per-service by the service manager and be passed
-        again using the usual file descriptor passing logic on the
-        next invocation of the service (see
-        <citerefentry><refentrytitle>sd_listen_fds</refentrytitle><manvolnum>3</manvolnum></citerefentry>).
-        This is useful for implementing service restart schemes where
-        services serialize their state to <filename>/run</filename>,
-        push their file descriptors to the system manager, and are
-        then restarted, retrieving their state again via socket
-        passing and <filename>/run</filename>. Note that the service
-        manager will accept messages for a service only if
-        <varname>FileDescriptorStoreMax=</varname> is set to non-zero
-        for it (defaults to zero). See
-        <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-        for details. Multiple arrays of file descriptors may be sent
-        in separate messages, in which case the arrays are combined.
-        Note that the service manager removes duplicate file
-        descriptors before passing them to the service. Use
-        <function>sd_pid_notify_with_fds()</function> to send messages
-        with <literal>FDSTORE=1</literal>, see
-        below.</para></listitem>
+        <listitem><para>Stores additional file descriptors in the service manager. File
+        descriptors sent this way will be maintained per-service by the service manager
+        and will be passed again using the usual file descriptor passing logic on the next
+        invocation of the service, see
+        <citerefentry><refentrytitle>sd_listen_fds</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+        This is useful for implementing service restart schemes where services serialize
+        their state to <filename>/run</filename>, push their file descriptors to the
+        system manager, and are then restarted, retrieving their state again via socket
+        passing and <filename>/run</filename>. Note that the service manager will accept
+        messages for a service only if <varname>FileDescriptorStoreMax=</varname> is set
+        to non-zero for it (defaults to zero, see
+        <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
+        File descriptors must be pollable, see
+        <citerefentry><refentrytitle>epoll_ctl</refentrytitle><manvolnum>2</manvolnum></citerefentry>.
+        Multiple arrays of file descriptors may be sent in separate messages, in which
+        case the arrays are combined.  Note that the service manager removes duplicate
+        file descriptors before passing them to the service. Use
+        <function>sd_pid_notify_with_fds()</function> to send messages with
+        <literal>FDSTORE=1</literal>, see below.</para></listitem>
       </varlistentry>
 
       <varlistentry>
index f21446339254a78df71fec637597d8afa51c569e..f718451a1b38d8d3cd30fa176e75b84b0c1fff45 100644 (file)
     </listitem>
   </varlistentry>
 
+  <varlistentry id='no-ask-password'>
+    <term><option>--no-ask-password</option></term>
+
+    <listitem><para>Do not query the user for authentication for privileged operations.</para></listitem>
+  </varlistentry>
+
   <varlistentry id='no-legend'>
     <term><option>--no-legend</option></term>
 
index ceeee519b79f864ccbf359fede0c91c3364c7e36..a44dd473c1106574472ae2cd84e7db7f2df935ae 100644 (file)
@@ -43,6 +43,14 @@ static inline void *mfree(void *memory) {
         return NULL;
 }
 
+#define free_and_replace(a, b)                  \
+        ({                                      \
+                free(a);                        \
+                (a) = (b);                      \
+                (b) = NULL;                     \
+                0;                              \
+        })
+
 void* memdup(const void *p, size_t l) _alloc_(2);
 
 static inline void freep(void *p) {
index 7c6f890cb253e9196953656ec42bae820eec0e88..2b557839446d87d49704b9db5aa4085748dd061a 100644 (file)
@@ -93,8 +93,11 @@ bool use_audit(void) {
                 int fd;
 
                 fd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_AUDIT);
-                if (fd < 0)
-                        cached_use = errno != EAFNOSUPPORT && errno != EPROTONOSUPPORT;
+                if (fd < 0) {
+                        cached_use = !IN_SET(errno, EAFNOSUPPORT, EPROTONOSUPPORT, EPERM);
+                        if (errno == EPERM)
+                                log_debug_errno(errno, "Audit access prohibited, won't talk to audit");
+                }
                 else {
                         cached_use = true;
                         safe_close(fd);
index a9c21fef2aca5ca77d3c56a1d02b1169dce3b34e..4a78b14d81221cd7a35106b338695dd6fbc4280e 100644 (file)
@@ -298,8 +298,9 @@ int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilities) {
         if (setresgid(gid, gid, gid) < 0)
                 return log_error_errno(errno, "Failed to change group ID: %m");
 
-        if (setgroups(0, NULL) < 0)
-                return log_error_errno(errno, "Failed to drop auxiliary groups list: %m");
+        r = maybe_setgroups(0, NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to drop auxiliary groups list: %m");
 
         /* Ensure we keep the permitted caps across the setresuid() */
         if (prctl(PR_SET_KEEPCAPS, 1) < 0)
index 5e53f447d03b63c18906000f58687926c503e484..44ab535cca2b488303da05a65c4a895499b19d1b 100644 (file)
@@ -134,6 +134,22 @@ int cg_read_event(const char *controller, const char *path, const char *event,
         return -ENOENT;
 }
 
+#if 0 /// UNNEEDED by elogind
+bool cg_ns_supported(void) {
+        static thread_local int enabled = -1;
+
+        if (enabled >= 0)
+                return enabled;
+
+        if (access("/proc/self/ns/cgroup", F_OK) == 0)
+                enabled = 1;
+        else
+                enabled = 0;
+
+        return enabled;
+}
+#endif //0
+
 int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d) {
         _cleanup_free_ char *fs = NULL;
         int r;
@@ -613,7 +629,7 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch
         if (!cg_controller_is_valid(controller))
                 return -EINVAL;
 
-        unified = cg_unified();
+        unified = cg_all_unified();
         if (unified < 0)
                 return unified;
 
@@ -641,7 +657,7 @@ static int controller_is_accessible(const char *controller) {
         if (!cg_controller_is_valid(controller))
                 return -EINVAL;
 
-        unified = cg_unified();
+        unified = cg_all_unified();
         if (unified < 0)
                 return unified;
         if (unified > 0) {
@@ -860,7 +876,7 @@ int cg_set_task_access(
         if (r < 0)
                 return r;
 
-        unified = cg_unified();
+        unified = cg_unified(controller);
         if (unified < 0)
                 return unified;
         if (unified)
@@ -873,6 +889,43 @@ int cg_set_task_access(
 
         return 0;
 }
+
+int cg_set_xattr(const char *controller, const char *path, const char *name, const void *value, size_t size, int flags) {
+        _cleanup_free_ char *fs = NULL;
+        int r;
+
+        assert(path);
+        assert(name);
+        assert(value || size <= 0);
+
+        r = cg_get_path(controller, path, NULL, &fs);
+        if (r < 0)
+                return r;
+
+        if (setxattr(fs, name, value, size, flags) < 0)
+                return -errno;
+
+        return 0;
+}
+
+int cg_get_xattr(const char *controller, const char *path, const char *name, void *value, size_t size) {
+        _cleanup_free_ char *fs = NULL;
+        ssize_t n;
+        int r;
+
+        assert(path);
+        assert(name);
+
+        r = cg_get_path(controller, path, NULL, &fs);
+        if (r < 0)
+                return r;
+
+        n = getxattr(fs, name, value, size);
+        if (n < 0)
+                return -errno;
+
+        return (int) n;
+}
 #endif // 0
 
 int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
@@ -885,18 +938,17 @@ int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
         assert(path);
         assert(pid >= 0);
 
-        unified = cg_unified();
+        if (controller) {
+                if (!cg_controller_is_valid(controller))
+                        return -EINVAL;
+        } else
+                controller = SYSTEMD_CGROUP_CONTROLLER;
+
+        unified = cg_unified(controller);
         if (unified < 0)
                 return unified;
-        if (unified == 0) {
-                if (controller) {
-                        if (!cg_controller_is_valid(controller))
-                                return -EINVAL;
-                } else
-                        controller = SYSTEMD_CGROUP_CONTROLLER;
-
+        if (unified == 0)
                 cs = strlen(controller);
-        }
 
         fs = procfs_file_alloca(pid, "cgroup");
         log_debug_elogind("Searching for PID %u in \"%s\" (controller \"%s\")",
@@ -964,7 +1016,7 @@ int cg_install_release_agent(const char *controller, const char *agent) {
 
         assert(agent);
 
-        unified = cg_unified();
+        unified = cg_unified(controller);
         if (unified < 0)
                 return unified;
         if (unified) /* doesn't apply to unified hierarchy */
@@ -1015,7 +1067,7 @@ int cg_uninstall_release_agent(const char *controller) {
         _cleanup_free_ char *fs = NULL;
         int r, unified;
 
-        unified = cg_unified();
+        unified = cg_unified(controller);
         if (unified < 0)
                 return unified;
         if (unified) /* Doesn't apply to unified hierarchy */
@@ -1071,7 +1123,7 @@ int cg_is_empty_recursive(const char *controller, const char *path) {
         if (controller && (isempty(path) || path_equal(path, "/")))
                 return false;
 
-        unified = cg_unified();
+        unified = cg_unified(controller);
         if (unified < 0)
                 return unified;
 
@@ -1277,7 +1329,11 @@ int cg_shift_path(const char *cgroup, const char *root, const char **shifted) {
         }
 
         p = path_startswith(cgroup, root);
+#if 0 /// With other controllers, elogind might end up in /elogind, and *p is 0
+        if (p && p > cgroup)
+#else
         if (p && p[0] && (p > cgroup))
+#endif // 0
                 *shifted = p - 1;
         else
                 *shifted = cgroup;
@@ -1696,7 +1752,7 @@ int cg_path_get_slice(const char *p, char **slice) {
                         if (!e) {
                                 char *s;
 
-                                s = strdup("-.slice");
+                                s = strdup(SPECIAL_ROOT_SLICE);
                                 if (!s)
                                         return -ENOMEM;
 
@@ -1853,7 +1909,7 @@ int cg_slice_to_path(const char *unit, char **ret) {
         assert(unit);
         assert(ret);
 
-        if (streq(unit, "-.slice")) {
+        if (streq(unit, SPECIAL_ROOT_SLICE)) {
                 char *x;
 
                 x = strdup("");
@@ -1938,6 +1994,49 @@ int cg_get_attribute(const char *controller, const char *path, const char *attri
 }
 
 #if 0 /// UNNEEDED by elogind
+int cg_get_keyed_attribute(const char *controller, const char *path, const char *attribute, const char **keys, char **values) {
+        _cleanup_free_ char *filename = NULL, *content = NULL;
+        char *line, *p;
+        int i, r;
+
+        for (i = 0; keys[i]; i++)
+                values[i] = NULL;
+
+        r = cg_get_path(controller, path, attribute, &filename);
+        if (r < 0)
+                return r;
+
+        r = read_full_file(filename, &content, NULL);
+        if (r < 0)
+                return r;
+
+        p = content;
+        while ((line = strsep(&p, "\n"))) {
+                char *key;
+
+                key = strsep(&line, " ");
+
+                for (i = 0; keys[i]; i++) {
+                        if (streq(key, keys[i])) {
+                                values[i] = strdup(line);
+                                break;
+                        }
+                }
+        }
+
+        for (i = 0; keys[i]; i++) {
+                if (!values[i]) {
+                        for (i = 0; keys[i]; i++) {
+                                free(values[i]);
+                                values[i] = NULL;
+                        }
+                        return -ENOENT;
+                }
+        }
+
+        return 0;
+}
+
 int cg_create_everywhere(CGroupMask supported, CGroupMask mask, const char *path) {
         CGroupController c;
         int r, unified;
@@ -1952,7 +2051,7 @@ int cg_create_everywhere(CGroupMask supported, CGroupMask mask, const char *path
                 return r;
 
         /* If we are in the unified hierarchy, we are done now */
-        unified = cg_unified();
+        unified = cg_all_unified();
         if (unified < 0)
                 return unified;
         if (unified > 0)
@@ -1982,7 +2081,7 @@ int cg_attach_everywhere(CGroupMask supported, const char *path, pid_t pid, cg_m
         if (r < 0)
                 return r;
 
-        unified = cg_unified();
+        unified = cg_all_unified();
         if (unified < 0)
                 return unified;
         if (unified > 0)
@@ -2034,7 +2133,7 @@ int cg_migrate_everywhere(CGroupMask supported, const char *from, const char *to
                         return r;
         }
 
-        unified = cg_unified();
+        unified = cg_all_unified();
         if (unified < 0)
                 return unified;
         if (unified > 0)
@@ -2067,7 +2166,7 @@ int cg_trim_everywhere(CGroupMask supported, const char *path, bool delete_root)
         if (r < 0)
                 return r;
 
-        unified = cg_unified();
+        unified = cg_all_unified();
         if (unified < 0)
                 return unified;
         if (unified > 0)
@@ -2094,7 +2193,7 @@ int cg_mask_supported(CGroupMask *ret) {
          * includes controllers we can make sense of and that are
          * actually accessible. */
 
-        unified = cg_unified();
+        unified = cg_all_unified();
         if (unified < 0)
                 return unified;
         if (unified > 0) {
@@ -2135,10 +2234,10 @@ int cg_mask_supported(CGroupMask *ret) {
                         mask |= CGROUP_CONTROLLER_TO_MASK(v);
                 }
 
-                /* Currently, we only support the memory, io and pids
+                /* Currently, we support the cpu, memory, io and pids
                  * controller in the unified hierarchy, mask
                  * everything else off. */
-                mask &= CGROUP_MASK_MEMORY | CGROUP_MASK_IO | CGROUP_MASK_PIDS;
+                mask &= CGROUP_MASK_CPU | CGROUP_MASK_MEMORY | CGROUP_MASK_IO | CGROUP_MASK_PIDS;
 
         } else {
                 CGroupController c;
@@ -2217,9 +2316,10 @@ int cg_kernel_controllers(Set *controllers) {
 }
 #endif // 0
 
-static thread_local int unified_cache = -1;
+static thread_local CGroupUnified unified_cache = CGROUP_UNIFIED_UNKNOWN;
+
+static int cg_update_unified(void) {
 
-int cg_unified(void) {
         struct statfs fs;
 
         /* Checks if we support the unified hierarchy. Returns an
@@ -2227,34 +2327,57 @@ int cg_unified(void) {
          * have any other trouble determining if the unified hierarchy
          * is supported. */
 
-        if (unified_cache >= 0)
-                return unified_cache;
+        if (unified_cache >= CGROUP_UNIFIED_NONE)
+                return 0;
 
         if (statfs("/sys/fs/cgroup/", &fs) < 0)
                 return -errno;
 
 #if 0 /// UNNEEDED by elogind
         if (F_TYPE_EQUAL(fs.f_type, CGROUP2_SUPER_MAGIC))
-                unified_cache = true;
-        else if (F_TYPE_EQUAL(fs.f_type, TMPFS_MAGIC))
+                unified_cache = CGROUP_UNIFIED_ALL;
+        else if (F_TYPE_EQUAL(fs.f_type, TMPFS_MAGIC)) {
+                if (statfs("/sys/fs/cgroup/systemd/", &fs) < 0)
+                        return -errno;
+
+                unified_cache = F_TYPE_EQUAL(fs.f_type, CGROUP2_SUPER_MAGIC) ?
+                        CGROUP_UNIFIED_SYSTEMD : CGROUP_UNIFIED_NONE;
+        } else
+                return -ENOMEDIUM;
 #else
         /* elogind can not support the unified hierarchy as a controller,
          * so always assume a classical hierarchy.
          * If, and only *if*, someone really wants to substitute systemd-login
          * in an environment managed by systemd with elogind, we might have to
          * add such a support. */
-        if (F_TYPE_EQUAL(fs.f_type, TMPFS_MAGIC))
+        unified_cache = CGROUP_UNIFIED_NONE;
 #endif // 0
-                unified_cache = false;
+
+        return 0;
+}
+
+int cg_unified(const char *controller) {
+
+        int r;
+
+        r = cg_update_unified();
+        if (r < 0)
+                return r;
+
+        if (streq_ptr(controller, SYSTEMD_CGROUP_CONTROLLER))
+                return unified_cache >= CGROUP_UNIFIED_SYSTEMD;
         else
-                return -ENOMEDIUM;
+                return unified_cache >= CGROUP_UNIFIED_ALL;
+}
 
-        return unified_cache;
+int cg_all_unified(void) {
+
+        return cg_unified(NULL);
 }
 
 #if 0 /// UNNEEDED by elogind
 void cg_unified_flush(void) {
-        unified_cache = -1;
+        unified_cache = CGROUP_UNIFIED_UNKNOWN;
 }
 
 int cg_enable_everywhere(CGroupMask supported, CGroupMask mask, const char *p) {
@@ -2267,7 +2390,7 @@ int cg_enable_everywhere(CGroupMask supported, CGroupMask mask, const char *p) {
         if (supported == 0)
                 return 0;
 
-        unified = cg_unified();
+        unified = cg_all_unified();
         if (unified < 0)
                 return unified;
         if (!unified) /* on the legacy hiearchy there's no joining of controllers defined */
@@ -2306,7 +2429,7 @@ bool cg_is_unified_wanted(void) {
 
         /* If the hierarchy is already mounted, then follow whatever
          * was chosen for it. */
-        unified = cg_unified();
+        unified = cg_all_unified();
         if (unified >= 0)
                 return unified;
 
@@ -2335,6 +2458,52 @@ bool cg_is_unified_wanted(void) {
 bool cg_is_legacy_wanted(void) {
         return !cg_is_unified_wanted();
 }
+
+bool cg_is_unified_systemd_controller_wanted(void) {
+        static thread_local int wanted = -1;
+        int r, unified;
+
+        /* If the unified hierarchy is requested in full, no need to
+         * bother with this. */
+        if (cg_is_unified_wanted())
+                return 0;
+
+        /* If the hierarchy is already mounted, then follow whatever
+         * was chosen for it. */
+        unified = cg_unified(SYSTEMD_CGROUP_CONTROLLER);
+        if (unified >= 0)
+                return unified;
+
+        /* Otherwise, let's see what the kernel command line has to
+         * say. Since checking that is expensive, let's cache the
+         * result. */
+        if (wanted >= 0)
+                return wanted;
+
+        r = get_proc_cmdline_key("systemd.legacy_systemd_cgroup_controller", NULL);
+        if (r > 0) {
+        if (r > 0)
+                wanted = false;
+        } else {
+        else {
+                _cleanup_free_ char *value = NULL;
+
+                r = get_proc_cmdline_key("systemd.legacy_systemd_cgroup_controller=", &value);
+                if (r < 0)
+                        return true;
+
+                if (r == 0)
+                        wanted = true;
+                else
+                        wanted = parse_boolean(value) <= 0;
+        }
+
+        return wanted;
+}
+
+bool cg_is_legacy_systemd_controller_wanted(void) {
+        return cg_is_legacy_wanted() && !cg_is_unified_systemd_controller_wanted();
+}
 #else
 bool cg_is_legacy_wanted(void) {
         return true;
@@ -2419,6 +2588,20 @@ int cg_blkio_weight_parse(const char *s, uint64_t *ret) {
 }
 #endif // 0
 
+bool is_cgroup_fs(const struct statfs *s) {
+        return is_fs_type(s, CGROUP_SUPER_MAGIC) ||
+               is_fs_type(s, CGROUP2_SUPER_MAGIC);
+}
+
+bool fd_is_cgroup_fs(int fd) {
+        struct statfs s;
+
+        if (fstatfs(fd, &s) < 0)
+                return -errno;
+
+        return is_cgroup_fs(&s);
+}
+
 static const char *cgroup_controller_table[_CGROUP_CONTROLLER_MAX] = {
         [CGROUP_CONTROLLER_CPU] = "cpu",
         [CGROUP_CONTROLLER_CPUACCT] = "cpuacct",
index 56598d22bde8b1de244d4729ecb6ea129b1377f6..73fce35a010c979b706e7e320e2634ae70e06053 100644 (file)
@@ -63,10 +63,12 @@ typedef enum CGroupMask {
 #define CGROUP_WEIGHT_MIN UINT64_C(1)
 #define CGROUP_WEIGHT_MAX UINT64_C(10000)
 #define CGROUP_WEIGHT_DEFAULT UINT64_C(100)
+#endif // 0
 
 #define CGROUP_LIMIT_MIN UINT64_C(0)
 #define CGROUP_LIMIT_MAX ((uint64_t) -1)
 
+#if 0 /// UNNEEDED by elogind
 static inline bool CGROUP_WEIGHT_IS_OK(uint64_t x) {
         return
             x == CGROUP_WEIGHT_INVALID ||
@@ -114,6 +116,17 @@ static inline bool CGROUP_BLKIO_WEIGHT_IS_OK(uint64_t x) {
 }
 #endif // 0
 
+/* Default resource limits */
+#define DEFAULT_TASKS_MAX_PERCENTAGE            15U /* 15% of PIDs, 4915 on default settings */
+#define DEFAULT_USER_TASKS_MAX_PERCENTAGE       33U /* 33% of PIDs, 10813 on default settings */
+
+typedef enum CGroupUnified {
+        CGROUP_UNIFIED_UNKNOWN = -1,
+        CGROUP_UNIFIED_NONE = 0,        /* Both systemd and controllers on legacy */
+        CGROUP_UNIFIED_SYSTEMD = 1,     /* Only systemd on unified */
+        CGROUP_UNIFIED_ALL = 2,         /* Both systemd and controllers on unified */
+} CGroupUnified;
+
 /*
  * General rules:
  *
@@ -171,10 +184,14 @@ int cg_create_and_attach(const char *controller, const char *path, pid_t pid);
 
 int cg_set_attribute(const char *controller, const char *path, const char *attribute, const char *value);
 int cg_get_attribute(const char *controller, const char *path, const char *attribute, char **ret);
-
 #if 0 /// UNNEEDED by elogind
+int cg_get_keyed_attribute(const char *controller, const char *path, const char *attribute, const char **keys, char **values);
+
 int cg_set_group_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid);
 int cg_set_task_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid);
+
+int cg_set_xattr(const char *controller, const char *path, const char *name, const void *value, size_t size, int flags);
+int cg_get_xattr(const char *controller, const char *path, const char *name, void *value, size_t size);
 #endif // 0
 
 int cg_install_release_agent(const char *controller, const char *agent);
@@ -232,15 +249,22 @@ int cg_mask_supported(CGroupMask *ret);
 
 #if 0 /// UNNEEDED by elogind
 int cg_kernel_controllers(Set *controllers);
+
+bool cg_ns_supported(void);
 #endif // 0
 
-int cg_unified(void);
+int cg_all_unified(void);
+int cg_unified(const char *controller);
 #if 0 /// UNNEEDED by elogind
 void cg_unified_flush(void);
 
 bool cg_is_unified_wanted(void);
 #endif // 0
 bool cg_is_legacy_wanted(void);
+#if 0 /// UNNEEDED by elogind
+bool cg_is_unified_systemd_controller_wanted(void);
+bool cg_is_legacy_systemd_controller_wanted(void);
+#endif // 0
 
 const char* cgroup_controller_to_string(CGroupController c) _const_;
 CGroupController cgroup_controller_from_string(const char *s) _pure_;
@@ -250,3 +274,6 @@ int cg_weight_parse(const char *s, uint64_t *ret);
 int cg_cpu_shares_parse(const char *s, uint64_t *ret);
 int cg_blkio_weight_parse(const char *s, uint64_t *ret);
 #endif // 0
+
+bool is_cgroup_fs(const struct statfs *s);
+bool fd_is_cgroup_fs(int fd);
index bc7826f7b82e65bae59a859a8b39857ff97d39a6..5ef23ff359ba5a00b939b01de040e8a5ed0628f0 100644 (file)
@@ -78,7 +78,7 @@
 #endif
 
 /* Return a nulstr for a standard cascade of configuration paths,
- * suitable to pass to conf_files_list_nulstr() or config_parse_many()
+ * suitable to pass to conf_files_list_nulstr() or config_parse_many_nulstr()
  * to implement drop-in directories for extending configuration
  * files. */
 #define CONF_PATHS_NULSTR(n) \
index 127ca2ecb2ced04c1d5a81177f7f8a6e536edbd4..aa5dece97e239628e551ca28f4626fd106aa9674 100644 (file)
@@ -333,7 +333,7 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi
                 assert(remaining > 0);
 
                 if (*f != '\\') {
-                        /* A literal literal, copy verbatim */
+                        /* A literal, copy verbatim */
                         *(t++) = *f;
                         continue;
                 }
index df432eaee4283f9c182fa01301e48cffc869fb13..4ad2acf3bd7d9f5a404c1b04f89fe378f4a0d6f5 100644 (file)
@@ -47,6 +47,8 @@
 #include "umask-util.h"
 #include "utf8.h"
 
+#define READ_FULL_BYTES_MAX (4U*1024U*1024U)
+
 int write_string_stream(FILE *f, const char *line, bool enforce_newline) {
 
         assert(f);
@@ -230,7 +232,7 @@ int read_full_stream(FILE *f, char **contents, size_t *size) {
         if (S_ISREG(st.st_mode)) {
 
                 /* Safety check */
-                if (st.st_size > 4*1024*1024)
+                if (st.st_size > READ_FULL_BYTES_MAX)
                         return -E2BIG;
 
                 /* Start with the right file size, but be prepared for
@@ -245,26 +247,31 @@ int read_full_stream(FILE *f, char **contents, size_t *size) {
                 char *t;
                 size_t k;
 
-                t = realloc(buf, n+1);
+                t = realloc(buf, n + 1);
                 if (!t)
                         return -ENOMEM;
 
                 buf = t;
                 k = fread(buf + l, 1, n - l, f);
+                if (k > 0)
+                        l += k;
 
-                if (k <= 0) {
-                        if (ferror(f))
-                                return -errno;
+                if (ferror(f))
+                        return -errno;
 
+                if (feof(f))
                         break;
-                }
 
-                l += k;
-                n *= 2;
+                /* We aren't expecting fread() to return a short read outside
+                 * of (error && eof), assert buffer is full and enlarge buffer.
+                 */
+                assert(l == n);
 
                 /* Safety check */
-                if (n > 4*1024*1024)
+                if (n >= READ_FULL_BYTES_MAX)
                         return -E2BIG;
+
+                n = MIN(n * 2, READ_FULL_BYTES_MAX);
         }
 
         buf[l] = 0;
@@ -1039,7 +1046,7 @@ int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
         if (r < 0)
                 return r;
 
-        fd = mkostemp_safe(t, O_WRONLY|O_CLOEXEC);
+        fd = mkostemp_safe(t);
         if (fd < 0) {
                 free(t);
                 return -errno;
@@ -1072,7 +1079,7 @@ int fflush_and_check(FILE *f) {
 }
 
 /* This is much like mkostemp() but is subject to umask(). */
-int mkostemp_safe(char *pattern, int flags) {
+int mkostemp_safe(char *pattern) {
         _cleanup_umask_ mode_t u = 0;
         int fd;
 
@@ -1080,7 +1087,7 @@ int mkostemp_safe(char *pattern, int flags) {
 
         u = umask(077);
 
-        fd = mkostemp(pattern, flags);
+        fd = mkostemp(pattern, O_CLOEXEC);
         if (fd < 0)
                 return -errno;
 
@@ -1166,8 +1173,8 @@ int tempfn_random_child(const char *p, const char *extra, char **ret) {
         char *t, *x;
         uint64_t u;
         unsigned i;
+        int r;
 
-        assert(p);
         assert(ret);
 
         /* Turns this:
@@ -1176,6 +1183,12 @@ int tempfn_random_child(const char *p, const char *extra, char **ret) {
          *         /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0
          */
 
+        if (!p) {
+                r = tmp_dir(&p);
+                if (r < 0)
+                        return r;
+        }
+
         if (!extra)
                 extra = "";
 
@@ -1262,24 +1275,25 @@ int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space)
 
 int open_tmpfile_unlinkable(const char *directory, int flags) {
         char *p;
-        int fd;
+        int fd, r;
 
-        if (!directory)
-                directory = "/tmp";
+        if (!directory) {
+                r = tmp_dir(&directory);
+                if (r < 0)
+                        return r;
+        }
 
         /* Returns an unlinked temporary file that cannot be linked into the file system anymore */
 
-#ifdef O_TMPFILE
         /* Try O_TMPFILE first, if it is supported */
         fd = open(directory, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR);
         if (fd >= 0)
                 return fd;
-#endif
 
         /* Fall back to unguessable name + unlinking */
         p = strjoina(directory, "/systemd-tmp-XXXXXX");
 
-        fd = mkostemp_safe(p, flags);
+        fd = mkostemp_safe(p);
         if (fd < 0)
                 return fd;
 
@@ -1302,7 +1316,6 @@ int open_tmpfile_linkable(const char *target, int flags, char **ret_path) {
          * which case "ret_path" will be returned as NULL. If not possible a the tempoary path name used is returned in
          * "ret_path". Use link_tmpfile() below to rename the result after writing the file in full. */
 
-#ifdef O_TMPFILE
         {
                 _cleanup_free_ char *dn = NULL;
 
@@ -1318,7 +1331,6 @@ int open_tmpfile_linkable(const char *target, int flags, char **ret_path) {
 
                 log_debug_errno(errno, "Failed to use O_TMPFILE on %s: %m", dn);
         }
-#endif
 
         r = tempfn_random(target, NULL, &tmp);
         if (r < 0)
index 2469b4ca4d9fff3b78577c73d06015806c6fbbd2..fe9506c3d3717f4b971e8b6d439c45deda81a5c0 100644 (file)
@@ -75,7 +75,7 @@ int search_and_fopen_nulstr(const char *path, const char *mode, const char *root
 int fflush_and_check(FILE *f);
 
 int fopen_temporary(const char *path, FILE **_f, char **_temp_path);
-int mkostemp_safe(char *pattern, int flags);
+int mkostemp_safe(char *pattern);
 
 int tempfn_xxxxxx(const char *p, const char *extra, char **ret);
 int tempfn_random(const char *p, const char *extra, char **ret);
index d2d7bb566f1324969997f4060a35d18a8bc9f929..59787552d2618519f5ff2e04c886188f321c0326 100644 (file)
@@ -501,34 +501,94 @@ int get_files_in_directory(const char *path, char ***list) {
 }
 
 #if 0 /// UNNEEDED by elogind
-int var_tmp(char **ret) {
-        const char *tmp_dir = NULL;
-        const char *env_tmp_dir = NULL;
-        char *c = NULL;
-        int r;
+static int getenv_tmp_dir(const char **ret_path) {
+        const char *n;
+        int r, ret = 0;
 
-        assert(ret);
+        assert(ret_path);
 
-        env_tmp_dir = getenv("TMPDIR");
-        if (env_tmp_dir != NULL) {
-                r = is_dir(env_tmp_dir, true);
-                if (r < 0 && r != -ENOENT)
-                        return r;
-                if (r > 0)
-                        tmp_dir = env_tmp_dir;
+        /* We use the same order of environment variables python uses in tempfile.gettempdir():
+         * https://docs.python.org/3/library/tempfile.html#tempfile.gettempdir */
+        FOREACH_STRING(n, "TMPDIR", "TEMP", "TMP") {
+                const char *e;
+
+                e = secure_getenv(n);
+                if (!e)
+                        continue;
+                if (!path_is_absolute(e)) {
+                        r = -ENOTDIR;
+                        goto next;
+                }
+                if (!path_is_safe(e)) {
+                        r = -EPERM;
+                        goto next;
+                }
+
+                r = is_dir(e, true);
+                if (r < 0)
+                        goto next;
+                if (r == 0) {
+                        r = -ENOTDIR;
+                        goto next;
+                }
+
+                *ret_path = e;
+                return 1;
+
+        next:
+                /* Remember first error, to make this more debuggable */
+                if (ret >= 0)
+                        ret = r;
         }
 
-        if (!tmp_dir)
-                tmp_dir = "/var/tmp";
+        if (ret < 0)
+                return ret;
 
-        c = strdup(tmp_dir);
-        if (!c)
-                return -ENOMEM;
-        *ret = c;
+        *ret_path = NULL;
+        return ret;
+}
+
+static int tmp_dir_internal(const char *def, const char **ret) {
+        const char *e;
+        int r, k;
+
+        assert(def);
+        assert(ret);
 
+        r = getenv_tmp_dir(&e);
+        if (r > 0) {
+                *ret = e;
+                return 0;
+        }
+
+        k = is_dir(def, true);
+        if (k == 0)
+                k = -ENOTDIR;
+        if (k < 0)
+                return r < 0 ? r : k;
+
+        *ret = def;
         return 0;
 }
 
+int var_tmp_dir(const char **ret) {
+
+        /* Returns the location for "larger" temporary files, that is backed by physical storage if available, and thus
+         * even might survive a boot: /var/tmp. If $TMPDIR (or related environment variables) are set, its value is
+         * returned preferably however. Note that both this function and tmp_dir() below are affected by $TMPDIR,
+         * making it a variable that overrides all temporary file storage locations. */
+
+        return tmp_dir_internal("/var/tmp", ret);
+}
+
+int tmp_dir(const char **ret) {
+
+        /* Similar to var_tmp_dir() above, but returns the location for "smaller" temporary files, which is usually
+         * backed by an in-memory file system: /tmp. */
+
+        return tmp_dir_internal("/tmp", ret);
+}
+
 int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
         char path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
         int r;
@@ -542,4 +602,187 @@ int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
 
         return r;
 }
+
+int chase_symlinks(const char *path, const char *_root, char **ret) {
+        _cleanup_free_ char *buffer = NULL, *done = NULL, *root = NULL;
+        _cleanup_close_ int fd = -1;
+        unsigned max_follow = 32; /* how many symlinks to follow before giving up and returning ELOOP */
+        char *todo;
+        int r;
+
+        assert(path);
+
+        /* This is a lot like canonicalize_file_name(), but takes an additional "root" parameter, that allows following
+         * symlinks relative to a root directory, instead of the root of the host.
+         *
+         * Note that "root" matters only if we encounter an absolute symlink, it's unused otherwise. Most importantly
+         * this means the path parameter passed in is not prefixed by it.
+         *
+         * Algorithmically this operates on two path buffers: "done" are the components of the path we already
+         * processed and resolved symlinks, "." and ".." of. "todo" are the components of the path we still need to
+         * process. On each iteration, we move one component from "todo" to "done", processing it's special meaning
+         * each time. The "todo" path always starts with at least one slash, the "done" path always ends in no
+         * slash. We always keep an O_PATH fd to the component we are currently processing, thus keeping lookup races
+         * at a minimum. */
+
+        r = path_make_absolute_cwd(path, &buffer);
+        if (r < 0)
+                return r;
+
+        if (_root) {
+                r = path_make_absolute_cwd(_root, &root);
+                if (r < 0)
+                        return r;
+        }
+
+        fd = open("/", O_CLOEXEC|O_NOFOLLOW|O_PATH);
+        if (fd < 0)
+                return -errno;
+
+        todo = buffer;
+        for (;;) {
+                _cleanup_free_ char *first = NULL;
+                _cleanup_close_ int child = -1;
+                struct stat st;
+                size_t n, m;
+
+                /* Determine length of first component in the path */
+                n = strspn(todo, "/");                  /* The slashes */
+                m = n + strcspn(todo + n, "/");         /* The entire length of the component */
+
+                /* Extract the first component. */
+                first = strndup(todo, m);
+                if (!first)
+                        return -ENOMEM;
+
+                todo += m;
+
+                /* Just a single slash? Then we reached the end. */
+                if (isempty(first) || path_equal(first, "/"))
+                        break;
+
+                /* Just a dot? Then let's eat this up. */
+                if (path_equal(first, "/."))
+                        continue;
+
+                /* Two dots? Then chop off the last bit of what we already found out. */
+                if (path_equal(first, "/..")) {
+                        _cleanup_free_ char *parent = NULL;
+                        int fd_parent = -1;
+
+                        if (isempty(done) || path_equal(done, "/"))
+                                return -EINVAL;
+
+                        parent = dirname_malloc(done);
+                        if (!parent)
+                                return -ENOMEM;
+
+                        /* Don't allow this to leave the root dir */
+                        if (root &&
+                            path_startswith(done, root) &&
+                            !path_startswith(parent, root))
+                                return -EINVAL;
+
+                        free_and_replace(done, parent);
+
+                        fd_parent = openat(fd, "..", O_CLOEXEC|O_NOFOLLOW|O_PATH);
+                        if (fd_parent < 0)
+                                return -errno;
+
+                        safe_close(fd);
+                        fd = fd_parent;
+
+                        continue;
+                }
+
+                /* Otherwise let's see what this is. */
+                child = openat(fd, first + n, O_CLOEXEC|O_NOFOLLOW|O_PATH);
+                if (child < 0)
+                        return -errno;
+
+                if (fstat(child, &st) < 0)
+                        return -errno;
+
+                if (S_ISLNK(st.st_mode)) {
+                        _cleanup_free_ char *destination = NULL;
+
+                        /* This is a symlink, in this case read the destination. But let's make sure we don't follow
+                         * symlinks without bounds. */
+                        if (--max_follow <= 0)
+                                return -ELOOP;
+
+                        r = readlinkat_malloc(fd, first + n, &destination);
+                        if (r < 0)
+                                return r;
+                        if (isempty(destination))
+                                return -EINVAL;
+
+                        if (path_is_absolute(destination)) {
+
+                                /* An absolute destination. Start the loop from the beginning, but use the root
+                                 * directory as base. */
+
+                                safe_close(fd);
+                                fd = open(root ?: "/", O_CLOEXEC|O_NOFOLLOW|O_PATH);
+                                if (fd < 0)
+                                        return -errno;
+
+                                free_and_replace(buffer, destination);
+
+                                todo = buffer;
+                                free(done);
+
+                                /* Note that we do not revalidate the root, we take it as is. */
+                                if (isempty(root))
+                                        done = NULL;
+                                else {
+                                        done = strdup(root);
+                                        if (!done)
+                                                return -ENOMEM;
+                                }
+
+                        } else {
+                                char *joined;
+
+                                /* A relative destination. If so, this is what we'll prefix what's left to do with what
+                                 * we just read, and start the loop again, but remain in the current directory. */
+
+                                joined = strjoin("/", destination, todo, NULL);
+                                if (!joined)
+                                        return -ENOMEM;
+
+                                free(buffer);
+                                todo = buffer = joined;
+                        }
+
+                        continue;
+                }
+
+                /* If this is not a symlink, then let's just add the name we read to what we already verified. */
+                if (!done) {
+                        done = first;
+                        first = NULL;
+                } else {
+                        if (!strextend(&done, first, NULL))
+                                return -ENOMEM;
+                }
+
+                /* And iterate again, but go one directory further down. */
+                safe_close(fd);
+                fd = child;
+                child = -1;
+        }
+
+        if (!done) {
+                /* Special case, turn the empty string into "/", to indicate the root directory. */
+                done = strdup("/");
+                if (!done)
+                        return -ENOMEM;
+        }
+
+        *ret = done;
+        done = NULL;
+
+        return 0;
+}
 #endif // 0
index ab31f061e13745fc8037ebcb51a034e48a06ab6d..871f7209f2f2ed3a1abbb428f05307a18ed1fbf5 100644 (file)
@@ -73,7 +73,8 @@ int mkfifo_atomic(const char *path, mode_t mode);
 int get_files_in_directory(const char *path, char ***list);
 
 #if 0 /// UNNEEDED by elogind
-int var_tmp(char **ret);
+int tmp_dir(const char **ret);
+int var_tmp_dir(const char **ret);
 
 #define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1)
 
@@ -88,4 +89,6 @@ union inotify_event_buffer {
 };
 
 int inotify_add_watch_fd(int fd, int what, uint32_t mask);
+
+int chase_symlinks(const char *path, const char *_root, char **ret);
 #endif // 0
index 542110503f7f37cd6119e0a4c0918620ea4ef330..e6ac0545a4efc5c0e0d5fc3d0c34c71eda0a53f5 100644 (file)
@@ -26,7 +26,7 @@
 char *
 utf8_prev_char (const char *p)
 {
-  while (1)
+  for (;;)
     {
       p--;
       if ((*p & 0xc0) != 0x80)
index a5cb62eb661e03eaf16682241f82d830ee952e46..5aebd89e34af753b414391616f6595cf79d17ea5 100644 (file)
@@ -168,7 +168,6 @@ char* hostname_cleanup(char *s) {
                         *(d++) = *p;
                         dot = false;
                 }
-
         }
 
         if (dot && d > s)
index 5962aa42113b5d425cd181241a7f17da9ef43439..c3771a177f70e494b94d868a62056bc5d8f6e6be 100644 (file)
                 } else {                                                \
                         if ((_b->name##_prev = _a->name##_prev))        \
                                 _b->name##_prev->name##_next = _b;      \
+                        else                                            \
+                                *_head = _b;                            \
                         _b->name##_next = _a;                           \
                         _a->name##_prev = _b;                           \
                 }                                                       \
index da6aa409b5b99b7ebef64f2420627db857fe9b1a..d84c9bf116b43c88d239079663e4e9f3ed235385 100644 (file)
@@ -135,7 +135,7 @@ static int create_log_socket(int type) {
         if (fd < 0)
                 return -errno;
 
-        fd_inc_sndbuf(fd, SNDBUF_SIZE);
+        (void) fd_inc_sndbuf(fd, SNDBUF_SIZE);
 
         /* We need a blocking fd here since we'd otherwise lose
         messages way too early. However, let's not hang forever in the
@@ -342,8 +342,6 @@ static int write_to_console(
                 const char *file,
                 int line,
                 const char *func,
-                const char *object_field,
-                const char *object,
                 const char *buffer) {
 
         char location[256], prefix[1 + DECIMAL_STR_MAX(int) + 2];
@@ -355,7 +353,7 @@ static int write_to_console(
                 return 0;
 
         if (log_target == LOG_TARGET_CONSOLE_PREFIXED) {
-                sprintf(prefix, "<%i>", level);
+                xsprintf(prefix, "<%i>", level);
                 IOVEC_SET_STRING(iovec[n++], prefix);
         }
 
@@ -402,8 +400,6 @@ static int write_to_syslog(
                 const char *file,
                 int line,
                 const char *func,
-                const char *object_field,
-                const char *object,
                 const char *buffer) {
 
         char header_priority[2 + DECIMAL_STR_MAX(int) + 1],
@@ -465,8 +461,6 @@ static int write_to_kmsg(
                 const char *file,
                 int line,
                 const char *func,
-                const char *object_field,
-                const char *object,
                 const char *buffer) {
 
         char header_priority[2 + DECIMAL_STR_MAX(int) + 1],
@@ -498,7 +492,8 @@ static int log_do_header(
                 int level,
                 int error,
                 const char *file, int line, const char *func,
-                const char *object_field, const char *object) {
+                const char *object_field, const char *object,
+                const char *extra_field, const char *extra) {
 
         snprintf(header, size,
                  "PRIORITY=%i\n"
@@ -508,6 +503,7 @@ static int log_do_header(
                  "%s%s%s"
                  "%s%.*i%s"
                  "%s%s%s"
+                 "%s%s%s"
                  "SYSLOG_IDENTIFIER=%s\n",
                  LOG_PRI(level),
                  LOG_FAC(level),
@@ -526,6 +522,9 @@ static int log_do_header(
                  isempty(object) ? "" : object_field,
                  isempty(object) ? "" : object,
                  isempty(object) ? "" : "\n",
+                 isempty(extra) ? "" : extra_field,
+                 isempty(extra) ? "" : extra,
+                 isempty(extra) ? "" : "\n",
                  program_invocation_short_name);
 
         return 0;
@@ -539,6 +538,8 @@ static int write_to_journal(
                 const char *func,
                 const char *object_field,
                 const char *object,
+                const char *extra_field,
+                const char *extra,
                 const char *buffer) {
 
         char header[LINE_MAX];
@@ -548,7 +549,7 @@ static int write_to_journal(
         if (journal_fd < 0)
                 return 0;
 
-        log_do_header(header, sizeof(header), level, error, file, line, func, object_field, object);
+        log_do_header(header, sizeof(header), level, error, file, line, func, object_field, object, extra_field, extra);
 
         IOVEC_SET_STRING(iovec[0], header);
         IOVEC_SET_STRING(iovec[1], "MESSAGE=");
@@ -573,10 +574,15 @@ static int log_dispatch(
                 const char *func,
                 const char *object_field,
                 const char *object,
+                const char *extra,
+                const char *extra_field,
                 char *buffer) {
 
         assert(buffer);
 
+        if (error < 0)
+                error = -error;
+
         if (log_target == LOG_TARGET_NULL)
                 return -error;
 
@@ -584,9 +590,6 @@ static int log_dispatch(
         if ((level & LOG_FACMASK) == 0)
                 level = log_facility | LOG_PRI(level);
 
-        if (error < 0)
-                error = -error;
-
         do {
                 char *e;
                 int k = 0;
@@ -604,7 +607,7 @@ static int log_dispatch(
                     log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
                     log_target == LOG_TARGET_JOURNAL) {
 
-                        k = write_to_journal(level, error, file, line, func, object_field, object, buffer);
+                        k = write_to_journal(level, error, file, line, func, object_field, object, extra_field, extra, buffer);
                         if (k < 0) {
                                 if (k != -EAGAIN)
                                         log_close_journal();
@@ -616,7 +619,7 @@ static int log_dispatch(
                 if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
                     log_target == LOG_TARGET_SYSLOG) {
 
-                        k = write_to_syslog(level, error, file, line, func, object_field, object, buffer);
+                        k = write_to_syslog(level, error, file, line, func, buffer);
                         if (k < 0) {
                                 if (k != -EAGAIN)
                                         log_close_syslog();
@@ -631,7 +634,7 @@ static int log_dispatch(
                      log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
                      log_target == LOG_TARGET_KMSG)) {
 
-                        k = write_to_kmsg(level, error, file, line, func, object_field, object, buffer);
+                        k = write_to_kmsg(level, error, file, line, func, buffer);
                         if (k < 0) {
                                 log_close_kmsg();
                                 log_open_console();
@@ -639,7 +642,7 @@ static int log_dispatch(
                 }
 
                 if (k <= 0)
-                        (void) write_to_console(level, error, file, line, func, object_field, object, buffer);
+                        (void) write_to_console(level, error, file, line, func, buffer);
 
                 buffer = e;
         } while (buffer);
@@ -665,7 +668,7 @@ int log_dump_internal(
         if (_likely_(LOG_PRI(level) > log_max_level))
                 return -error;
 
-        return log_dispatch(level, error, file, line, func, NULL, NULL, buffer);
+        return log_dispatch(level, error, file, line, func, NULL, NULL, NULL, NULL, buffer);
 }
 
 int log_internalv(
@@ -692,7 +695,7 @@ int log_internalv(
 
         vsnprintf(buffer, sizeof(buffer), format, ap);
 
-        return log_dispatch(level, error, file, line, func, NULL, NULL, buffer);
+        return log_dispatch(level, error, file, line, func, NULL, NULL, NULL, NULL, buffer);
 }
 
 int log_internal(
@@ -721,6 +724,8 @@ int log_object_internalv(
                 const char *func,
                 const char *object_field,
                 const char *object,
+                const char *extra_field,
+                const char *extra,
                 const char *format,
                 va_list ap) {
 
@@ -754,7 +759,7 @@ int log_object_internalv(
 
         vsnprintf(b, l, format, ap);
 
-        return log_dispatch(level, error, file, line, func, object_field, object, buffer);
+        return log_dispatch(level, error, file, line, func, object_field, object, extra_field, extra, buffer);
 }
 
 int log_object_internal(
@@ -765,13 +770,15 @@ int log_object_internal(
                 const char *func,
                 const char *object_field,
                 const char *object,
+                const char *extra_field,
+                const char *extra,
                 const char *format, ...) {
 
         va_list ap;
         int r;
 
         va_start(ap, format);
-        r = log_object_internalv(level, error, file, line, func, object_field, object, format, ap);
+        r = log_object_internalv(level, error, file, line, func, object_field, object, extra_field, extra, format, ap);
         va_end(ap);
 
         return r;
@@ -791,12 +798,12 @@ static void log_assert(
                 return;
 
         DISABLE_WARNING_FORMAT_NONLITERAL;
-        xsprintf(buffer, format, text, file, line, func);
+        snprintf(buffer, sizeof buffer, format, text, file, line, func);
         REENABLE_WARNING;
 
         log_abort_msg = buffer;
 
-        log_dispatch(level, 0, file, line, func, NULL, NULL, buffer);
+        log_dispatch(level, 0, file, line, func, NULL, NULL, NULL, NULL, buffer);
 }
 
 noreturn void log_assert_failed(const char *text, const char *file, int line, const char *func) {
@@ -905,7 +912,7 @@ int log_struct_internal(
                 bool fallback = false;
 
                 /* If the journal is available do structured logging */
-                log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL);
+                log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL, NULL, NULL);
                 IOVEC_SET_STRING(iovec[n++], header);
 
                 va_start(ap, format);
@@ -953,7 +960,7 @@ int log_struct_internal(
         if (!found)
                 return -error;
 
-        return log_dispatch(level, error, file, line, func, NULL, NULL, buf + 8);
+        return log_dispatch(level, error, file, line, func, NULL, NULL, NULL, NULL, buf + 8);
 }
 
 int log_set_target_from_string(const char *e) {
@@ -978,7 +985,7 @@ int log_set_max_level_from_string(const char *e) {
         return 0;
 }
 
-static int parse_proc_cmdline_item(const char *key, const char *value) {
+static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
 
         /*
          * The systemd.log_xyz= settings are parsed by all tools, and
@@ -1023,7 +1030,7 @@ void log_parse_environment(void) {
                 /* Only try to read the command line in daemons.
                    We assume that anything that has a controlling
                    tty is user stuff. */
-                (void) parse_proc_cmdline(parse_proc_cmdline_item);
+                (void) parse_proc_cmdline(parse_proc_cmdline_item, NULL, true);
 
         e = secure_getenv("SYSTEMD_LOG_TARGET");
         if (e && log_set_target_from_string(e) < 0)
index 0b82b768c97ac951f2bf96774b76a5242d42051a..2e1d8c5833bde82794d36f65d3798d3fa29ea77f 100644 (file)
@@ -102,18 +102,22 @@ int log_object_internal(
                 const char *func,
                 const char *object_field,
                 const char *object,
-                const char *format, ...) _printf_(8,9);
+                const char *extra_field,
+                const char *extra,
+                const char *format, ...) _printf_(10,11);
 
 int log_object_internalv(
                 int level,
                 int error,
-                const char*file,
+                const char *file,
                 int line,
                 const char *func,
                 const char *object_field,
                 const char *object,
+                const char *extra_field,
+                const char *extra,
                 const char *format,
-                va_list ap) _printf_(8,0);
+                va_list ap) _printf_(9,0);
 
 int log_struct_internal(
                 int level,
@@ -203,7 +207,6 @@ void log_assert_failed_return(
 #else
 #  define log_debug_elogind(...) do {} while (0)
 #endif // ENABLE_DEBUG_ELOGIND
-
 /* Structured logging */
 #define log_struct(level, ...) log_struct_internal(level, 0, __FILE__, __LINE__, __func__, __VA_ARGS__)
 #define log_struct_errno(level, error, ...) log_struct_internal(level, error, __FILE__, __LINE__, __func__, __VA_ARGS__)
index f2a0e1d8b0402605ace33e5a68db283e353e5948..2846644a13170f0eec32e4d36871466ee62b028f 100644 (file)
@@ -450,6 +450,10 @@ struct btrfs_ioctl_quota_ctl_args {
 #define CGROUP2_SUPER_MAGIC 0x63677270
 #endif
 
+#ifndef CLONE_NEWCGROUP
+#define CLONE_NEWCGROUP 0x02000000
+#endif
+
 #ifndef TMPFS_MAGIC
 #define TMPFS_MAGIC 0x01021994
 #endif
@@ -474,24 +478,44 @@ struct btrfs_ioctl_quota_ctl_args {
 #define MS_MOVE 8192
 #endif
 
+#ifndef MS_REC
+#define MS_REC 16384
+#endif
+
 #ifndef MS_PRIVATE
-#define MS_PRIVATE  (1 << 18)
+#define MS_PRIVATE      (1<<18)
 #endif
 
-#ifndef SCM_SECURITY
-#define SCM_SECURITY 0x03
+#ifndef MS_REC
+#define MS_REC          (1<<19)
+#endif
+
+#ifndef MS_SHARED
+#define MS_SHARED       (1<<20)
+#endif
+
+#ifndef MS_RELATIME
+#define MS_RELATIME     (1<<21)
+#endif
+
+#ifndef MS_KERNMOUNT
+#define MS_KERNMOUNT    (1<<22)
+#endif
+
+#ifndef MS_I_VERSION
+#define MS_I_VERSION    (1<<23)
 #endif
 
 #ifndef MS_STRICTATIME
-#define MS_STRICTATIME (1<<24)
+#define MS_STRICTATIME  (1<<24)
 #endif
 
-#ifndef MS_REC
-#define MS_REC 16384
+#ifndef MS_LAZYTIME
+#define MS_LAZYTIME     (1<<25)
 #endif
 
-#ifndef MS_SHARED
-#define MS_SHARED (1<<20)
+#ifndef SCM_SECURITY
+#define SCM_SECURITY 0x03
 #endif
 
 #ifndef PR_SET_NO_NEW_PRIVS
@@ -538,12 +562,21 @@ struct btrfs_ioctl_quota_ctl_args {
 #  define DRM_IOCTL_DROP_MASTER _IO('d', 0x1f)
 #endif
 
-#if defined(__i386__) || defined(__x86_64__)
-
-/* The precise definition of __O_TMPFILE is arch specific, so let's
- * just define this on x86 where we know the value. */
+/* The precise definition of __O_TMPFILE is arch specific; use the
+ * values defined by the kernel (note: some are hexa, some are octal,
+ * duplicated as-is from the kernel definitions):
+ * - alpha, parisc, sparc: each has a specific value;
+ * - others: they use the "generic" value.
+ */
 
 #ifndef __O_TMPFILE
+#if defined(__alpha__)
+#define __O_TMPFILE     0100000000
+#elif defined(__parisc__) || defined(__hppa__)
+#define __O_TMPFILE     0400000000
+#elif defined(__sparc__) || defined(__sparc64__)
+#define __O_TMPFILE     0x2000000
+#else
 #define __O_TMPFILE     020000000
 #endif
 
@@ -1048,6 +1081,10 @@ typedef int32_t key_serial_t;
 #define ETHERTYPE_LLDP 0x88cc
 #endif
 
+#ifndef IFA_F_MCAUTOJOIN
+#define IFA_F_MCAUTOJOIN 0x400
+#endif
+
 #endif
 
 #include "missing_syscall.h"
index 121619eed08d844c11e19fbb59b3954f1a05493d..e2bdfcd8a7c9d711e83fc9724a6dd72d5d52d23f 100644 (file)
@@ -75,7 +75,6 @@ static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id
         return safe_atoi(p, mnt_id);
 }
 
-
 int fd_is_mount_point(int fd, const char *filename, int flags) {
         union file_handle_union h = FILE_HANDLE_INIT, h_parent = FILE_HANDLE_INIT;
         int mount_id = -1, mount_id_parent = -1;
@@ -162,7 +161,7 @@ int fd_is_mount_point(int fd, const char *filename, int flags) {
 
 fallback_fdinfo:
         r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id);
-        if (r == -EOPNOTSUPP)
+        if (IN_SET(r, -EOPNOTSUPP, -EACCES))
                 goto fallback_fstat;
         if (r < 0)
                 return r;
@@ -289,10 +288,12 @@ int umount_recursive(const char *prefix, int flags) {
                                 continue;
 
                         if (umount2(p, flags) < 0) {
-                                r = -errno;
+                                r = log_debug_errno(errno, "Failed to umount %s: %m", p);
                                 continue;
                         }
 
+                        log_debug("Successfully unmounted %s", p);
+
                         again = true;
                         n++;
 
@@ -313,24 +314,21 @@ static int get_mount_flags(const char *path, unsigned long *flags) {
         return 0;
 }
 
-int bind_remount_recursive(const char *prefix, bool ro) {
+int bind_remount_recursive(const char *prefix, bool ro, char **blacklist) {
         _cleanup_set_free_free_ Set *done = NULL;
         _cleanup_free_ char *cleaned = NULL;
         int r;
 
-        /* Recursively remount a directory (and all its submounts)
-         * read-only or read-write. If the directory is already
-         * mounted, we reuse the mount and simply mark it
-         * MS_BIND|MS_RDONLY (or remove the MS_RDONLY for read-write
-         * operation). If it isn't we first make it one. Afterwards we
-         * apply MS_BIND|MS_RDONLY (or remove MS_RDONLY) to all
-         * submounts we can access, too. When mounts are stacked on
-         * the same mount point we only care for each individual
-         * "top-level" mount on each point, as we cannot
-         * influence/access the underlying mounts anyway. We do not
-         * have any effect on future submounts that might get
-         * propagated, they migt be writable. This includes future
-         * submounts that have been triggered via autofs. */
+        /* Recursively remount a directory (and all its submounts) read-only or read-write. If the directory is already
+         * mounted, we reuse the mount and simply mark it MS_BIND|MS_RDONLY (or remove the MS_RDONLY for read-write
+         * operation). If it isn't we first make it one. Afterwards we apply MS_BIND|MS_RDONLY (or remove MS_RDONLY) to
+         * all submounts we can access, too. When mounts are stacked on the same mount point we only care for each
+         * individual "top-level" mount on each point, as we cannot influence/access the underlying mounts anyway. We
+         * do not have any effect on future submounts that might get propagated, they migt be writable. This includes
+         * future submounts that have been triggered via autofs.
+         *
+         * If the "blacklist" parameter is specified it may contain a list of subtrees to exclude from the
+         * remount operation. Note that we'll ignore the blacklist for the top-level path. */
 
         cleaned = strdup(prefix);
         if (!cleaned)
@@ -387,6 +385,33 @@ int bind_remount_recursive(const char *prefix, bool ro) {
                         if (r < 0)
                                 return r;
 
+                        if (!path_startswith(p, cleaned))
+                                continue;
+
+                        /* Ignore this mount if it is blacklisted, but only if it isn't the top-level mount we shall
+                         * operate on. */
+                        if (!path_equal(cleaned, p)) {
+                                bool blacklisted = false;
+                                char **i;
+
+                                STRV_FOREACH(i, blacklist) {
+
+                                        if (path_equal(*i, cleaned))
+                                                continue;
+
+                                        if (!path_startswith(*i, cleaned))
+                                                continue;
+
+                                        if (path_startswith(p, *i)) {
+                                                blacklisted = true;
+                                                log_debug("Not remounting %s, because blacklisted by %s, called for %s", p, *i, cleaned);
+                                                break;
+                                        }
+                                }
+                                if (blacklisted)
+                                        continue;
+                        }
+
                         /* Let's ignore autofs mounts.  If they aren't
                          * triggered yet, we want to avoid triggering
                          * them, as we don't make any guarantees for
@@ -398,12 +423,9 @@ int bind_remount_recursive(const char *prefix, bool ro) {
                                 continue;
                         }
 
-                        if (path_startswith(p, cleaned) &&
-                            !set_contains(done, p)) {
-
+                        if (!set_contains(done, p)) {
                                 r = set_consume(todo, p);
                                 p = NULL;
-
                                 if (r == -EEXIST)
                                         continue;
                                 if (r < 0)
@@ -420,8 +442,7 @@ int bind_remount_recursive(const char *prefix, bool ro) {
 
                 if (!set_contains(done, cleaned) &&
                     !set_contains(todo, cleaned)) {
-                        /* The prefix directory itself is not yet a
-                         * mount, make it one. */
+                        /* The prefix directory itself is not yet a mount, make it one. */
                         if (mount(cleaned, cleaned, NULL, MS_BIND|MS_REC, NULL) < 0)
                                 return -errno;
 
@@ -432,6 +453,8 @@ int bind_remount_recursive(const char *prefix, bool ro) {
                         if (mount(NULL, prefix, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0)
                                 return -errno;
 
+                        log_debug("Made top-level directory %s a mount point.", prefix);
+
                         x = strdup(cleaned);
                         if (!x)
                                 return -ENOMEM;
@@ -449,8 +472,7 @@ int bind_remount_recursive(const char *prefix, bool ro) {
                         if (r < 0)
                                 return r;
 
-                        /* Deal with mount points that are obstructed by a
-                         * later mount */
+                        /* Deal with mount points that are obstructed by a later mount */
                         r = path_is_mount_point(x, 0);
                         if (r == -ENOENT || r == 0)
                                 continue;
@@ -465,6 +487,7 @@ int bind_remount_recursive(const char *prefix, bool ro) {
                         if (mount(NULL, x, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0)
                                 return -errno;
 
+                        log_debug("Remounted %s read-only.", x);
                 }
         }
 }
@@ -502,6 +525,7 @@ bool fstype_is_network(const char *fstype) {
                 "glusterfs\0"
                 "pvfs2\0" /* OrangeFS */
                 "ocfs2\0"
+                "lustre\0"
                 ;
 
         const char *x;
@@ -559,3 +583,110 @@ const char* mode_to_inaccessible_node(mode_t mode) {
         }
         return NULL;
 }
+
+#if 0 /// UNNEEDED by elogind
+#define FLAG(name) (flags & name ? STRINGIFY(name) "|" : "")
+static char* mount_flags_to_string(long unsigned flags) {
+        char *x;
+        _cleanup_free_ char *y = NULL;
+        long unsigned overflow;
+
+        overflow = flags & ~(MS_RDONLY |
+                             MS_NOSUID |
+                             MS_NODEV |
+                             MS_NOEXEC |
+                             MS_SYNCHRONOUS |
+                             MS_REMOUNT |
+                             MS_MANDLOCK |
+                             MS_DIRSYNC |
+                             MS_NOATIME |
+                             MS_NODIRATIME |
+                             MS_BIND |
+                             MS_MOVE |
+                             MS_REC |
+                             MS_SILENT |
+                             MS_POSIXACL |
+                             MS_UNBINDABLE |
+                             MS_PRIVATE |
+                             MS_SLAVE |
+                             MS_SHARED |
+                             MS_RELATIME |
+                             MS_KERNMOUNT |
+                             MS_I_VERSION |
+                             MS_STRICTATIME |
+                             MS_LAZYTIME);
+
+        if (flags == 0 || overflow != 0)
+                if (asprintf(&y, "%lx", overflow) < 0)
+                        return NULL;
+
+        x = strjoin(FLAG(MS_RDONLY),
+                    FLAG(MS_NOSUID),
+                    FLAG(MS_NODEV),
+                    FLAG(MS_NOEXEC),
+                    FLAG(MS_SYNCHRONOUS),
+                    FLAG(MS_REMOUNT),
+                    FLAG(MS_MANDLOCK),
+                    FLAG(MS_DIRSYNC),
+                    FLAG(MS_NOATIME),
+                    FLAG(MS_NODIRATIME),
+                    FLAG(MS_BIND),
+                    FLAG(MS_MOVE),
+                    FLAG(MS_REC),
+                    FLAG(MS_SILENT),
+                    FLAG(MS_POSIXACL),
+                    FLAG(MS_UNBINDABLE),
+                    FLAG(MS_PRIVATE),
+                    FLAG(MS_SLAVE),
+                    FLAG(MS_SHARED),
+                    FLAG(MS_RELATIME),
+                    FLAG(MS_KERNMOUNT),
+                    FLAG(MS_I_VERSION),
+                    FLAG(MS_STRICTATIME),
+                    FLAG(MS_LAZYTIME),
+                    y, NULL);
+        if (!x)
+                return NULL;
+        if (!y)
+                x[strlen(x) - 1] = '\0'; /* truncate the last | */
+        return x;
+}
+
+int mount_verbose(
+                int error_log_level,
+                const char *what,
+                const char *where,
+                const char *type,
+                unsigned long flags,
+                const char *options) {
+
+        _cleanup_free_ char *fl = NULL;
+
+        fl = mount_flags_to_string(flags);
+
+        if ((flags & MS_REMOUNT) && !what && !type)
+                log_debug("Remounting %s (%s \"%s\")...",
+                          where, strnull(fl), strempty(options));
+        else if (!what && !type)
+                log_debug("Mounting %s (%s \"%s\")...",
+                          where, strnull(fl), strempty(options));
+        else if ((flags & MS_BIND) && !type)
+                log_debug("Bind-mounting %s on %s (%s \"%s\")...",
+                          what, where, strnull(fl), strempty(options));
+        else
+                log_debug("Mounting %s on %s (%s \"%s\")...",
+                          strna(type), where, strnull(fl), strempty(options));
+        if (mount(what, where, type, flags, options) < 0)
+                return log_full_errno(error_log_level, errno,
+                                      "Failed to mount %s on %s (%s \"%s\"): %m",
+                                      strna(type), where, strnull(fl), strempty(options));
+        return 0;
+}
+
+int umount_verbose(const char *what) {
+        log_debug("Umounting %s...", what);
+        if (umount(what) < 0)
+                return log_error_errno(errno, "Failed to unmount %s: %m", what);
+        return 0;
+}
+#endif // 0
index 9ed5b284ceab5e275c02a1ac30b9c49b8accd02e..d538ea9533ac59b0906efec374d27c0c40cb69ae 100644 (file)
@@ -36,7 +36,7 @@ int path_is_mount_point(const char *path, int flags);
 int repeat_unmount(const char *path, int flags);
 
 int umount_recursive(const char *target, int flags);
-int bind_remount_recursive(const char *prefix, bool ro);
+int bind_remount_recursive(const char *prefix, bool ro, char **blacklist);
 
 int mount_move_root(const char *path);
 #endif // 0
@@ -56,3 +56,14 @@ union file_handle_union {
 const char* mode_to_inaccessible_node(mode_t mode);
 
 #define FILE_HANDLE_INIT { .handle.handle_bytes = MAX_HANDLE_SZ }
+
+#if 0 /// UNNEEDED by elogind
+int mount_verbose(
+                int error_log_level,
+                const char *what,
+                const char *where,
+                const char *type,
+                unsigned long flags,
+                const char *options);
+int umount_verbose(const char *where);
+#endif // 0
index 77e85f658a9a23f16cb63e72496739631076d7aa..b1cad55e7c1915090ff5f980f3d2ebe8677bdee6 100644 (file)
@@ -540,7 +540,7 @@ int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) {
         return 0;
 }
 
-int parse_percent(const char *p) {
+int parse_percent_unbounded(const char *p) {
         const char *pc, *n;
         unsigned v;
         int r;
@@ -553,8 +553,32 @@ int parse_percent(const char *p) {
         r = safe_atou(n, &v);
         if (r < 0)
                 return r;
+
+        return (int) v;
+}
+
+int parse_percent(const char *p) {
+        int v;
+
+        v = parse_percent_unbounded(p);
         if (v > 100)
                 return -ERANGE;
 
-        return (int) v;
+        return v;
 }
+
+#if 0 /// UNNEEDED by elogind
+int parse_nice(const char *p, int *ret) {
+        int n, r;
+
+        r = safe_atoi(p, &n);
+        if (r < 0)
+                return r;
+
+        if (!nice_is_valid(n))
+                return -ERANGE;
+
+        *ret = n;
+        return 0;
+}
+#endif // 0
index 1f420c050b9906ba137b440a986be3b405facb11..23b1937430a60d91293550a51ffeac1d2e127e6f 100644 (file)
@@ -108,4 +108,9 @@ int safe_atod(const char *s, double *ret_d);
 
 int parse_fractional_part_u(const char **s, size_t digits, unsigned *res);
 
+int parse_percent_unbounded(const char *p);
 int parse_percent(const char *p);
+
+#if 0 /// UNNEEDED by elogind
+int parse_nice(const char *p, int *ret);
+#endif // 0
index 123b4ce8c89e8db5f58660c31581b33667004a60..8cb013e6cb2beea724909568d0ca6bed93a55045 100644 (file)
@@ -290,9 +290,7 @@ char **path_strv_resolve(char **l, const char *prefix) {
                         } else {
                                 /* canonicalized path goes outside of
                                  * prefix, keep the original path instead */
-                                free(u);
-                                u = orig;
-                                orig = NULL;
+                                free_and_replace(u, orig);
                         }
                 } else
                         free(t);
@@ -358,6 +356,16 @@ char* path_startswith(const char *path, const char *prefix) {
         assert(path);
         assert(prefix);
 
+        /* Returns a pointer to the start of the first component after the parts matched by
+         * the prefix, iff
+         * - both paths are absolute or both paths are relative,
+         * and
+         * - each component in prefix in turn matches a component in path at the same position.
+         * An empty string will be returned when the prefix and path are equivalent.
+         *
+         * Returns NULL otherwise.
+         */
+
         if ((path[0] == '/') != (prefix[0] == '/'))
                 return NULL;
 
@@ -817,8 +825,79 @@ bool is_device_path(const char *path) {
         /* Returns true on paths that refer to a device, either in
          * sysfs or in /dev */
 
-        return
-                path_startswith(path, "/dev/") ||
-                path_startswith(path, "/sys/");
+        return path_startswith(path, "/dev/") ||
+               path_startswith(path, "/sys/");
+}
+
+bool is_deviceallow_pattern(const char *path) {
+        return path_startswith(path, "/dev/") ||
+               startswith(path, "block-") ||
+               startswith(path, "char-");
+}
+
+int systemd_installation_has_version(const char *root, unsigned minimal_version) {
+        const char *pattern;
+        int r;
+
+        /* Try to guess if systemd installation is later than the specified version. This
+         * is hacky and likely to yield false negatives, particularly if the installation
+         * is non-standard. False positives should be relatively rare.
+         */
+
+        NULSTR_FOREACH(pattern,
+                       /* /lib works for systems without usr-merge, and for systems with a sane
+                        * usr-merge, where /lib is a symlink to /usr/lib. /usr/lib is necessary
+                        * for Gentoo which does a merge without making /lib a symlink.
+                        */
+                       "lib/systemd/libsystemd-shared-*.so\0"
+                       "usr/lib/systemd/libsystemd-shared-*.so\0") {
+
+                _cleanup_strv_free_ char **names = NULL;
+                _cleanup_free_ char *path = NULL;
+                char *c, **name;
+
+                path = prefix_root(root, pattern);
+                if (!path)
+                        return -ENOMEM;
+
+                r = glob_extend(&names, path);
+                if (r == -ENOENT)
+                        continue;
+                if (r < 0)
+                        return r;
+
+                assert_se((c = endswith(path, "*.so")));
+                *c = '\0'; /* truncate the glob part */
+
+                STRV_FOREACH(name, names) {
+                        /* This is most likely to run only once, hence let's not optimize anything. */
+                        char *t, *t2;
+                        unsigned version;
+
+                        t = startswith(*name, path);
+                        if (!t)
+                                continue;
+
+                        t2 = endswith(t, ".so");
+                        if (!t2)
+                                continue;
+
+                        t2[0] = '\0'; /* truncate the suffix */
+
+                        r = safe_atou(t, &version);
+                        if (r < 0) {
+                                log_debug_errno(r, "Found libsystemd shared at \"%s.so\", but failed to parse version: %m", *name);
+                                continue;
+                        }
+
+                        log_debug("Found libsystemd shared at \"%s.so\", version %u (%s).",
+                                  *name, version,
+                                  version >= minimal_version ? "OK" : "too old");
+                        if (version >= minimal_version)
+                                return true;
+                }
+        }
+
+        return false;
 }
 #endif // 0
index 540a69c62754518c938be0492cb7d1157429540c..605485665d2962f9652ff9c7828143ded583be01 100644 (file)
@@ -140,4 +140,7 @@ bool hidden_or_backup_file(const char *filename) _pure_;
 
 #if 0 /// UNNEEDED by elogind
 bool is_device_path(const char *path);
+bool is_deviceallow_pattern(const char *path);
+
+int systemd_installation_has_version(const char *root, unsigned minimal_version);
 #endif // 0
index d2ec516d297ccaca972cb8d9d85bb36e600c8716..4570b8e4baab44afa49ef667257833be54568fde 100644 (file)
@@ -62,9 +62,7 @@ Prioq* prioq_free(Prioq *q) {
                 return NULL;
 
         free(q->items);
-        free(q);
-
-        return NULL;
+        return mfree(q);
 }
 
 int prioq_ensure_allocated(Prioq **q, compare_func_t compare_func) {
index 60a4e23226c57c8e4fdd18748f9efa2f699b557f..281833f883f86a09ac2b68ec44414abce5e53a00 100644 (file)
@@ -42,7 +42,9 @@ int proc_cmdline(char **ret) {
                 return read_one_line_file("/proc/cmdline", ret);
 }
 
-int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) {
+int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value, void *data),
+                       void *data,
+                       bool strip_prefix) {
         _cleanup_free_ char *line = NULL;
         const char *p;
         int r;
@@ -56,7 +58,7 @@ int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) {
         p = line;
         for (;;) {
                 _cleanup_free_ char *word = NULL;
-                char *value = NULL;
+                char *value = NULL, *unprefixed;
 
                 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
                 if (r < 0)
@@ -66,14 +68,15 @@ int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) {
 
                 /* Filter out arguments that are intended only for the
                  * initrd */
-                if (!in_initrd() && startswith(word, "rd."))
+                unprefixed = startswith(word, "rd.");
+                if (unprefixed && !in_initrd())
                         continue;
 
                 value = strchr(word, '=');
                 if (value)
                         *(value++) = 0;
 
-                r = parse_item(word, value);
+                r = parse_item(strip_prefix && unprefixed ? unprefixed : word, value, data);
                 if (r < 0)
                         return r;
         }
index 09a3e6690d9298052acefb31248c4d8cb0a709cb..3e2ca8813b7fc537ed1b58f7aa3cd0b419671ceb 100644 (file)
@@ -20,7 +20,9 @@
 ***/
 
 int proc_cmdline(char **ret);
-int parse_proc_cmdline(int (*parse_word)(const char *key, const char *value));
+int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value, void *data),
+                       void *data,
+                       bool strip_prefix);
 int get_proc_cmdline_key(const char *parameter, char **value);
 
 #if 0 /// UNNEEDED by elogind
index 6cf3a40b1f6dd83cd3dd626fb2fd2ff0d68b9b41..c05d05d7831990381c25f45590e2810a63d81422 100644 (file)
@@ -113,3 +113,9 @@ int sched_policy_from_string(const char *s);
 void valgrind_summary_hack(void);
 
 int pid_compare_func(const void *a, const void *b);
+
+#if 0 /// UNNEEDED by elogind
+static inline bool nice_is_valid(int n) {
+        return n >= PRIO_MIN && n < PRIO_MAX;
+}
+#endif // 0
index 474bfbf43586771417ea9fa3504ae0d5ca1e9260..78de895d35d7188aebd699f632ceaa088d735fbb 100644 (file)
@@ -27,6 +27,7 @@
 #include <unistd.h>
 
 //#include "btrfs-util.h"
+#include "cgroup-util.h"
 #include "fd-util.h"
 #include "log.h"
 #include "macro.h"
 #include "stat-util.h"
 #include "string-util.h"
 
+static bool is_physical_fs(const struct statfs *sfs) {
+        return !is_temporary_fs(sfs) && !is_cgroup_fs(sfs);
+}
+
 int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) {
         _cleanup_closedir_ DIR *d = NULL;
         int ret = 0, r;
+        struct statfs sfs;
 
         assert(fd >= 0);
 
@@ -47,13 +53,13 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) {
 
         if (!(flags & REMOVE_PHYSICAL)) {
 
-                r = fd_is_temporary_fs(fd);
+                r = fstatfs(fd, &sfs);
                 if (r < 0) {
                         safe_close(fd);
-                        return r;
+                        return -errno;
                 }
 
-                if (!r) {
+                if (is_physical_fs(&sfs)) {
                         /* We refuse to clean physical file systems
                          * with this call, unless explicitly
                          * requested. This is extra paranoia just to
@@ -214,7 +220,7 @@ int rm_rf(const char *path, RemoveFlags flags) {
                         if (statfs(path, &s) < 0)
                                 return -errno;
 
-                        if (!is_temporary_fs(&s)) {
+                        if (is_physical_fs(&s)) {
                                 log_error("Attempted to remove disk file system, and we can't allow that.");
                                 return -EPERM;
                         }
index 5a5c8edb463f1b587010b61e1899bad941e10f7d..70c462a1a2cc1bc8bfdec4ed7ad2b8930d338d68 100644 (file)
@@ -22,8 +22,8 @@
 #include "hashmap.h"
 #include "macro.h"
 
-Set *internal_set_new(const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS);
-#define set_new(ops) internal_set_new(ops  HASHMAP_DEBUG_SRC_ARGS)
+Set *internal_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
+#define set_new(ops) internal_set_new(ops HASHMAP_DEBUG_SRC_ARGS)
 
 static inline Set *set_free(Set *s) {
         internal_hashmap_free(HASHMAP_BASE(s));
@@ -41,8 +41,8 @@ static inline Set *set_copy(Set *s) {
         return (Set*) internal_hashmap_copy(HASHMAP_BASE(s));
 }
 
-int internal_set_ensure_allocated(Set **s, const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS);
-#define set_ensure_allocated(h, ops) internal_set_ensure_allocated(h, ops  HASHMAP_DEBUG_SRC_ARGS)
+int internal_set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
+#define set_ensure_allocated(h, ops) internal_set_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
 
 int set_put(Set *s, const void *key);
 /* no set_update */
index f47a8f04e0399c16233ebad5b9b8481681363e9c..4c1869353f31ff9d9e4f97ee92c2668105e5e27b 100644 (file)
@@ -441,7 +441,7 @@ const char* socket_address_get_path(const SocketAddress *a) {
 #endif // 0
 
 bool socket_ipv6_is_supported(void) {
-        if (access("/proc/net/sockstat6", F_OK) != 0)
+        if (access("/proc/net/if_inet6", F_OK) != 0)
                 return false;
 
         return true;
@@ -1052,3 +1052,36 @@ int flush_accept(int fd) {
         }
 }
 #endif // 0
+
+struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t length) {
+        struct cmsghdr *cmsg;
+
+        assert(mh);
+
+        CMSG_FOREACH(cmsg, mh)
+                if (cmsg->cmsg_level == level &&
+                    cmsg->cmsg_type == type &&
+                    (length == (socklen_t) -1 || length == cmsg->cmsg_len))
+                        return cmsg;
+
+        return NULL;
+}
+
+#if 0 /// UNNEEDED by elogind
+int socket_ioctl_fd(void) {
+        int fd;
+
+        /* Create a socket to invoke the various network interface ioctl()s on. Traditionally only AF_INET was good for
+         * that. Since kernel 4.6 AF_NETLINK works for this too. We first try to use AF_INET hence, but if that's not
+         * available (for example, because it is made unavailable via SECCOMP or such), we'll fall back to the more
+         * generic AF_NETLINK. */
+
+        fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, 0);
+        if (fd < 0)
+                fd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, NETLINK_GENERIC);
+        if (fd < 0)
+                return -errno;
+
+        return fd;
+}
+#endif // 0
index b5d1dc3ed45b0bbf7296e6b9a3625b0a9067eb74..718de9ba347ff07a8fd2618fd10a08735ced4423 100644 (file)
@@ -150,6 +150,8 @@ int flush_accept(int fd);
 #define CMSG_FOREACH(cmsg, mh)                                          \
         for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg)))
 
+struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t length);
+
 /* Covers only file system and abstract AF_UNIX socket addresses, but not unnamed socket addresses. */
 #define SOCKADDR_UN_LEN(sa)                                             \
         ({                                                              \
@@ -160,3 +162,7 @@ int flush_accept(int fd);
                          1 + strnlen(_sa->sun_path+1, sizeof(_sa->sun_path)-1) : \
                          strnlen(_sa->sun_path, sizeof(_sa->sun_path))); \
         })
+
+#if 0 /// UNNEEDED by elogind
+int socket_ioctl_fd(void);
+#endif // 0
index 293a15f9c041cf59f5354829cfdc86b0b0622a20..ebe146b03d817eab23e85990ce121fcf7c5a7b37 100644 (file)
@@ -22,6 +22,7 @@
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 #include "alloc-util.h"
 #include "gunicode.h"
@@ -291,6 +292,7 @@ char *strstrip(char *s) {
         return s;
 }
 
+#if 0 /// UNNEEDED by elogind
 char *delete_chars(char *s, const char *bad) {
         char *f, *t;
 
@@ -307,6 +309,7 @@ char *delete_chars(char *s, const char *bad) {
 
         return s;
 }
+#endif // 0
 
 char *truncate_nl(char *s) {
         assert(s);
@@ -315,6 +318,7 @@ char *truncate_nl(char *s) {
         return s;
 }
 
+#if 0 /// UNNEEDED by elogind
 char ascii_tolower(char x) {
 
         if (x >= 'A' && x <= 'Z')
@@ -323,6 +327,14 @@ char ascii_tolower(char x) {
         return x;
 }
 
+char ascii_toupper(char x) {
+
+        if (x >= 'a' && x <= 'z')
+                return x - 'a' + 'A';
+
+        return x;
+}
+
 char *ascii_strlower(char *t) {
         char *p;
 
@@ -334,6 +346,17 @@ char *ascii_strlower(char *t) {
         return t;
 }
 
+char *ascii_strupper(char *t) {
+        char *p;
+
+        assert(t);
+
+        for (p = t; *p; p++)
+                *p = ascii_toupper(*p);
+
+        return t;
+}
+
 char *ascii_strlower_n(char *t, size_t n) {
         size_t i;
 
@@ -386,6 +409,7 @@ bool chars_intersect(const char *a, const char *b) {
 
         return false;
 }
+#endif // 0
 
 bool string_has_cc(const char *p, const char *ok) {
         const char *t;
@@ -423,7 +447,7 @@ static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_le
         if (old_length <= 3 || old_length <= new_length)
                 return strndup(s, old_length);
 
-        r = new0(char, new_length+1);
+        r = new0(char, new_length+3);
         if (!r)
                 return NULL;
 
@@ -433,12 +457,12 @@ static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_le
                 x = new_length - 3;
 
         memcpy(r, s, x);
-        r[x] = '.';
-        r[x+1] = '.';
-        r[x+2] = '.';
+        r[x] = 0xe2; /* tri-dot ellipsis: â€¦ */
+        r[x+1] = 0x80;
+        r[x+2] = 0xa6;
         memcpy(r + x + 3,
-               s + old_length - (new_length - x - 3),
-               new_length - x - 3);
+               s + old_length - (new_length - x - 1),
+               new_length - x - 1);
 
         return r;
 }
@@ -590,8 +614,7 @@ char *strreplace(const char *text, const char *old_string, const char *new_strin
         return r;
 
 oom:
-        free(r);
-        return NULL;
+        return mfree(r);
 }
 
 char *strip_tab_ansi(char **ibuf, size_t *_isz) {
@@ -662,8 +685,7 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz) {
 
         if (ferror(f)) {
                 fclose(f);
-                free(obuf);
-                return NULL;
+                return mfree(obuf);
         }
 
         fclose(f);
@@ -803,25 +825,20 @@ int free_and_strdup(char **p, const char *s) {
         return 1;
 }
 
-#pragma GCC push_options
-#pragma GCC optimize("O0")
+/*
+ * Pointer to memset is volatile so that compiler must de-reference
+ * the pointer and can't assume that it points to any function in
+ * particular (such as memset, which it then might further "optimize")
+ * This approach is inspired by openssl's crypto/mem_clr.c.
+ */
+typedef void *(*memset_t)(void *,int,size_t);
 
-void* memory_erase(void *p, size_t l) {
-        volatile uint8_t* x = (volatile uint8_t*) p;
-
-        /* This basically does what memset() does, but hopefully isn't
-         * optimized away by the compiler. One of those days, when
-         * glibc learns memset_s() we should replace this call by
-         * memset_s(), but until then this has to do. */
-
-        for (; l > 0; l--)
-                *(x++) = 'x';
+static volatile memset_t memset_func = memset;
 
-        return p;
+void* memory_erase(void *p, size_t l) {
+        return memset_func(p, 'x', l);
 }
 
-#pragma GCC pop_options
-
 char* string_erase(char *x) {
 
         if (!x)
index 1209e1e2e14c11853b526891d31b34584c36db68..66e55cb2c615ab8cbab8fce97cd730068d395772 100644 (file)
@@ -66,10 +66,16 @@ static inline bool isempty(const char *p) {
         return !p || !p[0];
 }
 
+#if 0 /// UNNEEDED by elogind
 static inline const char *empty_to_null(const char *p) {
         return isempty(p) ? NULL : p;
 }
 
+static inline const char *strdash_if_empty(const char *str) {
+        return isempty(str) ? "-" : str;
+}
+#endif // 0
+
 static inline char *startswith(const char *s, const char *prefix) {
         size_t l;
 
@@ -80,6 +86,7 @@ static inline char *startswith(const char *s, const char *prefix) {
         return NULL;
 }
 
+#if 0 /// UNNEEDED by elogind
 static inline char *startswith_no_case(const char *s, const char *prefix) {
         size_t l;
 
@@ -89,6 +96,7 @@ static inline char *startswith_no_case(const char *s, const char *prefix) {
 
         return NULL;
 }
+#endif // 0
 
 char *endswith(const char *s, const char *postfix) _pure_;
 char *endswith_no_case(const char *s, const char *postfix) _pure_;
@@ -130,17 +138,24 @@ char *strjoin(const char *x, ...) _sentinel_;
         })
 
 char *strstrip(char *s);
+#if 0 /// UNNEEDED by elogind
 char *delete_chars(char *s, const char *bad);
+#endif // 0
 char *truncate_nl(char *s);
 
+#if 0 /// UNNEEDED by elogind
 char ascii_tolower(char x);
 char *ascii_strlower(char *s);
 char *ascii_strlower_n(char *s, size_t n);
 
+char ascii_toupper(char x);
+char *ascii_strupper(char *s);
+
 int ascii_strcasecmp_n(const char *a, const char *b, size_t n);
 int ascii_strcasecmp_nn(const char *a, size_t n, const char *b, size_t m);
 
 bool chars_intersect(const char *a, const char *b) _pure_;
+#endif // 0
 
 static inline bool _pure_ in_charset(const char *s, const char* charset) {
         assert(s);
index baaa72e674dc98b3ca3126efc1e385019ef361d0..c98e956fd92ce7be1cfa5a8e55e0276f77f59163 100644 (file)
@@ -87,8 +87,7 @@ void strv_clear(char **l) {
 
 char **strv_free(char **l) {
         strv_clear(l);
-        free(l);
-        return NULL;
+        return mfree(l);
 }
 
 char **strv_free_erase(char **l) {
@@ -431,8 +430,7 @@ char *strv_join_quoted(char **l) {
         return buf;
 
  oom:
-        free(buf);
-        return NULL;
+        return mfree(buf);
 }
 #endif // 0
 
@@ -882,8 +880,7 @@ char ***strv_free_free(char ***l) {
         for (i = l; *i; i++)
                 strv_free(*i);
 
-        free(l);
-        return NULL;
+        return mfree(l);
 }
 
 char **strv_skip(char **l, size_t n) {
index c95a637b43d811b229b5eddf7328c2970142207a..0a908c89345db05ffc25fe1d89c7a6251fa2094f 100644 (file)
@@ -110,10 +110,13 @@ bool strv_overlap(char **a, char **b) _pure_;
 #define STRV_FOREACH(s, l)                      \
         for ((s) = (l); (s) && *(s); (s)++)
 
-#define STRV_FOREACH_BACKWARDS(s, l)            \
-        STRV_FOREACH(s, l)                      \
-                ;                               \
-        for ((s)--; (l) && ((s) >= (l)); (s)--)
+#define STRV_FOREACH_BACKWARDS(s, l)                                \
+        for (s = ({                                                 \
+                        char **_l = l;                              \
+                        _l ? _l + strv_length(_l) - 1U : NULL;      \
+                        });                                         \
+             (l) && ((s) >= (l));                                   \
+             (s)--)
 
 #define STRV_FOREACH_PAIR(x, y, l)               \
         for ((x) = (l), (y) = (x+1); (x) && *(x) && *(y); (x) += 2, (y) = (x + 1))
@@ -157,6 +160,11 @@ void strv_print(char **l);
         })
 
 #define STR_IN_SET(x, ...) strv_contains(STRV_MAKE(__VA_ARGS__), x)
+#define STRPTR_IN_SET(x, ...)                                    \
+        ({                                                       \
+                const char* _x = (x);                            \
+                _x && strv_contains(STRV_MAKE(__VA_ARGS__), _x); \
+        })
 
 #define FOREACH_STRING(x, ...)                               \
         for (char **_l = ({                                  \
index 0659310a743b92a759c1a1743d8720c746982f0f..d29dcd5bec79df79c2d677e2386bb18ed3300105 100644 (file)
@@ -347,12 +347,7 @@ int open_terminal(const char *name, int mode) {
         }
 
         r = isatty(fd);
-        if (r < 0) {
-                safe_close(fd);
-                return -errno;
-        }
-
-        if (!r) {
+        if (r == 0) {
                 safe_close(fd);
                 return -ENOTTY;
         }
@@ -792,7 +787,7 @@ bool tty_is_vc_resolve(const char *tty) {
 }
 
 const char *default_term_for_tty(const char *tty) {
-        return tty && tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt220";
+        return tty && tty_is_vc_resolve(tty) ? "linux" : "vt220";
 }
 #endif // 0
 
@@ -1224,15 +1219,17 @@ bool colors_enabled(void) {
         static int enabled = -1;
 
         if (_unlikely_(enabled < 0)) {
-                const char *colors;
+#if 0 /// elogind does not allow such forcing, and we are never init!
+                int val;
 
-                colors = getenv("SYSTEMD_COLORS");
-                if (colors)
-                        enabled = parse_boolean(colors) != 0;
+                val = getenv_bool("SYSTEMD_COLORS");
+                if (val >= 0)
+                        enabled = val;
                 else if (getpid() == 1)
                         /* PID1 outputs to the console without holding it open all the time */
                         enabled = !getenv_terminal_is_dumb();
                 else
+#endif // 0
                         enabled = !terminal_is_dumb();
         }
 
index 561045871eae411c6c877b6f828dc7d6f92b815a..84ba3a7f70f925005c70577c49d7db6d61af3b6a 100644 (file)
 #define ANSI_HIGHLIGHT_YELLOW "\x1B[0;1;33m"
 #define ANSI_HIGHLIGHT_BLUE "\x1B[0;1;34m"
 #define ANSI_HIGHLIGHT_UNDERLINE "\x1B[0;1;4m"
+#define ANSI_HIGHLIGHT_RED_UNDERLINE "\x1B[0;1;4;31m"
+#define ANSI_HIGHLIGHT_GREEN_UNDERLINE "\x1B[0;1;4;32m"
+#define ANSI_HIGHLIGHT_YELLOW_UNDERLINE "\x1B[0;1;4;33m"
+#define ANSI_HIGHLIGHT_BLUE_UNDERLINE "\x1B[0;1;4;34m"
 #define ANSI_NORMAL "\x1B[0m"
 
 #define ANSI_ERASE_TO_END_OF_LINE "\x1B[K"
@@ -97,37 +101,24 @@ bool on_tty(void);
 bool terminal_is_dumb(void);
 bool colors_enabled(void);
 
-static inline const char *ansi_underline(void) {
-        return colors_enabled() ? ANSI_UNDERLINE : "";
-}
-
-static inline const char *ansi_highlight(void) {
-        return colors_enabled() ? ANSI_HIGHLIGHT : "";
-}
-
-static inline const char *ansi_highlight_underline(void) {
-        return colors_enabled() ? ANSI_HIGHLIGHT_UNDERLINE : "";
-}
-
-static inline const char *ansi_highlight_red(void) {
-        return colors_enabled() ? ANSI_HIGHLIGHT_RED : "";
-}
-
-static inline const char *ansi_highlight_green(void) {
-        return colors_enabled() ? ANSI_HIGHLIGHT_GREEN : "";
-}
-
-static inline const char *ansi_highlight_yellow(void) {
-        return colors_enabled() ? ANSI_HIGHLIGHT_YELLOW : "";
-}
-
-static inline const char *ansi_highlight_blue(void) {
-        return colors_enabled() ? ANSI_HIGHLIGHT_BLUE : "";
-}
-
-static inline const char *ansi_normal(void) {
-        return colors_enabled() ? ANSI_NORMAL : "";
-}
+#define DEFINE_ANSI_FUNC(name, NAME)                            \
+        static inline const char *ansi_##name(void) {           \
+                return colors_enabled() ? ANSI_##NAME : "";     \
+        }                                                       \
+        struct __useless_struct_to_allow_trailing_semicolon__
+
+DEFINE_ANSI_FUNC(underline,                  UNDERLINE);
+DEFINE_ANSI_FUNC(highlight,                  HIGHLIGHT);
+DEFINE_ANSI_FUNC(highlight_underline,        HIGHLIGHT_UNDERLINE);
+DEFINE_ANSI_FUNC(highlight_red,              HIGHLIGHT_RED);
+DEFINE_ANSI_FUNC(highlight_green,            HIGHLIGHT_GREEN);
+DEFINE_ANSI_FUNC(highlight_yellow,           HIGHLIGHT_YELLOW);
+DEFINE_ANSI_FUNC(highlight_blue,             HIGHLIGHT_BLUE);
+DEFINE_ANSI_FUNC(highlight_red_underline,    HIGHLIGHT_RED_UNDERLINE);
+DEFINE_ANSI_FUNC(highlight_green_underline,  HIGHLIGHT_GREEN_UNDERLINE);
+DEFINE_ANSI_FUNC(highlight_yellow_underline, HIGHLIGHT_YELLOW_UNDERLINE);
+DEFINE_ANSI_FUNC(highlight_blue_underline,   HIGHLIGHT_BLUE_UNDERLINE);
+DEFINE_ANSI_FUNC(normal,                     NORMAL);
 
 int get_ctty_devnr(pid_t pid, dev_t *d);
 int get_ctty(pid_t, dev_t *_devnr, char **r);
index 1c4999aae65d9f3cddcd0bce6792a95b5cfbeb0c..2455636843f8e80b13c0fa8f73ff42aa17fe581d 100644 (file)
 #include "strv.h"
 #include "time-util.h"
 
-#if 0 /// UNNEEDED by elogind
-static nsec_t timespec_load_nsec(const struct timespec *ts);
-#endif // 0
-
 static clockid_t map_clock_id(clockid_t c) {
 
         /* Some more exotic archs (s390, ppc, â€¦) lack the "ALARM" flavour of the clocks. Thus, clock_gettime() will
@@ -205,7 +201,7 @@ usec_t timespec_load(const struct timespec *ts) {
 }
 
 #if 0 /// UNNEEDED by elogind
-static nsec_t timespec_load_nsec(const struct timespec *ts) {
+nsec_t timespec_load_nsec(const struct timespec *ts) {
         assert(ts);
 
         if (ts->tv_sec == (time_t) -1 && ts->tv_nsec == (long) -1)
@@ -262,32 +258,95 @@ struct timeval *timeval_store(struct timeval *tv, usec_t u) {
         return tv;
 }
 
-static char *format_timestamp_internal(char *buf, size_t l, usec_t t,
-                                       bool utc, bool us) {
+static char *format_timestamp_internal(
+                char *buf,
+                size_t l,
+                usec_t t,
+                bool utc,
+                bool us) {
+
+        /* The weekdays in non-localized (English) form. We use this instead of the localized form, so that our
+         * generated timestamps may be parsed with parse_timestamp(), and always read the same. */
+        static const char * const weekdays[] = {
+                [0] = "Sun",
+                [1] = "Mon",
+                [2] = "Tue",
+                [3] = "Wed",
+                [4] = "Thu",
+                [5] = "Fri",
+                [6] = "Sat",
+        };
+
         struct tm tm;
         time_t sec;
-        int k;
+        size_t n;
 
         assert(buf);
-        assert(l > 0);
 
+        if (l <
+            3 +                  /* week day */
+            1 + 10 +             /* space and date */
+            1 + 8 +              /* space and time */
+            (us ? 1 + 6 : 0) +   /* "." and microsecond part */
+            1 + 1 +              /* space and shortest possible zone */
+            1)
+                return NULL; /* Not enough space even for the shortest form. */
         if (t <= 0 || t == USEC_INFINITY)
+                return NULL; /* Timestamp is unset */
+
+        sec = (time_t) (t / USEC_PER_SEC); /* Round down */
+        if ((usec_t) sec != (t / USEC_PER_SEC))
+                return NULL; /* overflow? */
+
+        if (!localtime_or_gmtime_r(&sec, &tm, utc))
                 return NULL;
 
-        sec = (time_t) (t / USEC_PER_SEC);
-        localtime_or_gmtime_r(&sec, &tm, utc);
+        /* Start with the week day */
+        assert((size_t) tm.tm_wday < ELEMENTSOF(weekdays));
+        memcpy(buf, weekdays[tm.tm_wday], 4);
 
-        if (us)
-                k = strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm);
-        else
-                k = strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", &tm);
+        /* Add the main components */
+        if (strftime(buf + 3, l - 3, " %Y-%m-%d %H:%M:%S", &tm) <= 0)
+                return NULL; /* Doesn't fit */
 
-        if (k <= 0)
-                return NULL;
+        /* Append the microseconds part, if that's requested */
         if (us) {
-                snprintf(buf + strlen(buf), l - strlen(buf), ".%06llu", (unsigned long long) (t % USEC_PER_SEC));
-                if (strftime(buf + strlen(buf), l - strlen(buf), " %Z", &tm) <= 0)
-                        return NULL;
+                n = strlen(buf);
+                if (n + 8 > l)
+                        return NULL; /* Microseconds part doesn't fit. */
+
+                sprintf(buf + n, ".%06llu", (unsigned long long) (t % USEC_PER_SEC));
+        }
+
+        /* Append the timezone */
+        n = strlen(buf);
+        if (utc) {
+                /* If this is UTC then let's explicitly use the "UTC" string here, because gmtime_r() normally uses the
+                 * obsolete "GMT" instead. */
+                if (n + 5 > l)
+                        return NULL; /* "UTC" doesn't fit. */
+
+                strcpy(buf + n, " UTC");
+
+        } else if (!isempty(tm.tm_zone)) {
+                size_t tn;
+
+                /* An explicit timezone is specified, let's use it, if it fits */
+                tn = strlen(tm.tm_zone);
+                if (n + 1 + tn + 1 > l) {
+                        /* The full time zone does not fit in. Yuck. */
+
+                        if (n + 1 + _POSIX_TZNAME_MAX + 1 > l)
+                                return NULL; /* Not even enough space for the POSIX minimum (of 6)? In that case, complain that it doesn't fit */
+
+                        /* So the time zone doesn't fit in fully, but the caller passed enough space for the POSIX
+                         * minimum time zone length. In this case suppress the timezone entirely, in order not to dump
+                         * an overly long, hard to read string on the user. This should be safe, because the user will
+                         * assume the local timezone anyway if none is shown. And so does parse_timestamp(). */
+                } else {
+                        buf[n++] = ' ';
+                        strcpy(buf + n, tm.tm_zone);
+                }
         }
 
         return buf;
@@ -554,12 +613,11 @@ int parse_timestamp(const char *t, usec_t *usec) {
                 { "Sat",       6 },
         };
 
-        const char *k;
-        const char *utc;
+        const char *k, *utc, *tzn = NULL;
         struct tm tm, copy;
         time_t x;
         usec_t x_usec, plus = 0, minus = 0, ret;
-        int r, weekday = -1;
+        int r, weekday = -1, dst = -1;
         unsigned i;
 
         /*
@@ -624,15 +682,55 @@ int parse_timestamp(const char *t, usec_t *usec) {
                 goto finish;
         }
 
+        /* See if the timestamp is suffixed with UTC */
         utc = endswith_no_case(t, " UTC");
         if (utc)
                 t = strndupa(t, utc - t);
+        else {
+                const char *e = NULL;
+                int j;
+
+                tzset();
+
+                /* See if the timestamp is suffixed by either the DST or non-DST local timezone. Note that we only
+                 * support the local timezones here, nothing else. Not because we wouldn't want to, but simply because
+                 * there are no nice APIs available to cover this. By accepting the local time zone strings, we make
+                 * sure that all timestamps written by format_timestamp() can be parsed correctly, even though we don't
+                 * support arbitrary timezone specifications.  */
+
+                for (j = 0; j <= 1; j++) {
 
-        x = ret / USEC_PER_SEC;
+                        if (isempty(tzname[j]))
+                                continue;
+
+                        e = endswith_no_case(t, tzname[j]);
+                        if (!e)
+                                continue;
+                        if (e == t)
+                                continue;
+                        if (e[-1] != ' ')
+                                continue;
+
+                        break;
+                }
+
+                if (IN_SET(j, 0, 1)) {
+                        /* Found one of the two timezones specified. */
+                        t = strndupa(t, e - t - 1);
+                        dst = j;
+                        tzn = tzname[j];
+                }
+        }
+
+        x = (time_t) (ret / USEC_PER_SEC);
         x_usec = 0;
 
-        assert_se(localtime_or_gmtime_r(&x, &tm, utc));
-        tm.tm_isdst = -1;
+        if (!localtime_or_gmtime_r(&x, &tm, utc))
+                return -EINVAL;
+
+        tm.tm_isdst = dst;
+        if (tzn)
+                tm.tm_zone = tzn;
 
         if (streq(t, "today")) {
                 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
@@ -649,7 +747,6 @@ int parse_timestamp(const char *t, usec_t *usec) {
                 goto from_tm;
         }
 
-
         for (i = 0; i < ELEMENTSOF(day_nr); i++) {
                 size_t skip;
 
@@ -742,7 +839,6 @@ parse_usec:
                         return -EINVAL;
 
                 x_usec = add;
-
         }
 
 from_tm:
index f80b6594f54b7779c35e03e0497e55360f5fddc9..eab708c2817e7450ceccfc123ca0da27534728a4 100644 (file)
@@ -68,7 +68,9 @@ typedef struct triple_timestamp {
 #define USEC_PER_YEAR ((usec_t) (31557600ULL*USEC_PER_SEC))
 #define NSEC_PER_YEAR ((nsec_t) (31557600ULL*NSEC_PER_SEC))
 
-#define FORMAT_TIMESTAMP_MAX ((4*4+1)+11+9+4+1) /* weekdays can be unicode */
+/* We assume a maximum timezone length of 6. TZNAME_MAX is not defined on Linux, but glibc internally initializes this
+ * to 6. Let's rely on that. */
+#define FORMAT_TIMESTAMP_MAX (3+1+10+1+8+1+6+1+6+1)
 #define FORMAT_TIMESTAMP_WIDTH 28 /* when outputting, assume this width */
 #define FORMAT_TIMESTAMP_RELATIVE_MAX 256
 #define FORMAT_TIMESPAN_MAX 64
@@ -113,6 +115,9 @@ static inline bool triple_timestamp_is_set(triple_timestamp *ts) {
 usec_t triple_timestamp_by_clock(triple_timestamp *ts, clockid_t clock);
 
 usec_t timespec_load(const struct timespec *ts) _pure_;
+#if 0 /// UNNEEDED by elogind
+nsec_t timespec_load_nsec(const struct timespec *ts) _pure_;
+#endif // 0
 struct timespec *timespec_store(struct timespec *ts, usec_t u);
 
 usec_t timeval_load(const struct timeval *tv) _pure_;
index fbe9f2a969987f86b225bd3a170173c0698aa7d5..9ef19a1f692df044c5c2f410e77e45e3efb6e55a 100644 (file)
 #include <string.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include <utmp.h>
 
-#include "missing.h"
 #include "alloc-util.h"
 #include "fd-util.h"
+#include "fileio.h"
 #include "formats-util.h"
 #include "macro.h"
+#include "missing.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "string-util.h"
+#include "strv.h"
 #include "user-util.h"
+#include "utf8.h"
 
 bool uid_is_valid(uid_t uid) {
 
@@ -175,6 +179,36 @@ int get_user_creds(
         return 0;
 }
 
+#if 0 /// UNNEEDED by elogind
+int get_user_creds_clean(
+                const char **username,
+                uid_t *uid, gid_t *gid,
+                const char **home,
+                const char **shell) {
+
+        int r;
+
+        /* Like get_user_creds(), but resets home/shell to NULL if they don't contain anything relevant. */
+
+        r = get_user_creds(username, uid, gid, home, shell);
+        if (r < 0)
+                return r;
+
+        if (shell &&
+            (isempty(*shell) || PATH_IN_SET(*shell,
+                                            "/bin/nologin",
+                                            "/sbin/nologin",
+                                            "/usr/bin/nologin",
+                                            "/usr/sbin/nologin")))
+                *shell = NULL;
+
+        if (home &&
+            (isempty(*home) || path_equal(*home, "/")))
+                *home = NULL;
+
+        return 0;
+}
+
 int get_group_creds(const char **groupname, gid_t *gid) {
         struct group *g;
         gid_t id;
@@ -216,6 +250,7 @@ int get_group_creds(const char **groupname, gid_t *gid) {
 
         return 0;
 }
+#endif // 0
 
 char* uid_to_name(uid_t uid) {
         char *ret;
@@ -431,9 +466,11 @@ int get_shell(char **_s) {
 #endif // 0
 
 int reset_uid_gid(void) {
+        int r;
 
-        if (setgroups(0, NULL) < 0)
-                return -errno;
+        r = maybe_setgroups(0, NULL);
+        if (r < 0)
+                return r;
 
         if (setresgid(0, 0, 0) < 0)
                 return -errno;
@@ -485,3 +522,123 @@ int take_etc_passwd_lock(const char *root) {
         return fd;
 }
 #endif // 0
+
+bool valid_user_group_name(const char *u) {
+        const char *i;
+        long sz;
+
+        /* Checks if the specified name is a valid user/group name. */
+
+        if (isempty(u))
+                return false;
+
+        if (!(u[0] >= 'a' && u[0] <= 'z') &&
+            !(u[0] >= 'A' && u[0] <= 'Z') &&
+            u[0] != '_')
+                return false;
+
+        for (i = u+1; *i; i++) {
+                if (!(*i >= 'a' && *i <= 'z') &&
+                    !(*i >= 'A' && *i <= 'Z') &&
+                    !(*i >= '0' && *i <= '9') &&
+                    *i != '_' &&
+                    *i != '-')
+                        return false;
+        }
+
+        sz = sysconf(_SC_LOGIN_NAME_MAX);
+        assert_se(sz > 0);
+
+        if ((size_t) (i-u) > (size_t) sz)
+                return false;
+
+        if ((size_t) (i-u) > UT_NAMESIZE - 1)
+                return false;
+
+        return true;
+}
+
+bool valid_user_group_name_or_id(const char *u) {
+
+        /* Similar as above, but is also fine with numeric UID/GID specifications, as long as they are in the right
+         * range, and not the invalid user ids. */
+
+        if (isempty(u))
+                return false;
+
+        if (valid_user_group_name(u))
+                return true;
+
+        return parse_uid(u, NULL) >= 0;
+}
+
+bool valid_gecos(const char *d) {
+
+        if (!d)
+                return false;
+
+        if (!utf8_is_valid(d))
+                return false;
+
+        if (string_has_cc(d, NULL))
+                return false;
+
+        /* Colons are used as field separators, and hence not OK */
+        if (strchr(d, ':'))
+                return false;
+
+        return true;
+}
+
+bool valid_home(const char *p) {
+
+        if (isempty(p))
+                return false;
+
+        if (!utf8_is_valid(p))
+                return false;
+
+        if (string_has_cc(p, NULL))
+                return false;
+
+        if (!path_is_absolute(p))
+                return false;
+
+        if (!path_is_safe(p))
+                return false;
+
+        /* Colons are used as field separators, and hence not OK */
+        if (strchr(p, ':'))
+                return false;
+
+        return true;
+}
+
+int maybe_setgroups(size_t size, const gid_t *list) {
+        int r;
+
+        /* Check if setgroups is allowed before we try to drop all the auxiliary groups */
+        if (size == 0) { /* Dropping all aux groups? */
+                _cleanup_free_ char *setgroups_content = NULL;
+                bool can_setgroups;
+
+                r = read_one_line_file("/proc/self/setgroups", &setgroups_content);
+                if (r == -ENOENT)
+                        /* Old kernels don't have /proc/self/setgroups, so assume we can use setgroups */
+                        can_setgroups = true;
+                else if (r < 0)
+                        return r;
+                else
+                        can_setgroups = streq(setgroups_content, "allow");
+
+                if (!can_setgroups) {
+                        log_debug("Skipping setgroups(), /proc/self/setgroups is set to 'deny'");
+                        return 0;
+                }
+        }
+
+        if (setgroups(size, list) < 0)
+                return -errno;
+
+        return 0;
+}
index 5d1d0abe4d1c960f12eda860335bd90453193e0b..4a1bc764ad586d3e35db3f86a47503afbc49f20d 100644 (file)
@@ -20,6 +20,7 @@
 ***/
 
 #include <stdbool.h>
+#include <stdint.h>
 #include <sys/types.h>
 #include <unistd.h>
 
@@ -41,7 +42,10 @@ char* getusername_malloc(void);
 #endif // 0
 
 int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home, const char **shell);
+#if 0 /// UNNEEDED by elogind
+int get_user_creds_clean(const char **username, uid_t *uid, gid_t *gid, const char **home, const char **shell);
 int get_group_creds(const char **groupname, gid_t *gid);
+#endif // 0
 
 char* uid_to_name(uid_t uid);
 char* gid_to_name(gid_t gid);
@@ -63,8 +67,19 @@ int take_etc_passwd_lock(const char *root);
 #define UID_INVALID ((uid_t) -1)
 #define GID_INVALID ((gid_t) -1)
 
-/* The following macros add 1 when converting things, since UID 0 is a
- * valid UID, while the pointer NULL is special */
+/* Let's pick a UIDs within the 16bit range, so that we are compatible with containers using 16bit
+ * user namespacing. At least on Fedora normal users are allocated until UID 60000, hence do not
+ * allocate from below this. Also stay away from the upper end of the range as that is often used
+ * for overflow/nobody users. */
+#define DYNAMIC_UID_MIN ((uid_t) UINT32_C(0x0000EF00))
+#define DYNAMIC_UID_MAX ((uid_t) UINT32_C(0x0000FFEF))
+
+static inline bool uid_is_dynamic(uid_t uid) {
+        return DYNAMIC_UID_MIN <= uid && uid <= DYNAMIC_UID_MAX;
+}
+
+/* The following macros add 1 when converting things, since UID 0 is a valid UID, while the pointer
+ * NULL is special */
 #define PTR_TO_UID(p) ((uid_t) (((uintptr_t) (p))-1))
 #define UID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1))
 
@@ -74,3 +89,10 @@ int take_etc_passwd_lock(const char *root);
 static inline bool userns_supported(void) {
         return access("/proc/self/uid_map", F_OK) >= 0;
 }
+
+bool valid_user_group_name(const char *u);
+bool valid_user_group_name_or_id(const char *u);
+bool valid_gecos(const char *d);
+bool valid_home(const char *p);
+
+int maybe_setgroups(size_t size, const gid_t *list);
index f14dba9d9144e31abcd9f4a44446aac1eb060ffb..27c3d483931d6ed5c39861b1707931ccff621087 100644 (file)
@@ -471,7 +471,7 @@ bool in_initrd(void) {
          * 2. the root file system must be a memory file system
          *
          * The second check is extra paranoia, since misdetecting an
-         * initrd can have bad bad consequences due the initrd
+         * initrd can have bad consequences due the initrd
          * emptying when transititioning to the main systemd.
          */
 
index 346221ca0c99682f055db0374d1215b05149dd41..75631c436bdc560edc0395246ada2f6814e96b33 100644 (file)
@@ -61,6 +61,10 @@ static inline const char* one_zero(bool b) {
         return b ? "1" : "0";
 }
 
+static inline const char* enable_disable(bool b) {
+        return b ? "enable" : "disable";
+}
+
 void execute_directories(const char* const* directories, usec_t timeout, char *argv[]);
 
 #if 0 /// UNNEEDED by elogind
index 0c08201035b815eec3835cc98c442c6e26597925..35beebe7fa4116f5dedfd2b2a0e50fd0cc97486c 100644 (file)
@@ -50,6 +50,8 @@ static int detect_vm_cpuid(void) {
                 { "VMwareVMware", VIRTUALIZATION_VMWARE    },
                 /* http://msdn.microsoft.com/en-us/library/ff542428.aspx */
                 { "Microsoft Hv", VIRTUALIZATION_MICROSOFT },
+                /* https://wiki.freebsd.org/bhyve */
+                { "bhyve bhyve ", VIRTUALIZATION_BHYVE     },
         };
 
         uint32_t eax, ecx;
@@ -179,6 +181,8 @@ static int detect_vm_dmi(void) {
                 { "Xen",           VIRTUALIZATION_XEN       },
                 { "Bochs",         VIRTUALIZATION_BOCHS     },
                 { "Parallels",     VIRTUALIZATION_PARALLELS },
+                /* https://wiki.freebsd.org/bhyve */
+                { "BHYVE",         VIRTUALIZATION_BHYVE     },
         };
         unsigned i;
         int r;
@@ -482,11 +486,86 @@ int detect_virtualization(void) {
 
         return r;
 }
+
+static int userns_has_mapping(const char *name) {
+        _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_free_ char *buf = NULL;
+        size_t n_allocated = 0;
+        ssize_t n;
+        uint32_t a, b, c;
+        int r;
+
+        f = fopen(name, "re");
+        if (!f) {
+                log_debug_errno(errno, "Failed to open %s: %m", name);
+                return errno == -ENOENT ? false : -errno;
+        }
+
+        n = getline(&buf, &n_allocated, f);
+        if (n < 0) {
+                if (feof(f)) {
+                        log_debug("%s is empty, we're in an uninitialized user namespace", name);
+                        return true;
+                }
+
+                return log_debug_errno(errno, "Failed to read %s: %m", name);
+        }
+
+        r = sscanf(buf, "%"PRIu32" %"PRIu32" %"PRIu32, &a, &b, &c);
+        if (r < 3)
+                return log_debug_errno(errno, "Failed to parse %s: %m", name);
+
+        if (a == 0 && b == 0 && c == UINT32_MAX) {
+                /* The kernel calls mappings_overlap() and does not allow overlaps */
+                log_debug("%s has a full 1:1 mapping", name);
+                return false;
+        }
+
+        /* Anything else implies that we are in a user namespace */
+        log_debug("Mapping found in %s, we're in a user namespace", name);
+        return true;
+}
+
+int running_in_userns(void) {
+        _cleanup_free_ char *line = NULL;
+        int r;
+
+        r = userns_has_mapping("/proc/self/uid_map");
+        if (r != 0)
+                return r;
+
+        r = userns_has_mapping("/proc/self/gid_map");
+        if (r != 0)
+                return r;
+
+        /* "setgroups" file was added in kernel v3.18-rc6-15-g9cc46516dd. It is also
+         * possible to compile a kernel without CONFIG_USER_NS, in which case "setgroups"
+         * also does not exist. We cannot distinguish those two cases, so assume that
+         * we're running on a stripped-down recent kernel, rather than on an old one,
+         * and if the file is not found, return false.
+         */
+        r = read_one_line_file("/proc/self/setgroups", &line);
+        if (r < 0) {
+                log_debug_errno(r, "/proc/self/setgroups: %m");
+                return r == -ENOENT ? false : r;
+        }
+
+        truncate_nl(line);
+        r = streq(line, "deny");
+        /* See user_namespaces(7) for a description of this "setgroups" contents. */
+        log_debug("/proc/self/setgroups contains \"%s\", %s user namespace", line, r ? "in" : "not in");
+        return r;
+}
 #endif // 0
 
 int running_in_chroot(void) {
         int ret;
 
+#if 0 /// elogind does not allow to ignore chroots, we are never init!
+        if (getenv_bool("SYSTEMD_IGNORE_CHROOT") > 0)
+                return 0;
+#endif // 0
+
         ret = files_same("/proc/1/root", "/");
         if (ret < 0)
                 return ret;
@@ -506,6 +585,7 @@ static const char *const virtualization_table[_VIRTUALIZATION_MAX] = {
         [VIRTUALIZATION_MICROSOFT] = "microsoft",
         [VIRTUALIZATION_ZVM] = "zvm",
         [VIRTUALIZATION_PARALLELS] = "parallels",
+        [VIRTUALIZATION_BHYVE] = "bhyve",
         [VIRTUALIZATION_VM_OTHER] = "vm-other",
 
         [VIRTUALIZATION_SYSTEMD_NSPAWN] = "systemd-nspawn",
index 1d88ab9ab681d8bc5bcd7eeaa6fdec2e23f3fd8c..f448f4e8fbc0afe8190c2f7e1f73a8ba18a4cba5 100644 (file)
@@ -37,6 +37,7 @@ enum {
         VIRTUALIZATION_MICROSOFT,
         VIRTUALIZATION_ZVM,
         VIRTUALIZATION_PARALLELS,
+        VIRTUALIZATION_BHYVE,
         VIRTUALIZATION_VM_OTHER,
         VIRTUALIZATION_VM_LAST = VIRTUALIZATION_VM_OTHER,
 
@@ -68,8 +69,9 @@ int detect_vm(void);
 int detect_container(void);
 #if 0 /// UNNEEDED by elogind
 int detect_virtualization(void);
-#endif // 0
 
+int running_in_userns(void);
+#endif // 0
 int running_in_chroot(void);
 
 const char *virtualization_to_string(int v) _const_;
index 4702c54a930c948dabaf640861b821f5c623e261..9e4e993263916428dd636c0958f7fb642002fba5 100644 (file)
@@ -58,12 +58,16 @@ void cgroup_context_init(CGroupContext *c) {
         /* Initialize everything to the kernel defaults, assuming the
          * structure is preinitialized to 0 */
 
+        c->cpu_weight = CGROUP_WEIGHT_INVALID;
+        c->startup_cpu_weight = CGROUP_WEIGHT_INVALID;
+        c->cpu_quota_per_sec_usec = USEC_INFINITY;
+
         c->cpu_shares = CGROUP_CPU_SHARES_INVALID;
         c->startup_cpu_shares = CGROUP_CPU_SHARES_INVALID;
-        c->cpu_quota_per_sec_usec = USEC_INFINITY;
 
         c->memory_high = CGROUP_LIMIT_MAX;
         c->memory_max = CGROUP_LIMIT_MAX;
+        c->memory_swap_max = CGROUP_LIMIT_MAX;
 
         c->memory_limit = CGROUP_LIMIT_MAX;
 
@@ -159,6 +163,8 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
                 "%sBlockIOAccounting=%s\n"
                 "%sMemoryAccounting=%s\n"
                 "%sTasksAccounting=%s\n"
+                "%sCPUWeight=%" PRIu64 "\n"
+                "%sStartupCPUWeight=%" PRIu64 "\n"
                 "%sCPUShares=%" PRIu64 "\n"
                 "%sStartupCPUShares=%" PRIu64 "\n"
                 "%sCPUQuotaPerSecSec=%s\n"
@@ -169,6 +175,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
                 "%sMemoryLow=%" PRIu64 "\n"
                 "%sMemoryHigh=%" PRIu64 "\n"
                 "%sMemoryMax=%" PRIu64 "\n"
+                "%sMemorySwapMax=%" PRIu64 "\n"
                 "%sMemoryLimit=%" PRIu64 "\n"
                 "%sTasksMax=%" PRIu64 "\n"
                 "%sDevicePolicy=%s\n"
@@ -178,6 +185,8 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
                 prefix, yes_no(c->blockio_accounting),
                 prefix, yes_no(c->memory_accounting),
                 prefix, yes_no(c->tasks_accounting),
+                prefix, c->cpu_weight,
+                prefix, c->startup_cpu_weight,
                 prefix, c->cpu_shares,
                 prefix, c->startup_cpu_shares,
                 prefix, format_timespan(u, sizeof(u), c->cpu_quota_per_sec_usec, 1),
@@ -188,6 +197,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
                 prefix, c->memory_low,
                 prefix, c->memory_high,
                 prefix, c->memory_max,
+                prefix, c->memory_swap_max,
                 prefix, c->memory_limit,
                 prefix, c->tasks_max,
                 prefix, cgroup_device_policy_to_string(c->device_policy),
@@ -383,6 +393,95 @@ fail:
         return -errno;
 }
 
+static bool cgroup_context_has_cpu_weight(CGroupContext *c) {
+        return c->cpu_weight != CGROUP_WEIGHT_INVALID ||
+                c->startup_cpu_weight != CGROUP_WEIGHT_INVALID;
+}
+
+static bool cgroup_context_has_cpu_shares(CGroupContext *c) {
+        return c->cpu_shares != CGROUP_CPU_SHARES_INVALID ||
+                c->startup_cpu_shares != CGROUP_CPU_SHARES_INVALID;
+}
+
+static uint64_t cgroup_context_cpu_weight(CGroupContext *c, ManagerState state) {
+        if (IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) &&
+            c->startup_cpu_weight != CGROUP_WEIGHT_INVALID)
+                return c->startup_cpu_weight;
+        else if (c->cpu_weight != CGROUP_WEIGHT_INVALID)
+                return c->cpu_weight;
+        else
+                return CGROUP_WEIGHT_DEFAULT;
+}
+
+static uint64_t cgroup_context_cpu_shares(CGroupContext *c, ManagerState state) {
+        if (IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) &&
+            c->startup_cpu_shares != CGROUP_CPU_SHARES_INVALID)
+                return c->startup_cpu_shares;
+        else if (c->cpu_shares != CGROUP_CPU_SHARES_INVALID)
+                return c->cpu_shares;
+        else
+                return CGROUP_CPU_SHARES_DEFAULT;
+}
+
+static void cgroup_apply_unified_cpu_config(Unit *u, uint64_t weight, uint64_t quota) {
+        char buf[MAX(DECIMAL_STR_MAX(uint64_t) + 1, (DECIMAL_STR_MAX(usec_t) + 1) * 2)];
+        int r;
+
+        xsprintf(buf, "%" PRIu64 "\n", weight);
+        r = cg_set_attribute("cpu", u->cgroup_path, "cpu.weight", buf);
+        if (r < 0)
+                log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+                              "Failed to set cpu.weight: %m");
+
+        if (quota != USEC_INFINITY)
+                xsprintf(buf, USEC_FMT " " USEC_FMT "\n",
+                         quota * CGROUP_CPU_QUOTA_PERIOD_USEC / USEC_PER_SEC, CGROUP_CPU_QUOTA_PERIOD_USEC);
+        else
+                xsprintf(buf, "max " USEC_FMT "\n", CGROUP_CPU_QUOTA_PERIOD_USEC);
+
+        r = cg_set_attribute("cpu", u->cgroup_path, "cpu.max", buf);
+
+        if (r < 0)
+                log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+                              "Failed to set cpu.max: %m");
+}
+
+static void cgroup_apply_legacy_cpu_config(Unit *u, uint64_t shares, uint64_t quota) {
+        char buf[MAX(DECIMAL_STR_MAX(uint64_t), DECIMAL_STR_MAX(usec_t)) + 1];
+        int r;
+
+        xsprintf(buf, "%" PRIu64 "\n", shares);
+        r = cg_set_attribute("cpu", u->cgroup_path, "cpu.shares", buf);
+        if (r < 0)
+                log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+                              "Failed to set cpu.shares: %m");
+
+        xsprintf(buf, USEC_FMT "\n", CGROUP_CPU_QUOTA_PERIOD_USEC);
+        r = cg_set_attribute("cpu", u->cgroup_path, "cpu.cfs_period_us", buf);
+        if (r < 0)
+                log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+                              "Failed to set cpu.cfs_period_us: %m");
+
+        if (quota != USEC_INFINITY) {
+                xsprintf(buf, USEC_FMT "\n", quota * CGROUP_CPU_QUOTA_PERIOD_USEC / USEC_PER_SEC);
+                r = cg_set_attribute("cpu", u->cgroup_path, "cpu.cfs_quota_us", buf);
+        } else
+                r = cg_set_attribute("cpu", u->cgroup_path, "cpu.cfs_quota_us", "-1");
+        if (r < 0)
+                log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+                              "Failed to set cpu.cfs_quota_us: %m");
+}
+
+static uint64_t cgroup_cpu_shares_to_weight(uint64_t shares) {
+        return CLAMP(shares * CGROUP_WEIGHT_DEFAULT / CGROUP_CPU_SHARES_DEFAULT,
+                     CGROUP_WEIGHT_MIN, CGROUP_WEIGHT_MAX);
+}
+
+static uint64_t cgroup_cpu_weight_to_shares(uint64_t weight) {
+        return CLAMP(weight * CGROUP_CPU_SHARES_DEFAULT / CGROUP_WEIGHT_DEFAULT,
+                     CGROUP_CPU_SHARES_MIN, CGROUP_CPU_SHARES_MAX);
+}
+
 static bool cgroup_context_has_io_config(CGroupContext *c) {
         return c->io_accounting ||
                 c->io_weight != CGROUP_WEIGHT_INVALID ||
@@ -522,7 +621,7 @@ static unsigned cgroup_apply_blkio_device_limit(Unit *u, const char *dev_path, u
 }
 
 static bool cgroup_context_has_unified_memory_config(CGroupContext *c) {
-        return c->memory_low > 0 || c->memory_high != CGROUP_LIMIT_MAX || c->memory_max != CGROUP_LIMIT_MAX;
+        return c->memory_low > 0 || c->memory_high != CGROUP_LIMIT_MAX || c->memory_max != CGROUP_LIMIT_MAX || c->memory_swap_max != CGROUP_LIMIT_MAX;
 }
 
 static void cgroup_apply_unified_memory_limit(Unit *u, const char *file, uint64_t v) {
@@ -567,30 +666,42 @@ static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) {
          * and missing cgroups, i.e. EROFS and ENOENT. */
 
         if ((mask & CGROUP_MASK_CPU) && !is_root) {
-                char buf[MAX(DECIMAL_STR_MAX(uint64_t), DECIMAL_STR_MAX(usec_t)) + 1];
+                bool has_weight = cgroup_context_has_cpu_weight(c);
+                bool has_shares = cgroup_context_has_cpu_shares(c);
 
-                sprintf(buf, "%" PRIu64 "\n",
-                        IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && c->startup_cpu_shares != CGROUP_CPU_SHARES_INVALID ? c->startup_cpu_shares :
-                        c->cpu_shares != CGROUP_CPU_SHARES_INVALID ? c->cpu_shares : CGROUP_CPU_SHARES_DEFAULT);
-                r = cg_set_attribute("cpu", path, "cpu.shares", buf);
-                if (r < 0)
-                        log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
-                                      "Failed to set cpu.shares: %m");
+                if (cg_all_unified() > 0) {
+                        uint64_t weight;
 
-                sprintf(buf, USEC_FMT "\n", CGROUP_CPU_QUOTA_PERIOD_USEC);
-                r = cg_set_attribute("cpu", path, "cpu.cfs_period_us", buf);
-                if (r < 0)
-                        log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
-                                      "Failed to set cpu.cfs_period_us: %m");
+                        if (has_weight)
+                                weight = cgroup_context_cpu_weight(c, state);
+                        else if (has_shares) {
+                                uint64_t shares = cgroup_context_cpu_shares(c, state);
 
-                if (c->cpu_quota_per_sec_usec != USEC_INFINITY) {
-                        sprintf(buf, USEC_FMT "\n", c->cpu_quota_per_sec_usec * CGROUP_CPU_QUOTA_PERIOD_USEC / USEC_PER_SEC);
-                        r = cg_set_attribute("cpu", path, "cpu.cfs_quota_us", buf);
-                } else
-                        r = cg_set_attribute("cpu", path, "cpu.cfs_quota_us", "-1");
-                if (r < 0)
-                        log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
-                                      "Failed to set cpu.cfs_quota_us: %m");
+                                weight = cgroup_cpu_shares_to_weight(shares);
+
+                                log_cgroup_compat(u, "Applying [Startup]CpuShares %" PRIu64 " as [Startup]CpuWeight %" PRIu64 " on %s",
+                                                  shares, weight, path);
+                        } else
+                                weight = CGROUP_WEIGHT_DEFAULT;
+
+                        cgroup_apply_unified_cpu_config(u, weight, c->cpu_quota_per_sec_usec);
+                } else {
+                        uint64_t shares;
+
+                        if (has_weight) {
+                                uint64_t weight = cgroup_context_cpu_weight(c, state);
+
+                                shares = cgroup_cpu_weight_to_shares(weight);
+
+                                log_cgroup_compat(u, "Applying [Startup]CpuWeight %" PRIu64 " as [Startup]CpuShares %" PRIu64 " on %s",
+                                                  weight, shares, path);
+                        } else if (has_shares)
+                                shares = cgroup_context_cpu_shares(c, state);
+                        else
+                                shares = CGROUP_CPU_SHARES_DEFAULT;
+
+                        cgroup_apply_legacy_cpu_config(u, shares, c->cpu_quota_per_sec_usec);
+                }
         }
 
         if (mask & CGROUP_MASK_IO) {
@@ -678,16 +789,16 @@ static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) {
                         char buf[DECIMAL_STR_MAX(uint64_t)+1];
                         uint64_t weight;
 
-                        if (has_blockio)
-                                weight = cgroup_context_blkio_weight(c, state);
-                        else if (has_io) {
+                        if (has_io) {
                                 uint64_t io_weight = cgroup_context_io_weight(c, state);
 
                                 weight = cgroup_weight_io_to_blkio(cgroup_context_io_weight(c, state));
 
                                 log_cgroup_compat(u, "Applying [Startup]IOWeight %" PRIu64 " as [Startup]BlockIOWeight %" PRIu64,
                                                   io_weight, weight);
-                        } else
+                        } else if (has_blockio)
+                                weight = cgroup_context_blkio_weight(c, state);
+                        else
                                 weight = CGROUP_BLKIO_WEIGHT_DEFAULT;
 
                         xsprintf(buf, "%" PRIu64 "\n", weight);
@@ -696,13 +807,7 @@ static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) {
                                 log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
                                               "Failed to set blkio.weight: %m");
 
-                        if (has_blockio) {
-                                CGroupBlockIODeviceWeight *w;
-
-                                /* FIXME: no way to reset this list */
-                                LIST_FOREACH(device_weights, w, c->blockio_device_weights)
-                                        cgroup_apply_blkio_device_weight(u, w->path, w->weight);
-                        } else if (has_io) {
+                        if (has_io) {
                                 CGroupIODeviceWeight *w;
 
                                 /* FIXME: no way to reset this list */
@@ -714,18 +819,17 @@ static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) {
 
                                         cgroup_apply_blkio_device_weight(u, w->path, weight);
                                 }
+                        } else if (has_blockio) {
+                                CGroupBlockIODeviceWeight *w;
+
+                                /* FIXME: no way to reset this list */
+                                LIST_FOREACH(device_weights, w, c->blockio_device_weights)
+                                        cgroup_apply_blkio_device_weight(u, w->path, w->weight);
                         }
                 }
 
                 /* Apply limits and free ones without config. */
-                if (has_blockio) {
-                        CGroupBlockIODeviceBandwidth *b, *next;
-
-                        LIST_FOREACH_SAFE(device_bandwidths, b, next, c->blockio_device_bandwidths) {
-                                if (!cgroup_apply_blkio_device_limit(u, b->path, b->rbps, b->wbps))
-                                        cgroup_context_free_blockio_device_bandwidth(c, b);
-                        }
-                } else if (has_io) {
+                if (has_io) {
                         CGroupIODeviceLimit *l, *next;
 
                         LIST_FOREACH_SAFE(device_limits, l, next, c->io_device_limits) {
@@ -735,16 +839,24 @@ static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) {
                                 if (!cgroup_apply_blkio_device_limit(u, l->path, l->limits[CGROUP_IO_RBPS_MAX], l->limits[CGROUP_IO_WBPS_MAX]))
                                         cgroup_context_free_io_device_limit(c, l);
                         }
+                } else if (has_blockio) {
+                        CGroupBlockIODeviceBandwidth *b, *next;
+
+                        LIST_FOREACH_SAFE(device_bandwidths, b, next, c->blockio_device_bandwidths)
+                                if (!cgroup_apply_blkio_device_limit(u, b->path, b->rbps, b->wbps))
+                                        cgroup_context_free_blockio_device_bandwidth(c, b);
                 }
         }
 
         if ((mask & CGROUP_MASK_MEMORY) && !is_root) {
-                if (cg_unified() > 0) {
-                        uint64_t max = c->memory_max;
+                if (cg_all_unified() > 0) {
+                        uint64_t max;
+                        uint64_t swap_max = CGROUP_LIMIT_MAX;
 
-                        if (cgroup_context_has_unified_memory_config(c))
+                        if (cgroup_context_has_unified_memory_config(c)) {
                                 max = c->memory_max;
-                        else {
+                                swap_max = c->memory_swap_max;
+                        } else {
                                 max = c->memory_limit;
 
                                 if (max != CGROUP_LIMIT_MAX)
@@ -754,16 +866,16 @@ static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) {
                         cgroup_apply_unified_memory_limit(u, "memory.low", c->memory_low);
                         cgroup_apply_unified_memory_limit(u, "memory.high", c->memory_high);
                         cgroup_apply_unified_memory_limit(u, "memory.max", max);
+                        cgroup_apply_unified_memory_limit(u, "memory.swap.max", swap_max);
                 } else {
                         char buf[DECIMAL_STR_MAX(uint64_t) + 1];
-                        uint64_t val = c->memory_limit;
+                        uint64_t val;
 
-                        if (val == CGROUP_LIMIT_MAX) {
+                        if (cgroup_context_has_unified_memory_config(c)) {
                                 val = c->memory_max;
-
-                                if (val != CGROUP_LIMIT_MAX)
-                                        log_cgroup_compat(u, "Applying MemoryMax %" PRIi64 " as MemoryLimit", c->memory_max);
-                        }
+                                log_cgroup_compat(u, "Applying MemoryMax %" PRIi64 " as MemoryLimit", val);
+                        } else
+                                val = c->memory_limit;
 
                         if (val == CGROUP_LIMIT_MAX)
                                 strncpy(buf, "-1\n", sizeof(buf));
@@ -846,7 +958,7 @@ static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) {
 
         if ((mask & CGROUP_MASK_PIDS) && !is_root) {
 
-                if (c->tasks_max != (uint64_t) -1) {
+                if (c->tasks_max != CGROUP_LIMIT_MAX) {
                         char buf[DECIMAL_STR_MAX(uint64_t) + 2];
 
                         sprintf(buf, "%" PRIu64 "\n", c->tasks_max);
@@ -866,8 +978,8 @@ CGroupMask cgroup_context_get_mask(CGroupContext *c) {
         /* Figure out which controllers we need */
 
         if (c->cpu_accounting ||
-            c->cpu_shares != CGROUP_CPU_SHARES_INVALID ||
-            c->startup_cpu_shares != CGROUP_CPU_SHARES_INVALID ||
+            cgroup_context_has_cpu_weight(c) ||
+            cgroup_context_has_cpu_shares(c) ||
             c->cpu_quota_per_sec_usec != USEC_INFINITY)
                 mask |= CGROUP_MASK_CPUACCT | CGROUP_MASK_CPU;
 
@@ -913,7 +1025,7 @@ CGroupMask unit_get_own_mask(Unit *u) {
                 e = unit_get_exec_context(u);
                 if (!e ||
                     exec_context_maintains_privileges(e) ||
-                    cg_unified() > 0)
+                    cg_all_unified() > 0)
                         return _CGROUP_MASK_ALL;
         }
 
@@ -1139,7 +1251,7 @@ int unit_watch_cgroup(Unit *u) {
                 return 0;
 
         /* Only applies to the unified hierarchy */
-        r = cg_unified();
+        r = cg_unified(SYSTEMD_CGROUP_CONTROLLER);
         if (r < 0)
                 return log_unit_error_errno(u, r, "Failed detect whether the unified hierarchy is used: %m");
         if (r == 0)
@@ -1249,6 +1361,26 @@ int unit_attach_pids_to_cgroup(Unit *u) {
         return 0;
 }
 
+static void cgroup_xattr_apply(Unit *u) {
+        char ids[SD_ID128_STRING_MAX];
+        int r;
+
+        assert(u);
+
+        if (!MANAGER_IS_SYSTEM(u->manager))
+                return;
+
+        if (sd_id128_is_null(u->invocation_id))
+                return;
+
+        r = cg_set_xattr(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path,
+                         "trusted.invocation_id",
+                         sd_id128_to_string(u->invocation_id, ids), 32,
+                         0);
+        if (r < 0)
+                log_unit_warning_errno(u, r, "Failed to set invocation ID on control group %s, ignoring: %m", u->cgroup_path);
+}
+
 static bool unit_has_mask_realized(Unit *u, CGroupMask target_mask, CGroupMask enable_mask) {
         assert(u);
 
@@ -1292,6 +1424,7 @@ static int unit_realize_cgroup_now(Unit *u, ManagerState state) {
 
         /* Finally, apply the necessary attributes. */
         cgroup_context_apply(u, target_mask, state);
+        cgroup_xattr_apply(u);
 
         return 0;
 }
@@ -1418,6 +1551,8 @@ void unit_prune_cgroup(Unit *u) {
         if (!u->cgroup_path)
                 return;
 
+        (void) unit_get_cpu_usage(u, NULL); /* Cache the last CPU usage value before we destroy the cgroup */
+
         is_root_slice = unit_has_name(u, SPECIAL_ROOT_SLICE);
 
         r = cg_trim_everywhere(u->manager->cgroup_supported, u->cgroup_path, !is_root_slice);
@@ -1539,7 +1674,7 @@ int unit_watch_all_pids(Unit *u) {
         if (!u->cgroup_path)
                 return -ENOENT;
 
-        if (cg_unified() > 0) /* On unified we can use proper notifications */
+        if (cg_unified(SYSTEMD_CGROUP_CONTROLLER) > 0) /* On unified we can use proper notifications */
                 return 0;
 
         return unit_watch_pids_in_path(u, u->cgroup_path);
@@ -1613,7 +1748,7 @@ static int on_cgroup_inotify_event(sd_event_source *s, int fd, uint32_t revents,
 int manager_setup_cgroup(Manager *m) {
         _cleanup_free_ char *path = NULL;
         CGroupController c;
-        int r, unified;
+        int r, all_unified, systemd_unified;
         char *e;
 
         assert(m);
@@ -1654,11 +1789,17 @@ int manager_setup_cgroup(Manager *m) {
         if (r < 0)
                 return log_error_errno(r, "Cannot find cgroup mount point: %m");
 
-        unified = cg_unified();
-        if (unified < 0)
-                return log_error_errno(r, "Couldn't determine if we are running in the unified hierarchy: %m");
-        if (unified > 0)
+        all_unified = cg_all_unified();
+        systemd_unified = cg_unified(SYSTEMD_CGROUP_CONTROLLER);
+
+        if (all_unified < 0 || systemd_unified < 0)
+                return log_error_errno(all_unified < 0 ? all_unified : systemd_unified,
+                                       "Couldn't determine if we are running in the unified hierarchy: %m");
+
+        if (all_unified > 0)
                 log_debug("Unified cgroup hierarchy is located at %s.", path);
+        else if (systemd_unified > 0)
+                log_debug("Unified cgroup hierarchy is located at %s. Controllers are on legacy hierarchies.", path);
         else
                 log_debug("Using cgroup controller " SYSTEMD_CGROUP_CONTROLLER ". File system hierarchy is at %s.", path);
 
@@ -1666,7 +1807,7 @@ int manager_setup_cgroup(Manager *m) {
                 const char *scope_path;
 
                 /* 3. Install agent */
-                if (unified) {
+                if (systemd_unified) {
 
                         /* In the unified hierarchy we can get
                          * cgroup empty notifications via inotify. */
@@ -1744,7 +1885,7 @@ int manager_setup_cgroup(Manager *m) {
                         return log_error_errno(errno, "Failed to open pin file: %m");
 
                 /* 6.  Always enable hierarchical support if it exists... */
-                if (!unified)
+                if (!all_unified)
                         (void) cg_set_attribute("memory", "/", "memory.use_hierarchy", "1");
         }
 
@@ -1881,7 +2022,6 @@ int manager_notify_cgroup_empty(Manager *m, const char *cgroup) {
         return 0;
 }
 #endif // 0
-
 #if 0 /// UNNEEDED by elogind
 int unit_get_memory_current(Unit *u, uint64_t *ret) {
         _cleanup_free_ char *v = NULL;
@@ -1896,7 +2036,7 @@ int unit_get_memory_current(Unit *u, uint64_t *ret) {
         if ((u->cgroup_realized_mask & CGROUP_MASK_MEMORY) == 0)
                 return -ENODATA;
 
-        if (cg_unified() <= 0)
+        if (cg_all_unified() <= 0)
                 r = cg_get_attribute("memory", u->cgroup_path, "memory.usage_in_bytes", &v);
         else
                 r = cg_get_attribute("memory", u->cgroup_path, "memory.current", &v);
@@ -1941,18 +2081,37 @@ static int unit_get_cpu_usage_raw(Unit *u, nsec_t *ret) {
         if (!u->cgroup_path)
                 return -ENODATA;
 
-        if ((u->cgroup_realized_mask & CGROUP_MASK_CPUACCT) == 0)
-                return -ENODATA;
+        if (cg_all_unified() > 0) {
+                const char *keys[] = { "usage_usec", NULL };
+                _cleanup_free_ char *val = NULL;
+                uint64_t us;
 
-        r = cg_get_attribute("cpuacct", u->cgroup_path, "cpuacct.usage", &v);
-        if (r == -ENOENT)
-                return -ENODATA;
-        if (r < 0)
-                return r;
+                if ((u->cgroup_realized_mask & CGROUP_MASK_CPU) == 0)
+                        return -ENODATA;
 
-        r = safe_atou64(v, &ns);
-        if (r < 0)
-                return r;
+                r = cg_get_keyed_attribute("cpu", u->cgroup_path, "cpu.stat", keys, &val);
+                if (r < 0)
+                        return r;
+
+                r = safe_atou64(val, &us);
+                if (r < 0)
+                        return r;
+
+                ns = us * NSEC_PER_USEC;
+        } else {
+                if ((u->cgroup_realized_mask & CGROUP_MASK_CPUACCT) == 0)
+                        return -ENODATA;
+
+                r = cg_get_attribute("cpuacct", u->cgroup_path, "cpuacct.usage", &v);
+                if (r == -ENOENT)
+                        return -ENODATA;
+                if (r < 0)
+                        return r;
+
+                r = safe_atou64(v, &ns);
+                if (r < 0)
+                        return r;
+        }
 
         *ret = ns;
         return 0;
@@ -1962,16 +2121,33 @@ int unit_get_cpu_usage(Unit *u, nsec_t *ret) {
         nsec_t ns;
         int r;
 
+        assert(u);
+
+        /* Retrieve the current CPU usage counter. This will subtract the CPU counter taken when the unit was
+         * started. If the cgroup has been removed already, returns the last cached value. To cache the value, simply
+         * call this function with a NULL return value. */
+
         r = unit_get_cpu_usage_raw(u, &ns);
+        if (r == -ENODATA && u->cpu_usage_last != NSEC_INFINITY) {
+                /* If we can't get the CPU usage anymore (because the cgroup was already removed, for example), use our
+                 * cached value. */
+
+                if (ret)
+                        *ret = u->cpu_usage_last;
+                return 0;
+        }
         if (r < 0)
                 return r;
 
-        if (ns > u->cpuacct_usage_base)
-                ns -= u->cpuacct_usage_base;
+        if (ns > u->cpu_usage_base)
+                ns -= u->cpu_usage_base;
         else
                 ns = 0;
 
-        *ret = ns;
+        u->cpu_usage_last = ns;
+        if (ret)
+                *ret = ns;
+
         return 0;
 }
 
@@ -1981,13 +2157,15 @@ int unit_reset_cpu_usage(Unit *u) {
 
         assert(u);
 
+        u->cpu_usage_last = NSEC_INFINITY;
+
         r = unit_get_cpu_usage_raw(u, &ns);
         if (r < 0) {
-                u->cpuacct_usage_base = 0;
+                u->cpu_usage_base = 0;
                 return r;
         }
 
-        u->cpuacct_usage_base = ns;
+        u->cpu_usage_base = ns;
         return 0;
 }
 
index c3b87bfc5ce5249b6c49013caf1ebd8fb501fa0f..dd8e436b969f45b91561893f702daa3ccd039f88 100644 (file)
@@ -90,6 +90,10 @@ struct CGroupContext {
         bool tasks_accounting;
 
         /* For unified hierarchy */
+        uint64_t cpu_weight;
+        uint64_t startup_cpu_weight;
+        usec_t cpu_quota_per_sec_usec;
+
         uint64_t io_weight;
         uint64_t startup_io_weight;
         LIST_HEAD(CGroupIODeviceWeight, io_device_weights);
@@ -98,11 +102,11 @@ struct CGroupContext {
         uint64_t memory_low;
         uint64_t memory_high;
         uint64_t memory_max;
+        uint64_t memory_swap_max;
 
         /* For legacy hierarchies */
         uint64_t cpu_shares;
         uint64_t startup_cpu_shares;
-        usec_t cpu_quota_per_sec_usec;
 
         uint64_t blockio_weight;
         uint64_t startup_blockio_weight;
index ca8c63b8a446f83453605d1d31b1bf35a37761c9..c551fa62b2838e066081815c701e27d85cefb15e 100644 (file)
@@ -105,10 +105,11 @@ static const MountPoint mount_table[] = {
         { "tmpfs",       "/sys/fs/cgroup",            "tmpfs",      "mode=755",                MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
           cg_is_legacy_wanted, MNT_FATAL|MNT_IN_CONTAINER },
 #if 0 /// UNNEEDED by elogind
+        { "cgroup",      "/sys/fs/cgroup/systemd",    "cgroup2",    NULL,                      MS_NOSUID|MS_NOEXEC|MS_NODEV,
+          cg_is_unified_systemd_controller_wanted, MNT_IN_CONTAINER },
         { "cgroup",      "/sys/fs/cgroup/systemd",    "cgroup",     "none,name=systemd,xattr", MS_NOSUID|MS_NOEXEC|MS_NODEV,
-          cg_is_legacy_wanted, MNT_IN_CONTAINER           },
+          cg_is_legacy_systemd_controller_wanted, MNT_IN_CONTAINER           },
         { "cgroup",      "/sys/fs/cgroup/systemd",    "cgroup",     "none,name=systemd",       MS_NOSUID|MS_NOEXEC|MS_NODEV,
-          cg_is_legacy_wanted, MNT_FATAL|MNT_IN_CONTAINER },
 #else
         { "cgroup",      "/sys/fs/cgroup/elogind",    "cgroup",     "none,name=elogind,xattr", MS_NOSUID|MS_NOEXEC|MS_NODEV,
           cg_is_legacy_wanted, MNT_IN_CONTAINER           },
index 97b68623bc05a8a60c02f2771af5d93169f53c96..e10e2b4a7da8742cf5f8969dc6004773ea65e022 100644 (file)
@@ -512,3 +512,14 @@ LIBSYSTEMD_231 {
 global:
         sd_event_get_iteration;
 } LIBSYSTEMD_226;
+
+LIBSYSTEMD_232 {
+global:
+        /* sd_bus_track_set_recursive; */
+        /* sd_bus_track_get_recursive; */
+        /* sd_bus_track_count_name; */
+        /* sd_bus_track_count_sender; */
+        sd_bus_set_exit_on_disconnect;
+        /* sd_bus_get_exit_on_disconnect; */
+        sd_id128_get_invocation;
+} LIBSYSTEMD_231;
index 6457cfe093a183cea5e3fe790182e424b18fc54e..ca027100671cd1d1f5e4cdf7527c231979e2fab6 100644 (file)
@@ -28,6 +28,7 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = {
 #if 0 /// UNNEEDED by elogind
         SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_UNIT,                 ENOENT),
         SD_BUS_ERROR_MAP(BUS_ERROR_NO_UNIT_FOR_PID,              ESRCH),
+        SD_BUS_ERROR_MAP(BUS_ERROR_NO_UNIT_FOR_INVOCATION_ID,    ENOENT),
         SD_BUS_ERROR_MAP(BUS_ERROR_UNIT_EXISTS,                  EEXIST),
         SD_BUS_ERROR_MAP(BUS_ERROR_LOAD_FAILED,                  EIO),
         SD_BUS_ERROR_MAP(BUS_ERROR_JOB_FAILED,                   EREMOTEIO),
@@ -45,12 +46,16 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = {
         SD_BUS_ERROR_MAP(BUS_ERROR_NO_ISOLATION,                 EPERM),
         SD_BUS_ERROR_MAP(BUS_ERROR_SHUTTING_DOWN,                ECANCELED),
         SD_BUS_ERROR_MAP(BUS_ERROR_SCOPE_NOT_RUNNING,            EHOSTDOWN),
+        SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_DYNAMIC_USER,         ESRCH),
+        SD_BUS_ERROR_MAP(BUS_ERROR_NOT_REFERENCED,               EUNATCH),
 
         SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_MACHINE,              ENXIO),
         SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_IMAGE,                ENOENT),
         SD_BUS_ERROR_MAP(BUS_ERROR_NO_MACHINE_FOR_PID,           ENXIO),
         SD_BUS_ERROR_MAP(BUS_ERROR_MACHINE_EXISTS,               EEXIST),
         SD_BUS_ERROR_MAP(BUS_ERROR_NO_PRIVATE_NETWORKING,        ENOSYS),
+        SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_USER_MAPPING,         ENXIO),
+        SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_GROUP_MAPPING,        ENXIO),
 #endif // 0
 
         SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_SESSION,              ENXIO),
@@ -64,6 +69,7 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = {
         SD_BUS_ERROR_MAP(BUS_ERROR_DEVICE_NOT_TAKEN,             EINVAL),
         SD_BUS_ERROR_MAP(BUS_ERROR_OPERATION_IN_PROGRESS,        EINPROGRESS),
         SD_BUS_ERROR_MAP(BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED,     EOPNOTSUPP),
+        SD_BUS_ERROR_MAP(BUS_ERROR_SESSION_BUSY,                 EBUSY),
 
 #if 0 /// UNNEEDED by elogind
         SD_BUS_ERROR_MAP(BUS_ERROR_AUTOMATIC_TIME_SYNC_ENABLED,  EALREADY),
@@ -83,6 +89,25 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = {
         SD_BUS_ERROR_MAP(BUS_ERROR_LINK_BUSY,                    EBUSY),
         SD_BUS_ERROR_MAP(BUS_ERROR_NETWORK_DOWN,                 ENETDOWN),
 
+        SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "FORMERR",               EBADMSG),
+        SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "SERVFAIL",              EHOSTDOWN),
+        SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "NXDOMAIN",              ENXIO),
+        SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "NOTIMP",                ENOSYS),
+        SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "REFUSED",               EACCES),
+        SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "YXDOMAIN",              EEXIST),
+        SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "YRRSET",                EEXIST),
+        SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "NXRRSET",               ENOENT),
+        SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "NOTAUTH",               EACCES),
+        SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "NOTZONE",               EREMOTE),
+        SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "BADVERS",               EBADMSG),
+        SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "BADKEY",                EKEYREJECTED),
+        SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "BADTIME",               EBADMSG),
+        SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "BADMODE",               EBADMSG),
+        SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "BADNAME",               EBADMSG),
+        SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "BADALG",                EBADMSG),
+        SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "BADTRUNC",              EBADMSG),
+        SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "BADCOOKIE",             EBADR),
+
         SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_TRANSFER,             ENXIO),
         SD_BUS_ERROR_MAP(BUS_ERROR_TRANSFER_IN_PROGRESS,         EBUSY),
 #endif // 0
index 26219bdeed514c51c7804a15800063572d75073e..378f7a377a5e150257786782621f5a6edb7f82a5 100644 (file)
@@ -70,11 +70,9 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_standard_errors[] = {
         SD_BUS_ERROR_MAP_END
 };
 
-/* GCC maps this magically to the beginning and end of the BUS_ERROR_MAP section.
- * Hide them; for currently unknown reasons they get exported to the shared libries
- * even without being listed in the sym file. */
-extern const sd_bus_error_map __start_BUS_ERROR_MAP[] _hidden_;
-extern const sd_bus_error_map __stop_BUS_ERROR_MAP[] _hidden_;
+/* GCC maps this magically to the beginning and end of the BUS_ERROR_MAP section */
+extern const sd_bus_error_map __start_BUS_ERROR_MAP[];
+extern const sd_bus_error_map __stop_BUS_ERROR_MAP[];
 
 /* Additional maps registered with sd_bus_error_add_map() are in this
  * NULL terminated array */
index 4f08ec19b3db2d82b40f090f0ffc2de63d5c4b29..4c912f582dde01e34d098256b50c9488c14675d9 100644 (file)
@@ -209,6 +209,9 @@ struct sd_bus {
         bool is_system:1;
         bool is_user:1;
         bool allow_interactive_authorization:1;
+        bool exit_on_disconnect:1;
+        bool exited:1;
+        bool exit_triggered:1;
 
         int use_memfd;
 
@@ -320,12 +323,13 @@ struct sd_bus {
         sd_bus_track *track_queue;
 
         LIST_HEAD(sd_bus_slot, slots);
+        LIST_HEAD(sd_bus_track, tracks);
 };
 
 #define BUS_DEFAULT_TIMEOUT ((usec_t) (25 * USEC_PER_SEC))
 
-#define BUS_WQUEUE_MAX 1024
-#define BUS_RQUEUE_MAX 64*1024
+#define BUS_WQUEUE_MAX (192*1024)
+#define BUS_RQUEUE_MAX (192*1024)
 
 #define BUS_MESSAGE_SIZE_MAX (64*1024*1024)
 #define BUS_AUTH_SIZE_MAX (64*1024)
index 364360ccaea16ebced20c2b87156899353f34d5d..cd5e9767470906d25ee7f37e93f344e508616f53 100644 (file)
@@ -212,9 +212,7 @@ _public_ sd_bus_slot* sd_bus_slot_unref(sd_bus_slot *slot) {
 
         bus_slot_disconnect(slot);
         free(slot->description);
-        free(slot);
-
-        return NULL;
+        return mfree(slot);
 }
 
 #if 0 /// UNNEEDED by elogind
index b2e562358bfd461c5a8831ef3ab5ba46ab8acc92..9714da690f6ee88fb5345b476651b4c11448929b 100644 (file)
 #include "bus-track.h"
 #include "bus-util.h"
 
+struct track_item {
+        unsigned n_ref;
+        char *name;
+        sd_bus_slot *slot;
+};
+
 struct sd_bus_track {
         unsigned n_ref;
+        unsigned n_adding; /* are we in the process of adding a new name? */
         sd_bus *bus;
         sd_bus_track_handler_t handler;
         void *userdata;
         Hashmap *names;
         LIST_FIELDS(sd_bus_track, queue);
         Iterator iterator;
-        bool in_queue;
-        bool modified;
+        bool in_list:1;    /* In bus->tracks? */
+        bool in_queue:1;   /* In bus->track_queue? */
+        bool modified:1;
+        bool recursive:1;
+
+        LIST_FIELDS(sd_bus_track, tracks);
 };
 
 #define MATCH_PREFIX                                        \
@@ -56,15 +67,45 @@ struct sd_bus_track {
                 _x;                                                     \
         })
 
+static struct track_item* track_item_free(struct track_item *i) {
+
+        if (!i)
+                return NULL;
+
+        sd_bus_slot_unref(i->slot);
+        free(i->name);
+        return mfree(i);
+}
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(struct track_item*, track_item_free);
+
 static void bus_track_add_to_queue(sd_bus_track *track) {
         assert(track);
 
+        /* Adds the bus track object to the queue of objects we should dispatch next, subject to a number of
+         * conditions. */
+
+        /* Already in the queue? */
         if (track->in_queue)
                 return;
 
+        /* if we are currently in the process of adding a new name, then let's not enqueue this just yet, let's wait
+         * until the addition is complete. */
+        if (track->n_adding > 0)
+                return;
+
+        /* still referenced? */
+        if (hashmap_size(track->names) > 0)
+                return;
+
+        /* Nothing to call? */
         if (!track->handler)
                 return;
 
+        /* Already closed? */
+        if (!track->in_list)
+                return;
+
         LIST_PREPEND(queue, track->bus->track_queue, track);
         track->in_queue = true;
 }
@@ -79,6 +120,24 @@ static void bus_track_remove_from_queue(sd_bus_track *track) {
         track->in_queue = false;
 }
 
+static int bus_track_remove_name_fully(sd_bus_track *track, const char *name) {
+        struct track_item *i;
+
+        assert(track);
+        assert(name);
+
+        i = hashmap_remove(track->names, name);
+        if (!i)
+                return 0;
+
+        track_item_free(i);
+
+        bus_track_add_to_queue(track);
+
+        track->modified = true;
+        return 1;
+}
+
 _public_ int sd_bus_track_new(
                 sd_bus *bus,
                 sd_bus_track **track,
@@ -102,6 +161,9 @@ _public_ int sd_bus_track_new(
         t->userdata = userdata;
         t->bus = sd_bus_ref(bus);
 
+        LIST_PREPEND(tracks, bus->tracks, t);
+        t->in_list = true;
+
         bus_track_add_to_queue(t);
 
         *track = t;
@@ -121,7 +183,7 @@ _public_ sd_bus_track* sd_bus_track_ref(sd_bus_track *track) {
 }
 
 _public_ sd_bus_track* sd_bus_track_unref(sd_bus_track *track) {
-        const char *n;
+        struct track_item *i;
 
         if (!track)
                 return NULL;
@@ -133,15 +195,16 @@ _public_ sd_bus_track* sd_bus_track_unref(sd_bus_track *track) {
                 return NULL;
         }
 
-        while ((n = hashmap_first_key(track->names)))
-                sd_bus_track_remove_name(track, n);
+        while ((i = hashmap_steal_first(track->names)))
+                track_item_free(i);
+
+        if (track->in_list)
+                LIST_REMOVE(tracks, track->bus->tracks, track);
 
         bus_track_remove_from_queue(track);
         hashmap_free(track->names);
         sd_bus_unref(track->bus);
-        free(track);
-
-        return NULL;
+        return mfree(track);
 }
 
 static int on_name_owner_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
@@ -156,49 +219,76 @@ static int on_name_owner_changed(sd_bus_message *message, void *userdata, sd_bus
         if (r < 0)
                 return 0;
 
-        sd_bus_track_remove_name(track, name);
+        bus_track_remove_name_fully(track, name);
         return 0;
 }
 
 _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) {
-        _cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot = NULL;
-        _cleanup_free_ char *n = NULL;
+        _cleanup_(track_item_freep) struct track_item *n = NULL;
+        struct track_item *i;
         const char *match;
         int r;
 
         assert_return(track, -EINVAL);
         assert_return(service_name_is_valid(name), -EINVAL);
 
+        i = hashmap_get(track->names, name);
+        if (i) {
+                if (track->recursive) {
+                        unsigned k = track->n_ref + 1;
+
+                        if (k < track->n_ref) /* Check for overflow */
+                                return -EOVERFLOW;
+
+                        track->n_ref = k;
+                }
+
+                bus_track_remove_from_queue(track);
+                return 0;
+        }
+
         r = hashmap_ensure_allocated(&track->names, &string_hash_ops);
         if (r < 0)
                 return r;
 
-        n = strdup(name);
+        n = new0(struct track_item, 1);
         if (!n)
                 return -ENOMEM;
+        n->name = strdup(name);
+        if (!n->name)
+                return -ENOMEM;
 
         /* First, subscribe to this name */
-        match = MATCH_FOR_NAME(n);
-        r = sd_bus_add_match(track->bus, &slot, match, on_name_owner_changed, track);
-        if (r < 0)
+        match = MATCH_FOR_NAME(name);
+
+        bus_track_remove_from_queue(track); /* don't dispatch this while we work in it */
+
+        track->n_adding++; /* make sure we aren't dispatched while we synchronously add this match */
+        r = sd_bus_add_match(track->bus, &n->slot, match, on_name_owner_changed, track);
+        track->n_adding--;
+        if (r < 0) {
+                bus_track_add_to_queue(track);
                 return r;
+        }
 
-        r = hashmap_put(track->names, n, slot);
-        if (r == -EEXIST)
-                return 0;
-        if (r < 0)
+        r = hashmap_put(track->names, n->name, n);
+        if (r < 0) {
+                bus_track_add_to_queue(track);
                 return r;
+        }
 
-        /* Second, check if it is currently existing, or maybe
-         * doesn't, or maybe disappeared already. */
-        r = sd_bus_get_name_creds(track->bus, n, 0, NULL);
+        /* Second, check if it is currently existing, or maybe doesn't, or maybe disappeared already. */
+        track->n_adding++; /* again, make sure this isn't dispatch while we are working in it */
+        r = sd_bus_get_name_creds(track->bus, name, 0, NULL);
+        track->n_adding--;
         if (r < 0) {
-                hashmap_remove(track->names, n);
+                hashmap_remove(track->names, name);
+                bus_track_add_to_queue(track);
                 return r;
         }
 
+        n->n_ref = 1;
         n = NULL;
-        slot = NULL;
 
         bus_track_remove_from_queue(track);
         track->modified = true;
@@ -207,37 +297,48 @@ _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) {
 }
 
 _public_ int sd_bus_track_remove_name(sd_bus_track *track, const char *name) {
-        _cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot = NULL;
-        _cleanup_free_ char *n = NULL;
+        struct track_item *i;
 
         assert_return(name, -EINVAL);
 
-        if (!track)
+        if (!track) /* Treat a NULL track object as an empty track object */
                 return 0;
 
-        slot = hashmap_remove2(track->names, (char*) name, (void**) &n);
-        if (!slot)
-                return 0;
+        if (!track->recursive)
+                return bus_track_remove_name_fully(track, name);
 
-        if (hashmap_isempty(track->names))
-                bus_track_add_to_queue(track);
+        i = hashmap_get(track->names, name);
+        if (!i)
+                return -EUNATCH;
+        if (i->n_ref <= 0)
+                return -EUNATCH;
 
-        track->modified = true;
+        i->n_ref--;
+
+        if (i->n_ref <= 0)
+                return bus_track_remove_name_fully(track, name);
 
         return 1;
 }
 
 _public_ unsigned sd_bus_track_count(sd_bus_track *track) {
-        if (!track)
+
+        if (!track) /* Let's consider a NULL object equivalent to an empty object */
                 return 0;
 
+        /* This signature really should have returned an int, so that we can propagate errors. But well, ... Also, note
+         * that this returns the number of names being watched, and multiple references to the same name are not
+         * counted. */
+
         return hashmap_size(track->names);
 }
 
 _public_ const char* sd_bus_track_contains(sd_bus_track *track, const char *name) {
-        assert_return(track, NULL);
         assert_return(name, NULL);
 
+        if (!track) /* Let's consider a NULL object equivalent to an empty object */
+                return NULL;
+
         return hashmap_get(track->names, (void*) name) ? name : NULL;
 }
 
@@ -273,6 +374,9 @@ _public_ int sd_bus_track_add_sender(sd_bus_track *track, sd_bus_message *m) {
         assert_return(track, -EINVAL);
         assert_return(m, -EINVAL);
 
+        if (sd_bus_message_get_bus(m) != track->bus)
+                return -EINVAL;
+
         sender = sd_bus_message_get_sender(m);
         if (!sender)
                 return -EINVAL;
@@ -283,9 +387,14 @@ _public_ int sd_bus_track_add_sender(sd_bus_track *track, sd_bus_message *m) {
 _public_ int sd_bus_track_remove_sender(sd_bus_track *track, sd_bus_message *m) {
         const char *sender;
 
-        assert_return(track, -EINVAL);
         assert_return(m, -EINVAL);
 
+        if (!track) /* Treat a NULL track object as an empty track object */
+                return 0;
+
+        if (sd_bus_message_get_bus(m) != track->bus)
+                return -EINVAL;
+
         sender = sd_bus_message_get_sender(m);
         if (!sender)
                 return -EINVAL;
@@ -303,7 +412,6 @@ void bus_track_dispatch(sd_bus_track *track) {
         int r;
 
         assert(track);
-        assert(track->in_queue);
         assert(track->handler);
 
         bus_track_remove_from_queue(track);
@@ -319,6 +427,34 @@ void bus_track_dispatch(sd_bus_track *track) {
         sd_bus_track_unref(track);
 }
 
+void bus_track_close(sd_bus_track *track) {
+        struct track_item *i;
+
+        assert(track);
+
+        /* Called whenever our bus connected is closed. If so, and our track object is non-empty, dispatch it
+         * immediately, as we are closing now, but first flush out all names. */
+
+        if (!track->in_list)
+                return; /* We already closed this one, don't close it again. */
+
+        /* Remember that this one is closed now */
+        LIST_REMOVE(tracks, track->bus->tracks, track);
+        track->in_list = false;
+
+        /* If there's no name in this one anyway, we don't have to dispatch */
+        if (hashmap_isempty(track->names))
+                return;
+
+        /* Let's flush out all names */
+        while ((i = hashmap_steal_first(track->names)))
+                track_item_free(i);
+
+        /* Invoke handler */
+        if (track->handler)
+                bus_track_dispatch(track);
+}
+
 #if 0 /// UNNEEDED by elogind
 _public_ void *sd_bus_track_get_userdata(sd_bus_track *track) {
         assert_return(track, NULL);
@@ -336,4 +472,56 @@ _public_ void *sd_bus_track_set_userdata(sd_bus_track *track, void *userdata) {
 
         return ret;
 }
+
+_public_ int sd_bus_track_set_recursive(sd_bus_track *track, int b) {
+        assert_return(track, -EINVAL);
+
+        if (track->recursive == !!b)
+                return 0;
+
+        if (!hashmap_isempty(track->names))
+                return -EBUSY;
+
+        track->recursive = b;
+        return 0;
+}
+
+_public_ int sd_bus_track_get_recursive(sd_bus_track *track) {
+        assert_return(track, -EINVAL);
+
+        return track->recursive;
+}
+
+_public_ int sd_bus_track_count_sender(sd_bus_track *track, sd_bus_message *m) {
+        const char *sender;
+
+        assert_return(m, -EINVAL);
+
+        if (!track) /* Let's consider a NULL object equivalent to an empty object */
+                return 0;
+
+        if (sd_bus_message_get_bus(m) != track->bus)
+                return -EINVAL;
+
+        sender = sd_bus_message_get_sender(m);
+        if (!sender)
+                return -EINVAL;
+
+        return sd_bus_track_count_name(track, sender);
+}
+
+_public_ int sd_bus_track_count_name(sd_bus_track *track, const char *name) {
+        struct track_item *i;
+
+        assert_return(service_name_is_valid(name), -EINVAL);
+
+        if (!track) /* Let's consider a NULL object equivalent to an empty object */
+                return 0;
+
+        i = hashmap_get(track->names, name);
+        if (!i)
+                return 0;
+
+        return i->n_ref;
+}
 #endif // 0
index 7d93a727d6a7222f8e839924c8bf1da68c01695b..26bd05f5c768ad258aa6df48be495cfefd587bec 100644 (file)
@@ -20,3 +20,4 @@
 ***/
 
 void bus_track_dispatch(sd_bus_track *track);
+void bus_track_close(sd_bus_track *track);
index c35bd5a01189e819d297d95d2610a5f63787fb1d..3c6b210bd2a7fc279e17bb7d2e7622765bb211a9 100644 (file)
@@ -109,6 +109,7 @@ static void bus_free(sd_bus *b) {
 
         assert(b);
         assert(!b->track_queue);
+        assert(!b->tracks);
 
         b->state = BUS_CLOSED;
 
@@ -2664,62 +2665,101 @@ null_message:
         return r;
 }
 
-static int process_closing(sd_bus *bus, sd_bus_message **ret) {
+static int bus_exit_now(sd_bus *bus) {
+        assert(bus);
+
+        /* Exit due to close, if this is requested. If this is bus object is attached to an event source, invokes
+         * sd_event_exit(), otherwise invokes libc exit(). */
+
+        if (bus->exited) /* did we already exit? */
+                return 0;
+        if (!bus->exit_triggered) /* was the exit condition triggered? */
+                return 0;
+        if (!bus->exit_on_disconnect) /* Shall we actually exit on disconnection? */
+                return 0;
+
+        bus->exited = true; /* never exit more than once */
+
+        log_debug("Bus connection disconnected, exiting.");
+
+        if (bus->event)
+                return sd_event_exit(bus->event, EXIT_FAILURE);
+        else
+                exit(EXIT_FAILURE);
+
+        assert_not_reached("exit() didn't exit?");
+}
+
+static int process_closing_reply_callback(sd_bus *bus, struct reply_callback *c) {
+        _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
-        struct reply_callback *c;
+        sd_bus_slot *slot;
         int r;
 
         assert(bus);
-        assert(bus->state == BUS_CLOSING);
+        assert(c);
 
-        c = ordered_hashmap_first(bus->reply_callbacks);
-        if (c) {
-                _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
-                sd_bus_slot *slot;
+        r = bus_message_new_synthetic_error(
+                        bus,
+                        c->cookie,
+                        &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Connection terminated"),
+                        &m);
+        if (r < 0)
+                return r;
 
-                /* First, fail all outstanding method calls */
-                r = bus_message_new_synthetic_error(
-                                bus,
-                                c->cookie,
-                                &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Connection terminated"),
-                                &m);
-                if (r < 0)
-                        return r;
+        r = bus_seal_synthetic_message(bus, m);
+        if (r < 0)
+                return r;
 
-                r = bus_seal_synthetic_message(bus, m);
-                if (r < 0)
-                        return r;
+        if (c->timeout != 0) {
+                prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx);
+                c->timeout = 0;
+        }
 
-                if (c->timeout != 0) {
-                        prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx);
-                        c->timeout = 0;
-                }
+        ordered_hashmap_remove(bus->reply_callbacks, &c->cookie);
+        c->cookie = 0;
+
+        slot = container_of(c, sd_bus_slot, reply_callback);
 
-                ordered_hashmap_remove(bus->reply_callbacks, &c->cookie);
-                c->cookie = 0;
+        bus->iteration_counter++;
 
-                slot = container_of(c, sd_bus_slot, reply_callback);
+        bus->current_message = m;
+        bus->current_slot = sd_bus_slot_ref(slot);
+        bus->current_handler = c->callback;
+        bus->current_userdata = slot->userdata;
+        r = c->callback(m, slot->userdata, &error_buffer);
+        bus->current_userdata = NULL;
+        bus->current_handler = NULL;
+        bus->current_slot = NULL;
+        bus->current_message = NULL;
 
-                bus->iteration_counter++;
+        if (slot->floating) {
+                bus_slot_disconnect(slot);
+                sd_bus_slot_unref(slot);
+        }
 
-                bus->current_message = m;
-                bus->current_slot = sd_bus_slot_ref(slot);
-                bus->current_handler = c->callback;
-                bus->current_userdata = slot->userdata;
-                r = c->callback(m, slot->userdata, &error_buffer);
-                bus->current_userdata = NULL;
-                bus->current_handler = NULL;
-                bus->current_slot = NULL;
-                bus->current_message = NULL;
+        sd_bus_slot_unref(slot);
 
-                if (slot->floating) {
-                        bus_slot_disconnect(slot);
-                        sd_bus_slot_unref(slot);
-                }
+        return bus_maybe_reply_error(m, r, &error_buffer);
+}
 
-                sd_bus_slot_unref(slot);
+static int process_closing(sd_bus *bus, sd_bus_message **ret) {
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+        struct reply_callback *c;
+        int r;
+
+        assert(bus);
+        assert(bus->state == BUS_CLOSING);
 
-                return bus_maybe_reply_error(m, r, &error_buffer);
+        /* First, fail all outstanding method calls */
+        c = ordered_hashmap_first(bus->reply_callbacks);
+        if (c)
+                return process_closing_reply_callback(bus, c);
+
+        /* Then, fake-drop all remaining bus tracking references */
+        if (bus->tracks) {
+                bus_track_close(bus->tracks);
+                return 1;
         }
 
         /* Then, synthesize a Disconnected message */
@@ -2751,6 +2791,10 @@ static int process_closing(sd_bus *bus, sd_bus_message **ret) {
         if (r != 0)
                 goto finish;
 
+        /* Nothing else to do, exit now, if the condition holds */
+        bus->exit_triggered = true;
+        (void) bus_exit_now(bus);
+
         if (ret) {
                 *ret = m;
                 m = NULL;
@@ -3833,3 +3877,23 @@ _public_ void sd_bus_default_flush_close(void) {
         flush_close(default_system_bus);
 }
 #endif // 0
+
+_public_ int sd_bus_set_exit_on_disconnect(sd_bus *bus, int b) {
+        assert_return(bus, -EINVAL);
+
+        /* Turns on exit-on-disconnect, and triggers it immediately if the bus connection was already
+         * disconnected. Note that this is triggered exclusively on disconnections triggered by the server side, never
+         * from the client side. */
+        bus->exit_on_disconnect = b;
+
+        /* If the exit condition was triggered already, exit immediately. */
+        return bus_exit_now(bus);
+}
+
+#if 0 /// UNNEEDED by elogind
+_public_ int sd_bus_get_exit_on_disconnect(sd_bus *bus) {
+        assert_return(bus, -EINVAL);
+
+        return bus->exit_on_disconnect;
+}
+#endif // 0
index cfd5a55457758a7ceadd8ab9d0299af6f7920926..c3673f08a65a0b1d8d8ff7b214fa442ff1630c03 100644 (file)
@@ -732,6 +732,7 @@ static void event_unmask_signal_data(sd_event *e, struct signal_data *d, int sig
 
                 /* If all the mask is all-zero we can get rid of the structure */
                 hashmap_remove(e->signal_data, &d->priority);
+                assert(!d->current);
                 safe_close(d->fd);
                 free(d);
                 return;
index c3f527d6570f83d7ad323e42fec039b5c4303418..a6687b0c9327b36c04bc358826f5989c6449a865 100644 (file)
@@ -153,6 +153,7 @@ int id128_read(const char *p, Id128Format f, sd_id128_t *ret) {
         return id128_read_fd(fd, f, ret);
 }
 
+#if 0 /// UNNEEDED by elogind
 int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync) {
         char buffer[36 + 2];
         size_t sz;
@@ -192,3 +193,17 @@ int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync) {
 
         return id128_write_fd(fd, f, id, do_sync);
 }
+
+void id128_hash_func(const void *p, struct siphash *state) {
+        siphash24_compress(p, 16, state);
+}
+
+int id128_compare_func(const void *a, const void *b) {
+        return memcmp(a, b, 16);
+}
+
+const struct hash_ops id128_hash_ops = {
+        .hash = id128_hash_func,
+        .compare = id128_compare_func,
+};
+#endif // 0
index 3ba59acbcab33ae3074f198c2b4bfb0efadc6d6c..e5262cdcda200c956c8442caff1df5df03467f91 100644 (file)
@@ -22,6 +22,8 @@
 #include <stdbool.h>
 
 #include "sd-id128.h"
+
+#include "hash-funcs.h"
 #include "macro.h"
 
 char *id128_to_uuid_string(sd_id128_t id, char s[37]);
@@ -41,5 +43,11 @@ typedef enum Id128Format {
 int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret);
 int id128_read(const char *p, Id128Format f, sd_id128_t *ret);
 
+#if 0 /// UNNEEDED by elogind
 int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync);
 int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync);
+
+void id128_hash_func(const void *p, struct siphash *state);
+int id128_compare_func(const void *a, const void *b) _pure_;
+extern const struct hash_ops id128_hash_ops;
+#endif // 0
index 9f47d04e61b26f1fe61750ae2858e87d4bf93172..d4450c70a003c357b0dafce92a542e2f67f87459 100644 (file)
@@ -129,6 +129,28 @@ _public_ int sd_id128_get_boot(sd_id128_t *ret) {
         return 0;
 }
 
+_public_ int sd_id128_get_invocation(sd_id128_t *ret) {
+        static thread_local sd_id128_t saved_invocation_id = {};
+        int r;
+
+        assert_return(ret, -EINVAL);
+
+        if (sd_id128_is_null(saved_invocation_id)) {
+                const char *e;
+
+                e = secure_getenv("INVOCATION_ID");
+                if (!e)
+                        return -ENXIO;
+
+                r = sd_id128_from_string(e, &saved_invocation_id);
+                if (r < 0)
+                        return r;
+        }
+
+        *ret = saved_invocation_id;
+        return 0;
+}
+
 static sd_id128_t make_v4_uuid(sd_id128_t id) {
         /* Stolen from generate_random_uuid() of drivers/char/random.c
          * in the kernel sources */
index f188a8e548fb8926e89ed037137b50c098eb39d8..2cb247488cc90ca58afb9d5b4cc643bd9cd8132c 100644 (file)
@@ -2,11 +2,11 @@
 #
 # Used by systemd --user instances.
 
-account  include system-auth
+account required pam_unix.so
 
 m4_ifdef(`HAVE_SELINUX',
 session  required pam_selinux.so close
 session  required pam_selinux.so nottys open
 )m4_dnl
 session  required pam_loginuid.so
-session  include system-auth
+session optional pam_elogind.so
index 5ff9ed7f2139c73c3b8e06b5f2fdc32a53949a71..5da9ae6a2d7536462726c7cd7469ff9741a35b48 100644 (file)
@@ -145,7 +145,7 @@ int elogind_setup_cgroups_agent(Manager *m) {
         if (!MANAGER_IS_SYSTEM(m))
                 return 0;
 
-        if (cg_unified() > 0) /* We don't need this anymore on the unified hierarchy */
+        if (cg_unified(SYSTEMD_CGROUP_CONTROLLER) > 0) /* We don't need this anymore on the unified hierarchy */
                 return 0;
 
         if (m->cgroups_agent_fd < 0) {
index 2eeaf0b9ef0586fdf46f2d57b89d03b28d5e2d8e..450fbc1ebad10f576218703b6c0242cce90d0569 100644 (file)
@@ -98,6 +98,34 @@ static OutputFlags get_output_flags(void) {
 }
 #endif // 0
 
+static int get_session_path(sd_bus *bus, const char *session_id, sd_bus_error *error, char **path) {
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        int r;
+        char *ans;
+
+        r = sd_bus_call_method(
+                        bus,
+                        "org.freedesktop.login1",
+                        "/org/freedesktop/login1",
+                        "org.freedesktop.login1.Manager",
+                        "GetSession",
+                        error, &reply,
+                        "s", session_id);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_read(reply, "o", &ans);
+        if (r < 0)
+                return r;
+
+        ans = strdup(ans);
+        if (!ans)
+                return -ENOMEM;
+
+        *path = ans;
+        return 0;
+}
+
 static int list_sessions(int argc, char *argv[], void *userdata) {
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
@@ -130,10 +158,38 @@ static int list_sessions(int argc, char *argv[], void *userdata) {
                 return bus_log_parse_error(r);
 
         if (arg_legend)
-                printf("%10s %10s %-16s %-16s\n", "SESSION", "UID", "USER", "SEAT");
+                printf("%10s %10s %-16s %-16s %-16s\n", "SESSION", "UID", "USER", "SEAT", "TTY");
 
         while ((r = sd_bus_message_read(reply, "(susso)", &id, &uid, &user, &seat, &object)) > 0) {
-                printf("%10s %10u %-16s %-16s\n", id, (unsigned) uid, user, seat);
+                _cleanup_(sd_bus_error_free) sd_bus_error error2 = SD_BUS_ERROR_NULL;
+                _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply2 = NULL;
+                _cleanup_free_ char *path = NULL;
+                const char *tty = NULL;
+
+                r = get_session_path(bus, id, &error2, &path);
+                if (r < 0)
+                        log_warning("Failed to get session path: %s", bus_error_message(&error, r));
+                else {
+                        r = sd_bus_get_property(
+                                        bus,
+                                        "org.freedesktop.login1",
+                                        path,
+                                        "org.freedesktop.login1.Session",
+                                        "TTY",
+                                        &error2,
+                                        &reply2,
+                                        "s");
+                        if (r < 0)
+                                log_warning("Failed to get TTY for session %s: %s",
+                                            id, bus_error_message(&error2, r));
+                        else {
+                                r = sd_bus_message_read(reply2, "s", &tty);
+                                if (r < 0)
+                                        return bus_log_parse_error(r);
+                        }
+                }
+
+                printf("%10s %10"PRIu32" %-16s %-16s %-16s\n", id, uid, user, seat, strna(tty));
                 k++;
         }
         if (r < 0)
@@ -180,7 +236,7 @@ static int list_users(int argc, char *argv[], void *userdata) {
                 printf("%10s %-16s\n", "UID", "USER");
 
         while ((r = sd_bus_message_read(reply, "(uso)", &uid, &user, &object)) > 0) {
-                printf("%10u %-16s\n", (unsigned) uid, user);
+                printf("%10"PRIu32" %-16s\n", uid, user);
                 k++;
         }
         if (r < 0)
@@ -479,9 +535,9 @@ static int print_session_status_info(sd_bus *bus, const char *path, bool *new_li
         printf("%s - ", strna(i.id));
 
         if (i.name)
-                printf("%s (%u)\n", i.name, (unsigned) i.uid);
+                printf("%s (%"PRIu32")\n", i.name, i.uid);
         else
-                printf("%u\n", (unsigned) i.uid);
+                printf("%"PRIu32"\n", i.uid);
 
         s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
         s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
@@ -494,7 +550,7 @@ static int print_session_status_info(sd_bus *bus, const char *path, bool *new_li
         if (i.leader > 0) {
                 _cleanup_free_ char *t = NULL;
 
-                printf("\t  Leader: %u", (unsigned) i.leader);
+                printf("\t  Leader: %"PRIu32, i.leader);
 
                 get_process_comm(i.leader, &t);
                 if (t)
@@ -608,9 +664,9 @@ static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line)
         *new_line = true;
 
         if (i.name)
-                printf("%s (%u)\n", i.name, (unsigned) i.uid);
+                printf("%s (%"PRIu32")\n", i.name, i.uid);
         else
-                printf("%u\n", (unsigned) i.uid);
+                printf("%"PRIu32"\n", i.uid);
 
         s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
         s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
@@ -908,26 +964,14 @@ static int show_session(int argc, char *argv[], void *userdata) {
 
         for (i = 1; i < argc; i++) {
                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-                _cleanup_(sd_bus_message_unrefp) sd_bus_message * reply = NULL;
-                const char *path = NULL;
+                _cleanup_free_ char *path = NULL;
 
-                r = sd_bus_call_method(
-                                bus,
-                                "org.freedesktop.login1",
-                                "/org/freedesktop/login1",
-                                "org.freedesktop.login1.Manager",
-                                "GetSession",
-                                &error, &reply,
-                                "s", argv[i]);
+                r = get_session_path(bus, argv[1], &error, &path);
                 if (r < 0) {
-                        log_error("Failed to get session: %s", bus_error_message(&error, r));
+                        log_error("Failed to get session path: %s", bus_error_message(&error, r));
                         return r;
                 }
 
-                r = sd_bus_message_read(reply, "o", &path);
-                if (r < 0)
-                        return bus_log_parse_error(r);
-
                 if (properties)
                         r = show_properties(bus, path, &new_line);
                 else
index baa6b7113c1038ff4f706589273ad3d421f29d10..90fb93bbaf85ecc6b80bd3383cfcc6381eb59dd7 100644 (file)
@@ -43,15 +43,12 @@ Button* button_new(Manager *m, const char *name) {
                 return NULL;
 
         b->name = strdup(name);
-        if (!b->name) {
-                free(b);
-                return NULL;
-        }
+        if (!b->name)
+                return mfree(b);
 
         if (hashmap_put(m->buttons, b->name, b) < 0) {
                 free(b->name);
-                free(b);
-                return NULL;
+                return mfree(b);
         }
 
         b->manager = m;
index eb5edd1cd5e11d2ce8ef2731668a1e65701497ad..6537fa04bfcbd6685fa5132d28ca508aea81b591 100644 (file)
@@ -34,15 +34,12 @@ Device* device_new(Manager *m, const char *sysfs, bool master) {
                 return NULL;
 
         d->sysfs = strdup(sysfs);
-        if (!d->sysfs) {
-                free(d);
-                return NULL;
-        }
+        if (!d->sysfs)
+                return mfree(d);
 
         if (hashmap_put(m->devices, d->sysfs, d) < 0) {
                 free(d->sysfs);
-                free(d);
-                return NULL;
+                return mfree(d);
         }
 
         d->manager = m;
index 6c78e0dddc9f0d8e255a2e2b2d0614001750084a..c93b24009bbc451ebca77c987c6f3606be18cd2f 100644 (file)
@@ -45,17 +45,14 @@ Inhibitor* inhibitor_new(Manager *m, const char* id) {
                 return NULL;
 
         i->state_file = strappend("/run/systemd/inhibit/", id);
-        if (!i->state_file) {
-                free(i);
-                return NULL;
-        }
+        if (!i->state_file)
+                return mfree(i);
 
         i->id = basename(i->state_file);
 
         if (hashmap_put(m->inhibitors, i->id, i) < 0) {
                 free(i->state_file);
-                free(i);
-                return NULL;
+                return mfree(i);
         }
 
         i->manager = m;
index ae42811dea4d12dcc3242fb5361cab4e09525424..194ebc1b794de88c7986d96c0ab7c992b7f6f0d5 100644 (file)
@@ -48,18 +48,15 @@ Seat *seat_new(Manager *m, const char *id) {
                 return NULL;
 
         s->state_file = strappend("/run/systemd/seats/", id);
-        if (!s->state_file) {
-                free(s);
-                return NULL;
-        }
+        if (!s->state_file)
+                return mfree(s);
 
         s->id = basename(s->state_file);
         s->manager = m;
 
         if (hashmap_put(m->seats, s->id, s) < 0) {
                 free(s->state_file);
-                free(s);
-                return NULL;
+                return mfree(s);
         }
 
         return s;
index 7b45f783002f0bc3f369160ae0da1dabaa308fae..a39486527ca8331a0f9e953ba458075c3778c25f 100644 (file)
@@ -775,7 +775,6 @@ int session_send_create_reply(Session *s, sd_bus_error *error) {
 #if 1 /// Additionally elogind saves the user state file
         user_save(s->user);
 #endif // 1
-
         p = session_bus_path(s);
         if (!p)
                 return -ENOMEM;
index 06ad99e1fec4eaeb6d0488de1bc4e6a0b6ca99b7..b8071264b9533e9d6eac985d8e0d9a969189f31f 100644 (file)
@@ -62,16 +62,13 @@ Session* session_new(Manager *m, const char *id) {
                 return NULL;
 
         s->state_file = strappend("/run/systemd/sessions/", id);
-        if (!s->state_file) {
-                free(s);
-                return NULL;
-        }
+        if (!s->state_file)
+                return mfree(s);
 
         s->devices = hashmap_new(&devt_hash_ops);
         if (!s->devices) {
                 free(s->state_file);
-                free(s);
-                return NULL;
+                return mfree(s);
         }
 
         s->id = basename(s->state_file);
@@ -79,8 +76,7 @@ Session* session_new(Manager *m, const char *id) {
         if (hashmap_put(m->sessions, s->id, s) < 0) {
                 hashmap_free(s->devices);
                 free(s->state_file);
-                free(s);
-                return NULL;
+                return mfree(s);
         }
 
         s->manager = m;
@@ -643,7 +639,7 @@ static int session_stop_scope(Session *s, bool force) {
                 return 0;
 
         /* Let's always abandon the scope first. This tells systemd that we are not interested anymore, and everything
-         * that is left in in the scope is "left-over". Informing systemd about this has the benefit that it will log
+         * that is left in the scope is "left-over". Informing systemd about this has the benefit that it will log
          * when killing any processes left after this point. */
         r = manager_abandon_scope(s->manager, s->scope, &error);
         if (r < 0)
index 171a4a670e7222530bce43830a6f0cdd95b5f6a1..304e6b512915f7ea4b00f7dabdf00737ff7b063c 100644 (file)
@@ -52,7 +52,6 @@
 #if 1 /// elogind uses a static value here
 #  define SPECIAL_USER_SLICE "user.slice"
 #endif // 1
-
 int user_new(User **out, Manager *m, uid_t uid, gid_t gid, const char *name) {
         _cleanup_(user_freep) User *u = NULL;
         char lu[DECIMAL_STR_MAX(uid_t) + 1];
@@ -363,14 +362,12 @@ static int user_mkdir_runtime_path(User *u) {
 
                 r = mount("tmpfs", u->runtime_path, "tmpfs", MS_NODEV|MS_NOSUID, t);
                 if (r < 0) {
-                        if (errno != EPERM) {
+                        if (errno != EPERM && errno != EACCES) {
                                 r = log_error_errno(errno, "Failed to mount per-user tmpfs directory %s: %m", u->runtime_path);
                                 goto fail;
                         }
 
-                        /* Lacking permissions, maybe
-                         * CAP_SYS_ADMIN-less container? In this case,
-                         * just use a normal directory. */
+                        log_debug_errno(errno, "Failed to mount per-user tmpfs directory %s, assuming containerized execution, ignoring: %m", u->runtime_path);
 
                         r = chmod_and_chown(u->runtime_path, 0700, u->uid, u->gid);
                         if (r < 0) {
@@ -638,9 +635,14 @@ int user_finalize(User *u) {
         if (k < 0)
                 r = k;
 
-        /* Clean SysV + POSIX IPC objects */
-        if (u->manager->remove_ipc) {
-                k = clean_ipc(u->uid);
+        /* Clean SysV + POSIX IPC objects, but only if this is not a system user. Background: in many setups cronjobs
+         * are run in full PAM and thus logind sessions, even if the code run doesn't belong to actual users but to
+         * system components. Since enable RemoveIPC= globally for all users, we need to be a bit careful with such
+         * cases, as we shouldn't accidentally remove a system service's IPC objects while it is running, just because
+         * a cronjob running as the same user just finished. Hence: exclude system users generally from IPC clean-up,
+         * and do it only for normal users. */
+        if (u->manager->remove_ipc && u->uid > SYSTEM_UID_MAX) {
+                k = clean_ipc_by_uid(u->uid);
                 if (k < 0)
                         r = k;
         }
@@ -938,7 +940,17 @@ int config_parse_user_tasks_max(
         assert(rvalue);
         assert(data);
 
-        /* First, try to parse as percentage */
+        if (isempty(rvalue)) {
+                *m = system_tasks_max_scale(DEFAULT_USER_TASKS_MAX_PERCENTAGE, 100U);
+                return 0;
+        }
+
+        if (streq(rvalue, "infinity")) {
+                *m = CGROUP_LIMIT_MAX;
+                return 0;
+        }
+
+        /* Try to parse as percentage */
         r = parse_percent(rvalue);
         if (r >= 0)
                 k = system_tasks_max_scale(r, 100U);
index 917aa72aa2fbed0a30797e596daf157f1dbd5c95..4fcc25a1e15718632911ba470fb853b5841951ae 100644 (file)
@@ -74,7 +74,7 @@ bool logind_wall_tty_filter(const char *tty, void *userdata) {
 static int warn_wall(Manager *m, usec_t n) {
         char date[FORMAT_TIMESTAMP_MAX] = {};
         _cleanup_free_ char *l = NULL;
-        bool left;
+        usec_t left;
         int r;
 
         assert(m);
@@ -148,7 +148,6 @@ int manager_setup_wall_message_timer(Manager *m) {
         if (!m->enable_wall_messages)
                 return 0;
 #endif // 1
-
         n = now(CLOCK_REALTIME);
         elapse = m->scheduled_shutdown_timeout;
 
index dab6e7f443d016cf23ca42cc9879222f384e4caa..2efa78c19ff638c31f4be7d9798d9617524ca027 100644 (file)
@@ -42,7 +42,6 @@
 #include "signal-util.h"
 #include "strv.h"
 #include "udev-util.h"
-
 /// Additional includes needed by elogind
 #include "cgroup.h"       // From src/core/
 #include "elogind.h"
@@ -74,7 +73,7 @@ static void manager_reset_config(Manager *m) {
         m->idle_action = HANDLE_IGNORE;
 
         m->runtime_dir_size = physical_memory_scale(10U, 100U); /* 10% */
-        m->user_tasks_max = system_tasks_max_scale(33U, 100U); /* 33% */
+        m->user_tasks_max = system_tasks_max_scale(DEFAULT_USER_TASKS_MAX_PERCENTAGE, 100U); /* 33% */
         m->sessions_max = 8192;
         m->inhibitors_max = 8192;
 
@@ -1047,7 +1046,7 @@ static int manager_parse_config_file(Manager *m) {
 #if 0 /// elogind parses its own config file
         assert(m);
 
-        return config_parse_many(PKGSYSCONFDIR "/logind.conf",
+        return config_parse_many_nulstr(PKGSYSCONFDIR "/logind.conf",
                                  CONF_PATHS_NULSTR("systemd/logind.conf.d"),
                                  "Login\0",
                                  config_item_perf_lookup, logind_gperf_lookup,
index b99ecbba5bc0f41a62747287c33b75d49d989908..2963f9fc4b42fcc2667fb57c3fd82144ffd604e8 100644 (file)
@@ -163,7 +163,7 @@ int add_base_acls_if_needed(acl_t *acl_p, const char *path) {
 
 int acl_search_groups(const char *path, char ***ret_groups) {
         _cleanup_strv_free_ char **g = NULL;
-        _cleanup_(acl_freep) acl_t acl = NULL;
+        _cleanup_(acl_free) acl_t acl = NULL;
         bool ret = false;
         acl_entry_t entry;
         int r;
index 5ea4e56087d3fd01b6310652a80dff2379db21d8..8bba92092f51eac37102818faba3cef111888d57 100644 (file)
@@ -1020,19 +1020,19 @@ static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_
                 return r;
 
         switch (type) {
+
         case SD_BUS_TYPE_STRING: {
-                const char *s;
                 char **p = userdata;
+                const char *s;
 
                 r = sd_bus_message_read_basic(m, type, &s);
                 if (r < 0)
-                        break;
+                        return r;
 
                 if (isempty(s))
-                        break;
+                        s = NULL;
 
-                r = free_and_strdup(p, s);
-                break;
+                return free_and_strdup(p, s);
         }
 
         case SD_BUS_TYPE_ARRAY: {
@@ -1041,13 +1041,12 @@ static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_
 
                 r = bus_message_read_strv_extend(m, &l);
                 if (r < 0)
-                        break;
+                        return r;
 
                 strv_free(*p);
                 *p = l;
                 l = NULL;
-
-                break;
+                return 0;
         }
 
         case SD_BUS_TYPE_BOOLEAN: {
@@ -1056,57 +1055,48 @@ static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_
 
                 r = sd_bus_message_read_basic(m, type, &b);
                 if (r < 0)
-                        break;
+                        return r;
 
                 *p = b;
-
-                break;
+                return 0;
         }
 
+        case SD_BUS_TYPE_INT32:
         case SD_BUS_TYPE_UINT32: {
-                uint32_t u;
-                uint32_t *p = userdata;
+                uint32_t u, *p = userdata;
 
                 r = sd_bus_message_read_basic(m, type, &u);
                 if (r < 0)
-                        break;
+                        return r;
 
                 *p = u;
-
-                break;
+                return 0;
         }
 
+        case SD_BUS_TYPE_INT64:
         case SD_BUS_TYPE_UINT64: {
-                uint64_t t;
-                uint64_t *p = userdata;
+                uint64_t t, *p = userdata;
 
                 r = sd_bus_message_read_basic(m, type, &t);
                 if (r < 0)
-                        break;
+                        return r;
 
                 *p = t;
-
-                break;
+                return 0;
         }
 
         case SD_BUS_TYPE_DOUBLE: {
-                double d;
-                double *p = userdata;
+                double d, *p = userdata;
 
                 r = sd_bus_message_read_basic(m, type, &d);
                 if (r < 0)
-                        break;
+                        return r;
 
                 *p = d;
+                return 0;
+        }}
 
-                break;
-        }
-
-        default:
-                break;
-        }
-
-        return r;
+        return -EOPNOTSUPP;
 }
 
 int bus_message_map_all_properties(
@@ -1246,12 +1236,13 @@ int bus_map_all_properties(
         return bus_message_map_all_properties(m, map, userdata);
 }
 
-int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
+int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **ret) {
+        _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
         int r;
 
         assert(transport >= 0);
         assert(transport < _BUS_TRANSPORT_MAX);
-        assert(bus);
+        assert(ret);
 
         assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
         assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
@@ -1261,26 +1252,35 @@ int bus_connect_transport(BusTransport transport, const char *host, bool user, s
         case BUS_TRANSPORT_LOCAL:
 #if 0 /// elogind does not support a user bus
                 if (user)
-                        r = sd_bus_default_user(bus);
+                        r = sd_bus_default_user(&bus);
                 else
 #endif // 0
-                        r = sd_bus_default_system(bus);
+                        r = sd_bus_default_system(&bus);
 
                 break;
 
         case BUS_TRANSPORT_REMOTE:
-                r = sd_bus_open_system_remote(bus, host);
+                r = sd_bus_open_system_remote(&bus, host);
                 break;
 
         case BUS_TRANSPORT_MACHINE:
-                r = sd_bus_open_system_machine(bus, host);
+                r = sd_bus_open_system_machine(&bus, host);
                 break;
 
         default:
                 assert_not_reached("Hmm, unknown transport type.");
         }
+        if (r < 0)
+                return r;
 
-        return r;
+        r = sd_bus_set_exit_on_disconnect(bus, true);
+        if (r < 0)
+                return r;
+
+        *ret = bus;
+        bus = NULL;
+
+        return 0;
 }
 
 #if 0 /// UNNEEDED by elogind
@@ -1334,6 +1334,25 @@ int bus_property_get_bool(
         return sd_bus_message_append_basic(reply, 'b', &b);
 }
 
+#if 0 /// UNNEEDED by elogind
+int bus_property_get_id128(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        sd_id128_t *id = userdata;
+
+        if (sd_id128_is_null(*id)) /* Add an empty array if the ID is zero */
+                return sd_bus_message_append(reply, "ay", 0);
+        else
+                return sd_bus_message_append_array(reply, 'y', id->bytes, 16);
+}
+#endif // 0
+
 #if __SIZEOF_SIZE_T__ != 8
 int bus_property_get_size(
                 sd_bus *bus,
index 88c2804d66c81eb33b792c8d40f592beaedba406..614f626e0ce27ab32ef67600701b18101c0390a2 100644 (file)
@@ -91,6 +91,9 @@ int bus_print_property(const char *name, sd_bus_message *property, bool value, b
 int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool value, bool all);
 
 int bus_property_get_bool(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
+#if 0 /// UNNEEDED by elogind
+int bus_property_get_id128(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
+#endif // 0
 
 #define bus_property_get_usec ((sd_bus_property_get_t) NULL)
 #define bus_property_set_usec ((sd_bus_property_set_t) NULL)
index 5ba296cc8ca76e462ad68bbdae55f75cb2c26572..8c60bdc1f2be77ae301b7d95a96ccde5ac87690d 100644 (file)
 #include "macro.h"
 #include "string-util.h"
 #include "strv.h"
+#include "user-util.h"
 
-static int clean_sysvipc_shm(uid_t delete_uid) {
+static bool match_uid_gid(uid_t subject_uid, gid_t subject_gid, uid_t delete_uid, gid_t delete_gid) {
+
+        if (uid_is_valid(delete_uid) && subject_uid == delete_uid)
+                return true;
+
+        if (gid_is_valid(delete_gid) && subject_gid == delete_gid)
+                return true;
+
+        return false;
+}
+
+static int clean_sysvipc_shm(uid_t delete_uid, gid_t delete_gid) {
         _cleanup_fclose_ FILE *f = NULL;
         char line[LINE_MAX];
         bool first = true;
@@ -77,7 +89,7 @@ static int clean_sysvipc_shm(uid_t delete_uid) {
                 if (n_attached > 0)
                         continue;
 
-                if (uid != delete_uid)
+                if (!match_uid_gid(uid, gid, delete_uid, delete_gid))
                         continue;
 
                 if (shmctl(shmid, IPC_RMID, NULL) < 0) {
@@ -89,7 +101,8 @@ static int clean_sysvipc_shm(uid_t delete_uid) {
                         ret = log_warning_errno(errno,
                                                 "Failed to remove SysV shared memory segment %i: %m",
                                                 shmid);
-                }
+                } else
+                        log_debug("Removed SysV shared memory segment %i.", shmid);
         }
 
         return ret;
@@ -98,7 +111,7 @@ fail:
         return log_warning_errno(errno, "Failed to read /proc/sysvipc/shm: %m");
 }
 
-static int clean_sysvipc_sem(uid_t delete_uid) {
+static int clean_sysvipc_sem(uid_t delete_uid, gid_t delete_gid) {
         _cleanup_fclose_ FILE *f = NULL;
         char line[LINE_MAX];
         bool first = true;
@@ -128,7 +141,7 @@ static int clean_sysvipc_sem(uid_t delete_uid) {
                            &semid, &uid, &gid, &cuid, &cgid) != 5)
                         continue;
 
-                if (uid != delete_uid)
+                if (!match_uid_gid(uid, gid, delete_uid, delete_gid))
                         continue;
 
                 if (semctl(semid, 0, IPC_RMID) < 0) {
@@ -140,7 +153,8 @@ static int clean_sysvipc_sem(uid_t delete_uid) {
                         ret = log_warning_errno(errno,
                                                 "Failed to remove SysV semaphores object %i: %m",
                                                 semid);
-                }
+                } else
+                        log_debug("Removed SysV semaphore %i.", semid);
         }
 
         return ret;
@@ -149,7 +163,7 @@ fail:
         return log_warning_errno(errno, "Failed to read /proc/sysvipc/sem: %m");
 }
 
-static int clean_sysvipc_msg(uid_t delete_uid) {
+static int clean_sysvipc_msg(uid_t delete_uid, gid_t delete_gid) {
         _cleanup_fclose_ FILE *f = NULL;
         char line[LINE_MAX];
         bool first = true;
@@ -180,7 +194,7 @@ static int clean_sysvipc_msg(uid_t delete_uid) {
                            &msgid, &cpid, &lpid, &uid, &gid, &cuid, &cgid) != 7)
                         continue;
 
-                if (uid != delete_uid)
+                if (!match_uid_gid(uid, gid, delete_uid, delete_gid))
                         continue;
 
                 if (msgctl(msgid, IPC_RMID, NULL) < 0) {
@@ -192,7 +206,8 @@ static int clean_sysvipc_msg(uid_t delete_uid) {
                         ret = log_warning_errno(errno,
                                                 "Failed to remove SysV message queue %i: %m",
                                                 msgid);
-                }
+                } else
+                        log_debug("Removed SysV message queue %i.", msgid);
         }
 
         return ret;
@@ -201,13 +216,13 @@ fail:
         return log_warning_errno(errno, "Failed to read /proc/sysvipc/msg: %m");
 }
 
-static int clean_posix_shm_internal(DIR *dir, uid_t uid) {
+static int clean_posix_shm_internal(DIR *dir, uid_t uid, gid_t gid) {
         struct dirent *de;
         int ret = 0, r;
 
         assert(dir);
 
-        FOREACH_DIRENT(de, dir, goto fail) {
+        FOREACH_DIRENT_ALL(de, dir, goto fail) {
                 struct stat st;
 
                 if (STR_IN_SET(de->d_name, "..", "."))
@@ -217,12 +232,11 @@ static int clean_posix_shm_internal(DIR *dir, uid_t uid) {
                         if (errno == ENOENT)
                                 continue;
 
-                        log_warning_errno(errno, "Failed to stat() POSIX shared memory segment %s: %m", de->d_name);
-                        ret = -errno;
+                        ret = log_warning_errno(errno, "Failed to stat() POSIX shared memory segment %s: %m", de->d_name);
                         continue;
                 }
 
-                if (st.st_uid != uid)
+                if (!match_uid_gid(st.st_uid, st.st_gid, uid, gid))
                         continue;
 
                 if (S_ISDIR(st.st_mode)) {
@@ -230,12 +244,10 @@ static int clean_posix_shm_internal(DIR *dir, uid_t uid) {
 
                         kid = xopendirat(dirfd(dir), de->d_name, O_NOFOLLOW|O_NOATIME);
                         if (!kid) {
-                                if (errno != ENOENT) {
-                                        log_warning_errno(errno, "Failed to enter shared memory directory %s: %m", de->d_name);
-                                        ret = -errno;
-                                }
+                                if (errno != ENOENT)
+                                        ret = log_warning_errno(errno, "Failed to enter shared memory directory %s: %m", de->d_name);
                         } else {
-                                r = clean_posix_shm_internal(kid, uid);
+                                r = clean_posix_shm_internal(kid, uid, gid);
                                 if (r < 0)
                                         ret = r;
                         }
@@ -245,9 +257,9 @@ static int clean_posix_shm_internal(DIR *dir, uid_t uid) {
                                 if (errno == ENOENT)
                                         continue;
 
-                                log_warning_errno(errno, "Failed to remove POSIX shared memory directory %s: %m", de->d_name);
-                                ret = -errno;
-                        }
+                                ret = log_warning_errno(errno, "Failed to remove POSIX shared memory directory %s: %m", de->d_name);
+                        } else
+                                log_debug("Removed POSIX shared memory directory %s", de->d_name);
                 } else {
 
                         if (unlinkat(dirfd(dir), de->d_name, 0) < 0) {
@@ -255,20 +267,19 @@ static int clean_posix_shm_internal(DIR *dir, uid_t uid) {
                                 if (errno == ENOENT)
                                         continue;
 
-                                log_warning_errno(errno, "Failed to remove POSIX shared memory segment %s: %m", de->d_name);
-                                ret = -errno;
-                        }
+                                ret = log_warning_errno(errno, "Failed to remove POSIX shared memory segment %s: %m", de->d_name);
+                        } else
+                                log_debug("Removed POSIX shared memory segment %s", de->d_name);
                 }
         }
 
         return ret;
 
 fail:
-        log_warning_errno(errno, "Failed to read /dev/shm: %m");
-        return -errno;
+        return log_warning_errno(errno, "Failed to read /dev/shm: %m");
 }
 
-static int clean_posix_shm(uid_t uid) {
+static int clean_posix_shm(uid_t uid, gid_t gid) {
         _cleanup_closedir_ DIR *dir = NULL;
 
         dir = opendir("/dev/shm");
@@ -279,11 +290,11 @@ static int clean_posix_shm(uid_t uid) {
                 return log_warning_errno(errno, "Failed to open /dev/shm: %m");
         }
 
-        return clean_posix_shm_internal(dir, uid);
+        return clean_posix_shm_internal(dir, uid, gid);
 }
 
 #if 0 /// UNNEEDED by elogind
-static int clean_posix_mq(uid_t uid) {
+static int clean_posix_mq(uid_t uid, gid_t gid) {
         _cleanup_closedir_ DIR *dir = NULL;
         struct dirent *de;
         int ret = 0;
@@ -296,7 +307,7 @@ static int clean_posix_mq(uid_t uid) {
                 return log_warning_errno(errno, "Failed to open /dev/mqueue: %m");
         }
 
-        FOREACH_DIRENT(de, dir, goto fail) {
+        FOREACH_DIRENT_ALL(de, dir, goto fail) {
                 struct stat st;
                 char fn[1+strlen(de->d_name)+1];
 
@@ -313,7 +324,7 @@ static int clean_posix_mq(uid_t uid) {
                         continue;
                 }
 
-                if (st.st_uid != uid)
+                if (!match_uid_gid(st.st_uid, st.st_gid, uid, gid))
                         continue;
 
                 fn[0] = '/';
@@ -326,7 +337,8 @@ static int clean_posix_mq(uid_t uid) {
                         ret = log_warning_errno(errno,
                                                 "Failed to unlink POSIX message queue %s: %m",
                                                 fn);
-                }
+                } else
+                        log_debug("Removed POSIX message queue %s", fn);
         }
 
         return ret;
@@ -336,34 +348,48 @@ fail:
 }
 #endif // 0
 
-int clean_ipc(uid_t uid) {
+int clean_ipc(uid_t uid, gid_t gid) {
         int ret = 0, r;
 
-        /* Refuse to clean IPC of the root and system users */
-        if (uid <= SYSTEM_UID_MAX)
+        /* Anything to do? */
+        if (!uid_is_valid(uid) && !gid_is_valid(gid))
+                return 0;
+
+        /* Refuse to clean IPC of the root user */
+        if (uid == 0 && gid == 0)
                 return 0;
 
-        r = clean_sysvipc_shm(uid);
+        r = clean_sysvipc_shm(uid, gid);
         if (r < 0)
                 ret = r;
 
-        r = clean_sysvipc_sem(uid);
+        r = clean_sysvipc_sem(uid, gid);
         if (r < 0)
                 ret = r;
 
-        r = clean_sysvipc_msg(uid);
+        r = clean_sysvipc_msg(uid, gid);
         if (r < 0)
                 ret = r;
 
-        r = clean_posix_shm(uid);
+        r = clean_posix_shm(uid, gid);
         if (r < 0)
                 ret = r;
 
 #if 0 /// elogind does not use mq_open anywhere
-        r = clean_posix_mq(uid);
+        r = clean_posix_mq(uid, gid);
         if (r < 0)
                 ret = r;
 #endif // 0
 
         return ret;
 }
+
+int clean_ipc_by_uid(uid_t uid) {
+        return clean_ipc(uid, GID_INVALID);
+}
+
+#if 0 /// UNNEEDED by elogind
+int clean_ipc_by_gid(gid_t gid) {
+        return clean_ipc(UID_INVALID, gid);
+}
+#endif // 0
index 44a83afcf703dc1a1f960aba6dd51ef12abfa014..7cd896df0ec36f04b722fd162f5ae1ed5649a5e2 100644 (file)
@@ -21,4 +21,8 @@
 
 #include <sys/types.h>
 
-int clean_ipc(uid_t uid);
+int clean_ipc(uid_t uid, gid_t gid);
+int clean_ipc_by_uid(uid_t uid);
+#if 0 /// UNNEEDED by elogind
+int clean_ipc_by_gid(gid_t gid);
+#endif // 0
index 8e6fffe1876addb2b85490761d82513293f0c46f..90f3167f523dc39233743d0b0f6b9027e9456bc8 100644 (file)
@@ -395,22 +395,18 @@ int config_parse(const char *unit,
         return 0;
 }
 
-/* Parse each config file in the specified directories. */
-int config_parse_many(const char *conf_file,
-                      const char *conf_file_dirs,
-                      const char *sections,
-                      ConfigItemLookup lookup,
-                      const void *table,
-                      bool relaxed,
-                      void *userdata) {
-        _cleanup_strv_free_ char **files = NULL;
+static int config_parse_many_files(
+                const char *conf_file,
+                char **files,
+                const char *sections,
+                ConfigItemLookup lookup,
+                const void *table,
+                bool relaxed,
+                void *userdata) {
+
         char **fn;
         int r;
 
-        r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
-        if (r < 0)
-                return r;
-
         if (conf_file) {
                 r = config_parse(NULL, conf_file, NULL, sections, lookup, table, relaxed, false, true, userdata);
                 if (r < 0)
@@ -426,6 +422,58 @@ int config_parse_many(const char *conf_file,
         return 0;
 }
 
+/* Parse each config file in the directories specified as nulstr. */
+int config_parse_many_nulstr(
+                const char *conf_file,
+                const char *conf_file_dirs,
+                const char *sections,
+                ConfigItemLookup lookup,
+                const void *table,
+                bool relaxed,
+                void *userdata) {
+
+        _cleanup_strv_free_ char **files = NULL;
+        int r;
+
+        r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
+        if (r < 0)
+                return r;
+
+        return config_parse_many_files(conf_file, files,
+                                       sections, lookup, table, relaxed, userdata);
+}
+
+#if 0 /// UNNEEDED by elogind
+/* Parse each config file in the directories specified as strv. */
+int config_parse_many(
+                const char *conf_file,
+                const char* const* conf_file_dirs,
+                const char *dropin_dirname,
+                const char *sections,
+                ConfigItemLookup lookup,
+                const void *table,
+                bool relaxed,
+                void *userdata) {
+
+        _cleanup_strv_free_ char **dropin_dirs = NULL;
+        _cleanup_strv_free_ char **files = NULL;
+        const char *suffix;
+        int r;
+
+        suffix = strjoina("/", dropin_dirname);
+        r = strv_extend_strv_concat(&dropin_dirs, (char**) conf_file_dirs, suffix);
+        if (r < 0)
+                return r;
+
+        r = conf_files_list_strv(&files, ".conf", NULL, (const char* const*) dropin_dirs);
+        if (r < 0)
+                return r;
+
+        return config_parse_many_files(conf_file, files,
+                                       sections, lookup, table, relaxed, userdata);
+}
+#endif // 0
+
 #define DEFINE_PARSER(type, vartype, conv_func)                         \
         int config_parse_##type(                                        \
                         const char *unit,                               \
@@ -459,7 +507,10 @@ int config_parse_many(const char *conf_file,
 
 DEFINE_PARSER(int, int, safe_atoi);
 DEFINE_PARSER(long, long, safe_atoli);
+#if 0 /// UNNEEDED by elogind
+DEFINE_PARSER(uint16, uint16_t, safe_atou16);
 DEFINE_PARSER(uint32, uint32_t, safe_atou32);
+#endif // 0
 DEFINE_PARSER(uint64, uint64_t, safe_atou64);
 DEFINE_PARSER(unsigned, unsigned, safe_atou);
 DEFINE_PARSER(double, double, safe_atod);
index 627aacb2eb60377284f5f021b8ad6d410b4a108f..76d60232208394ec14e727d5d063f42c1f3cc3e4 100644 (file)
@@ -84,30 +84,47 @@ int config_item_table_lookup(const void *table, const char *section, const char
  * ConfigPerfItem tables */
 int config_item_perf_lookup(const void *table, const char *section, const char *lvalue, ConfigParserCallback *func, int *ltype, void **data, void *userdata);
 
-int config_parse(const char *unit,
-                 const char *filename,
-                 FILE *f,
-                 const char *sections,  /* nulstr */
-                 ConfigItemLookup lookup,
-                 const void *table,
-                 bool relaxed,
-                 bool allow_include,
-                 bool warn,
-                 void *userdata);
-
-int config_parse_many(const char *conf_file,      /* possibly NULL */
-                      const char *conf_file_dirs, /* nulstr */
-                      const char *sections,       /* nulstr */
-                      ConfigItemLookup lookup,
-                      const void *table,
-                      bool relaxed,
-                      void *userdata);
+int config_parse(
+                const char *unit,
+                const char *filename,
+                FILE *f,
+                const char *sections,  /* nulstr */
+                ConfigItemLookup lookup,
+                const void *table,
+                bool relaxed,
+                bool allow_include,
+                bool warn,
+                void *userdata);
+
+int config_parse_many_nulstr(
+                const char *conf_file,      /* possibly NULL */
+                const char *conf_file_dirs, /* nulstr */
+                const char *sections,       /* nulstr */
+                ConfigItemLookup lookup,
+                const void *table,
+                bool relaxed,
+                void *userdata);
+
+#if 0 /// UNNEEDED by elogind
+int config_parse_many(
+                const char *conf_file,      /* possibly NULL */
+                const char* const* conf_file_dirs,
+                const char *dropin_dirname,
+                const char *sections,       /* nulstr */
+                ConfigItemLookup lookup,
+                const void *table,
+                bool relaxed,
+                void *userdata);
+#endif // 0
 
 /* Generic parsers */
 int config_parse_int(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_unsigned(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_long(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+#if 0 /// UNNEEDED by elogind
+int config_parse_uint16(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_uint32(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+#endif // 0
 int config_parse_uint64(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_double(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line,  const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_iec_size(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
index bb3e17fee2af206041162b7f0297c9cde520a461..184a0f57846dcb520ed79cd6fec9adc93bcafa36 100644 (file)
@@ -36,6 +36,7 @@
 #include "process-util.h"
 #include "signal-util.h"
 #include "string-util.h"
+#include "strv.h"
 #include "terminal-util.h"
 
 static pid_t pager_pid = 0;
@@ -71,7 +72,7 @@ int pager_open(bool no_pager, bool jump_to_end) {
                 pager = getenv("PAGER");
 
         /* If the pager is explicitly turned off, honour it */
-        if (pager && (pager[0] == 0 || streq(pager, "cat")))
+        if (pager && STR_IN_SET(pager, "", "cat"))
                 return 0;
 
         /* Determine and cache number of columns before we spawn the
index 7d47e79ebf1493c151285b51eb0c28e8c45c4f77..a57ebacd2a124bf2a74dccf68dffd95f32c2710a 100644 (file)
@@ -59,7 +59,7 @@ int parse_sleep_config(const char *verb, char ***_modes, char ***_states) {
                 {}
         };
 
-        config_parse_many(PKGSYSCONFDIR "/sleep.conf",
+        config_parse_many_nulstr(PKGSYSCONFDIR "/sleep.conf",
                           CONF_PATHS_NULSTR("systemd/sleep.conf.d"),
                           "Sleep\0", config_item_table_lookup, items,
                           false, NULL);
index ae5cba51ba65cd07799dc3af9a4473207b615c8b..997cf9f00bca1ab3677067fd30b1ac18d6b59c27 100644 (file)
@@ -153,6 +153,10 @@ int sd_bus_set_allow_interactive_authorization(sd_bus *bus, int b);
 #if 0 /// UNNEEDED by elogind
 int sd_bus_get_allow_interactive_authorization(sd_bus *bus);
 #endif // 0
+int sd_bus_set_exit_on_disconnect(sd_bus *bus, int b);
+#if 0 /// UNNEEDED by elogind
+int sd_bus_get_exit_on_disconnect(sd_bus *bus);
+#endif // 0
 
 int sd_bus_start(sd_bus *ret);
 
@@ -506,8 +510,18 @@ int sd_bus_track_remove_sender(sd_bus_track *track, sd_bus_message *m);
 int sd_bus_track_add_name(sd_bus_track *track, const char *name);
 int sd_bus_track_remove_name(sd_bus_track *track, const char *name);
 
+#if 0 /// UNNEEDED by elogind
+int sd_bus_track_set_recursive(sd_bus_track *track, int b);
+int sd_bus_track_get_recursive(sd_bus_track *track);
+#endif // 0
+
 unsigned sd_bus_track_count(sd_bus_track *track);
-const char* sd_bus_track_contains(sd_bus_track *track, const char *names);
+#if 0 /// UNNEEDED by elogind
+int sd_bus_track_count_sender(sd_bus_track *track, sd_bus_message *m);
+int sd_bus_track_count_name(sd_bus_track *track, const char *name);
+#endif // 0
+
+const char* sd_bus_track_contains(sd_bus_track *track, const char *name);
 const char* sd_bus_track_first(sd_bus_track *track);
 const char* sd_bus_track_next(sd_bus_track *track);
 
index 4dff0b9b811df5d61cea402907a77294aaedb556..ee011b1861b7531d83d67486cb74865a2dd5fbd8 100644 (file)
@@ -45,8 +45,8 @@ int sd_id128_from_string(const char *s, sd_id128_t *ret);
 int sd_id128_randomize(sd_id128_t *ret);
 
 int sd_id128_get_machine(sd_id128_t *ret);
-
 int sd_id128_get_boot(sd_id128_t *ret);
+int sd_id128_get_invocation(sd_id128_t *ret);
 
 #define SD_ID128_MAKE(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) \
         ((const sd_id128_t) { .bytes = { 0x##v0, 0x##v1, 0x##v2, 0x##v3, 0x##v4, 0x##v5, 0x##v6, 0x##v7, \
index 3c44d63021bce5ebf69cc12eeca6474d6a328264..79246ae0600d4d9b4b08adb76dc82e321146b391 100644 (file)
@@ -40,6 +40,7 @@ _SD_BEGIN_DECLARATIONS;
 #define SD_MESSAGE_JOURNAL_USAGE    SD_ID128_MAKE(ec,38,7f,57,7b,84,4b,8f,a9,48,f3,3c,ad,9a,75,e6)
 
 #define SD_MESSAGE_COREDUMP         SD_ID128_MAKE(fc,2e,22,bc,6e,e6,47,b6,b9,07,29,ab,34,a2,50,b1)
+#define SD_MESSAGE_TRUNCATED_CORE   SD_ID128_MAKE(5a,ad,d8,e9,54,dc,4b,1a,8c,95,4d,63,fd,9e,11,37)
 
 #define SD_MESSAGE_SESSION_START    SD_ID128_MAKE(8d,45,62,0c,1a,43,48,db,b1,74,10,da,57,c6,0c,66)
 #define SD_MESSAGE_SESSION_STOP     SD_ID128_MAKE(33,54,93,94,24,b4,45,6d,98,02,ca,83,33,ed,42,4a)
index 9f021725001d2c40190ae0c99969de9d2933eb0a..5e2d2c60e600df57e31917a317c361339933601a 100644 (file)
@@ -112,7 +112,7 @@ static int get_current_runlevel(Context *c) {
                 if (r < 0)
                         return log_warning_errno(r, "Failed to get state: %s", bus_error_message(&error, r));
 
-                if (streq(state, "active") || streq(state, "reloading"))
+                if (STR_IN_SET(state, "active", "reloading"))
                         return table[i].runlevel;
         }